a868630dd183c4db16308561d5349fe115869eca
[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                                       NULL,
826                                       0,
827                                       (void *)&stIORequestCB,
828                                       sizeof( AFSPIOCtlIORequestCB),
829                                       &stIOResultCB,
830                                       &ulBytesReturned);
831
832         if( !NT_SUCCESS( ntStatus))
833         {
834
835             try_return( ntStatus);
836         }
837
838         //
839         // Update the length written
840         //
841
842         Irp->IoStatus.Information = stIOResultCB.BytesProcessed;
843
844 try_exit:
845
846         if( stIORequestCB.MappedBuffer != NULL)
847         {
848
849             AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer,
850                                          Irp->MdlAddress);
851         }
852
853         if( pFcb != NULL)
854         {
855
856             AFSReleaseResource( &pFcb->NPFcb->Resource);
857         }
858     }
859
860     return ntStatus;
861 }
862
863 //
864 // This function is called when we know we have to read from the AFS Cache.
865 //
866 // It ensures that we have exents for the entirety of the write and
867 // then pins the extents into memory (meaning that although we may
868 // add we will not remove).  Then it creates a scatter gather write
869 // and fires off the IRPs
870 //
871 static
872 NTSTATUS
873 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
874                    IN PIRP Irp,
875                    IN LARGE_INTEGER StartingByte,
876                    IN ULONG ByteCount)
877 {
878     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
879     VOID              *pSystemBuffer = NULL;
880     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
881     BOOLEAN            bLocked = FALSE;
882     BOOLEAN            bCompleteIrp = TRUE;
883     AFSGatherIo       *pGatherIo = NULL;
884     AFSIoRun          *pIoRuns = NULL;
885     AFSIoRun           stIoRuns[AFS_MAX_STACK_IO_RUNS];
886     ULONG              extentsCount = 0, runCount = 0;
887     AFSExtent         *pStartExtent = NULL;
888     AFSExtent         *pIgnoreExtent = NULL;
889     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
890     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
891     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
892     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
893     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
894     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
895     LARGE_INTEGER      liCurrentTime, liLastRequestTime;
896     AFSDeviceExt      *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
897     PFILE_OBJECT       pCacheFileObject = NULL;
898     BOOLEAN            bDerefExtents = FALSE;
899
900     __Enter
901     {
902         Irp->IoStatus.Information = 0;
903
904         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
905                       AFS_TRACE_LEVEL_VERBOSE,
906                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX\n",
907                       pFileObject,
908                       StartingByte.HighPart,
909                       StartingByte.LowPart,
910                       ByteCount);
911
912         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
913         {
914
915             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
916                           AFS_TRACE_LEVEL_ERROR,
917                           "AFSNonCachedWrite (%p) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
918                           Irp,
919                           ByteCount,
920                           pIrpSp->Parameters.Write.Length,
921                           pDevExt->Specific.RDR.MaxIo.QuadPart);
922
923             try_return( ntStatus = STATUS_UNSUCCESSFUL);
924         }
925
926         //
927         // Get the mapping for the buffer
928         //
929         pSystemBuffer = AFSLockSystemBuffer( Irp,
930                                              ByteCount);
931
932         if( pSystemBuffer == NULL)
933         {
934
935             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
936                           AFS_TRACE_LEVEL_ERROR,
937                           "AFSNonCachedWrite (%p) Failed to map system buffer\n",
938                           Irp);
939
940             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
941         }
942
943
944         //
945         // Provoke a get of the extents - if we need to.
946         //
947
948         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
949                       AFS_TRACE_LEVEL_VERBOSE,
950                       "AFSNonCachedWrite Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
951                       pFcb->ObjectInformation->FileId.Cell,
952                       pFcb->ObjectInformation->FileId.Volume,
953                       pFcb->ObjectInformation->FileId.Vnode,
954                       pFcb->ObjectInformation->FileId.Unique,
955                       StartingByte.QuadPart,
956                       ByteCount);
957
958         ntStatus = AFSRequestExtentsAsync( pFcb,
959                                            pCcb,
960                                            &StartingByte,
961                                            ByteCount);
962
963         if (!NT_SUCCESS(ntStatus))
964         {
965
966             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
967                           AFS_TRACE_LEVEL_ERROR,
968                           "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
969                           Irp,
970                           ntStatus);
971
972             try_return( ntStatus);
973         }
974
975         KeQueryTickCount( &liLastRequestTime);
976
977         while (TRUE)
978         {
979
980             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
981                           AFS_TRACE_LEVEL_VERBOSE,
982                           "AFSNonCachedWrite Acquiring Fcb extents lock %p SHARED %08lX\n",
983                           &pFcb->NPFcb->Specific.File.ExtentsResource,
984                           PsGetCurrentThread());
985
986             ASSERT( !ExIsResourceAcquiredLite( &pFcb->NPFcb->Specific.File.ExtentsResource ));
987
988             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE );
989             bLocked = TRUE;
990
991             pStartExtent = NULL;
992             pIgnoreExtent = NULL;
993
994             if ( AFSDoExtentsMapRegion( pFcb, &StartingByte, ByteCount, &pStartExtent, &pIgnoreExtent ))
995             {
996                 break;
997             }
998
999             KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete );
1000
1001             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1002                           AFS_TRACE_LEVEL_VERBOSE,
1003                           "AFSNonCachedWrite Releasing(1) Fcb extents lock %p SHARED %08lX\n",
1004                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1005                           PsGetCurrentThread());
1006
1007             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1008             bLocked= FALSE;
1009
1010             //
1011             // We will re-request the extents after waiting for them
1012             //
1013
1014             KeQueryTickCount( &liCurrentTime);
1015
1016             if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart)
1017             {
1018
1019                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1020                               AFS_TRACE_LEVEL_VERBOSE,
1021                               "AFSNonCachedWrite Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
1022                               pFcb->ObjectInformation->FileId.Cell,
1023                               pFcb->ObjectInformation->FileId.Volume,
1024                               pFcb->ObjectInformation->FileId.Vnode,
1025                               pFcb->ObjectInformation->FileId.Unique,
1026                               StartingByte.QuadPart,
1027                               ByteCount);
1028
1029                 ntStatus = AFSRequestExtentsAsync( pFcb,
1030                                                    pCcb,
1031                                                    &StartingByte,
1032                                                    ByteCount);
1033
1034                 if (!NT_SUCCESS(ntStatus))
1035                 {
1036
1037                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1038                                   AFS_TRACE_LEVEL_ERROR,
1039                                   "AFSNonCachedWrite (%p) Failed to request extents Status %08lX\n",
1040                                   Irp,
1041                                   ntStatus);
1042
1043                     try_return( ntStatus);
1044                 }
1045
1046                 KeQueryTickCount( &liLastRequestTime);
1047             }
1048
1049
1050             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1051                           AFS_TRACE_LEVEL_VERBOSE,
1052                           "AFSNonCachedWrite Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
1053                           pFcb->ObjectInformation->FileId.Cell,
1054                           pFcb->ObjectInformation->FileId.Volume,
1055                           pFcb->ObjectInformation->FileId.Vnode,
1056                           pFcb->ObjectInformation->FileId.Unique,
1057                           StartingByte.QuadPart,
1058                           ByteCount);
1059
1060             //
1061             // Wait for it
1062             //
1063
1064             ntStatus =  AFSWaitForExtentMapping ( pFcb, pCcb);
1065
1066             if (!NT_SUCCESS(ntStatus))
1067             {
1068
1069                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1070                               AFS_TRACE_LEVEL_ERROR,
1071                               "AFSNonCachedWrite Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n",
1072                               pFcb->ObjectInformation->FileId.Cell,
1073                               pFcb->ObjectInformation->FileId.Volume,
1074                               pFcb->ObjectInformation->FileId.Vnode,
1075                               pFcb->ObjectInformation->FileId.Unique,
1076                               StartingByte.QuadPart,
1077                               ByteCount,
1078                               ntStatus);
1079
1080                 try_return( ntStatus);
1081             }
1082         }
1083
1084         //
1085         // As per the read path -
1086         //
1087
1088         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1089                       AFS_TRACE_LEVEL_VERBOSE,
1090                       "AFSNonCachedWrite Extents located for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
1091                       pFcb->ObjectInformation->FileId.Cell,
1092                       pFcb->ObjectInformation->FileId.Volume,
1093                       pFcb->ObjectInformation->FileId.Vnode,
1094                       pFcb->ObjectInformation->FileId.Unique,
1095                       StartingByte.QuadPart,
1096                       ByteCount);
1097
1098         ntStatus = AFSGetExtents( pFcb,
1099                                   &StartingByte,
1100                                   ByteCount,
1101                                   pStartExtent,
1102                                   &extentsCount,
1103                                   &runCount);
1104
1105         if (!NT_SUCCESS(ntStatus))
1106         {
1107
1108             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1109                           AFS_TRACE_LEVEL_ERROR,
1110                           "AFSNonCachedWrite (%p) Failed to retrieve mapped extents Status %08lX\n",
1111                           Irp,
1112                           ntStatus);
1113
1114             try_return( ntStatus );
1115         }
1116
1117         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1118                       AFS_TRACE_LEVEL_VERBOSE,
1119                       "AFSNonCachedWrite (%p) Successfully retrieved map extents count %d run count %d\n",
1120                       Irp,
1121                       extentsCount,
1122                       runCount);
1123
1124         if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
1125         {
1126
1127             Irp->IoStatus.Information = ByteCount;
1128
1129 #if GEN_MD5
1130             //
1131             // Setup the MD5 for each extent
1132             //
1133
1134             AFSSetupMD5Hash( pFcb,
1135                              pStartExtent,
1136                              extentsCount,
1137                              pSystemBuffer,
1138                              &StartingByte,
1139                              ByteCount);
1140 #endif
1141
1142             ntStatus = AFSProcessExtentRun( pSystemBuffer,
1143                                             &StartingByte,
1144                                             ByteCount,
1145                                             pStartExtent,
1146                                             TRUE);
1147
1148             if (!NT_SUCCESS(ntStatus))
1149             {
1150
1151                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1152                               AFS_TRACE_LEVEL_ERROR,
1153                               "AFSNonCachedWrite (%p) Failed to process extent run for non-persistent cache Status %08lX\n",
1154                               Irp,
1155                               ntStatus);
1156             }
1157
1158             try_return( ntStatus);
1159         }
1160
1161         //
1162         // Retrieve the cache file object
1163         //
1164
1165         pCacheFileObject = AFSReferenceCacheFileObject();
1166
1167         if( pCacheFileObject == NULL)
1168         {
1169
1170             ntStatus = STATUS_DEVICE_NOT_READY;
1171
1172             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1173                           AFS_TRACE_LEVEL_ERROR,
1174                           "AFSNonCachedWrite Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n",
1175                           pFcb->ObjectInformation->FileId.Cell,
1176                           pFcb->ObjectInformation->FileId.Volume,
1177                           pFcb->ObjectInformation->FileId.Vnode,
1178                           pFcb->ObjectInformation->FileId.Unique,
1179                           StartingByte.QuadPart,
1180                           ByteCount,
1181                           ntStatus);
1182
1183             try_return( ntStatus);
1184         }
1185
1186         if (runCount > AFS_MAX_STACK_IO_RUNS)
1187         {
1188
1189             pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool,
1190                                                             runCount * sizeof( AFSIoRun ),
1191                                                             AFS_IO_RUN_TAG );
1192             if (NULL == pIoRuns)
1193             {
1194
1195                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1196                               AFS_TRACE_LEVEL_ERROR,
1197                               "AFSNonCachedWrite (%p) Failed to allocate IO run block\n",
1198                               Irp);
1199
1200                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1201             }
1202         }
1203         else
1204         {
1205
1206             pIoRuns = stIoRuns;
1207         }
1208
1209         RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun ));
1210
1211         ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject),
1212                                   Irp,
1213                                   pSystemBuffer,
1214                                   pIoRuns,
1215                                   &StartingByte,
1216                                   ByteCount,
1217                                   pStartExtent,
1218                                   &runCount );
1219
1220         if (!NT_SUCCESS(ntStatus))
1221         {
1222
1223             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1224                           AFS_TRACE_LEVEL_ERROR,
1225                           "AFSNonCachedWrite (%p) Failed to initialize IO run block Status %08lX\n",
1226                           Irp,
1227                           ntStatus);
1228
1229             try_return( ntStatus );
1230         }
1231
1232         AFSReferenceActiveExtents( pStartExtent,
1233                                    extentsCount);
1234
1235         bDerefExtents = TRUE;
1236
1237         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1238                       AFS_TRACE_LEVEL_VERBOSE,
1239                       "AFSNonCachedWrite Releasing(2) Fcb extents lock %p SHARED %08lX\n",
1240                       &pFcb->NPFcb->Specific.File.ExtentsResource,
1241                       PsGetCurrentThread());
1242
1243         AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1244         bLocked = FALSE;
1245
1246         pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool,
1247                                                              sizeof( AFSGatherIo),
1248                                                              AFS_GATHER_TAG);
1249
1250         if (NULL == pGatherIo)
1251         {
1252
1253             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1254                           AFS_TRACE_LEVEL_ERROR,
1255                           "AFSNonCachedWrite (%p) Failed to allocate IO gather block\n",
1256                           Irp);
1257
1258             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1259                           AFS_TRACE_LEVEL_VERBOSE,
1260                           "AFSNonCachedWrite Acquiring(1) Fcb extents lock %p SHARED %08lX\n",
1261                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1262                           PsGetCurrentThread());
1263
1264             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1265                               TRUE);
1266             bLocked = TRUE;
1267
1268             AFSDereferenceActiveExtents( pStartExtent,
1269                                          extentsCount);
1270
1271             try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1272         }
1273
1274         RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo ));
1275
1276         //
1277         // Initialize count to 1, that was we won't get an early
1278         // completion if the first irp completes before the second is
1279         // queued.
1280         //
1281         pGatherIo->Count = 1;
1282         pGatherIo->Status = STATUS_SUCCESS;
1283         pGatherIo->MasterIrp = Irp;
1284         pGatherIo->Synchronous = TRUE;
1285         pGatherIo->CompleteMasterIrp = FALSE;
1286
1287         bCompleteIrp = TRUE;
1288
1289         if( pGatherIo->Synchronous)
1290         {
1291             KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE );
1292         }
1293
1294 #if GEN_MD5
1295         //
1296         // Setup the MD5 for each extent
1297         //
1298
1299         AFSSetupMD5Hash( pFcb,
1300                          pStartExtent,
1301                          extentsCount,
1302                          pSystemBuffer,
1303                          &StartingByte,
1304                          ByteCount);
1305 #endif
1306
1307         //
1308         // Pre-emptively set up the count
1309         //
1310
1311         Irp->IoStatus.Information = ByteCount;
1312
1313         ntStatus = AFSQueueStartIos( pCacheFileObject,
1314                                      IRP_MJ_WRITE,
1315                                      IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API,
1316                                      pIoRuns,
1317                                      runCount,
1318                                      pGatherIo);
1319
1320         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1321                       AFS_TRACE_LEVEL_VERBOSE,
1322                       "AFSNonCachedWrite (%p) AFSStartIos completed Status %08lX\n",
1323                       Irp,
1324                       ntStatus);
1325
1326         if( !NT_SUCCESS( ntStatus))
1327         {
1328
1329             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1330                           AFS_TRACE_LEVEL_VERBOSE,
1331                           "AFSNonCachedWrite Acquiring(2) Fcb extents lock %p SHARED %08lX\n",
1332                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1333                           PsGetCurrentThread());
1334
1335             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1336                               TRUE);
1337             bLocked = TRUE;
1338
1339             AFSDereferenceActiveExtents( pStartExtent,
1340                                          extentsCount);
1341
1342             try_return( ntStatus);
1343         }
1344
1345         //
1346         // Wait for completion of All IOs we started.
1347         //
1348
1349         ntStatus = KeWaitForSingleObject( &pGatherIo->Event,
1350                                           Executive,
1351                                           KernelMode,
1352                                           FALSE,
1353                                           NULL);
1354
1355         if( NT_SUCCESS( ntStatus))
1356         {
1357
1358             ntStatus = pGatherIo->Status;
1359         }
1360
1361         if( !NT_SUCCESS( ntStatus))
1362         {
1363
1364             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1365                           AFS_TRACE_LEVEL_VERBOSE,
1366                           "AFSNonCachedWrite Acquiring(3) Fcb extents lock %p SHARED %08lX\n",
1367                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1368                           PsGetCurrentThread());
1369
1370             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1371                               TRUE);
1372             bLocked = TRUE;
1373
1374             AFSDereferenceActiveExtents( pStartExtent,
1375                                          extentsCount);
1376
1377             try_return( ntStatus);
1378         }
1379
1380 try_exit:
1381
1382         if( NT_SUCCESS( ntStatus) &&
1383             pStartExtent != NULL &&
1384             Irp->IoStatus.Information > 0)
1385         {
1386
1387             if ( !bLocked)
1388             {
1389
1390                 AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1391                                   TRUE);
1392                 bLocked = TRUE;
1393             }
1394
1395             //
1396             // Since this is dirty we can mark the extents dirty now.
1397             // AFSMarkDirty will dereference the extents.  Do not call
1398             // AFSDereferenceActiveExtents() in this code path.
1399             //
1400
1401             AFSMarkDirty( pFcb,
1402                           pStartExtent,
1403                           extentsCount,
1404                           &StartingByte,
1405                           bDerefExtents);
1406
1407             if (!bPagingIo)
1408             {
1409                 //
1410                 // This was an uncached user write - tell the server to do
1411                 // the flush when the worker thread next wakes up
1412                 //
1413                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1414             }
1415         }
1416
1417         if( pCacheFileObject != NULL)
1418         {
1419             AFSReleaseCacheFileObject( pCacheFileObject);
1420         }
1421
1422         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1423                       AFS_TRACE_LEVEL_VERBOSE,
1424                       "AFSNonCachedWrite (FO: %p) StartingByte %08lX:%08lX Length %08lX Status %08lX\n",
1425                       pFileObject,
1426                       StartingByte.HighPart,
1427                       StartingByte.LowPart,
1428                       ByteCount,
1429                       ntStatus);
1430
1431         if (NT_SUCCESS(ntStatus) &&
1432             !bPagingIo &&
1433             bSynchronousFo)
1434         {
1435
1436             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1437         }
1438
1439         if( bLocked)
1440         {
1441
1442             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1443                           AFS_TRACE_LEVEL_VERBOSE,
1444                           "AFSNonCachedWrite Releasing Fcb extents lock %p SHARED %08lX\n",
1445                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1446                           PsGetCurrentThread());
1447
1448             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1449         }
1450
1451         if( pGatherIo)
1452         {
1453             AFSExFreePoolWithTag(pGatherIo, AFS_GATHER_TAG);
1454         }
1455
1456         if( NULL != pIoRuns &&
1457             stIoRuns != pIoRuns)
1458         {
1459             AFSExFreePoolWithTag(pIoRuns, AFS_IO_RUN_TAG);
1460         }
1461
1462         if( bCompleteIrp)
1463         {
1464
1465             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1466                           AFS_TRACE_LEVEL_VERBOSE,
1467                           "AFSNonCachedWrite Completing Irp %p Status %08lX Info %08lX\n",
1468                           Irp,
1469                           ntStatus,
1470                           Irp->IoStatus.Information);
1471
1472             AFSCompleteRequest( Irp, ntStatus);
1473         }
1474     }
1475
1476     return ntStatus;
1477 }
1478
1479 static
1480 NTSTATUS
1481 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1482                 IN PIRP Irp,
1483                 IN LARGE_INTEGER StartingByte,
1484                 IN ULONG ByteCount,
1485                 IN BOOLEAN ForceFlush)
1486 {
1487     UNREFERENCED_PARAMETER(DeviceObject);
1488     PVOID              pSystemBuffer = NULL;
1489     NTSTATUS           ntStatus = STATUS_SUCCESS;
1490     IO_STATUS_BLOCK    iosbFlush;
1491     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1492     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1493     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1494     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1495     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1496     PMDL               pCurrentMdl = Irp->MdlAddress;
1497     LARGE_INTEGER      liCurrentOffset;
1498
1499     __Enter
1500     {
1501
1502         Irp->IoStatus.Information = 0;
1503
1504         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1505         {
1506
1507             __try
1508             {
1509
1510                 CcPrepareMdlWrite( pFileObject,
1511                                    &StartingByte,
1512                                    ByteCount,
1513                                    &Irp->MdlAddress,
1514                                    &Irp->IoStatus);
1515
1516                 ntStatus = Irp->IoStatus.Status;
1517             }
1518             __except( EXCEPTION_EXECUTE_HANDLER)
1519             {
1520                 ntStatus = GetExceptionCode();
1521
1522                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1523                               AFS_TRACE_LEVEL_ERROR,
1524                               "AFSCachedWrite (%p) Exception thrown while preparing mdl write Status %08lX\n",
1525                               Irp,
1526                               ntStatus);
1527             }
1528
1529             if( !NT_SUCCESS( ntStatus))
1530             {
1531
1532                 //
1533                 // Free up any potentially allocated mdl's
1534                 //
1535
1536                 CcMdlWriteComplete( pFileObject,
1537                                     &StartingByte,
1538                                     Irp->MdlAddress);
1539
1540                 Irp->MdlAddress = NULL;
1541
1542                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1543                               AFS_TRACE_LEVEL_ERROR,
1544                               "AFSCachedWrite (%p) Failed to process MDL write Status %08lX\n",
1545                               Irp,
1546                               ntStatus);
1547             }
1548
1549             try_return( ntStatus);
1550         }
1551
1552         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1553
1554         while( ulTotalLen > 0)
1555         {
1556
1557             ntStatus = STATUS_SUCCESS;
1558
1559             if( pCurrentMdl != NULL)
1560             {
1561
1562                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1563                                                               NormalPagePriority);
1564
1565                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1566
1567                 if( ulCurrentIO > ulTotalLen)
1568                 {
1569                     ulCurrentIO = ulTotalLen;
1570                 }
1571             }
1572             else
1573             {
1574
1575                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1576                                                      ulTotalLen);
1577
1578                 ulCurrentIO = ulTotalLen;
1579             }
1580
1581             if( pSystemBuffer == NULL)
1582             {
1583
1584                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1585                               AFS_TRACE_LEVEL_ERROR,
1586                               "AFSCachedWrite (%p) Failed to lock system buffer\n",
1587                               Irp);
1588
1589                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1590             }
1591
1592             __try
1593             {
1594
1595                 if( !CcCopyWrite( pFileObject,
1596                                   &liCurrentOffset,
1597                                   ulCurrentIO,
1598                                   TRUE,
1599                                   pSystemBuffer))
1600                 {
1601                     //
1602                     // Failed to process request.
1603                     //
1604
1605                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1606                                   AFS_TRACE_LEVEL_ERROR,
1607                                   "AFSCachedWrite (%p) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1608                                   Irp,
1609                                   &pFileObject->FileName,
1610                                   liCurrentOffset.QuadPart,
1611                                   Irp->IoStatus.Status);
1612
1613                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1614                 }
1615             }
1616             __except( EXCEPTION_EXECUTE_HANDLER)
1617             {
1618
1619                 ntStatus = GetExceptionCode();
1620
1621                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1622                               AFS_TRACE_LEVEL_ERROR,
1623                               "AFSCachedWrite (%p) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1624                               Irp,
1625                               &pFileObject->FileName,
1626                               liCurrentOffset.QuadPart,
1627                               ntStatus);
1628             }
1629
1630             if( !NT_SUCCESS( ntStatus))
1631             {
1632                 try_return( ntStatus);
1633             }
1634
1635             if( ForceFlush ||
1636                 BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1637             {
1638
1639                 //
1640                 // We have detected a file we do a write through with.
1641                 //
1642
1643                 CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1644                              &liCurrentOffset,
1645                              ulCurrentIO,
1646                              &iosbFlush);
1647
1648                 if( !NT_SUCCESS( iosbFlush.Status))
1649                 {
1650
1651                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1652                                   AFS_TRACE_LEVEL_ERROR,
1653                                   "AFSCachedWrite (%p) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1654                                   Irp,
1655                                   &pFileObject->FileName,
1656                                   pFcb->ObjectInformation->FileId.Cell,
1657                                   pFcb->ObjectInformation->FileId.Volume,
1658                                   pFcb->ObjectInformation->FileId.Vnode,
1659                                   pFcb->ObjectInformation->FileId.Unique,
1660                                   iosbFlush.Status,
1661                                   iosbFlush.Information);
1662
1663                     try_return( ntStatus = iosbFlush.Status);
1664                 }
1665             }
1666
1667             if( ulTotalLen <= ulCurrentIO)
1668             {
1669                 break;
1670             }
1671
1672             liCurrentOffset.QuadPart += ulCurrentIO;
1673
1674             ulTotalLen -= ulCurrentIO;
1675
1676             pCurrentMdl = pCurrentMdl->Next;
1677         }
1678
1679 try_exit:
1680
1681         if( NT_SUCCESS( ntStatus))
1682         {
1683
1684             Irp->IoStatus.Information = ByteCount;
1685
1686             if( bSynchronousFo)
1687             {
1688
1689                 pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1690             }
1691
1692             //
1693             // If this extended the Vdl, then update it accordingly
1694             //
1695
1696             if( StartingByte.QuadPart + ByteCount > pFcb->Header.ValidDataLength.QuadPart)
1697             {
1698
1699                 pFcb->Header.ValidDataLength.QuadPart = StartingByte.QuadPart + ByteCount;
1700             }
1701
1702             if ( ForceFlush ||
1703                  BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1704             {
1705                 //
1706                 // Write through asked for... Set things so that we get
1707                 // flush when the worker thread next wakes up
1708                 //
1709                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1710             }
1711
1712             if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
1713             {
1714
1715                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
1716
1717                 KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
1718             }
1719         }
1720
1721         AFSCompleteRequest( Irp,
1722                             ntStatus);
1723     }
1724
1725     return ntStatus;
1726 }
1727
1728 static
1729 NTSTATUS
1730 AFSExtendingWrite( IN AFSFcb *Fcb,
1731                    IN PFILE_OBJECT FileObject,
1732                    IN LONGLONG NewLength)
1733 {
1734     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
1735     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
1736     NTSTATUS      ntStatus = STATUS_SUCCESS;
1737     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
1738
1739     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
1740     {
1741
1742         Fcb->Header.AllocationSize.QuadPart = NewLength;
1743
1744         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
1745     }
1746
1747     if( NewLength > Fcb->Header.FileSize.QuadPart)
1748     {
1749
1750         Fcb->Header.FileSize.QuadPart = NewLength;
1751
1752         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
1753     }
1754
1755     //
1756     // Tell the server
1757     //
1758
1759     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentFileId,
1760                                          Fcb->ObjectInformation,
1761                                          &pCcb->AuthGroup);
1762
1763     if (NT_SUCCESS(ntStatus))
1764     {
1765
1766         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
1767
1768         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1769
1770         //
1771         // If the file is currently cached, then let the MM know about the extension
1772         //
1773
1774         if( CcIsFileCached( FileObject))
1775         {
1776             CcSetFileSizes( FileObject,
1777                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1778         }
1779     }
1780     else
1781     {
1782         Fcb->Header.FileSize = liSaveFileSize;
1783         Fcb->Header.AllocationSize = liSaveAllocation;
1784     }
1785
1786     //
1787     // DownConvert file resource to shared
1788     //
1789     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
1790
1791     return ntStatus;
1792 }
1793
1794 NTSTATUS
1795 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
1796                IN PIRP Irp)
1797 {
1798
1799     UNREFERENCED_PARAMETER(DeviceObject);
1800     NTSTATUS ntStatus = STATUS_SUCCESS;
1801     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1802     AFSFcb *pFcb = NULL;
1803     AFSCcb *pCcb = NULL;
1804     AFSPipeIORequestCB *pIoRequest = NULL;
1805     void *pBuffer = NULL;
1806     AFSPipeIOResultCB stIoResult;
1807     ULONG ulBytesReturned = 0;
1808
1809     __Enter
1810     {
1811
1812         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1813
1814         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1815
1816         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1817                       AFS_TRACE_LEVEL_VERBOSE,
1818                       "AFSShareWrite On pipe %wZ Length %08lX\n",
1819                       &pCcb->DirectoryCB->NameInformation.FileName,
1820                       pIrpSp->Parameters.Write.Length);
1821
1822         if( pIrpSp->Parameters.Write.Length == 0)
1823         {
1824
1825             //
1826             // Nothing to do in this case
1827             //
1828
1829             try_return( ntStatus);
1830         }
1831
1832         //
1833         // Retrieve the buffer for the read request
1834         //
1835
1836         pBuffer = AFSLockSystemBuffer( Irp,
1837                                        pIrpSp->Parameters.Write.Length);
1838
1839         if( pBuffer == NULL)
1840         {
1841
1842             AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1843                           AFS_TRACE_LEVEL_ERROR,
1844                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
1845                           &pCcb->DirectoryCB->NameInformation.FileName);
1846
1847             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1848         }
1849
1850         AFSAcquireShared( &pFcb->NPFcb->Resource,
1851                           TRUE);
1852
1853         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
1854                                                                      sizeof( AFSPipeIORequestCB) +
1855                                                                                 pIrpSp->Parameters.Write.Length,
1856                                                                      AFS_GENERIC_MEMORY_14_TAG);
1857
1858         if( pIoRequest == NULL)
1859         {
1860
1861             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1862         }
1863
1864         RtlZeroMemory( pIoRequest,
1865                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
1866
1867         pIoRequest->RequestId = pCcb->RequestID;
1868
1869         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
1870
1871         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
1872
1873         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
1874                        pBuffer,
1875                        pIrpSp->Parameters.Write.Length);
1876
1877         stIoResult.BytesProcessed = 0;
1878
1879         ulBytesReturned = sizeof( AFSPipeIOResultCB);
1880
1881         //
1882         // Issue the open request to the service
1883         //
1884
1885         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
1886                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
1887                                       &pCcb->AuthGroup,
1888                                       &pCcb->DirectoryCB->NameInformation.FileName,
1889                                       NULL,
1890                                       NULL,
1891                                       0,
1892                                       pIoRequest,
1893                                       sizeof( AFSPipeIORequestCB) +
1894                                                 pIrpSp->Parameters.Write.Length,
1895                                       &stIoResult,
1896                                       &ulBytesReturned);
1897
1898         if( !NT_SUCCESS( ntStatus))
1899         {
1900
1901             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1902                           AFS_TRACE_LEVEL_ERROR,
1903                           "AFSShareWrite (%p) Failed service write Status %08lX\n",
1904                           Irp,
1905                           ntStatus);
1906
1907             try_return( ntStatus);
1908         }
1909
1910         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1911                       AFS_TRACE_LEVEL_VERBOSE,
1912                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
1913                       &pCcb->DirectoryCB->NameInformation.FileName,
1914                       stIoResult.BytesProcessed);
1915
1916         Irp->IoStatus.Information = stIoResult.BytesProcessed;
1917
1918 try_exit:
1919
1920         if( pFcb != NULL)
1921         {
1922
1923             AFSReleaseResource( &pFcb->NPFcb->Resource);
1924         }
1925
1926         if( pIoRequest != NULL)
1927         {
1928
1929             AFSExFreePoolWithTag( pIoRequest, AFS_GENERIC_MEMORY_14_TAG);
1930         }
1931     }
1932
1933     return ntStatus;
1934 }