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