Windows: AFSCommonWrite add bWriteToEndOfFile var
[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_ACCESS_DENIED);
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                         if (pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart)
596                         {
597                             liStartingByte = pFcb->Header.ValidDataLength;
598                         }
599                         else
600                         {
601                             liStartingByte = pFcb->Header.FileSize;
602                         }
603                     }
604
605                     //
606                     // We have the correct lock - even if we don't end up truncating
607                     //
608                     bLockOK = TRUE;
609                 }
610                 else
611                 {
612                     ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
613
614                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
615                                   AFS_TRACE_LEVEL_VERBOSE,
616                                   "AFSCommonWrite Acquiring Fcb lock %p SHARED %08lX\n",
617                                   &pNPFcb->Resource,
618                                   PsGetCurrentThread()));
619
620                     AFSAcquireShared( &pNPFcb->Resource,
621                                       TRUE);
622
623                     bReleaseMain = TRUE;
624
625                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
626                                   AFS_TRACE_LEVEL_VERBOSE,
627                                   "AFSCommonWrite Acquiring Fcb SectionObject lock %p SHARED %08lX\n",
628                                   &pNPFcb->SectionObjectResource,
629                                   PsGetCurrentThread()));
630
631                     AFSAcquireShared( &pNPFcb->SectionObjectResource,
632                                       TRUE);
633
634                     bReleaseSectionObject = TRUE;
635
636                     //
637                     // Have things moved?  Are we extending? If so, the the lock isn't OK
638                     //
639                     bLockOK = (liStartingByte.QuadPart + ulByteCount) < pFcb->Header.FileSize.QuadPart;
640
641                     if (!bLockOK)
642                     {
643
644                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
645                                       AFS_TRACE_LEVEL_VERBOSE,
646                                       "AFSCommonWrite Releasing Fcb SectionObject lock %p SHARED %08lX\n",
647                                       &pNPFcb->SectionObjectResource,
648                                       PsGetCurrentThread()));
649
650                         AFSReleaseResource( &pNPFcb->SectionObjectResource);
651
652                         bReleaseSectionObject = FALSE;
653
654                         AFSReleaseResource( &pNPFcb->Resource);
655
656                         bReleaseMain = FALSE;
657                     }
658                 }
659             }
660         }
661         while (!bLockOK);
662
663         if( !bPagingIo)
664         {
665
666             //
667             // Check the BR locks on the file.
668             //
669
670             if ( !FsRtlCheckLockForWriteAccess( &pFcb->Specific.File.FileLock,
671                                                 Irp))
672             {
673
674                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
675                               AFS_TRACE_LEVEL_ERROR,
676                               "AFSCommonWrite (%p) Request failed due to lock conflict\n",
677                               Irp));
678
679                 try_return( ntStatus = STATUS_FILE_LOCK_CONFLICT);
680             }
681
682             if( bExtendingWrite)
683             {
684
685                 ntStatus = AFSExtendingWrite( pFcb, pFileObject, (liStartingByte.QuadPart + ulByteCount));
686
687                 //
688                 // Fcb->NPFcb->Resource is now held SHARED
689                 //
690
691                 if( !NT_SUCCESS(ntStatus))
692                 {
693
694                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
695                                   AFS_TRACE_LEVEL_ERROR,
696                                   "AFSCommonWrite (%p) Failed extending write request Status %08lX\n",
697                                   Irp,
698                                   ntStatus));
699
700                     try_return( ntStatus );
701                 }
702             }
703         }
704
705         //
706         // Fire off the request as appropriate
707         //
708         bCompleteIrp = FALSE;
709
710         if( !bPagingIo &&
711             !bNonCachedIo)
712         {
713
714             //
715             // Main resource held Shared
716             // SectionObject resource held exclusive if extending write
717             //
718
719             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
720                           AFS_TRACE_LEVEL_VERBOSE,
721                           "AFSCommonWrite (%p) Processing CACHED request Offset %0I64X Len %08lX%s\n",
722                           Irp,
723                           liStartingByte.QuadPart,
724                           ulByteCount,
725                           bRetry ? " RETRY" : ""));
726
727             ntStatus = AFSCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount, bForceFlush);
728         }
729         else
730         {
731
732             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
733                           AFS_TRACE_LEVEL_VERBOSE,
734                           "AFSCommonWrite (%p) Processing NON-CACHED request Offset %0I64X Len %08lX%s\n",
735                           Irp,
736                           liStartingByte.QuadPart,
737                           ulByteCount,
738                           bRetry ? " RETRY" : ""));
739
740             if( BooleanFlagOn( pRDRDevExt->DeviceFlags, AFS_DEVICE_FLAG_DIRECT_SERVICE_IO))
741             {
742
743                 ntStatus = AFSNonCachedWriteDirect( DeviceObject, Irp,  liStartingByte, ulByteCount);
744             }
745             else
746             {
747                 ntStatus = AFSNonCachedWrite( DeviceObject, Irp,  liStartingByte, ulByteCount);
748             }
749         }
750
751 try_exit:
752
753         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
754                       AFS_TRACE_LEVEL_VERBOSE,
755                       "AFSCommonWrite (%p) Process complete Status %08lX\n",
756                       Irp,
757                       ntStatus));
758
759         if ( NT_SUCCESS( ntStatus) &&
760              ntStatus != STATUS_PENDING)
761         {
762             if ( !bPagingIo)
763             {
764
765                 if( bSynchronousFo)
766                 {
767
768                     pFileObject->CurrentByteOffset.QuadPart = liStartingByte.QuadPart + ulByteCount;
769                 }
770
771                 //
772                 // If this extended the VDL, then update it accordingly.
773                 // Increasing the VDL does not require a call to CcSetFileSizes.
774                 //
775
776                 if( liStartingByte.QuadPart + ulByteCount > pFcb->Header.ValidDataLength.QuadPart)
777                 {
778
779                     pFcb->Header.ValidDataLength.QuadPart = liStartingByte.QuadPart + ulByteCount;
780                 }
781
782                 if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
783                 {
784
785                     SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
786
787                     KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
788                 }
789             }
790         }
791
792         if ( ntStatus != STATUS_PENDING &&
793              !bPagingIo && bNonCachedIo && CcIsFileCached( pFileObject) &&
794              pNPFcb->SectionObjectPointers.DataSectionObject != NULL &&
795              bReleaseSectionObject)
796         {
797             //
798             // Regardless of whether or not the a non-paging non-cached write
799             // succeeds or fails, if the file is cached the contents of the
800             // cache are no longer up to date.  A CcPurgeCacheSection must be
801             // performed to force subsequent cached reads to obtain the data
802             // from the service.
803             //
804             // The Fcb Resource is dropped in order to permit filters that perform
805             // an open via a worker thread in response to a purge to do so without
806             // deadlocking.  The SectionObjectResource is held across the purge to
807             // prevent racing with other cache operations.
808             //
809
810             if( bReleaseMain)
811             {
812
813                 AFSReleaseResource( &pNPFcb->Resource);
814
815                 bReleaseMain = FALSE;
816             }
817
818             __try
819             {
820
821                 if ( !CcPurgeCacheSection( &pNPFcb->SectionObjectPointers,
822                                            &liStartingByte,
823                                            ulByteCount,
824                                            FALSE))
825                 {
826
827                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
828                                   AFS_TRACE_LEVEL_WARNING,
829                                   "AFSCommonWrite CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
830                                   pFcb->ObjectInformation->FileId.Cell,
831                                   pFcb->ObjectInformation->FileId.Volume,
832                                   pFcb->ObjectInformation->FileId.Vnode,
833                                   pFcb->ObjectInformation->FileId.Unique));
834
835                     SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
836                 }
837             }
838             __except( EXCEPTION_EXECUTE_HANDLER)
839             {
840
841                 DWORD ntStatus2 = GetExceptionCode();
842
843                 AFSDbgTrace(( 0,
844                               0,
845                               "EXCEPTION - AFSCommonWrite CcPurgeCacheSection failed FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
846                               pFcb->ObjectInformation->FileId.Cell,
847                               pFcb->ObjectInformation->FileId.Volume,
848                               pFcb->ObjectInformation->FileId.Vnode,
849                               pFcb->ObjectInformation->FileId.Unique,
850                               ntStatus2));
851
852                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
853             }
854         }
855
856         ObDereferenceObject(pFileObject);
857
858         if( bReleaseSectionObject)
859         {
860
861             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
862                           AFS_TRACE_LEVEL_VERBOSE,
863                           "AFSCommonWrite Releasing Fcb SectionObject lock %p EXCL/SHARED %08lX\n",
864                           &pNPFcb->SectionObjectResource,
865                           PsGetCurrentThread()));
866
867             AFSReleaseResource( &pNPFcb->SectionObjectResource);
868         }
869
870         if( bReleasePaging)
871         {
872
873             AFSReleaseResource( &pNPFcb->PagingResource);
874         }
875
876         if( bReleaseMain)
877         {
878
879             AFSReleaseResource( &pNPFcb->Resource);
880         }
881
882         if( bCompleteIrp)
883         {
884
885             AFSCompleteRequest( Irp,
886                                 ntStatus);
887         }
888     }
889
890     return ntStatus;
891 }
892
893 NTSTATUS
894 AFSIOCtlWrite( IN PDEVICE_OBJECT DeviceObject,
895                IN PIRP Irp)
896 {
897
898     UNREFERENCED_PARAMETER(DeviceObject);
899     NTSTATUS ntStatus = STATUS_SUCCESS;
900     AFSPIOCtlIORequestCB stIORequestCB;
901     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
902     AFSFcb *pFcb = NULL;
903     AFSCcb *pCcb = NULL;
904     AFSPIOCtlIOResultCB stIOResultCB;
905     ULONG ulBytesReturned = 0;
906     AFSFileID stParentFID;
907
908     __Enter
909     {
910
911         Irp->IoStatus.Information = 0;
912
913         RtlZeroMemory( &stIORequestCB,
914                        sizeof( AFSPIOCtlIORequestCB));
915
916         if( pIrpSp->Parameters.Write.Length == 0)
917         {
918
919             //
920             // Nothing to do in this case
921             //
922
923             try_return( ntStatus);
924         }
925
926         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
927
928         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
929
930         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
931                       AFS_TRACE_LEVEL_VERBOSE,
932                       "AFSIOCtlWrite Acquiring Fcb lock %p SHARED %08lX\n",
933                       &pFcb->NPFcb->Resource,
934                       PsGetCurrentThread()));
935
936         AFSAcquireShared( &pFcb->NPFcb->Resource,
937                           TRUE);
938
939         //
940         // Get the parent fid to pass to the cm
941         //
942
943         RtlZeroMemory( &stParentFID,
944                        sizeof( AFSFileID));
945
946         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
947         {
948
949             //
950             // The parent directory FID of the node
951             //
952
953             stParentFID = pFcb->ObjectInformation->ParentFileId;
954         }
955
956         //
957         // Set the control block up
958         //
959
960         stIORequestCB.RequestId = pCcb->RequestID;
961
962         if( pFcb->ObjectInformation->VolumeCB != NULL)
963         {
964             stIORequestCB.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
965         }
966
967         //
968         // Lock down the buffer
969         //
970
971         stIORequestCB.MappedBuffer = AFSMapToService( Irp,
972                                                       pIrpSp->Parameters.Write.Length);
973
974         if( stIORequestCB.MappedBuffer == NULL)
975         {
976
977             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
978         }
979
980         stIORequestCB.BufferLength = pIrpSp->Parameters.Write.Length;
981
982         stIOResultCB.BytesProcessed = 0;
983
984         ulBytesReturned = sizeof( AFSPIOCtlIOResultCB);
985
986         //
987         // Issue the request to the service
988         //
989
990         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_WRITE,
991                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
992                                       &pCcb->AuthGroup,
993                                       NULL,
994                                       &stParentFID,
995                                       NULL,
996                                       0,
997                                       (void *)&stIORequestCB,
998                                       sizeof( AFSPIOCtlIORequestCB),
999                                       &stIOResultCB,
1000                                       &ulBytesReturned);
1001
1002         if( !NT_SUCCESS( ntStatus))
1003         {
1004
1005             try_return( ntStatus);
1006         }
1007
1008         //
1009         // Update the length written
1010         //
1011
1012         Irp->IoStatus.Information = stIOResultCB.BytesProcessed;
1013
1014 try_exit:
1015
1016         if( stIORequestCB.MappedBuffer != NULL)
1017         {
1018
1019             AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer,
1020                                          Irp->MdlAddress);
1021         }
1022
1023         if( pFcb != NULL)
1024         {
1025
1026             AFSReleaseResource( &pFcb->NPFcb->Resource);
1027         }
1028     }
1029
1030     return ntStatus;
1031 }
1032
1033 //
1034 // This function is called when we know we have to read from the AFS Cache.
1035 //
1036 // It ensures that we have exents for the entirety of the write and
1037 // then pins the extents into memory (meaning that although we may
1038 // add we will not remove).  Then it creates a scatter gather write
1039 // and fires off the IRPs
1040 //
1041 static
1042 NTSTATUS
1043 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1044                    IN PIRP Irp,
1045                    IN LARGE_INTEGER StartingByte,
1046                    IN ULONG ByteCount)
1047 {
1048     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
1049     VOID              *pSystemBuffer = NULL;
1050     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
1051     BOOLEAN            bLocked = FALSE;
1052     BOOLEAN            bCompleteIrp = TRUE;
1053     AFSGatherIo       *pGatherIo = NULL;
1054     AFSIoRun          *pIoRuns = NULL;
1055     AFSIoRun           stIoRuns[AFS_MAX_STACK_IO_RUNS];
1056     ULONG              extentsCount = 0, runCount = 0;
1057     AFSExtent         *pStartExtent = NULL;
1058     AFSExtent         *pIgnoreExtent = NULL;
1059     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1060     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1061     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1062     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1063     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1064     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
1065     LARGE_INTEGER      liCurrentTime, liLastRequestTime;
1066     AFSDeviceExt      *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1067     PFILE_OBJECT       pCacheFileObject = NULL;
1068     BOOLEAN            bDerefExtents = FALSE;
1069
1070     __Enter
1071     {
1072
1073         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1074                       AFS_TRACE_LEVEL_VERBOSE,
1075                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX\n",
1076                       pFileObject,
1077                       StartingByte.HighPart,
1078                       StartingByte.LowPart,
1079                       ByteCount));
1080
1081         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
1082         {
1083
1084             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1085                           AFS_TRACE_LEVEL_ERROR,
1086                           "AFSNonCachedWrite (%p) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
1087                           Irp,
1088                           ByteCount,
1089                           pIrpSp->Parameters.Write.Length,
1090                           pDevExt->Specific.RDR.MaxIo.QuadPart));
1091
1092             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1093         }
1094
1095         //
1096         // Get the mapping for the buffer
1097         //
1098         pSystemBuffer = AFSLockSystemBuffer( Irp,
1099                                              ByteCount);
1100
1101         if( pSystemBuffer == NULL)
1102         {
1103
1104             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1105                           AFS_TRACE_LEVEL_ERROR,
1106                           "AFSNonCachedWrite (%p) Failed to map system buffer\n",
1107                           Irp));
1108
1109             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1110         }
1111
1112
1113         //
1114         // Provoke a get of the extents - if we need to.
1115         //
1116
1117         AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1118                       AFS_TRACE_LEVEL_VERBOSE,
1119                       "AFSNonCachedWrite Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1120                       pFcb->ObjectInformation->FileId.Cell,
1121                       pFcb->ObjectInformation->FileId.Volume,
1122                       pFcb->ObjectInformation->FileId.Vnode,
1123                       pFcb->ObjectInformation->FileId.Unique,
1124                       StartingByte.QuadPart,
1125                       ByteCount));
1126
1127         ntStatus = AFSRequestExtentsAsync( pFcb,
1128                                            pCcb,
1129                                            &StartingByte,
1130                                            ByteCount);
1131
1132         if (!NT_SUCCESS(ntStatus))
1133         {
1134
1135             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1136                           AFS_TRACE_LEVEL_ERROR,
1137                           "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
1138                           Irp,
1139                           ntStatus));
1140
1141             try_return( ntStatus);
1142         }
1143
1144         KeQueryTickCount( &liLastRequestTime);
1145
1146         while (TRUE)
1147         {
1148
1149             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1150                           AFS_TRACE_LEVEL_VERBOSE,
1151                           "AFSNonCachedWrite Acquiring Fcb extents lock %p SHARED %08lX\n",
1152                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1153                           PsGetCurrentThread()));
1154
1155             ASSERT( !ExIsResourceAcquiredLite( &pFcb->NPFcb->Specific.File.ExtentsResource ));
1156
1157             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE );
1158             bLocked = TRUE;
1159
1160             pStartExtent = NULL;
1161             pIgnoreExtent = NULL;
1162
1163             if ( AFSDoExtentsMapRegion( pFcb, &StartingByte, ByteCount, &pStartExtent, &pIgnoreExtent ))
1164             {
1165                 break;
1166             }
1167
1168             KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete );
1169
1170             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1171                           AFS_TRACE_LEVEL_VERBOSE,
1172                           "AFSNonCachedWrite Releasing(1) Fcb extents lock %p SHARED %08lX\n",
1173                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1174                           PsGetCurrentThread()));
1175
1176             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1177             bLocked= FALSE;
1178
1179             //
1180             // We will re-request the extents after waiting for them
1181             //
1182
1183             KeQueryTickCount( &liCurrentTime);
1184
1185             if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart)
1186             {
1187
1188                 AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1189                               AFS_TRACE_LEVEL_VERBOSE,
1190                               "AFSNonCachedWrite Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1191                               pFcb->ObjectInformation->FileId.Cell,
1192                               pFcb->ObjectInformation->FileId.Volume,
1193                               pFcb->ObjectInformation->FileId.Vnode,
1194                               pFcb->ObjectInformation->FileId.Unique,
1195                               StartingByte.QuadPart,
1196                               ByteCount));
1197
1198                 ntStatus = AFSRequestExtentsAsync( pFcb,
1199                                                    pCcb,
1200                                                    &StartingByte,
1201                                                    ByteCount);
1202
1203                 if (!NT_SUCCESS(ntStatus))
1204                 {
1205
1206                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1207                                   AFS_TRACE_LEVEL_ERROR,
1208                                   "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
1209                                   Irp,
1210                                   ntStatus));
1211
1212                     try_return( ntStatus);
1213                 }
1214
1215                 KeQueryTickCount( &liLastRequestTime);
1216             }
1217
1218
1219             AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1220                           AFS_TRACE_LEVEL_VERBOSE,
1221                           "AFSNonCachedWrite Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1222                           pFcb->ObjectInformation->FileId.Cell,
1223                           pFcb->ObjectInformation->FileId.Volume,
1224                           pFcb->ObjectInformation->FileId.Vnode,
1225                           pFcb->ObjectInformation->FileId.Unique,
1226                           StartingByte.QuadPart,
1227                           ByteCount));
1228
1229             //
1230             // Wait for it
1231             //
1232
1233             ntStatus =  AFSWaitForExtentMapping ( pFcb, pCcb);
1234
1235             if (!NT_SUCCESS(ntStatus))
1236             {
1237
1238                 AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1239                               AFS_TRACE_LEVEL_ERROR,
1240                               "AFSNonCachedWrite Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX Status %08lX\n",
1241                               pFcb->ObjectInformation->FileId.Cell,
1242                               pFcb->ObjectInformation->FileId.Volume,
1243                               pFcb->ObjectInformation->FileId.Vnode,
1244                               pFcb->ObjectInformation->FileId.Unique,
1245                               StartingByte.QuadPart,
1246                               ByteCount,
1247                               ntStatus));
1248
1249                 try_return( ntStatus);
1250             }
1251         }
1252
1253         //
1254         // As per the read path -
1255         //
1256
1257         AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1258                       AFS_TRACE_LEVEL_VERBOSE,
1259                       "AFSNonCachedWrite Extents located for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX\n",
1260                       pFcb->ObjectInformation->FileId.Cell,
1261                       pFcb->ObjectInformation->FileId.Volume,
1262                       pFcb->ObjectInformation->FileId.Vnode,
1263                       pFcb->ObjectInformation->FileId.Unique,
1264                       StartingByte.QuadPart,
1265                       ByteCount));
1266
1267         ntStatus = AFSGetExtents( pFcb,
1268                                   &StartingByte,
1269                                   ByteCount,
1270                                   pStartExtent,
1271                                   &extentsCount,
1272                                   &runCount);
1273
1274         if (!NT_SUCCESS(ntStatus))
1275         {
1276
1277             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1278                           AFS_TRACE_LEVEL_ERROR,
1279                           "AFSNonCachedWrite (%p) Failed to retrieve mapped extents Status %08lX\n",
1280                           Irp,
1281                           ntStatus));
1282
1283             try_return( ntStatus );
1284         }
1285
1286         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1287                       AFS_TRACE_LEVEL_VERBOSE,
1288                       "AFSNonCachedWrite (%p) Successfully retrieved map extents count %d run count %d\n",
1289                       Irp,
1290                       extentsCount,
1291                       runCount));
1292
1293         if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
1294         {
1295
1296             Irp->IoStatus.Information = ByteCount;
1297
1298 #if GEN_MD5
1299             //
1300             // Setup the MD5 for each extent
1301             //
1302
1303             AFSSetupMD5Hash( pFcb,
1304                              pStartExtent,
1305                              extentsCount,
1306                              pSystemBuffer,
1307                              &StartingByte,
1308                              ByteCount);
1309 #endif
1310
1311             ntStatus = AFSProcessExtentRun( pSystemBuffer,
1312                                             &StartingByte,
1313                                             ByteCount,
1314                                             pStartExtent,
1315                                             TRUE);
1316
1317             if (!NT_SUCCESS(ntStatus))
1318             {
1319
1320                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1321                               AFS_TRACE_LEVEL_ERROR,
1322                               "AFSNonCachedWrite (%p) Failed to process extent run for non-persistent cache Status %08lX\n",
1323                               Irp,
1324                               ntStatus));
1325             }
1326
1327             try_return( ntStatus);
1328         }
1329
1330         //
1331         // Retrieve the cache file object
1332         //
1333
1334         pCacheFileObject = AFSReferenceCacheFileObject();
1335
1336         if( pCacheFileObject == NULL)
1337         {
1338
1339             ntStatus = STATUS_DEVICE_NOT_READY;
1340
1341             AFSDbgTrace(( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1342                           AFS_TRACE_LEVEL_ERROR,
1343                           "AFSNonCachedWrite Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %0I64X Length %08lX Status %08lX\n",
1344                           pFcb->ObjectInformation->FileId.Cell,
1345                           pFcb->ObjectInformation->FileId.Volume,
1346                           pFcb->ObjectInformation->FileId.Vnode,
1347                           pFcb->ObjectInformation->FileId.Unique,
1348                           StartingByte.QuadPart,
1349                           ByteCount,
1350                           ntStatus));
1351
1352             try_return( ntStatus);
1353         }
1354
1355         if (runCount > AFS_MAX_STACK_IO_RUNS)
1356         {
1357
1358             pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool,
1359                                                             runCount * sizeof( AFSIoRun ),
1360                                                             AFS_IO_RUN_TAG );
1361             if (NULL == pIoRuns)
1362             {
1363
1364                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1365                               AFS_TRACE_LEVEL_ERROR,
1366                               "AFSNonCachedWrite (%p) Failed to allocate IO run block\n",
1367                               Irp));
1368
1369                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1370             }
1371         }
1372         else
1373         {
1374
1375             pIoRuns = stIoRuns;
1376         }
1377
1378         RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun ));
1379
1380         ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject),
1381                                   Irp,
1382                                   pSystemBuffer,
1383                                   pIoRuns,
1384                                   &StartingByte,
1385                                   ByteCount,
1386                                   pStartExtent,
1387                                   &runCount );
1388
1389         if (!NT_SUCCESS(ntStatus))
1390         {
1391
1392             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1393                           AFS_TRACE_LEVEL_ERROR,
1394                           "AFSNonCachedWrite (%p) Failed to initialize IO run block Status %08lX\n",
1395                           Irp,
1396                           ntStatus));
1397
1398             try_return( ntStatus );
1399         }
1400
1401         AFSReferenceActiveExtents( pStartExtent,
1402                                    extentsCount);
1403
1404         bDerefExtents = TRUE;
1405
1406         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1407                       AFS_TRACE_LEVEL_VERBOSE,
1408                       "AFSNonCachedWrite Releasing(2) Fcb extents lock %p SHARED %08lX\n",
1409                       &pFcb->NPFcb->Specific.File.ExtentsResource,
1410                       PsGetCurrentThread()));
1411
1412         AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1413         bLocked = FALSE;
1414
1415         pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool,
1416                                                              sizeof( AFSGatherIo),
1417                                                              AFS_GATHER_TAG);
1418
1419         if (NULL == pGatherIo)
1420         {
1421
1422             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1423                           AFS_TRACE_LEVEL_ERROR,
1424                           "AFSNonCachedWrite (%p) Failed to allocate IO gather block\n",
1425                           Irp));
1426
1427             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1428                           AFS_TRACE_LEVEL_VERBOSE,
1429                           "AFSNonCachedWrite Acquiring(1) Fcb extents lock %p SHARED %08lX\n",
1430                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1431                           PsGetCurrentThread()));
1432
1433             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1434                               TRUE);
1435             bLocked = TRUE;
1436
1437             AFSDereferenceActiveExtents( pStartExtent,
1438                                          extentsCount);
1439
1440             try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1441         }
1442
1443         RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo ));
1444
1445         //
1446         // Initialize count to 1, that was we won't get an early
1447         // completion if the first irp completes before the second is
1448         // queued.
1449         //
1450         pGatherIo->Count = 1;
1451         pGatherIo->Status = STATUS_SUCCESS;
1452         pGatherIo->MasterIrp = Irp;
1453         pGatherIo->Synchronous = TRUE;
1454         pGatherIo->CompleteMasterIrp = FALSE;
1455
1456         bCompleteIrp = TRUE;
1457
1458         if( pGatherIo->Synchronous)
1459         {
1460             KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE );
1461         }
1462
1463 #if GEN_MD5
1464         //
1465         // Setup the MD5 for each extent
1466         //
1467
1468         AFSSetupMD5Hash( pFcb,
1469                          pStartExtent,
1470                          extentsCount,
1471                          pSystemBuffer,
1472                          &StartingByte,
1473                          ByteCount);
1474 #endif
1475
1476         //
1477         // Pre-emptively set up the count
1478         //
1479
1480         Irp->IoStatus.Information = ByteCount;
1481
1482         ntStatus = AFSQueueStartIos( pCacheFileObject,
1483                                      IRP_MJ_WRITE,
1484                                      IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API,
1485                                      pIoRuns,
1486                                      runCount,
1487                                      pGatherIo);
1488
1489         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1490                       AFS_TRACE_LEVEL_VERBOSE,
1491                       "AFSNonCachedWrite (%p) AFSStartIos completed Status %08lX\n",
1492                       Irp,
1493                       ntStatus));
1494
1495         if( !NT_SUCCESS( ntStatus))
1496         {
1497
1498             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1499                           AFS_TRACE_LEVEL_VERBOSE,
1500                           "AFSNonCachedWrite Acquiring(2) Fcb extents lock %p SHARED %08lX\n",
1501                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1502                           PsGetCurrentThread()));
1503
1504             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1505                               TRUE);
1506             bLocked = TRUE;
1507
1508             AFSDereferenceActiveExtents( pStartExtent,
1509                                          extentsCount);
1510
1511             try_return( ntStatus);
1512         }
1513
1514         //
1515         // Wait for completion of All IOs we started.
1516         //
1517
1518         ntStatus = KeWaitForSingleObject( &pGatherIo->Event,
1519                                           Executive,
1520                                           KernelMode,
1521                                           FALSE,
1522                                           NULL);
1523
1524         if( NT_SUCCESS( ntStatus))
1525         {
1526
1527             ntStatus = pGatherIo->Status;
1528         }
1529
1530         if( !NT_SUCCESS( ntStatus))
1531         {
1532
1533             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1534                           AFS_TRACE_LEVEL_VERBOSE,
1535                           "AFSNonCachedWrite Acquiring(3) Fcb extents lock %p SHARED %08lX\n",
1536                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1537                           PsGetCurrentThread()));
1538
1539             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1540                               TRUE);
1541             bLocked = TRUE;
1542
1543             AFSDereferenceActiveExtents( pStartExtent,
1544                                          extentsCount);
1545
1546             try_return( ntStatus);
1547         }
1548
1549 try_exit:
1550
1551         if( NT_SUCCESS( ntStatus) &&
1552             pStartExtent != NULL &&
1553             Irp->IoStatus.Information > 0)
1554         {
1555
1556             if ( !bLocked)
1557             {
1558
1559                 AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1560                                   TRUE);
1561                 bLocked = TRUE;
1562             }
1563
1564             //
1565             // Since this is dirty we can mark the extents dirty now.
1566             // AFSMarkDirty will dereference the extents.  Do not call
1567             // AFSDereferenceActiveExtents() in this code path.
1568             //
1569
1570             AFSMarkDirty( pFcb,
1571                           pStartExtent,
1572                           extentsCount,
1573                           &StartingByte,
1574                           bDerefExtents);
1575
1576             if (!bPagingIo)
1577             {
1578                 //
1579                 // This was an uncached user write - tell the server to do
1580                 // the flush when the worker thread next wakes up
1581                 //
1582                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1583             }
1584         }
1585
1586         if( pCacheFileObject != NULL)
1587         {
1588             AFSReleaseCacheFileObject( pCacheFileObject);
1589         }
1590
1591         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1592                       AFS_TRACE_LEVEL_VERBOSE,
1593                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX Status %08lX\n",
1594                       pFileObject,
1595                       StartingByte.HighPart,
1596                       StartingByte.LowPart,
1597                       ByteCount,
1598                       ntStatus));
1599
1600         if (NT_SUCCESS(ntStatus) &&
1601             !bPagingIo &&
1602             bSynchronousFo)
1603         {
1604
1605             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1606         }
1607
1608         if( bLocked)
1609         {
1610
1611             AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1612                           AFS_TRACE_LEVEL_VERBOSE,
1613                           "AFSNonCachedWrite Releasing Fcb extents lock %p SHARED %08lX\n",
1614                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1615                           PsGetCurrentThread()));
1616
1617             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1618         }
1619
1620         if( pGatherIo)
1621         {
1622             AFSExFreePoolWithTag(pGatherIo, AFS_GATHER_TAG);
1623         }
1624
1625         if( NULL != pIoRuns &&
1626             stIoRuns != pIoRuns)
1627         {
1628             AFSExFreePoolWithTag(pIoRuns, AFS_IO_RUN_TAG);
1629         }
1630
1631         if( bCompleteIrp)
1632         {
1633
1634             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1635                           AFS_TRACE_LEVEL_VERBOSE,
1636                           "AFSNonCachedWrite Completing Irp %p Status %08lX Info %08lX\n",
1637                           Irp,
1638                           ntStatus,
1639                           Irp->IoStatus.Information));
1640
1641             AFSCompleteRequest( Irp, ntStatus);
1642         }
1643     }
1644
1645     return ntStatus;
1646 }
1647
1648 static
1649 NTSTATUS
1650 AFSNonCachedWriteDirect( IN PDEVICE_OBJECT DeviceObject,
1651                          IN PIRP Irp,
1652                          IN LARGE_INTEGER StartingByte,
1653                          IN ULONG ByteCount)
1654 {
1655     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
1656     VOID              *pSystemBuffer = NULL;
1657     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
1658     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1659     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1660     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1661     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1662     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1663     BOOLEAN            bNoIntermediateBuffering = BooleanFlagOn( pFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING);
1664     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
1665     AFSFileIOCB        stFileIORequest;
1666     AFSFileIOResultCB  stFileIOResult;
1667     ULONG              ulResultLen = 0;
1668     ULONG              ulFlags;
1669
1670     __Enter
1671     {
1672         Irp->IoStatus.Information = 0;
1673
1674         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1675                       AFS_TRACE_LEVEL_VERBOSE,
1676                       "AFSNonCachedWriteDirect (FO: %p) StartingByte %08lX:%08lX Length %08lX\n",
1677                       pFileObject,
1678                       StartingByte.HighPart,
1679                       StartingByte.LowPart,
1680                       ByteCount));
1681
1682         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
1683         {
1684
1685             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1686                           AFS_TRACE_LEVEL_ERROR,
1687                           "AFSNonCachedWriteDirect (%p) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
1688                           Irp,
1689                           ByteCount,
1690                           pIrpSp->Parameters.Write.Length,
1691                           pDevExt->Specific.RDR.MaxIo.QuadPart));
1692
1693             try_return( ntStatus = STATUS_UNSUCCESSFUL);
1694         }
1695
1696         //
1697         // Get the mapping for the buffer
1698         //
1699         pSystemBuffer = AFSLockSystemBuffer( Irp,
1700                                              ByteCount);
1701
1702         if( pSystemBuffer == NULL)
1703         {
1704
1705             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1706                           AFS_TRACE_LEVEL_ERROR,
1707                           "AFSNonCachedWriteDirect (%p) Failed to map system buffer\n",
1708                           Irp));
1709
1710             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1711         }
1712
1713         //
1714         // Issue the request at the service for processing
1715         //
1716
1717         ulResultLen = sizeof( AFSFileIOResultCB);
1718
1719         RtlZeroMemory( &stFileIORequest,
1720                        sizeof( AFSFileIOCB));
1721
1722         RtlZeroMemory( &stFileIOResult,
1723                        sizeof( AFSFileIOResultCB));
1724
1725         stFileIORequest.SystemIOBuffer = pSystemBuffer;
1726
1727         stFileIORequest.SystemIOBufferMdl = Irp->MdlAddress;
1728
1729         stFileIORequest.IOLength = ByteCount;
1730
1731         stFileIORequest.IOOffset = StartingByte;
1732
1733         ulFlags = AFS_REQUEST_FLAG_SYNCHRONOUS;
1734
1735         if ( bNoIntermediateBuffering)
1736         {
1737
1738             ulFlags |= AFS_REQUEST_FLAG_CACHE_BYPASS;
1739         }
1740
1741         //
1742         // Update file metadata
1743         //
1744
1745         stFileIORequest.EndOfFile = pFcb->ObjectInformation->EndOfFile;
1746
1747         stFileIORequest.CreateTime = pFcb->ObjectInformation->CreationTime;
1748
1749         stFileIORequest.ChangeTime = pFcb->ObjectInformation->ChangeTime;
1750
1751         stFileIORequest.LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
1752
1753         stFileIORequest.LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
1754
1755         //
1756         // Write the data to the service
1757         //
1758
1759         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PROCESS_WRITE_FILE,
1760                                       ulFlags,
1761                                       &pCcb->AuthGroup,
1762                                       &pCcb->DirectoryCB->NameInformation.FileName,
1763                                       &pFcb->ObjectInformation->FileId,
1764                                       pFcb->ObjectInformation->VolumeCB->VolumeInformation.Cell,
1765                                       pFcb->ObjectInformation->VolumeCB->VolumeInformation.CellLength,
1766                                       &stFileIORequest,
1767                                       sizeof( AFSFileIOCB),
1768                                       &stFileIOResult,
1769                                       &ulResultLen);
1770
1771         if( NT_SUCCESS( ntStatus))
1772         {
1773
1774             Irp->IoStatus.Information = (ULONG_PTR)stFileIOResult.Length;
1775         }
1776         else
1777         {
1778
1779             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1780                           AFS_TRACE_LEVEL_ERROR,
1781                           "AFSNonCachedWriteDirect (%p) Failed to send write to service Status %08lX\n",
1782                           Irp,
1783                           ntStatus));
1784         }
1785
1786 try_exit:
1787
1788         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1789                       AFS_TRACE_LEVEL_VERBOSE,
1790                       "AFSNonCachedWriteDirect (FO: %p) StartingByte %08lX:%08lX Length %08lX Status %08lX\n",
1791                       pFileObject,
1792                       StartingByte.HighPart,
1793                       StartingByte.LowPart,
1794                       ByteCount,
1795                       ntStatus));
1796
1797         if (NT_SUCCESS(ntStatus) &&
1798             !bPagingIo &&
1799             bSynchronousFo)
1800         {
1801
1802             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1803         }
1804
1805         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1806                       AFS_TRACE_LEVEL_VERBOSE,
1807                       "AFSNonCachedWriteDirect Completing Irp %p Status %08lX Info %08lX\n",
1808                       Irp,
1809                       ntStatus,
1810                       Irp->IoStatus.Information));
1811
1812         AFSCompleteRequest( Irp, ntStatus);
1813     }
1814
1815     return ntStatus;
1816 }
1817
1818 static
1819 NTSTATUS
1820 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1821                 IN PIRP Irp,
1822                 IN LARGE_INTEGER StartingByte,
1823                 IN ULONG ByteCount,
1824                 IN BOOLEAN ForceFlush)
1825 {
1826     UNREFERENCED_PARAMETER(DeviceObject);
1827     PVOID              pSystemBuffer = NULL;
1828     NTSTATUS           ntStatus = STATUS_SUCCESS;
1829     IO_STATUS_BLOCK    iosbFlush;
1830     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1831     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1832     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1833     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1834     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1835     PMDL               pCurrentMdl = Irp->MdlAddress;
1836     LARGE_INTEGER      liCurrentOffset;
1837
1838     __Enter
1839     {
1840
1841         Irp->IoStatus.Information = 0;
1842
1843         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1844         {
1845
1846             __try
1847             {
1848
1849                 CcPrepareMdlWrite( pFileObject,
1850                                    &StartingByte,
1851                                    ByteCount,
1852                                    &Irp->MdlAddress,
1853                                    &Irp->IoStatus);
1854
1855                 ntStatus = Irp->IoStatus.Status;
1856             }
1857             __except( EXCEPTION_EXECUTE_HANDLER)
1858             {
1859                 ntStatus = GetExceptionCode();
1860
1861                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1862                               AFS_TRACE_LEVEL_ERROR,
1863                               "AFSCachedWrite (%p) Exception thrown while preparing mdl write Status %08lX\n",
1864                               Irp,
1865                               ntStatus));
1866             }
1867
1868             if( !NT_SUCCESS( ntStatus))
1869             {
1870
1871                 //
1872                 // Free up any potentially allocated mdl's
1873                 //
1874
1875                 CcMdlWriteComplete( pFileObject,
1876                                     &StartingByte,
1877                                     Irp->MdlAddress);
1878
1879                 Irp->MdlAddress = NULL;
1880
1881                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1882                               AFS_TRACE_LEVEL_ERROR,
1883                               "AFSCachedWrite (%p) Failed to process MDL write Status %08lX\n",
1884                               Irp,
1885                               ntStatus));
1886             }
1887
1888             try_return( ntStatus);
1889         }
1890
1891         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1892
1893         while( ulTotalLen > 0)
1894         {
1895
1896             ntStatus = STATUS_SUCCESS;
1897
1898             if( pCurrentMdl != NULL)
1899             {
1900
1901                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1902                                                               NormalPagePriority);
1903
1904                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1905
1906                 if( ulCurrentIO > ulTotalLen)
1907                 {
1908                     ulCurrentIO = ulTotalLen;
1909                 }
1910             }
1911             else
1912             {
1913
1914                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1915                                                      ulTotalLen);
1916
1917                 ulCurrentIO = ulTotalLen;
1918             }
1919
1920             if( pSystemBuffer == NULL)
1921             {
1922
1923                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1924                               AFS_TRACE_LEVEL_ERROR,
1925                               "AFSCachedWrite (%p) Failed to lock system buffer\n",
1926                               Irp));
1927
1928                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1929             }
1930
1931             __try
1932             {
1933
1934                 if( !CcCopyWrite( pFileObject,
1935                                   &liCurrentOffset,
1936                                   ulCurrentIO,
1937                                   TRUE,
1938                                   pSystemBuffer))
1939                 {
1940                     //
1941                     // Failed to process request.
1942                     //
1943
1944                     AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1945                                   AFS_TRACE_LEVEL_ERROR,
1946                                   "AFSCachedWrite (%p) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1947                                   Irp,
1948                                   &pFileObject->FileName,
1949                                   liCurrentOffset.QuadPart,
1950                                   Irp->IoStatus.Status));
1951
1952                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1953                 }
1954             }
1955             __except( EXCEPTION_EXECUTE_HANDLER)
1956             {
1957
1958                 ntStatus = GetExceptionCode();
1959
1960                 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1961                               AFS_TRACE_LEVEL_ERROR,
1962                               "AFSCachedWrite (%p) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1963                               Irp,
1964                               &pFileObject->FileName,
1965                               liCurrentOffset.QuadPart,
1966                               ntStatus));
1967             }
1968
1969             if( !NT_SUCCESS( ntStatus))
1970             {
1971                 try_return( ntStatus);
1972             }
1973
1974             if( ForceFlush ||
1975                 BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1976             {
1977
1978                 __try
1979                 {
1980                     //
1981                     // We have detected a file we do a write through with.
1982                     //
1983
1984                     CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1985                                   &liCurrentOffset,
1986                                   ulCurrentIO,
1987                                   &iosbFlush);
1988
1989                     if( !NT_SUCCESS( iosbFlush.Status))
1990                     {
1991
1992                         AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
1993                                       AFS_TRACE_LEVEL_ERROR,
1994                                       "AFSCachedWrite (%p) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1995                                       Irp,
1996                                       &pFileObject->FileName,
1997                                       pFcb->ObjectInformation->FileId.Cell,
1998                                       pFcb->ObjectInformation->FileId.Volume,
1999                                       pFcb->ObjectInformation->FileId.Vnode,
2000                                       pFcb->ObjectInformation->FileId.Unique,
2001                                       iosbFlush.Status,
2002                                       iosbFlush.Information));
2003
2004                         try_return( ntStatus = iosbFlush.Status);
2005                     }
2006                 }
2007                 __except( EXCEPTION_EXECUTE_HANDLER)
2008                 {
2009
2010                     ntStatus = GetExceptionCode();
2011
2012                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
2013                                   AFS_TRACE_LEVEL_ERROR,
2014                                   "AFSCachedWrite (%p) CcFlushCache Threw exception %wZ @ %0I64X Status %08lX\n",
2015                                   Irp,
2016                                   &pFileObject->FileName,
2017                                   liCurrentOffset.QuadPart,
2018                                   ntStatus));
2019
2020                     try_return( ntStatus);
2021                 }
2022             }
2023
2024             if( ulTotalLen <= ulCurrentIO)
2025             {
2026                 break;
2027             }
2028
2029             liCurrentOffset.QuadPart += ulCurrentIO;
2030
2031             ulTotalLen -= ulCurrentIO;
2032
2033             pCurrentMdl = pCurrentMdl->Next;
2034         }
2035
2036 try_exit:
2037
2038         if( NT_SUCCESS( ntStatus))
2039         {
2040
2041             Irp->IoStatus.Information = ByteCount;
2042
2043             if ( ForceFlush ||
2044                  BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
2045             {
2046                 //
2047                 // Write through asked for... Set things so that we get
2048                 // flush when the worker thread next wakes up
2049                 //
2050                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
2051             }
2052         }
2053
2054         AFSCompleteRequest( Irp,
2055                             ntStatus);
2056     }
2057
2058     return ntStatus;
2059 }
2060
2061 //
2062 // Called with Fcb->NPFcb->SectionObjectResource and Fcb->NPFcb->Resource held
2063 //
2064
2065 static
2066 NTSTATUS
2067 AFSExtendingWrite( IN AFSFcb *Fcb,
2068                    IN PFILE_OBJECT FileObject,
2069                    IN LONGLONG NewLength)
2070 {
2071     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
2072     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
2073     NTSTATUS      ntStatus = STATUS_SUCCESS;
2074     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
2075
2076     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
2077     {
2078
2079         Fcb->Header.AllocationSize.QuadPart = NewLength;
2080
2081         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
2082     }
2083
2084     if( NewLength > Fcb->Header.FileSize.QuadPart)
2085     {
2086
2087         Fcb->Header.FileSize.QuadPart = NewLength;
2088
2089         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
2090     }
2091
2092     //
2093     // Tell the server
2094     //
2095
2096     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentFileId,
2097                                          Fcb->ObjectInformation,
2098                                          &pCcb->AuthGroup);
2099
2100     if (NT_SUCCESS(ntStatus))
2101     {
2102
2103         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
2104
2105         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
2106
2107         //
2108         // If the file is currently cached, then let the MM know about the extension
2109         //
2110         // The CcSetFileSizes call should be made with only the PagingResource held
2111         // which we are currently not holding.
2112         //
2113
2114         if( CcIsFileCached( FileObject))
2115         {
2116             CcSetFileSizes( FileObject,
2117                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
2118         }
2119     }
2120     else
2121     {
2122         Fcb->Header.FileSize = liSaveFileSize;
2123         Fcb->Header.AllocationSize = liSaveAllocation;
2124     }
2125
2126     //
2127     // DownConvert file resource to shared
2128     //
2129     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
2130
2131     return ntStatus;
2132 }
2133
2134 NTSTATUS
2135 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
2136                IN PIRP Irp)
2137 {
2138
2139     UNREFERENCED_PARAMETER(DeviceObject);
2140     NTSTATUS ntStatus = STATUS_SUCCESS;
2141     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2142     AFSFcb *pFcb = NULL;
2143     AFSCcb *pCcb = NULL;
2144     AFSPipeIORequestCB *pIoRequest = NULL;
2145     void *pBuffer = NULL;
2146     AFSPipeIOResultCB stIoResult;
2147     ULONG ulBytesReturned = 0;
2148
2149     __Enter
2150     {
2151
2152         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
2153
2154         AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2155                       AFS_TRACE_LEVEL_VERBOSE,
2156                       "AFSShareWrite On pipe %wZ Length %08lX\n",
2157                       &pCcb->DirectoryCB->NameInformation.FileName,
2158                       pIrpSp->Parameters.Write.Length));
2159
2160         if( pIrpSp->Parameters.Write.Length == 0)
2161         {
2162
2163             //
2164             // Nothing to do in this case
2165             //
2166
2167             try_return( ntStatus);
2168         }
2169
2170         //
2171         // Retrieve the buffer for the read request
2172         //
2173
2174         pBuffer = AFSLockSystemBuffer( Irp,
2175                                        pIrpSp->Parameters.Write.Length);
2176
2177         if( pBuffer == NULL)
2178         {
2179
2180             AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2181                           AFS_TRACE_LEVEL_ERROR,
2182                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
2183                           &pCcb->DirectoryCB->NameInformation.FileName));
2184
2185             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2186         }
2187
2188         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
2189
2190         AFSAcquireShared( &pFcb->NPFcb->Resource,
2191                           TRUE);
2192
2193         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
2194                                                                      sizeof( AFSPipeIORequestCB) +
2195                                                                                 pIrpSp->Parameters.Write.Length,
2196                                                                      AFS_GENERIC_MEMORY_14_TAG);
2197
2198         if( pIoRequest == NULL)
2199         {
2200
2201             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2202         }
2203
2204         RtlZeroMemory( pIoRequest,
2205                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
2206
2207         pIoRequest->RequestId = pCcb->RequestID;
2208
2209         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
2210
2211         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
2212
2213         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
2214                        pBuffer,
2215                        pIrpSp->Parameters.Write.Length);
2216
2217         stIoResult.BytesProcessed = 0;
2218
2219         ulBytesReturned = sizeof( AFSPipeIOResultCB);
2220
2221         //
2222         // Issue the open request to the service
2223         //
2224
2225         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
2226                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
2227                                       &pCcb->AuthGroup,
2228                                       &pCcb->DirectoryCB->NameInformation.FileName,
2229                                       NULL,
2230                                       NULL,
2231                                       0,
2232                                       pIoRequest,
2233                                       sizeof( AFSPipeIORequestCB) +
2234                                                 pIrpSp->Parameters.Write.Length,
2235                                       &stIoResult,
2236                                       &ulBytesReturned);
2237
2238         if( !NT_SUCCESS( ntStatus))
2239         {
2240
2241             AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
2242                           AFS_TRACE_LEVEL_ERROR,
2243                           "AFSShareWrite (%p) Failed service write Status %08lX\n",
2244                           Irp,
2245                           ntStatus));
2246
2247             try_return( ntStatus);
2248         }
2249
2250         AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
2251                       AFS_TRACE_LEVEL_VERBOSE,
2252                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
2253                       &pCcb->DirectoryCB->NameInformation.FileName,
2254                       stIoResult.BytesProcessed));
2255
2256         Irp->IoStatus.Information = stIoResult.BytesProcessed;
2257
2258 try_exit:
2259
2260         if( pFcb != NULL)
2261         {
2262
2263             AFSReleaseResource( &pFcb->NPFcb->Resource);
2264         }
2265
2266         if( pIoRequest != NULL)
2267         {
2268
2269             AFSExFreePoolWithTag( pIoRequest, AFS_GENERIC_MEMORY_14_TAG);
2270         }
2271     }
2272
2273     return ntStatus;
2274 }