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