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