b5232b4939dbf40b9d6867bd80d5242ef98bc1c2
[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             if ( !bLocked)
1305             {
1306
1307                 AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1308                                   TRUE);
1309                 bLocked = TRUE;
1310             }
1311
1312             //
1313             // Since this is dirty we can mark the extents dirty now.
1314             // AFSMarkDirty will dereference the extents.  Do not call
1315             // AFSDereferenceActiveExtents() in this code path.
1316             //
1317
1318             AFSMarkDirty( pFcb,
1319                           pStartExtent,
1320                           extentsCount,
1321                           &StartingByte,
1322                           bDerefExtents);
1323
1324             if (!bPagingIo)
1325             {
1326                 //
1327                 // This was an uncached user write - tell the server to do
1328                 // the flush when the worker thread next wakes up
1329                 //
1330                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1331             }
1332         }
1333
1334         if( pCacheFileObject != NULL)
1335         {
1336             AFSReleaseCacheFileObject( pCacheFileObject);
1337         }
1338
1339         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1340                       AFS_TRACE_LEVEL_VERBOSE,
1341                       "AFSNonCachedWrite (%08lX) Completed request Status %08lX\n",
1342                       Irp,
1343                       ntStatus);
1344
1345         if (NT_SUCCESS(ntStatus) &&
1346             !bPagingIo &&
1347             bSynchronousFo)
1348         {
1349
1350             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1351         }
1352
1353         if( bLocked)
1354         {
1355
1356             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1357                           AFS_TRACE_LEVEL_VERBOSE,
1358                           "AFSNonCachedWrite Releasing Fcb extents lock %08lX SHARED %08lX\n",
1359                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1360                           PsGetCurrentThread());
1361
1362             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1363         }
1364
1365         if( pGatherIo)
1366         {
1367             AFSExFreePoolWithTag(pGatherIo, AFS_GATHER_TAG);
1368         }
1369
1370         if( NULL != pIoRuns &&
1371             stIoRuns != pIoRuns)
1372         {
1373             AFSExFreePoolWithTag(pIoRuns, AFS_IO_RUN_TAG);
1374         }
1375
1376         if( bCompleteIrp)
1377         {
1378
1379             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1380                           AFS_TRACE_LEVEL_VERBOSE,
1381                           "AFSNonCachedWrite Completing Irp %08lX Status %08lX Info %08lX\n",
1382                           Irp,
1383                           ntStatus,
1384                           Irp->IoStatus.Information);
1385
1386             AFSCompleteRequest( Irp, ntStatus);
1387         }
1388     }
1389
1390     return ntStatus;
1391 }
1392
1393 static
1394 NTSTATUS
1395 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1396                 IN PIRP Irp,
1397                 IN LARGE_INTEGER StartingByte,
1398                 IN ULONG ByteCount,
1399                 IN BOOLEAN ForceFlush)
1400 {
1401     PVOID              pSystemBuffer = NULL;
1402     NTSTATUS           ntStatus = STATUS_SUCCESS;
1403     IO_STATUS_BLOCK    iosbFlush;
1404     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1405     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1406     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1407     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1408     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1409     BOOLEAN            bMapped = FALSE;
1410     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1411     PMDL               pCurrentMdl = Irp->MdlAddress;
1412     LARGE_INTEGER      liCurrentOffset;
1413
1414     __Enter
1415     {
1416
1417         Irp->IoStatus.Information = 0;
1418
1419         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1420         {
1421
1422             __try
1423             {
1424
1425                 CcPrepareMdlWrite( pFileObject,
1426                                    &StartingByte,
1427                                    ByteCount,
1428                                    &Irp->MdlAddress,
1429                                    &Irp->IoStatus);
1430
1431                 ntStatus = Irp->IoStatus.Status;
1432             }
1433             __except( EXCEPTION_EXECUTE_HANDLER)
1434             {
1435                 ntStatus = GetExceptionCode();
1436
1437                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1438                               AFS_TRACE_LEVEL_ERROR,
1439                               "AFSCachedWrite (%08lX) Exception thrown while preparing mdl write Status %08lX\n",
1440                               Irp,
1441                               ntStatus);
1442             }
1443
1444             if( !NT_SUCCESS( ntStatus))
1445             {
1446
1447                 //
1448                 // Free up any potentially allocated mdl's
1449                 //
1450
1451                 CcMdlWriteComplete( pFileObject,
1452                                     &StartingByte,
1453                                     Irp->MdlAddress);
1454
1455                 Irp->MdlAddress = NULL;
1456
1457                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1458                               AFS_TRACE_LEVEL_ERROR,
1459                               "AFSCachedWrite (%08lX) Failed to process MDL write Status %08lX\n",
1460                               Irp,
1461                               ntStatus);
1462             }
1463
1464             try_return( ntStatus);
1465         }
1466
1467         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1468
1469         while( ulTotalLen > 0)
1470         {
1471
1472             ntStatus = STATUS_SUCCESS;
1473
1474             if( pCurrentMdl != NULL)
1475             {
1476
1477                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1478                                                               NormalPagePriority);
1479
1480                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1481
1482                 if( ulCurrentIO > ulTotalLen)
1483                 {
1484                     ulCurrentIO = ulTotalLen;
1485                 }
1486             }
1487             else
1488             {
1489
1490                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1491                                                      ulTotalLen);
1492
1493                 ulCurrentIO = ulTotalLen;
1494             }
1495
1496             if( pSystemBuffer == NULL)
1497             {
1498
1499                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1500                               AFS_TRACE_LEVEL_ERROR,
1501                               "AFSCachedWrite (%08lX) Failed to lock system buffer\n",
1502                               Irp);
1503
1504                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1505             }
1506
1507             __try
1508             {
1509
1510                 if( !CcCopyWrite( pFileObject,
1511                                   &liCurrentOffset,
1512                                   ulCurrentIO,
1513                                   TRUE,
1514                                   pSystemBuffer))
1515                 {
1516                     //
1517                     // Failed to process request.
1518                     //
1519
1520                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1521                                   AFS_TRACE_LEVEL_ERROR,
1522                                   "AFSCachedWrite (%08lX) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1523                                   Irp,
1524                                   &pFileObject->FileName,
1525                                   liCurrentOffset.QuadPart,
1526                                   Irp->IoStatus.Status);
1527
1528                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1529                 }
1530             }
1531             __except( EXCEPTION_EXECUTE_HANDLER)
1532             {
1533
1534                 ntStatus = GetExceptionCode();
1535
1536                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1537                               AFS_TRACE_LEVEL_ERROR,
1538                               "AFSCachedWrite (%08lX) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1539                               Irp,
1540                               &pFileObject->FileName,
1541                               liCurrentOffset.QuadPart,
1542                               ntStatus);
1543             }
1544
1545             if( !NT_SUCCESS( ntStatus))
1546             {
1547                 try_return( ntStatus);
1548             }
1549
1550             if( ForceFlush)
1551             {
1552
1553                 //
1554                 // We have detected a file we do a write through with.
1555                 //
1556
1557                 CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1558                              &liCurrentOffset,
1559                              ulCurrentIO,
1560                              &iosbFlush);
1561
1562                 if( !NT_SUCCESS( iosbFlush.Status))
1563                 {
1564
1565                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1566                                   AFS_TRACE_LEVEL_ERROR,
1567                                   "AFSCachedWrite (%08lX) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1568                                   Irp,
1569                                   &pFileObject->FileName,
1570                                   pFcb->ObjectInformation->FileId.Cell,
1571                                   pFcb->ObjectInformation->FileId.Volume,
1572                                   pFcb->ObjectInformation->FileId.Vnode,
1573                                   pFcb->ObjectInformation->FileId.Unique,
1574                                   iosbFlush.Status,
1575                                   iosbFlush.Information);
1576
1577                     try_return( ntStatus = iosbFlush.Status);
1578                 }
1579             }
1580
1581             if( ulTotalLen <= ulCurrentIO)
1582             {
1583                 break;
1584             }
1585
1586             liCurrentOffset.QuadPart += ulCurrentIO;
1587
1588             ulTotalLen -= ulCurrentIO;
1589
1590             pCurrentMdl = pCurrentMdl->Next;
1591         }
1592
1593 try_exit:
1594
1595         if( NT_SUCCESS( ntStatus))
1596         {
1597
1598             Irp->IoStatus.Information = ByteCount;
1599
1600             if( bSynchronousFo)
1601             {
1602
1603                 pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1604             }
1605
1606             //
1607             // If this extended the Vdl, then update it accordingly
1608             //
1609
1610             if( StartingByte.QuadPart + ByteCount > pFcb->Header.ValidDataLength.QuadPart)
1611             {
1612
1613                 pFcb->Header.ValidDataLength.QuadPart = StartingByte.QuadPart + ByteCount;
1614             }
1615
1616             if (BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1617             {
1618                 //
1619                 // Write through asked for... Set things so that we get
1620                 // flush when the worker thread next wakes up
1621                 //
1622                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1623             }
1624
1625             if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
1626             {
1627
1628                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
1629
1630                 KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
1631             }
1632         }
1633
1634         AFSCompleteRequest( Irp,
1635                             ntStatus);
1636     }
1637
1638     return ntStatus;
1639 }
1640
1641 static
1642 NTSTATUS
1643 AFSExtendingWrite( IN AFSFcb *Fcb,
1644                    IN PFILE_OBJECT FileObject,
1645                    IN LONGLONG NewLength)
1646 {
1647     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
1648     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
1649     NTSTATUS      ntStatus = STATUS_SUCCESS;
1650     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
1651
1652     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1653                   AFS_TRACE_LEVEL_VERBOSE,
1654                   "AFSExtendingWrite Acquiring Fcb PagingIo lock %08lX EXCL %08lX\n",
1655                   &Fcb->NPFcb->PagingResource,
1656                   PsGetCurrentThread());
1657
1658     AFSAcquireExcl( &Fcb->NPFcb->PagingResource,
1659                     TRUE);
1660
1661     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
1662     {
1663
1664         Fcb->Header.AllocationSize.QuadPart = NewLength;
1665
1666         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
1667     }
1668
1669     if( NewLength > Fcb->Header.FileSize.QuadPart)
1670     {
1671
1672         Fcb->Header.FileSize.QuadPart = NewLength;
1673
1674         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
1675     }
1676
1677     //
1678     // Tell the server
1679     //
1680
1681     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentObjectInformation->FileId,
1682                                          Fcb->ObjectInformation,
1683                                          &pCcb->AuthGroup);
1684
1685     if (NT_SUCCESS(ntStatus))
1686     {
1687
1688         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
1689
1690         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1691
1692         //
1693         // If the file is currently cached, then let the MM know about the extension
1694         //
1695
1696         if( CcIsFileCached( FileObject))
1697         {
1698             CcSetFileSizes( FileObject,
1699                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1700         }
1701     }
1702     else
1703     {
1704         Fcb->Header.FileSize = liSaveFileSize;
1705         Fcb->Header.AllocationSize = liSaveAllocation;
1706     }
1707
1708     AFSReleaseResource( &Fcb->NPFcb->PagingResource);
1709
1710     //
1711     // DownConvert file resource to shared
1712     //
1713     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
1714
1715     return ntStatus;
1716 }
1717
1718 NTSTATUS
1719 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
1720                IN PIRP Irp)
1721 {
1722
1723     NTSTATUS ntStatus = STATUS_SUCCESS;
1724     AFSPIOCtlIORequestCB stIORequestCB;
1725     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1726     AFSFcb *pFcb = NULL;
1727     AFSCcb *pCcb = NULL;
1728     AFSPipeIORequestCB *pIoRequest = NULL;
1729     void *pBuffer = NULL;
1730     AFSPipeIOResultCB stIoResult;
1731     ULONG ulBytesReturned = 0;
1732
1733     __Enter
1734     {
1735
1736         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1737
1738         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1739
1740         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1741                       AFS_TRACE_LEVEL_VERBOSE,
1742                       "AFSShareWrite On pipe %wZ Length %08lX\n",
1743                       &pCcb->DirectoryCB->NameInformation.FileName,
1744                       pIrpSp->Parameters.Write.Length);
1745
1746         if( pIrpSp->Parameters.Write.Length == 0)
1747         {
1748
1749             //
1750             // Nothing to do in this case
1751             //
1752
1753             try_return( ntStatus);
1754         }
1755
1756         //
1757         // Retrieve the buffer for the read request
1758         //
1759
1760         pBuffer = AFSLockSystemBuffer( Irp,
1761                                        pIrpSp->Parameters.Write.Length);
1762
1763         if( pBuffer == NULL)
1764         {
1765
1766             AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1767                           AFS_TRACE_LEVEL_ERROR,
1768                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
1769                           &pCcb->DirectoryCB->NameInformation.FileName);
1770
1771             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1772         }
1773
1774         AFSAcquireShared( &pFcb->NPFcb->Resource,
1775                           TRUE);
1776
1777         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
1778                                                                      sizeof( AFSPipeIORequestCB) +
1779                                                                                 pIrpSp->Parameters.Write.Length,
1780                                                                      AFS_GENERIC_MEMORY_14_TAG);
1781
1782         if( pIoRequest == NULL)
1783         {
1784
1785             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1786         }
1787
1788         RtlZeroMemory( pIoRequest,
1789                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
1790
1791         pIoRequest->RequestId = pCcb->RequestID;
1792
1793         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
1794
1795         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
1796
1797         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
1798                        pBuffer,
1799                        pIrpSp->Parameters.Write.Length);
1800
1801         stIoResult.BytesProcessed = 0;
1802
1803         ulBytesReturned = sizeof( AFSPipeIOResultCB);
1804
1805         //
1806         // Issue the open request to the service
1807         //
1808
1809         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
1810                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
1811                                       &pCcb->AuthGroup,
1812                                       &pCcb->DirectoryCB->NameInformation.FileName,
1813                                       NULL,
1814                                       pIoRequest,
1815                                       sizeof( AFSPipeIORequestCB) +
1816                                                 pIrpSp->Parameters.Write.Length,
1817                                       &stIoResult,
1818                                       &ulBytesReturned);
1819
1820         if( !NT_SUCCESS( ntStatus))
1821         {
1822
1823             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1824                           AFS_TRACE_LEVEL_ERROR,
1825                           "AFSShareWrite (%08lX) Failed service write Status %08lX\n",
1826                           Irp,
1827                           ntStatus);
1828
1829             try_return( ntStatus);
1830         }
1831
1832         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1833                       AFS_TRACE_LEVEL_VERBOSE,
1834                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
1835                       &pCcb->DirectoryCB->NameInformation.FileName,
1836                       stIoResult.BytesProcessed);
1837
1838         Irp->IoStatus.Information = stIoResult.BytesProcessed;
1839
1840 try_exit:
1841
1842         if( pFcb != NULL)
1843         {
1844
1845             AFSReleaseResource( &pFcb->NPFcb->Resource);
1846         }
1847
1848         if( pIoRequest != NULL)
1849         {
1850
1851             AFSExFreePoolWithTag( pIoRequest, AFS_GENERIC_MEMORY_14_TAG);
1852         }
1853     }
1854
1855     return ntStatus;
1856 }