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