Windows: Deny writes/truncation to files w RO attr
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSWrite.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSWrite.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 static
42 NTSTATUS
43 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
44                 IN PIRP Irp,
45                 IN LARGE_INTEGER StartingByte,
46                 IN ULONG ByteCount,
47                 IN BOOLEAN ForceFlush);
48 static
49 NTSTATUS
50 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
51                    IN PIRP Irp,
52                    IN LARGE_INTEGER StartingByte,
53                    IN ULONG ByteCount);
54
55 static
56 NTSTATUS
57 AFSNonCachedWriteDirect( IN PDEVICE_OBJECT DeviceObject,
58                          IN PIRP Irp,
59                          IN LARGE_INTEGER StartingByte,
60                          IN ULONG ByteCount);
61
62 static
63 NTSTATUS
64 AFSExtendingWrite( IN AFSFcb *Fcb,
65                    IN PFILE_OBJECT FileObject,
66                    IN LONGLONG NewLength);
67
68 //
69 // Function: AFSWrite
70 //
71 // Description:
72 //
73 //      This is the dispatch handler for the IRP_MJ_WRITE request
74 //
75 // Return:
76 //
77 //      A status is returned for the function
78 //
79 NTSTATUS
80 AFSWrite( IN PDEVICE_OBJECT LibDeviceObject,
81           IN PIRP Irp)
82 {
83
84     UNREFERENCED_PARAMETER(LibDeviceObject);
85     NTSTATUS ntStatus = STATUS_SUCCESS;
86
87     __try
88     {
89
90         ntStatus = AFSCommonWrite( AFSRDRDeviceObject, Irp, NULL, FALSE);
91     }
92     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
93     {
94
95         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
96     }
97
98     return ntStatus;
99 }
100
101 NTSTATUS
102 AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
103                 IN PIRP Irp,
104                 IN HANDLE OnBehalfOf,
105                 IN BOOLEAN bRetry)
106 {
107
108     NTSTATUS           ntStatus = STATUS_SUCCESS;
109     AFSDeviceExt      *pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
110     IO_STACK_LOCATION *pIrpSp;
111     AFSFcb            *pFcb = NULL;
112     AFSCcb            *pCcb = NULL;
113     AFSNonPagedFcb    *pNPFcb = NULL;
114     ULONG              ulByteCount = 0;
115     LARGE_INTEGER      liStartingByte;
116     PFILE_OBJECT       pFileObject;
117     BOOLEAN            bPagingIo = FALSE;
118     BOOLEAN            bNonCachedIo = FALSE;
119     BOOLEAN            bReleaseMain = FALSE;
120     BOOLEAN            bReleaseSectionObject = FALSE;
121     BOOLEAN            bReleasePaging = FALSE;
122     BOOLEAN            bExtendingWrite = FALSE;
123     BOOLEAN            bSynchronousFo = FALSE;
124     BOOLEAN            bWriteToEndOfFile = FALSE;
125     BOOLEAN            bWait = FALSE;
126     BOOLEAN            bCompleteIrp = TRUE;
127     BOOLEAN            bForceFlush = FALSE;
128     BOOLEAN            bLockOK;
129     HANDLE             hCallingUser = OnBehalfOf;
130     ULONGLONG          ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
131     AFSDeviceExt       *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
132
133     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
134
135     __Enter
136     {
137
138         Irp->IoStatus.Information = 0;
139
140         pFileObject = pIrpSp->FileObject;
141
142         //
143         // Extract the fileobject references
144         //
145
146         pFcb = (AFSFcb *)pFileObject->FsContext;
147         pCcb = (AFSCcb *)pFileObject->FsContext2;
148
149         ObReferenceObject( pFileObject);
150
151         if( pFcb == NULL)
152         {
153
154             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
155                           AFS_TRACE_LEVEL_ERROR,
156                           "AFSCommonWrite Attempted write (%p) when pFcb == NULL\n",
157                           Irp));
158
159             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
160         }
161
162         pNPFcb = pFcb->NPFcb;
163
164         //
165         // If we are in shutdown mode then fail the request
166         //
167
168         if( BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
169         {
170
171             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
172                           AFS_TRACE_LEVEL_WARNING,
173                           "AFSCommonWrite (%p) Open request after shutdown\n",
174                           Irp));
175
176             try_return( ntStatus = STATUS_TOO_LATE);
177         }
178
179         liStartingByte = pIrpSp->Parameters.Write.ByteOffset;
180         bPagingIo      = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
181         bNonCachedIo   = BooleanFlagOn( Irp->Flags, IRP_NOCACHE);
182         bWait          = IoIsOperationSynchronous( Irp);
183         ulByteCount    = pIrpSp->Parameters.Write.Length;
184         bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
185
186         if( pFcb->Header.NodeTypeCode != AFS_IOCTL_FCB &&
187             pFcb->Header.NodeTypeCode != AFS_FILE_FCB  &&
188             pFcb->Header.NodeTypeCode != AFS_SPECIAL_SHARE_FCB)
189         {
190
191             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
192                           AFS_TRACE_LEVEL_ERROR,
193                           "AFSCommonWrite Attempted write (%p) on an invalid node type %08lX\n",
194                           Irp,
195                           pFcb->Header.NodeTypeCode));
196
197             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
198         }
199
200         //
201         // If this is a write against an IOCtl node then handle it
202         // in a different pathway
203         //
204
205         if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB)
206         {
207
208             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
209                           AFS_TRACE_LEVEL_VERBOSE,
210                           "AFSCommonWrite (%p) Processing file (PIOCTL) Offset %0I64X Length %08lX Irp Flags %08lX\n",
211                           Irp,
212                           liStartingByte.QuadPart,
213                           ulByteCount,
214                           Irp->Flags));
215
216             ntStatus = AFSIOCtlWrite( DeviceObject,
217                                       Irp);
218
219             try_return( ntStatus);
220         }
221         else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
222         {
223
224             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
225                           AFS_TRACE_LEVEL_VERBOSE,
226                           "AFSCommonWrite (%p) Processing file (SHARE) Offset %0I64X Length %08lX Irp Flags %08lX\n",
227                           Irp,
228                           liStartingByte.QuadPart,
229                           ulByteCount,
230                           Irp->Flags));
231
232             ntStatus = AFSShareWrite( DeviceObject,
233                                       Irp);
234
235             try_return( ntStatus);
236         }
237
238         //
239         // Is the Cache not there yet?  Exit.
240         //
241         if( !BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE) &&
242             !BooleanFlagOn( pRDRDevExt->DeviceFlags, AFS_REDIR_INIT_PERFORM_SERVICE_IO) &&
243             NULL == pDeviceExt->Specific.RDR.CacheFileObject)
244         {
245
246             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
247                           AFS_TRACE_LEVEL_ERROR,
248                           "AFSCommonWrite (%p) Request failed due to AFS cache closed\n",
249                           Irp));
250
251             try_return( ntStatus = STATUS_TOO_LATE );
252         }
253
254         if( pFcb->ObjectInformation->VolumeCB != NULL &&
255             BooleanFlagOn( pFcb->ObjectInformation->VolumeCB->VolumeInformation.FileSystemAttributes, FILE_READ_ONLY_VOLUME))
256         {
257
258             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
259                           AFS_TRACE_LEVEL_ERROR,
260                           "AFSCommonWrite (%p) Request failed due to read only volume\n",
261                           Irp));
262
263             try_return( ntStatus = STATUS_MEDIA_WRITE_PROTECTED);
264         }
265
266         //
267         // We need to know on whose behalf we have been called (which
268         // we will eventually tell to the server - for non paging
269         // writes).  If we were posted then we were told.  If this is
270         // the first time we saw the irp then we grab it now.
271         //
272         if( NULL == OnBehalfOf )
273         {
274
275             hCallingUser = PsGetCurrentProcessId();
276         }
277         else
278         {
279
280             hCallingUser = OnBehalfOf;
281         }
282
283         //
284         // Check for zero length write
285         //
286
287         if( ulByteCount == 0)
288         {
289
290             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
291                           AFS_TRACE_LEVEL_VERBOSE,
292                           "AFSCommonWrite (%p) Request completed due to zero length\n",
293                           Irp));
294
295             try_return( ntStatus);
296         }
297
298         //
299         // Is this Fcb valid???
300         //
301
302         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID))
303         {
304
305             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
306                           AFS_TRACE_LEVEL_ERROR,
307                           "AFSCommonWrite (%p) Failing request due to INVALID fcb\n",
308                           Irp));
309
310             try_return( ntStatus = STATUS_FILE_DELETED);
311         }
312
313         if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED) ||
314             BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
315         {
316
317             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
318                           AFS_TRACE_LEVEL_ERROR,
319                           "AFSCommonWrite (%p) Request failed due to file deleted\n",
320                           Irp));
321
322             try_return( ntStatus = STATUS_FILE_DELETED);
323         }
324
325         if( FlagOn( pIrpSp->MinorFunction, IRP_MN_COMPLETE))
326         {
327
328             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
329                           AFS_TRACE_LEVEL_VERBOSE,
330                           "AFSCommonWrite (%p) IRP_MN_COMPLETE being processed\n",
331                           Irp));
332
333             CcMdlWriteComplete(pFileObject, &pIrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress);
334
335             //
336             // Mdl is now Deallocated
337             //
338
339             Irp->MdlAddress = NULL;
340
341             try_return( ntStatus = STATUS_SUCCESS );
342         }
343
344         //
345         // If we get a non cached IO for a cached file we should do a purge.
346         // For now we will just promote to cached
347         //
348         if( NULL != pFileObject->SectionObjectPointer->DataSectionObject && !bPagingIo && bNonCachedIo)
349         {
350             bNonCachedIo = FALSE;
351             bForceFlush = TRUE;
352         }
353
354         if ( !bNonCachedIo && !bPagingIo)
355         {
356
357             if( pFileObject->PrivateCacheMap == NULL)
358             {
359
360                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
361                               AFS_TRACE_LEVEL_VERBOSE,
362                               "AFSCommonWrite Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
363                               &pNPFcb->SectionObjectResource,
364                               PsGetCurrentThread()));
365
366                 AFSAcquireExcl( &pNPFcb->SectionObjectResource,
367                                 TRUE);
368
369                 bReleaseSectionObject = TRUE;
370
371                 __try
372                 {
373
374                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
375                                   AFS_TRACE_LEVEL_VERBOSE,
376                                   "AFSCommonWrite Initialize caching on Fcb %p FileObject %p\n",
377                                   pFcb,
378                                   pFileObject));
379
380                     CcInitializeCacheMap( pFileObject,
381                                           (PCC_FILE_SIZES)&pFcb->Header.AllocationSize,
382                                           FALSE,
383                                           AFSLibCacheManagerCallbacks,
384                                           pFcb);
385
386                     CcSetReadAheadGranularity( pFileObject,
387                                                pDeviceExt->Specific.RDR.MaximumRPCLength);
388
389                     CcSetDirtyPageThreshold( pFileObject,
390                                              AFS_DIRTY_CHUNK_THRESHOLD * pDeviceExt->Specific.RDR.MaximumRPCLength / 4096);
391                 }
392                 __except( EXCEPTION_EXECUTE_HANDLER)
393                 {
394
395                     ntStatus = GetExceptionCode();
396
397                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
398                                   AFS_TRACE_LEVEL_ERROR,
399                                   "AFSCommonWrite (%p) Exception thrown while initializing cache map Status %08lX\n",
400                                   Irp,
401                                   ntStatus));
402                 }
403
404                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
405                               AFS_TRACE_LEVEL_VERBOSE,
406                               "AFSCommonWrite Releasing Fcb SectionObject lock %p EXCL %08lX\n",
407                               &pNPFcb->SectionObjectResource,
408                               PsGetCurrentThread()));
409
410                 AFSReleaseResource( &pNPFcb->SectionObjectResource);
411
412                 bReleaseSectionObject = FALSE;
413
414                 if( !NT_SUCCESS( ntStatus))
415                 {
416
417                     try_return( ntStatus);
418                 }
419             }
420
421             //
422             // On versions of Microsoft Windows older than Vista the IO Manager
423             // will issue multiple outstanding writes on a synchronous file object
424             // if one of the cached writes completes with STATUS_PENDING.  This can
425             // result in the writes being completed out of order which can corrupt
426             // the end of file marker.  On OS versions older than Vista use a spin
427             // loop instead of deferring the write.
428             //
429
430             if ( bSynchronousFo &&
431                  AFSRtlSysVersion.dwMajorVersion < 6)
432             {
433
434                 while (!CcCanIWrite( pFileObject,
435                                      ulByteCount,
436                                      bWait && !bRetry,
437                                      bRetry))
438                 {
439                     static const LONGLONG llWriteDelay = (LONGLONG)-100000;
440                     bRetry = TRUE;
441
442                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
443                                   AFS_TRACE_LEVEL_WARNING,
444                                   "AFSCommonWrite (FO: %p) CcCanIWrite says No room for %u bytes! Retry in 10ms\n",
445                                   pFileObject,
446                                   ulByteCount);
447
448                     KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay);
449                 }
450             }
451             else
452             {
453
454                 if (!CcCanIWrite( pFileObject,
455                                   ulByteCount,
456                                   bWait && !bRetry,
457                                   bRetry))
458                 {
459
460                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
461                                   AFS_TRACE_LEVEL_WARNING,
462                                   "AFSCommonWrite (FO: %p) CcCanIWrite says No room for Offset %0I64X Length %08lX bytes! Deferring%s\n",
463                                   pFileObject,
464                                   liStartingByte.QuadPart,
465                                   ulByteCount,
466                                   bRetry ? " RETRY" : ""));
467
468                     ntStatus = AFSDeferWrite( DeviceObject, pFileObject, hCallingUser, Irp, ulByteCount, bRetry);
469
470                     if ( STATUS_PENDING == ntStatus)
471                     {
472
473                         bCompleteIrp = FALSE;
474                     }
475                     else
476                     {
477
478                         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
479                                       AFS_TRACE_LEVEL_ERROR,
480                                       "AFSCommonWrite (FO: %p) AFSDeferWrite failure Status %08lX\n",
481                                       pFileObject,
482                                       ntStatus));
483                     }
484
485                     try_return( ntStatus);
486                 }
487             }
488         }
489
490         //
491         // Save off the PID if this is not a paging IO
492         //
493
494         if( !bPagingIo &&
495             ( pFcb->Specific.File.ExtentRequestProcessId == 0 ||
496               ( ullProcessId != (ULONGLONG)AFSSysProcess &&
497                 pFcb->Specific.File.ExtentRequestProcessId != ullProcessId)))
498         {
499
500             pFcb->Specific.File.ExtentRequestProcessId = ullProcessId;
501
502             if( ullProcessId == (ULONGLONG)AFSSysProcess)
503             {
504                 AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
505                               AFS_TRACE_LEVEL_WARNING,
506                               "%s Setting LastWriterExtentProcessId to system process for Fcb %p\n",
507                               __FUNCTION__,
508                               pFcb));
509             }
510         }
511
512         //
513         // Take locks
514         //
515         //   - if Paging then we need to do nothing (the precalls will
516         //     have acquired the paging resource), for clarity we will collect
517         //     the paging resource
518         //   - If extending Write then take the fileresource EX (EOF will change, Allocation will only move out)
519         //   - Otherwise we collect the file shared, check against extending and
520         //
521
522         bLockOK = FALSE;
523
524         do
525         {
526
527             if( bPagingIo)
528             {
529
530                 //ASSERT( NULL != OnBehalfOf || ExIsResourceAcquiredLite( &pNPFcb->Resource ));
531
532                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
533                               AFS_TRACE_LEVEL_VERBOSE,
534                               "AFSCommonWrite Acquiring Fcb PagingIo lock %p SHARED %08lX\n",
535                               &pNPFcb->PagingResource,
536                               PsGetCurrentThread()));
537
538                 AFSAcquireShared( &pNPFcb->PagingResource,
539                                   TRUE);
540
541                 bReleasePaging = TRUE;
542
543                 //
544                 // We have the correct lock - we cannot have the wrong one
545                 //
546                 bLockOK = TRUE;
547             }
548             else
549             {
550
551                 bWriteToEndOfFile = liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
552                                     liStartingByte.HighPart == -1;
553
554                 bExtendingWrite = ( bWriteToEndOfFile ||
555                                     ((liStartingByte.QuadPart + ulByteCount) >=
556                                       pFcb->Header.FileSize.QuadPart));
557
558                 if( bExtendingWrite || bNonCachedIo)
559                 {
560                     //
561                     // Check for lock inversion
562                     //
563
564                     //
565                     // For bExtendingWrite the PagingResource is needed to protect
566                     // the CcSetFileSizes call in AFSExtendingWrite
567                     //
568
569                     ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
570
571                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
572                                   AFS_TRACE_LEVEL_VERBOSE,
573                                   "AFSCommonWrite Acquiring Fcb lock %p EXCL %08lX\n",
574                                   &pNPFcb->Resource,
575                                   PsGetCurrentThread()));
576
577                     AFSAcquireExcl( &pNPFcb->Resource,
578                                     TRUE);
579
580                     bReleaseMain = TRUE;
581
582                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
583                                   AFS_TRACE_LEVEL_VERBOSE,
584                                   "AFSCommonWrite Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
585                                   &pNPFcb->SectionObjectResource,
586                                   PsGetCurrentThread()));
587
588                     AFSAcquireExcl( &pNPFcb->SectionObjectResource,
589                                     TRUE);
590
591                     bReleaseSectionObject = TRUE;
592
593                     if ( bWriteToEndOfFile)
594                     {
595
596                         if (pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart)
597                         {
598
599                             liStartingByte = pFcb->Header.ValidDataLength;
600                         }
601                         else
602                         {
603
604                             liStartingByte = pFcb->Header.FileSize;
605                         }
606
607                         pIrpSp->Parameters.Write.ByteOffset = liStartingByte;
608                     }
609
610                     //
611                     // We have the correct lock - even if we don't end up truncating
612                     //
613                     bLockOK = TRUE;
614                 }
615                 else
616                 {
617                     ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
618
619                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
620                                   AFS_TRACE_LEVEL_VERBOSE,
621                                   "AFSCommonWrite Acquiring Fcb lock %p SHARED %08lX\n",
622                                   &pNPFcb->Resource,
623                                   PsGetCurrentThread()));
624
625                     AFSAcquireShared( &pNPFcb->Resource,
626                                       TRUE);
627
628                     bReleaseMain = TRUE;
629
630                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
631                                   AFS_TRACE_LEVEL_VERBOSE,
632                                   "AFSCommonWrite Acquiring Fcb SectionObject lock %p SHARED %08lX\n",
633                                   &pNPFcb->SectionObjectResource,
634                                   PsGetCurrentThread()));
635
636                     AFSAcquireShared( &pNPFcb->SectionObjectResource,
637                                       TRUE);
638
639                     bReleaseSectionObject = TRUE;
640
641                     //
642                     // Have things moved?  Are we extending? If so, the the lock isn't OK
643                     //
644                     bLockOK = (liStartingByte.QuadPart + ulByteCount) < pFcb->Header.FileSize.QuadPart;
645
646                     if (!bLockOK)
647                     {
648
649                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
650                                       AFS_TRACE_LEVEL_VERBOSE,
651                                       "AFSCommonWrite Releasing Fcb SectionObject lock %p SHARED %08lX\n",
652                                       &pNPFcb->SectionObjectResource,
653                                       PsGetCurrentThread()));
654
655                         AFSReleaseResource( &pNPFcb->SectionObjectResource);
656
657                         bReleaseSectionObject = FALSE;
658
659                         AFSReleaseResource( &pNPFcb->Resource);
660
661                         bReleaseMain = FALSE;
662                     }
663                 }
664             }
665         }
666         while (!bLockOK);
667
668         if( !bPagingIo)
669         {
670
671             //
672             // Check the BR locks on the file.
673             //
674
675             if ( !FsRtlCheckLockForWriteAccess( &pFcb->Specific.File.FileLock,
676                                                 Irp))
677             {
678
679                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
680                               AFS_TRACE_LEVEL_ERROR,
681                               "AFSCommonWrite (%p) Request failed due to lock conflict\n",
682                               Irp));
683
684                 try_return( ntStatus = STATUS_FILE_LOCK_CONFLICT);
685             }
686
687             if( bExtendingWrite)
688             {
689
690                 ntStatus = AFSExtendingWrite( pFcb, pFileObject, (liStartingByte.QuadPart + ulByteCount));
691
692                 //
693                 // Fcb->NPFcb->Resource is now held SHARED
694                 //
695
696                 if( !NT_SUCCESS(ntStatus))
697                 {
698
699                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
700                                   AFS_TRACE_LEVEL_ERROR,
701                                   "AFSCommonWrite (%p) Failed extending write request Status %08lX\n",
702                                   Irp,
703                                   ntStatus));
704
705                     try_return( ntStatus );
706                 }
707             }
708         }
709
710         //
711         // Fire off the request as appropriate
712         //
713         bCompleteIrp = FALSE;
714
715         if( !bPagingIo &&
716             !bNonCachedIo)
717         {
718
719             //
720             // Main resource held Shared
721             // SectionObject resource held exclusive if extending write
722             //
723
724             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
725                           AFS_TRACE_LEVEL_VERBOSE,
726                           "AFSCommonWrite (%p) Processing CACHED request Offset %0I64X Len %08lX%s\n",
727                           Irp,
728                           liStartingByte.QuadPart,
729                           ulByteCount,
730                           bRetry ? " RETRY" : ""));
731
732             ntStatus = AFSCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount, bForceFlush);
733         }
734         else
735         {
736
737             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
738                           AFS_TRACE_LEVEL_VERBOSE,
739                           "AFSCommonWrite (%p) Processing NON-CACHED request Offset %0I64X Len %08lX%s\n",
740                           Irp,
741                           liStartingByte.QuadPart,
742                           ulByteCount,
743                           bRetry ? " RETRY" : ""));
744
745             if( BooleanFlagOn( pRDRDevExt->DeviceFlags, AFS_DEVICE_FLAG_DIRECT_SERVICE_IO))
746             {
747
748                 ntStatus = AFSNonCachedWriteDirect( DeviceObject, Irp,  liStartingByte, ulByteCount);
749             }
750             else
751             {
752                 ntStatus = AFSNonCachedWrite( DeviceObject, Irp,  liStartingByte, ulByteCount);
753             }
754         }
755
756 try_exit:
757
758         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
759                       AFS_TRACE_LEVEL_VERBOSE,
760                       "AFSCommonWrite (%p) Process complete Status %08lX\n",
761                       Irp,
762                       ntStatus));
763
764         if ( NT_SUCCESS( ntStatus) &&
765              ntStatus != STATUS_PENDING)
766         {
767             if ( !bPagingIo)
768             {
769
770                 if( bSynchronousFo)
771                 {
772
773                     pFileObject->CurrentByteOffset.QuadPart = liStartingByte.QuadPart + ulByteCount;
774                 }
775
776                 //
777                 // If this extended the VDL, then update it accordingly.
778                 // Increasing the VDL does not require a call to CcSetFileSizes.
779                 //
780
781                 if( liStartingByte.QuadPart + ulByteCount > pFcb->Header.ValidDataLength.QuadPart)
782                 {
783
784                     pFcb->Header.ValidDataLength.QuadPart = liStartingByte.QuadPart + ulByteCount;
785                 }
786
787                 if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
788                 {
789
790                     SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
791
792                     KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
793                 }
794             }
795         }
796
797         if ( ntStatus != STATUS_PENDING &&
798              !bPagingIo && bNonCachedIo && CcIsFileCached( pFileObject) &&
799              pNPFcb->SectionObjectPointers.DataSectionObject != NULL &&
800              bReleaseSectionObject)
801         {
802             //
803             // Regardless of whether or not the a non-paging non-cached write
804             // succeeds or fails, if the file is cached the contents of the
805             // cache are no longer up to date.  A CcPurgeCacheSection must be
806             // performed to force subsequent cached reads to obtain the data
807             // from the service.
808             //
809             // The Fcb Resource is dropped in order to permit filters that perform
810             // an open via a worker thread in response to a purge to do so without
811             // deadlocking.  The SectionObjectResource is held across the purge to
812             // prevent racing with other cache operations.
813             //
814
815             if( bReleaseMain)
816             {
817
818                 AFSReleaseResource( &pNPFcb->Resource);
819
820                 bReleaseMain = FALSE;
821             }
822
823             __try
824             {
825
826                 if ( !CcPurgeCacheSection( &pNPFcb->SectionObjectPointers,
827                                            &liStartingByte,
828                                            ulByteCount,
829                                            FALSE))
830                 {
831
832                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
833                                   AFS_TRACE_LEVEL_WARNING,
834                                   "AFSCommonWrite CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
835                                   pFcb->ObjectInformation->FileId.Cell,
836                                   pFcb->ObjectInformation->FileId.Volume,
837                                   pFcb->ObjectInformation->FileId.Vnode,
838                                   pFcb->ObjectInformation->FileId.Unique));
839
840                     SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
841                 }
842             }
843             __except( EXCEPTION_EXECUTE_HANDLER)
844             {
845
846                 DWORD ntStatus2 = GetExceptionCode();
847
848                 AFSDbgTrace(( 0,
849                               0,
850                               "EXCEPTION - AFSCommonWrite CcPurgeCacheSection failed FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
851                               pFcb->ObjectInformation->FileId.Cell,
852                               pFcb->ObjectInformation->FileId.Volume,
853                               pFcb->ObjectInformation->FileId.Vnode,
854                               pFcb->ObjectInformation->FileId.Unique,
855                               ntStatus2));
856
857                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
858             }
859         }
860
861         ObDereferenceObject(pFileObject);
862
863         if( bReleaseSectionObject)
864         {
865
866             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
867                           AFS_TRACE_LEVEL_VERBOSE,
868                           "AFSCommonWrite Releasing Fcb SectionObject lock %p EXCL/SHARED %08lX\n",
869                           &pNPFcb->SectionObjectResource,
870                           PsGetCurrentThread()));
871
872             AFSReleaseResource( &pNPFcb->SectionObjectResource);
873         }
874
875         if( bReleasePaging)
876         {
877
878             AFSReleaseResource( &pNPFcb->PagingResource);
879         }
880
881         if( bReleaseMain)
882         {
883
884             AFSReleaseResource( &pNPFcb->Resource);
885         }
886
887         if( bCompleteIrp)
888         {
889
890             AFSCompleteRequest( Irp,
891                                 ntStatus);
892         }
893     }
894
895     return ntStatus;
896 }
897
898 NTSTATUS
899 AFSIOCtlWrite( IN PDEVICE_OBJECT DeviceObject,
900                IN PIRP Irp)
901 {
902
903     UNREFERENCED_PARAMETER(DeviceObject);
904     NTSTATUS ntStatus = STATUS_SUCCESS;
905     AFSPIOCtlIORequestCB stIORequestCB;
906     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
907     AFSFcb *pFcb = NULL;
908     AFSCcb *pCcb = NULL;
909     AFSPIOCtlIOResultCB stIOResultCB;
910     ULONG ulBytesReturned = 0;
911     AFSFileID stParentFID;
912
913     __Enter
914     {
915
916         Irp->IoStatus.Information = 0;
917
918         RtlZeroMemory( &stIORequestCB,
919                        sizeof( AFSPIOCtlIORequestCB));
920
921         if( pIrpSp->Parameters.Write.Length == 0)
922         {
923
924             //
925             // Nothing to do in this case
926             //
927
928             try_return( ntStatus);
929         }
930
931         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
932
933         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
934
935         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
936                       AFS_TRACE_LEVEL_VERBOSE,
937                       "AFSIOCtlWrite Acquiring Fcb lock %p SHARED %08lX\n",
938                       &pFcb->NPFcb->Resource,
939                       PsGetCurrentThread()));
940
941         AFSAcquireShared( &pFcb->NPFcb->Resource,
942                           TRUE);
943
944         //
945         // Get the parent fid to pass to the cm
946         //
947
948         RtlZeroMemory( &stParentFID,
949                        sizeof( AFSFileID));
950
951         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
952         {
953
954             //
955             // The parent directory FID of the node
956             //
957
958             stParentFID = pFcb->ObjectInformation->ParentFileId;
959         }
960
961         //
962         // Set the control block up
963         //
964
965         stIORequestCB.RequestId = pCcb->RequestID;
966
967         if( pFcb->ObjectInformation->VolumeCB != NULL)
968         {
969             stIORequestCB.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
970         }
971
972         //
973         // Lock down the buffer
974         //
975
976         stIORequestCB.MappedBuffer = AFSMapToService( Irp,
977                                                       pIrpSp->Parameters.Write.Length);
978
979         if( stIORequestCB.MappedBuffer == NULL)
980         {
981
982             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
983         }
984
985         stIORequestCB.BufferLength = pIrpSp->Parameters.Write.Length;
986
987         stIOResultCB.BytesProcessed = 0;
988
989         ulBytesReturned = sizeof( AFSPIOCtlIOResultCB);
990
991         //
992         // Issue the request to the service
993         //
994
995         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_WRITE,
996                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
997                                       &pCcb->AuthGroup,
998                                       NULL,
999                                       &stParentFID,
1000                                       NULL,
1001                                       0,
1002                                       (void *)&stIORequestCB,
1003                                       sizeof( AFSPIOCtlIORequestCB),
1004                                       &stIOResultCB,
1005                                       &ulBytesReturned);
1006
1007         if( !NT_SUCCESS( ntStatus))
1008         {
1009
1010             try_return( ntStatus);
1011         }
1012
1013         //
1014         // Update the length written
1015         //
1016
1017         Irp->IoStatus.Information = stIOResultCB.BytesProcessed;
1018
1019 try_exit:
1020
1021         if( stIORequestCB.MappedBuffer != NULL)
1022         {
1023
1024             AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer,
1025                                          Irp->MdlAddress);
1026         }
1027
1028         if( pFcb != NULL)
1029         {
1030
1031             AFSReleaseResource( &pFcb->NPFcb->Resource);
1032         }
1033     }
1034
1035     return ntStatus;
1036 }
1037
1038 //
1039 // This function is called when we know we have to read from the AFS Cache.
1040 //
1041 // It ensures that we have exents for the entirety of the write and
1042 // then pins the extents into memory (meaning that although we may
1043 // add we will not remove).  Then it creates a scatter gather write
1044 // and fires off the IRPs
1045 //
1046 static
1047 NTSTATUS
1048 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1049                    IN PIRP Irp,
1050                    IN LARGE_INTEGER StartingByte,
1051                    IN ULONG ByteCount)
1052 {
1053     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
1054     VOID              *pSystemBuffer = NULL;
1055     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
1056     BOOLEAN            bLocked = FALSE;
1057     BOOLEAN            bCompleteIrp = TRUE;
1058     AFSGatherIo       *pGatherIo = NULL;
1059     AFSIoRun          *pIoRuns = NULL;
1060     AFSIoRun           stIoRuns[AFS_MAX_STACK_IO_RUNS];
1061     ULONG              extentsCount = 0, runCount = 0;
1062     AFSExtent         *pStartExtent = NULL;
1063     AFSExtent         *pIgnoreExtent = NULL;
1064     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1065     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1066     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1067     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1068     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1069     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
1070     LARGE_INTEGER      liCurrentTime, liLastRequestTime;
1071     AFSDeviceExt      *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1072     PFILE_OBJECT       pCacheFileObject = NULL;
1073     BOOLEAN            bDerefExtents = FALSE;
1074
1075     __Enter
1076     {
1077
1078         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1079                       AFS_TRACE_LEVEL_VERBOSE,
1080                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX\n",
1081                       pFileObject,
1082                       StartingByte.HighPart,
1083                       StartingByte.LowPart,
1084                       ByteCount));
1085
1086         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
1087         {
1088
1089             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1090                           AFS_TRACE_LEVEL_ERROR,
1091                           "AFSNonCachedWrite (%p) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
1092                           Irp,
1093                           ByteCount,
1094                           pIrpSp->Parameters.Write.Length,
1095                           pDevExt->Specific.RDR.MaxIo.QuadPart));
1096
1097             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1098         }
1099
1100         //
1101         // Get the mapping for the buffer
1102         //
1103         pSystemBuffer = AFSLockSystemBuffer( Irp,
1104                                              ByteCount);
1105
1106         if( pSystemBuffer == NULL)
1107         {
1108
1109             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1110                           AFS_TRACE_LEVEL_ERROR,
1111                           "AFSNonCachedWrite (%p) Failed to map system buffer\n",
1112                           Irp));
1113
1114             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1115         }
1116
1117
1118         //
1119         // Provoke a get of the extents - if we need to.
1120         //
1121
1122         AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1123                       AFS_TRACE_LEVEL_VERBOSE,
1124                       "AFSNonCachedWrite Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1125                       pFcb->ObjectInformation->FileId.Cell,
1126                       pFcb->ObjectInformation->FileId.Volume,
1127                       pFcb->ObjectInformation->FileId.Vnode,
1128                       pFcb->ObjectInformation->FileId.Unique,
1129                       StartingByte.QuadPart,
1130                       ByteCount));
1131
1132         ntStatus = AFSRequestExtentsAsync( pFcb,
1133                                            pCcb,
1134                                            &StartingByte,
1135                                            ByteCount);
1136
1137         if (!NT_SUCCESS(ntStatus))
1138         {
1139
1140             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1141                           AFS_TRACE_LEVEL_ERROR,
1142                           "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
1143                           Irp,
1144                           ntStatus));
1145
1146             try_return( ntStatus);
1147         }
1148
1149         KeQueryTickCount( &liLastRequestTime);
1150
1151         while (TRUE)
1152         {
1153
1154             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1155                           AFS_TRACE_LEVEL_VERBOSE,
1156                           "AFSNonCachedWrite Acquiring Fcb extents lock %p SHARED %08lX\n",
1157                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1158                           PsGetCurrentThread()));
1159
1160             ASSERT( !ExIsResourceAcquiredLite( &pFcb->NPFcb->Specific.File.ExtentsResource ));
1161
1162             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE );
1163             bLocked = TRUE;
1164
1165             pStartExtent = NULL;
1166             pIgnoreExtent = NULL;
1167
1168             if ( AFSDoExtentsMapRegion( pFcb, &StartingByte, ByteCount, &pStartExtent, &pIgnoreExtent ))
1169             {
1170                 break;
1171             }
1172
1173             KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete );
1174
1175             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1176                           AFS_TRACE_LEVEL_VERBOSE,
1177                           "AFSNonCachedWrite Releasing(1) Fcb extents lock %p SHARED %08lX\n",
1178                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1179                           PsGetCurrentThread()));
1180
1181             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1182             bLocked= FALSE;
1183
1184             //
1185             // We will re-request the extents after waiting for them
1186             //
1187
1188             KeQueryTickCount( &liCurrentTime);
1189
1190             if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart)
1191             {
1192
1193                 AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1194                               AFS_TRACE_LEVEL_VERBOSE,
1195                               "AFSNonCachedWrite Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1196                               pFcb->ObjectInformation->FileId.Cell,
1197                               pFcb->ObjectInformation->FileId.Volume,
1198                               pFcb->ObjectInformation->FileId.Vnode,
1199                               pFcb->ObjectInformation->FileId.Unique,
1200                               StartingByte.QuadPart,
1201                               ByteCount));
1202
1203                 ntStatus = AFSRequestExtentsAsync( pFcb,
1204                                                    pCcb,
1205                                                    &StartingByte,
1206                                                    ByteCount);
1207
1208                 if (!NT_SUCCESS(ntStatus))
1209                 {
1210
1211                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1212                                   AFS_TRACE_LEVEL_ERROR,
1213                                   "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
1214                                   Irp,
1215                                   ntStatus));
1216
1217                     try_return( ntStatus);
1218                 }
1219
1220                 KeQueryTickCount( &liLastRequestTime);
1221             }
1222
1223
1224             AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1225                           AFS_TRACE_LEVEL_VERBOSE,
1226                           "AFSNonCachedWrite Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1227                           pFcb->ObjectInformation->FileId.Cell,
1228                           pFcb->ObjectInformation->FileId.Volume,
1229                           pFcb->ObjectInformation->FileId.Vnode,
1230                           pFcb->ObjectInformation->FileId.Unique,
1231                           StartingByte.QuadPart,
1232                           ByteCount));
1233
1234             //
1235             // Wait for it
1236             //
1237
1238             ntStatus =  AFSWaitForExtentMapping ( pFcb, pCcb);
1239
1240             if (!NT_SUCCESS(ntStatus))
1241             {
1242
1243                 AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1244                               AFS_TRACE_LEVEL_ERROR,
1245                               "AFSNonCachedWrite Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX Status %08lX\n",
1246                               pFcb->ObjectInformation->FileId.Cell,
1247                               pFcb->ObjectInformation->FileId.Volume,
1248                               pFcb->ObjectInformation->FileId.Vnode,
1249                               pFcb->ObjectInformation->FileId.Unique,
1250                               StartingByte.QuadPart,
1251                               ByteCount,
1252                               ntStatus));
1253
1254                 try_return( ntStatus);
1255             }
1256         }
1257
1258         //
1259         // As per the read path -
1260         //
1261
1262         AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1263                       AFS_TRACE_LEVEL_VERBOSE,
1264                       "AFSNonCachedWrite Extents located for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1265                       pFcb->ObjectInformation->FileId.Cell,
1266                       pFcb->ObjectInformation->FileId.Volume,
1267                       pFcb->ObjectInformation->FileId.Vnode,
1268                       pFcb->ObjectInformation->FileId.Unique,
1269                       StartingByte.QuadPart,
1270                       ByteCount));
1271
1272         ntStatus = AFSGetExtents( pFcb,
1273                                   &StartingByte,
1274                                   ByteCount,
1275                                   pStartExtent,
1276                                   &extentsCount,
1277                                   &runCount);
1278
1279         if (!NT_SUCCESS(ntStatus))
1280         {
1281
1282             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1283                           AFS_TRACE_LEVEL_ERROR,
1284                           "AFSNonCachedWrite (%p) Failed to retrieve mapped extents Status %08lX\n",
1285                           Irp,
1286                           ntStatus));
1287
1288             try_return( ntStatus );
1289         }
1290
1291         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1292                       AFS_TRACE_LEVEL_VERBOSE,
1293                       "AFSNonCachedWrite (%p) Successfully retrieved map extents count %d run count %d\n",
1294                       Irp,
1295                       extentsCount,
1296                       runCount));
1297
1298         if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
1299         {
1300
1301             Irp->IoStatus.Information = ByteCount;
1302
1303 #if GEN_MD5
1304             //
1305             // Setup the MD5 for each extent
1306             //
1307
1308             AFSSetupMD5Hash( pFcb,
1309                              pStartExtent,
1310                              extentsCount,
1311                              pSystemBuffer,
1312                              &StartingByte,
1313                              ByteCount);
1314 #endif
1315
1316             ntStatus = AFSProcessExtentRun( pSystemBuffer,
1317                                             &StartingByte,
1318                                             ByteCount,
1319                                             pStartExtent,
1320                                             TRUE);
1321
1322             if (!NT_SUCCESS(ntStatus))
1323             {
1324
1325                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1326                               AFS_TRACE_LEVEL_ERROR,
1327                               "AFSNonCachedWrite (%p) Failed to process extent run for non-persistent cache Status %08lX\n",
1328                               Irp,
1329                               ntStatus));
1330             }
1331
1332             try_return( ntStatus);
1333         }
1334
1335         //
1336         // Retrieve the cache file object
1337         //
1338
1339         pCacheFileObject = AFSReferenceCacheFileObject();
1340
1341         if( pCacheFileObject == NULL)
1342         {
1343
1344             ntStatus = STATUS_DEVICE_NOT_READY;
1345
1346             AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1347                           AFS_TRACE_LEVEL_ERROR,
1348                           "AFSNonCachedWrite Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX Status %08lX\n",
1349                           pFcb->ObjectInformation->FileId.Cell,
1350                           pFcb->ObjectInformation->FileId.Volume,
1351                           pFcb->ObjectInformation->FileId.Vnode,
1352                           pFcb->ObjectInformation->FileId.Unique,
1353                           StartingByte.QuadPart,
1354                           ByteCount,
1355                           ntStatus));
1356
1357             try_return( ntStatus);
1358         }
1359
1360         if (runCount > AFS_MAX_STACK_IO_RUNS)
1361         {
1362
1363             pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool,
1364                                                             runCount * sizeof( AFSIoRun ),
1365                                                             AFS_IO_RUN_TAG );
1366             if (NULL == pIoRuns)
1367             {
1368
1369                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1370                               AFS_TRACE_LEVEL_ERROR,
1371                               "AFSNonCachedWrite (%p) Failed to allocate IO run block\n",
1372                               Irp));
1373
1374                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1375             }
1376         }
1377         else
1378         {
1379
1380             pIoRuns = stIoRuns;
1381         }
1382
1383         RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun ));
1384
1385         ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject),
1386                                   Irp,
1387                                   pSystemBuffer,
1388                                   pIoRuns,
1389                                   &StartingByte,
1390                                   ByteCount,
1391                                   pStartExtent,
1392                                   &runCount );
1393
1394         if (!NT_SUCCESS(ntStatus))
1395         {
1396
1397             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1398                           AFS_TRACE_LEVEL_ERROR,
1399                           "AFSNonCachedWrite (%p) Failed to initialize IO run block Status %08lX\n",
1400                           Irp,
1401                           ntStatus));
1402
1403             try_return( ntStatus );
1404         }
1405
1406         AFSReferenceActiveExtents( pStartExtent,
1407                                    extentsCount);
1408
1409         bDerefExtents = TRUE;
1410
1411         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1412                       AFS_TRACE_LEVEL_VERBOSE,
1413                       "AFSNonCachedWrite Releasing(2) Fcb extents lock %p SHARED %08lX\n",
1414                       &pFcb->NPFcb->Specific.File.ExtentsResource,
1415                       PsGetCurrentThread()));
1416
1417         AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1418         bLocked = FALSE;
1419
1420         pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool,
1421                                                              sizeof( AFSGatherIo),
1422                                                              AFS_GATHER_TAG);
1423
1424         if (NULL == pGatherIo)
1425         {
1426
1427             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1428                           AFS_TRACE_LEVEL_ERROR,
1429                           "AFSNonCachedWrite (%p) Failed to allocate IO gather block\n",
1430                           Irp));
1431
1432             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1433                           AFS_TRACE_LEVEL_VERBOSE,
1434                           "AFSNonCachedWrite Acquiring(1) Fcb extents lock %p SHARED %08lX\n",
1435                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1436                           PsGetCurrentThread()));
1437
1438             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1439                               TRUE);
1440             bLocked = TRUE;
1441
1442             AFSDereferenceActiveExtents( pStartExtent,
1443                                          extentsCount);
1444
1445             try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1446         }
1447
1448         RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo ));
1449
1450         //
1451         // Initialize count to 1, that was we won't get an early
1452         // completion if the first irp completes before the second is
1453         // queued.
1454         //
1455         pGatherIo->Count = 1;
1456         pGatherIo->Status = STATUS_SUCCESS;
1457         pGatherIo->MasterIrp = Irp;
1458         pGatherIo->Synchronous = TRUE;
1459         pGatherIo->CompleteMasterIrp = FALSE;
1460
1461         bCompleteIrp = TRUE;
1462
1463         if( pGatherIo->Synchronous)
1464         {
1465             KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE );
1466         }
1467
1468 #if GEN_MD5
1469         //
1470         // Setup the MD5 for each extent
1471         //
1472
1473         AFSSetupMD5Hash( pFcb,
1474                          pStartExtent,
1475                          extentsCount,
1476                          pSystemBuffer,
1477                          &StartingByte,
1478                          ByteCount);
1479 #endif
1480
1481         //
1482         // Pre-emptively set up the count
1483         //
1484
1485         Irp->IoStatus.Information = ByteCount;
1486
1487         ntStatus = AFSQueueStartIos( pCacheFileObject,
1488                                      IRP_MJ_WRITE,
1489                                      IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API,
1490                                      pIoRuns,
1491                                      runCount,
1492                                      pGatherIo);
1493
1494         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1495                       AFS_TRACE_LEVEL_VERBOSE,
1496                       "AFSNonCachedWrite (%p) AFSStartIos completed Status %08lX\n",
1497                       Irp,
1498                       ntStatus));
1499
1500         if( !NT_SUCCESS( ntStatus))
1501         {
1502
1503             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1504                           AFS_TRACE_LEVEL_VERBOSE,
1505                           "AFSNonCachedWrite Acquiring(2) Fcb extents lock %p SHARED %08lX\n",
1506                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1507                           PsGetCurrentThread()));
1508
1509             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1510                               TRUE);
1511             bLocked = TRUE;
1512
1513             AFSDereferenceActiveExtents( pStartExtent,
1514                                          extentsCount);
1515
1516             try_return( ntStatus);
1517         }
1518
1519         //
1520         // Wait for completion of All IOs we started.
1521         //
1522
1523         ntStatus = KeWaitForSingleObject( &pGatherIo->Event,
1524                                           Executive,
1525                                           KernelMode,
1526                                           FALSE,
1527                                           NULL);
1528
1529         if( NT_SUCCESS( ntStatus))
1530         {
1531
1532             ntStatus = pGatherIo->Status;
1533         }
1534
1535         if( !NT_SUCCESS( ntStatus))
1536         {
1537
1538             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1539                           AFS_TRACE_LEVEL_VERBOSE,
1540                           "AFSNonCachedWrite Acquiring(3) Fcb extents lock %p SHARED %08lX\n",
1541                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1542                           PsGetCurrentThread()));
1543
1544             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1545                               TRUE);
1546             bLocked = TRUE;
1547
1548             AFSDereferenceActiveExtents( pStartExtent,
1549                                          extentsCount);
1550
1551             try_return( ntStatus);
1552         }
1553
1554 try_exit:
1555
1556         if( NT_SUCCESS( ntStatus) &&
1557             pStartExtent != NULL &&
1558             Irp->IoStatus.Information > 0)
1559         {
1560
1561             if ( !bLocked)
1562             {
1563
1564                 AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1565                                   TRUE);
1566                 bLocked = TRUE;
1567             }
1568
1569             //
1570             // Since this is dirty we can mark the extents dirty now.
1571             // AFSMarkDirty will dereference the extents.  Do not call
1572             // AFSDereferenceActiveExtents() in this code path.
1573             //
1574
1575             AFSMarkDirty( pFcb,
1576                           pStartExtent,
1577                           extentsCount,
1578                           &StartingByte,
1579                           bDerefExtents);
1580
1581             if (!bPagingIo)
1582             {
1583                 //
1584                 // This was an uncached user write - tell the server to do
1585                 // the flush when the worker thread next wakes up
1586                 //
1587                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1588             }
1589         }
1590
1591         if( pCacheFileObject != NULL)
1592         {
1593             AFSReleaseCacheFileObject( pCacheFileObject);
1594         }
1595
1596         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1597                       AFS_TRACE_LEVEL_VERBOSE,
1598                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX Status %08lX\n",
1599                       pFileObject,
1600                       StartingByte.HighPart,
1601                       StartingByte.LowPart,
1602                       ByteCount,
1603                       ntStatus));
1604
1605         if (NT_SUCCESS(ntStatus) &&
1606             !bPagingIo &&
1607             bSynchronousFo)
1608         {
1609
1610             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1611         }
1612
1613         if( bLocked)
1614         {
1615
1616             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1617                           AFS_TRACE_LEVEL_VERBOSE,
1618                           "AFSNonCachedWrite Releasing Fcb extents lock %p SHARED %08lX\n",
1619                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1620                           PsGetCurrentThread()));
1621
1622             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1623         }
1624
1625         if( pGatherIo)
1626         {
1627             AFSExFreePoolWithTag(pGatherIo, AFS_GATHER_TAG);
1628         }
1629
1630         if( NULL != pIoRuns &&
1631             stIoRuns != pIoRuns)
1632         {
1633             AFSExFreePoolWithTag(pIoRuns, AFS_IO_RUN_TAG);
1634         }
1635
1636         if( bCompleteIrp)
1637         {
1638
1639             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1640                           AFS_TRACE_LEVEL_VERBOSE,
1641                           "AFSNonCachedWrite Completing Irp %p Status %08lX Info %08lX\n",
1642                           Irp,
1643                           ntStatus,
1644                           Irp->IoStatus.Information));
1645
1646             AFSCompleteRequest( Irp, ntStatus);
1647         }
1648     }
1649
1650     return ntStatus;
1651 }
1652
1653 static
1654 NTSTATUS
1655 AFSNonCachedWriteDirect( IN PDEVICE_OBJECT DeviceObject,
1656                          IN PIRP Irp,
1657                          IN LARGE_INTEGER StartingByte,
1658                          IN ULONG ByteCount)
1659 {
1660     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
1661     VOID              *pSystemBuffer = NULL;
1662     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
1663     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1664     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1665     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1666     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1667     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1668     BOOLEAN            bNoIntermediateBuffering = BooleanFlagOn( pFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING);
1669     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
1670     AFSFileIOCB        stFileIORequest;
1671     AFSFileIOResultCB  stFileIOResult;
1672     ULONG              ulResultLen = 0;
1673     ULONG              ulFlags;
1674
1675     __Enter
1676     {
1677         Irp->IoStatus.Information = 0;
1678
1679         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1680                       AFS_TRACE_LEVEL_VERBOSE,
1681                       "AFSNonCachedWriteDirect (FO: %p) StartingByte %08lX:%08lX Length %08lX\n",
1682                       pFileObject,
1683                       StartingByte.HighPart,
1684                       StartingByte.LowPart,
1685                       ByteCount));
1686
1687         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
1688         {
1689
1690             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1691                           AFS_TRACE_LEVEL_ERROR,
1692                           "AFSNonCachedWriteDirect (%p) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
1693                           Irp,
1694                           ByteCount,
1695                           pIrpSp->Parameters.Write.Length,
1696                           pDevExt->Specific.RDR.MaxIo.QuadPart));
1697
1698             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1699         }
1700
1701         //
1702         // Get the mapping for the buffer
1703         //
1704         pSystemBuffer = AFSLockSystemBuffer( Irp,
1705                                              ByteCount);
1706
1707         if( pSystemBuffer == NULL)
1708         {
1709
1710             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1711                           AFS_TRACE_LEVEL_ERROR,
1712                           "AFSNonCachedWriteDirect (%p) Failed to map system buffer\n",
1713                           Irp));
1714
1715             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1716         }
1717
1718         //
1719         // Issue the request at the service for processing
1720         //
1721
1722         ulResultLen = sizeof( AFSFileIOResultCB);
1723
1724         RtlZeroMemory( &stFileIORequest,
1725                        sizeof( AFSFileIOCB));
1726
1727         RtlZeroMemory( &stFileIOResult,
1728                        sizeof( AFSFileIOResultCB));
1729
1730         stFileIORequest.SystemIOBuffer = pSystemBuffer;
1731
1732         stFileIORequest.SystemIOBufferMdl = Irp->MdlAddress;
1733
1734         stFileIORequest.IOLength = ByteCount;
1735
1736         stFileIORequest.IOOffset = StartingByte;
1737
1738         ulFlags = AFS_REQUEST_FLAG_SYNCHRONOUS;
1739
1740         if ( bNoIntermediateBuffering)
1741         {
1742
1743             ulFlags |= AFS_REQUEST_FLAG_CACHE_BYPASS;
1744         }
1745
1746         //
1747         // Update file metadata
1748         //
1749
1750         stFileIORequest.EndOfFile = pFcb->ObjectInformation->EndOfFile;
1751
1752         stFileIORequest.CreateTime = pFcb->ObjectInformation->CreationTime;
1753
1754         stFileIORequest.ChangeTime = pFcb->ObjectInformation->ChangeTime;
1755
1756         stFileIORequest.LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
1757
1758         stFileIORequest.LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
1759
1760         //
1761         // Write the data to the service
1762         //
1763
1764         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PROCESS_WRITE_FILE,
1765                                       ulFlags,
1766                                       &pCcb->AuthGroup,
1767                                       &pCcb->DirectoryCB->NameInformation.FileName,
1768                                       &pFcb->ObjectInformation->FileId,
1769                                       pFcb->ObjectInformation->VolumeCB->VolumeInformation.Cell,
1770                                       pFcb->ObjectInformation->VolumeCB->VolumeInformation.CellLength,
1771                                       &stFileIORequest,
1772                                       sizeof( AFSFileIOCB),
1773                                       &stFileIOResult,
1774                                       &ulResultLen);
1775
1776         if( NT_SUCCESS( ntStatus))
1777         {
1778
1779             Irp->IoStatus.Information = (ULONG_PTR)stFileIOResult.Length;
1780         }
1781         else
1782         {
1783
1784             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1785                           AFS_TRACE_LEVEL_ERROR,
1786                           "AFSNonCachedWriteDirect (%p) Failed to send write to service Status %08lX\n",
1787                           Irp,
1788                           ntStatus));
1789         }
1790
1791 try_exit:
1792
1793         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1794                       AFS_TRACE_LEVEL_VERBOSE,
1795                       "AFSNonCachedWriteDirect (FO: %p) StartingByte %08lX:%08lX Length %08lX Status %08lX\n",
1796                       pFileObject,
1797                       StartingByte.HighPart,
1798                       StartingByte.LowPart,
1799                       ByteCount,
1800                       ntStatus));
1801
1802         if (NT_SUCCESS(ntStatus) &&
1803             !bPagingIo &&
1804             bSynchronousFo)
1805         {
1806
1807             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1808         }
1809
1810         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1811                       AFS_TRACE_LEVEL_VERBOSE,
1812                       "AFSNonCachedWriteDirect Completing Irp %p Status %08lX Info %08lX\n",
1813                       Irp,
1814                       ntStatus,
1815                       Irp->IoStatus.Information));
1816
1817         AFSCompleteRequest( Irp, ntStatus);
1818     }
1819
1820     return ntStatus;
1821 }
1822
1823 static
1824 NTSTATUS
1825 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1826                 IN PIRP Irp,
1827                 IN LARGE_INTEGER StartingByte,
1828                 IN ULONG ByteCount,
1829                 IN BOOLEAN ForceFlush)
1830 {
1831     UNREFERENCED_PARAMETER(DeviceObject);
1832     PVOID              pSystemBuffer = NULL;
1833     NTSTATUS           ntStatus = STATUS_SUCCESS;
1834     IO_STATUS_BLOCK    iosbFlush;
1835     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1836     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1837     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1838     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1839     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1840     PMDL               pCurrentMdl = Irp->MdlAddress;
1841     LARGE_INTEGER      liCurrentOffset;
1842
1843     __Enter
1844     {
1845
1846         Irp->IoStatus.Information = 0;
1847
1848         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1849         {
1850
1851             __try
1852             {
1853
1854                 CcPrepareMdlWrite( pFileObject,
1855                                    &StartingByte,
1856                                    ByteCount,
1857                                    &Irp->MdlAddress,
1858                                    &Irp->IoStatus);
1859
1860                 ntStatus = Irp->IoStatus.Status;
1861             }
1862             __except( EXCEPTION_EXECUTE_HANDLER)
1863             {
1864                 ntStatus = GetExceptionCode();
1865
1866                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1867                               AFS_TRACE_LEVEL_ERROR,
1868                               "AFSCachedWrite (%p) Exception thrown while preparing mdl write Status %08lX\n",
1869                               Irp,
1870                               ntStatus));
1871             }
1872
1873             if( !NT_SUCCESS( ntStatus))
1874             {
1875
1876                 //
1877                 // Free up any potentially allocated mdl's
1878                 //
1879
1880                 CcMdlWriteComplete( pFileObject,
1881                                     &StartingByte,
1882                                     Irp->MdlAddress);
1883
1884                 Irp->MdlAddress = NULL;
1885
1886                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1887                               AFS_TRACE_LEVEL_ERROR,
1888                               "AFSCachedWrite (%p) Failed to process MDL write Status %08lX\n",
1889                               Irp,
1890                               ntStatus));
1891             }
1892
1893             try_return( ntStatus);
1894         }
1895
1896         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1897
1898         while( ulTotalLen > 0)
1899         {
1900
1901             ntStatus = STATUS_SUCCESS;
1902
1903             if( pCurrentMdl != NULL)
1904             {
1905
1906                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1907                                                               NormalPagePriority);
1908
1909                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1910
1911                 if( ulCurrentIO > ulTotalLen)
1912                 {
1913                     ulCurrentIO = ulTotalLen;
1914                 }
1915             }
1916             else
1917             {
1918
1919                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1920                                                      ulTotalLen);
1921
1922                 ulCurrentIO = ulTotalLen;
1923             }
1924
1925             if( pSystemBuffer == NULL)
1926             {
1927
1928                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1929                               AFS_TRACE_LEVEL_ERROR,
1930                               "AFSCachedWrite (%p) Failed to lock system buffer\n",
1931                               Irp));
1932
1933                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1934             }
1935
1936             __try
1937             {
1938
1939                 if( !CcCopyWrite( pFileObject,
1940                                   &liCurrentOffset,
1941                                   ulCurrentIO,
1942                                   TRUE,
1943                                   pSystemBuffer))
1944                 {
1945                     //
1946                     // Failed to process request.
1947                     //
1948
1949                     AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1950                                   AFS_TRACE_LEVEL_ERROR,
1951                                   "AFSCachedWrite (%p) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1952                                   Irp,
1953                                   &pFileObject->FileName,
1954                                   liCurrentOffset.QuadPart,
1955                                   Irp->IoStatus.Status));
1956
1957                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1958                 }
1959             }
1960             __except( EXCEPTION_EXECUTE_HANDLER)
1961             {
1962
1963                 ntStatus = GetExceptionCode();
1964
1965                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1966                               AFS_TRACE_LEVEL_ERROR,
1967                               "AFSCachedWrite (%p) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1968                               Irp,
1969                               &pFileObject->FileName,
1970                               liCurrentOffset.QuadPart,
1971                               ntStatus));
1972             }
1973
1974             if( !NT_SUCCESS( ntStatus))
1975             {
1976                 try_return( ntStatus);
1977             }
1978
1979             if( ForceFlush ||
1980                 BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1981             {
1982
1983                 __try
1984                 {
1985                     //
1986                     // We have detected a file we do a write through with.
1987                     //
1988
1989                     CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1990                                   &liCurrentOffset,
1991                                   ulCurrentIO,
1992                                   &iosbFlush);
1993
1994                     if( !NT_SUCCESS( iosbFlush.Status))
1995                     {
1996
1997                         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1998                                       AFS_TRACE_LEVEL_ERROR,
1999                                       "AFSCachedWrite (%p) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
2000                                       Irp,
2001                                       &pFileObject->FileName,
2002                                       pFcb->ObjectInformation->FileId.Cell,
2003                                       pFcb->ObjectInformation->FileId.Volume,
2004                                       pFcb->ObjectInformation->FileId.Vnode,
2005                                       pFcb->ObjectInformation->FileId.Unique,
2006                                       iosbFlush.Status,
2007                                       iosbFlush.Information));
2008
2009                         try_return( ntStatus = iosbFlush.Status);
2010                     }
2011                 }
2012                 __except( EXCEPTION_EXECUTE_HANDLER)
2013                 {
2014
2015                     ntStatus = GetExceptionCode();
2016
2017                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2018                                   AFS_TRACE_LEVEL_ERROR,
2019                                   "AFSCachedWrite (%p) CcFlushCache Threw exception %wZ @ %0I64X Status %08lX\n",
2020                                   Irp,
2021                                   &pFileObject->FileName,
2022                                   liCurrentOffset.QuadPart,
2023                                   ntStatus));
2024
2025                     try_return( ntStatus);
2026                 }
2027             }
2028
2029             if( ulTotalLen <= ulCurrentIO)
2030             {
2031                 break;
2032             }
2033
2034             liCurrentOffset.QuadPart += ulCurrentIO;
2035
2036             ulTotalLen -= ulCurrentIO;
2037
2038             pCurrentMdl = pCurrentMdl->Next;
2039         }
2040
2041 try_exit:
2042
2043         if( NT_SUCCESS( ntStatus))
2044         {
2045
2046             Irp->IoStatus.Information = ByteCount;
2047
2048             if ( ForceFlush ||
2049                  BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
2050             {
2051                 //
2052                 // Write through asked for... Set things so that we get
2053                 // flush when the worker thread next wakes up
2054                 //
2055                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
2056             }
2057         }
2058
2059         AFSCompleteRequest( Irp,
2060                             ntStatus);
2061     }
2062
2063     return ntStatus;
2064 }
2065
2066 //
2067 // Called with Fcb->NPFcb->SectionObjectResource and Fcb->NPFcb->Resource held
2068 //
2069
2070 static
2071 NTSTATUS
2072 AFSExtendingWrite( IN AFSFcb *Fcb,
2073                    IN PFILE_OBJECT FileObject,
2074                    IN LONGLONG NewLength)
2075 {
2076     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
2077     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
2078     NTSTATUS      ntStatus = STATUS_SUCCESS;
2079     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
2080
2081     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
2082     {
2083
2084         Fcb->Header.AllocationSize.QuadPart = NewLength;
2085
2086         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
2087     }
2088
2089     if( NewLength > Fcb->Header.FileSize.QuadPart)
2090     {
2091
2092         Fcb->Header.FileSize.QuadPart = NewLength;
2093
2094         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
2095     }
2096
2097     //
2098     // Tell the server
2099     //
2100
2101     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentFileId,
2102                                          Fcb->ObjectInformation,
2103                                          &pCcb->AuthGroup);
2104
2105     if (NT_SUCCESS(ntStatus))
2106     {
2107
2108         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
2109
2110         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
2111
2112         //
2113         // If the file is currently cached, then let the MM know about the extension
2114         //
2115         // The CcSetFileSizes call should be made with only the PagingResource held
2116         // which we are currently not holding.
2117         //
2118
2119         if( CcIsFileCached( FileObject))
2120         {
2121             CcSetFileSizes( FileObject,
2122                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
2123         }
2124     }
2125     else
2126     {
2127         Fcb->Header.FileSize = liSaveFileSize;
2128         Fcb->Header.AllocationSize = liSaveAllocation;
2129     }
2130
2131     //
2132     // DownConvert file resource to shared
2133     //
2134     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
2135
2136     return ntStatus;
2137 }
2138
2139 NTSTATUS
2140 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
2141                IN PIRP Irp)
2142 {
2143
2144     UNREFERENCED_PARAMETER(DeviceObject);
2145     NTSTATUS ntStatus = STATUS_SUCCESS;
2146     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2147     AFSFcb *pFcb = NULL;
2148     AFSCcb *pCcb = NULL;
2149     AFSPipeIORequestCB *pIoRequest = NULL;
2150     void *pBuffer = NULL;
2151     AFSPipeIOResultCB stIoResult;
2152     ULONG ulBytesReturned = 0;
2153
2154     __Enter
2155     {
2156
2157         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
2158
2159         AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2160                       AFS_TRACE_LEVEL_VERBOSE,
2161                       "AFSShareWrite On pipe %wZ Length %08lX\n",
2162                       &pCcb->DirectoryCB->NameInformation.FileName,
2163                       pIrpSp->Parameters.Write.Length));
2164
2165         if( pIrpSp->Parameters.Write.Length == 0)
2166         {
2167
2168             //
2169             // Nothing to do in this case
2170             //
2171
2172             try_return( ntStatus);
2173         }
2174
2175         //
2176         // Retrieve the buffer for the read request
2177         //
2178
2179         pBuffer = AFSLockSystemBuffer( Irp,
2180                                        pIrpSp->Parameters.Write.Length);
2181
2182         if( pBuffer == NULL)
2183         {
2184
2185             AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2186                           AFS_TRACE_LEVEL_ERROR,
2187                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
2188                           &pCcb->DirectoryCB->NameInformation.FileName));
2189
2190             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2191         }
2192
2193         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
2194
2195         AFSAcquireShared( &pFcb->NPFcb->Resource,
2196                           TRUE);
2197
2198         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
2199                                                                      sizeof( AFSPipeIORequestCB) +
2200                                                                                 pIrpSp->Parameters.Write.Length,
2201                                                                      AFS_GENERIC_MEMORY_14_TAG);
2202
2203         if( pIoRequest == NULL)
2204         {
2205
2206             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2207         }
2208
2209         RtlZeroMemory( pIoRequest,
2210                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
2211
2212         pIoRequest->RequestId = pCcb->RequestID;
2213
2214         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
2215
2216         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
2217
2218         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
2219                        pBuffer,
2220                        pIrpSp->Parameters.Write.Length);
2221
2222         stIoResult.BytesProcessed = 0;
2223
2224         ulBytesReturned = sizeof( AFSPipeIOResultCB);
2225
2226         //
2227         // Issue the open request to the service
2228         //
2229
2230         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
2231                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
2232                                       &pCcb->AuthGroup,
2233                                       &pCcb->DirectoryCB->NameInformation.FileName,
2234                                       NULL,
2235                                       NULL,
2236                                       0,
2237                                       pIoRequest,
2238                                       sizeof( AFSPipeIORequestCB) +
2239                                                 pIrpSp->Parameters.Write.Length,
2240                                       &stIoResult,
2241                                       &ulBytesReturned);
2242
2243         if( !NT_SUCCESS( ntStatus))
2244         {
2245
2246             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2247                           AFS_TRACE_LEVEL_ERROR,
2248                           "AFSShareWrite (%p) Failed service write Status %08lX\n",
2249                           Irp,
2250                           ntStatus));
2251
2252             try_return( ntStatus);
2253         }
2254
2255         AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2256                       AFS_TRACE_LEVEL_VERBOSE,
2257                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
2258                       &pCcb->DirectoryCB->NameInformation.FileName,
2259                       stIoResult.BytesProcessed));
2260
2261         Irp->IoStatus.Information = stIoResult.BytesProcessed;
2262
2263 try_exit:
2264
2265         if( pFcb != NULL)
2266         {
2267
2268             AFSReleaseResource( &pFcb->NPFcb->Resource);
2269         }
2270
2271         if( pIoRequest != NULL)
2272         {
2273
2274             AFSExFreePoolWithTag( pIoRequest, AFS_GENERIC_MEMORY_14_TAG);
2275         }
2276     }
2277
2278     return ntStatus;
2279 }