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