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