Windows: AFSParseMountPointTarget buffer overrun
[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
840     __Enter
841     {
842         Irp->IoStatus.Information = 0;
843
844         if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart)
845         {
846
847             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
848                           AFS_TRACE_LEVEL_ERROR,
849                           "AFSNonCachedWrite (%08lX) Request %08lX Actual %08lX larger than MaxIO %I64X\n",
850                           Irp,
851                           ByteCount,
852                           pIrpSp->Parameters.Write.Length,
853                           pDevExt->Specific.RDR.MaxIo.QuadPart);
854
855             try_return( ntStatus = STATUS_UNSUCCESSFUL);
856         }
857
858         //
859         // Get the mapping for the buffer
860         //
861         pSystemBuffer = AFSLockSystemBuffer( Irp,
862                                              ByteCount);
863
864         if( pSystemBuffer == NULL)
865         {
866
867             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
868                           AFS_TRACE_LEVEL_ERROR,
869                           "AFSNonCachedWrite (%08lX) Failed to map system buffer\n",
870                           Irp);
871
872             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
873         }
874
875
876         //
877         // Provoke a get of the extents - if we need to.
878         //
879
880         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
881                       AFS_TRACE_LEVEL_VERBOSE,
882                       "AFSNonCachedWrite Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
883                       pFcb->ObjectInformation->FileId.Cell,
884                       pFcb->ObjectInformation->FileId.Volume,
885                       pFcb->ObjectInformation->FileId.Vnode,
886                       pFcb->ObjectInformation->FileId.Unique,
887                       StartingByte.QuadPart,
888                       ByteCount);
889
890         ntStatus = AFSRequestExtentsAsync( pFcb,
891                                            pCcb,
892                                            &StartingByte,
893                                            ByteCount);
894
895         if (!NT_SUCCESS(ntStatus))
896         {
897
898             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
899                           AFS_TRACE_LEVEL_ERROR,
900                           "AFSNonCachedWrite (%08lX) Failed to request extents Status %08lX\n",
901                           Irp,
902                           ntStatus);
903
904             try_return( ntStatus);
905         }
906
907         KeQueryTickCount( &liLastRequestTime);
908
909         while (TRUE)
910         {
911
912             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
913                           AFS_TRACE_LEVEL_VERBOSE,
914                           "AFSNonCachedWrite Acquiring Fcb extents lock %08lX SHARED %08lX\n",
915                           &pFcb->NPFcb->Specific.File.ExtentsResource,
916                           PsGetCurrentThread());
917
918             ASSERT( !ExIsResourceAcquiredLite( &pFcb->NPFcb->Specific.File.ExtentsResource ));
919
920             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE );
921             bLocked = TRUE;
922
923             pStartExtent = NULL;
924             pIgnoreExtent = NULL;
925
926             if ( AFSDoExtentsMapRegion( pFcb, &StartingByte, ByteCount, &pStartExtent, &pIgnoreExtent ))
927             {
928                 break;
929             }
930
931             KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete );
932
933             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
934                           AFS_TRACE_LEVEL_VERBOSE,
935                           "AFSNonCachedWrite Releasing(1) Fcb extents lock %08lX SHARED %08lX\n",
936                           &pFcb->NPFcb->Specific.File.ExtentsResource,
937                           PsGetCurrentThread());
938
939             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
940             bLocked= FALSE;
941
942             //
943             // We will re-request the extents after waiting for them
944             //
945
946             KeQueryTickCount( &liCurrentTime);
947
948             if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart)
949             {
950
951                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
952                               AFS_TRACE_LEVEL_VERBOSE,
953                               "AFSNonCachedWrite Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
954                               pFcb->ObjectInformation->FileId.Cell,
955                               pFcb->ObjectInformation->FileId.Volume,
956                               pFcb->ObjectInformation->FileId.Vnode,
957                               pFcb->ObjectInformation->FileId.Unique,
958                               StartingByte.QuadPart,
959                               ByteCount);
960
961                 ntStatus = AFSRequestExtentsAsync( pFcb,
962                                                    pCcb,
963                                                    &StartingByte,
964                                                    ByteCount);
965
966                 if (!NT_SUCCESS(ntStatus))
967                 {
968
969                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
970                                   AFS_TRACE_LEVEL_ERROR,
971                                   "AFSNonCachedWrite (%08lX) Failed to request extents Status %08lX\n",
972                                   Irp,
973                                   ntStatus);
974
975                     try_return( ntStatus);
976                 }
977
978                 KeQueryTickCount( &liLastRequestTime);
979             }
980
981
982             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
983                           AFS_TRACE_LEVEL_VERBOSE,
984                           "AFSNonCachedWrite Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
985                           pFcb->ObjectInformation->FileId.Cell,
986                           pFcb->ObjectInformation->FileId.Volume,
987                           pFcb->ObjectInformation->FileId.Vnode,
988                           pFcb->ObjectInformation->FileId.Unique,
989                           StartingByte.QuadPart,
990                           ByteCount);
991
992             //
993             // Wait for it
994             //
995
996             ntStatus =  AFSWaitForExtentMapping ( pFcb, pCcb);
997
998             if (!NT_SUCCESS(ntStatus))
999             {
1000
1001                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1002                               AFS_TRACE_LEVEL_ERROR,
1003                               "AFSNonCachedWrite Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n",
1004                               pFcb->ObjectInformation->FileId.Cell,
1005                               pFcb->ObjectInformation->FileId.Volume,
1006                               pFcb->ObjectInformation->FileId.Vnode,
1007                               pFcb->ObjectInformation->FileId.Unique,
1008                               StartingByte.QuadPart,
1009                               ByteCount,
1010                               ntStatus);
1011
1012                 try_return( ntStatus);
1013             }
1014         }
1015
1016         //
1017         // As per the read path -
1018         //
1019
1020         AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1021                       AFS_TRACE_LEVEL_VERBOSE,
1022                       "AFSNonCachedWrite Extents located for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n",
1023                       pFcb->ObjectInformation->FileId.Cell,
1024                       pFcb->ObjectInformation->FileId.Volume,
1025                       pFcb->ObjectInformation->FileId.Vnode,
1026                       pFcb->ObjectInformation->FileId.Unique,
1027                       StartingByte.QuadPart,
1028                       ByteCount);
1029
1030         ntStatus = AFSGetExtents( pFcb,
1031                                   &StartingByte,
1032                                   ByteCount,
1033                                   pStartExtent,
1034                                   &extentsCount,
1035                                   &runCount);
1036
1037         if (!NT_SUCCESS(ntStatus))
1038         {
1039
1040             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1041                           AFS_TRACE_LEVEL_ERROR,
1042                           "AFSNonCachedWrite (%08lX) Failed to retrieve mapped extents Status %08lX\n",
1043                           Irp,
1044                           ntStatus);
1045
1046             try_return( ntStatus );
1047         }
1048
1049         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1050                       AFS_TRACE_LEVEL_VERBOSE,
1051                       "AFSNonCachedWrite (%08lX) Successfully retrieved map extents count %08lX run count %08lX\n",
1052                       Irp,
1053                       extentsCount,
1054                       runCount);
1055
1056         if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE))
1057         {
1058
1059             Irp->IoStatus.Information = ByteCount;
1060
1061 #if GEN_MD5
1062             //
1063             // Setup the MD5 for each extent
1064             //
1065
1066             AFSSetupMD5Hash( pFcb,
1067                              pStartExtent,
1068                              extentsCount,
1069                              pSystemBuffer,
1070                              &StartingByte,
1071                              ByteCount);
1072 #endif
1073
1074             ntStatus = AFSProcessExtentRun( pSystemBuffer,
1075                                             &StartingByte,
1076                                             ByteCount,
1077                                             pStartExtent,
1078                                             TRUE);
1079
1080             if (!NT_SUCCESS(ntStatus))
1081             {
1082
1083                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1084                               AFS_TRACE_LEVEL_ERROR,
1085                               "AFSNonCachedWrite (%08lX) Failed to process extent run for non-persistent cache Status %08lX\n",
1086                               Irp,
1087                               ntStatus);
1088             }
1089
1090             try_return( ntStatus);
1091         }
1092
1093         //
1094         // Retrieve the cache file object
1095         //
1096
1097         pCacheFileObject = AFSReferenceCacheFileObject();
1098
1099         if( pCacheFileObject == NULL)
1100         {
1101
1102             ntStatus = STATUS_DEVICE_NOT_READY;
1103
1104             AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
1105                           AFS_TRACE_LEVEL_ERROR,
1106                           "AFSNonCachedWrite Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n",
1107                           pFcb->ObjectInformation->FileId.Cell,
1108                           pFcb->ObjectInformation->FileId.Volume,
1109                           pFcb->ObjectInformation->FileId.Vnode,
1110                           pFcb->ObjectInformation->FileId.Unique,
1111                           StartingByte.QuadPart,
1112                           ByteCount,
1113                           ntStatus);
1114
1115             try_return( ntStatus);
1116         }
1117
1118         if (runCount > AFS_MAX_STACK_IO_RUNS)
1119         {
1120
1121             pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool,
1122                                                             runCount * sizeof( AFSIoRun ),
1123                                                             AFS_IO_RUN_TAG );
1124             if (NULL == pIoRuns)
1125             {
1126
1127                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1128                               AFS_TRACE_LEVEL_ERROR,
1129                               "AFSNonCachedWrite (%08lX) Failed to allocate IO run block\n",
1130                               Irp);
1131
1132                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1133             }
1134         }
1135         else
1136         {
1137
1138             pIoRuns = stIoRuns;
1139         }
1140
1141         RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun ));
1142
1143         ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject),
1144                                   Irp,
1145                                   pSystemBuffer,
1146                                   pIoRuns,
1147                                   &StartingByte,
1148                                   ByteCount,
1149                                   pStartExtent,
1150                                   &runCount );
1151
1152         if (!NT_SUCCESS(ntStatus))
1153         {
1154
1155             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1156                           AFS_TRACE_LEVEL_ERROR,
1157                           "AFSNonCachedWrite (%08lX) Failed to initialize IO run block Status %08lX\n",
1158                           Irp,
1159                           ntStatus);
1160
1161             try_return( ntStatus );
1162         }
1163
1164         AFSReferenceActiveExtents( pStartExtent,
1165                                    extentsCount);
1166
1167         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1168                       AFS_TRACE_LEVEL_VERBOSE,
1169                       "AFSNonCachedWrite Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
1170                       &pFcb->NPFcb->Specific.File.ExtentsResource,
1171                       PsGetCurrentThread());
1172
1173         AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1174         bLocked = FALSE;
1175
1176         pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool,
1177                                                              sizeof( AFSGatherIo),
1178                                                              AFS_GATHER_TAG);
1179
1180         if (NULL == pGatherIo)
1181         {
1182
1183             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1184                           AFS_TRACE_LEVEL_ERROR,
1185                           "AFSNonCachedWrite (%08lX) Failed to allocate IO gather block\n",
1186                           Irp);
1187
1188             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1189                           AFS_TRACE_LEVEL_VERBOSE,
1190                           "AFSNonCachedWrite Acquiring(1) Fcb extents lock %08lX SHARED %08lX\n",
1191                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1192                           PsGetCurrentThread());
1193
1194             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1195                               TRUE);
1196             bLocked = TRUE;
1197
1198             AFSDereferenceActiveExtents( pStartExtent,
1199                                          extentsCount);
1200
1201             try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1202         }
1203
1204         RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo ));
1205
1206         //
1207         // Initialize count to 1, that was we won't get an early
1208         // completion if the first irp completes before the second is
1209         // queued.
1210         //
1211         pGatherIo->Count = 1;
1212         pGatherIo->Status = STATUS_SUCCESS;
1213         pGatherIo->MasterIrp = Irp;
1214         pGatherIo->Synchronous = TRUE;
1215         pGatherIo->CompleteMasterIrp = FALSE;
1216
1217         bCompleteIrp = TRUE;
1218
1219         if( pGatherIo->Synchronous)
1220         {
1221             KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE );
1222         }
1223
1224 #if GEN_MD5
1225         //
1226         // Setup the MD5 for each extent
1227         //
1228
1229         AFSSetupMD5Hash( pFcb,
1230                          pStartExtent,
1231                          extentsCount,
1232                          pSystemBuffer,
1233                          &StartingByte,
1234                          ByteCount);
1235 #endif
1236
1237         //
1238         // Pre-emptively set up the count
1239         //
1240
1241         Irp->IoStatus.Information = ByteCount;
1242
1243         ntStatus = AFSQueueStartIos( pCacheFileObject,
1244                                      IRP_MJ_WRITE,
1245                                      IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API,
1246                                      pIoRuns,
1247                                      runCount,
1248                                      pGatherIo);
1249
1250         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1251                       AFS_TRACE_LEVEL_VERBOSE,
1252                       "AFSNonCachedWrite (%08lX) AFSStartIos completed Status %08lX\n",
1253                       Irp,
1254                       ntStatus);
1255
1256         if( !NT_SUCCESS( ntStatus))
1257         {
1258
1259             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1260                           AFS_TRACE_LEVEL_VERBOSE,
1261                           "AFSNonCachedWrite Acquiring(2) Fcb extents lock %08lX SHARED %08lX\n",
1262                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1263                           PsGetCurrentThread());
1264
1265             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1266                               TRUE);
1267             bLocked = TRUE;
1268
1269             AFSDereferenceActiveExtents( pStartExtent,
1270                                          extentsCount);
1271
1272             try_return( ntStatus);
1273         }
1274
1275         //
1276         // Wait for completion of All IOs we started.
1277         //
1278
1279         ntStatus = KeWaitForSingleObject( &pGatherIo->Event,
1280                                           Executive,
1281                                           KernelMode,
1282                                           FALSE,
1283                                           NULL);
1284
1285         if( NT_SUCCESS( ntStatus))
1286         {
1287
1288             ntStatus = pGatherIo->Status;
1289         }
1290
1291         if( !NT_SUCCESS( ntStatus))
1292         {
1293
1294             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1295                           AFS_TRACE_LEVEL_VERBOSE,
1296                           "AFSNonCachedWrite Acquiring(3) Fcb extents lock %08lX SHARED %08lX\n",
1297                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1298                           PsGetCurrentThread());
1299
1300             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1301                               TRUE);
1302             bLocked = TRUE;
1303
1304             AFSDereferenceActiveExtents( pStartExtent,
1305                                          extentsCount);
1306
1307             try_return( ntStatus);
1308         }
1309
1310         //
1311         // Since this is dirty we can mark the extents dirty now.
1312         // AFSMarkDirty will dereference the extents.  Do not call
1313         // AFSDereferenceActiveExtents() in this code path.
1314         //
1315
1316         AFSMarkDirty( pFcb,
1317                       pStartExtent,
1318                       extentsCount,
1319                       &StartingByte);
1320
1321         if (!bPagingIo)
1322         {
1323             //
1324             // This was an uncached user write - tell the server to do
1325             // the flush when the worker thread next wakes up
1326             //
1327             pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1328         }
1329
1330         //
1331         // All done
1332         //
1333
1334 try_exit:
1335
1336         if( pCacheFileObject != NULL)
1337         {
1338             AFSReleaseCacheFileObject( pCacheFileObject);
1339         }
1340
1341         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1342                       AFS_TRACE_LEVEL_VERBOSE,
1343                       "AFSNonCachedWrite (%08lX) Completed request Status %08lX\n",
1344                       Irp,
1345                       ntStatus);
1346
1347         if (NT_SUCCESS(ntStatus) &&
1348             !bPagingIo &&
1349             bSynchronousFo)
1350         {
1351
1352             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1353         }
1354
1355         if( bLocked)
1356         {
1357
1358             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1359                           AFS_TRACE_LEVEL_VERBOSE,
1360                           "AFSNonCachedWrite Releasing Fcb extents lock %08lX SHARED %08lX\n",
1361                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1362                           PsGetCurrentThread());
1363
1364             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1365         }
1366
1367         if( pGatherIo)
1368         {
1369             AFSExFreePool(pGatherIo);
1370         }
1371
1372         if( NULL != pIoRuns &&
1373             stIoRuns != pIoRuns)
1374         {
1375             AFSExFreePool(pIoRuns);
1376         }
1377
1378         if( bCompleteIrp)
1379         {
1380
1381             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1382                           AFS_TRACE_LEVEL_VERBOSE,
1383                           "AFSNonCachedWrite Completing Irp %08lX Status %08lX Info %08lX\n",
1384                           Irp,
1385                           ntStatus,
1386                           Irp->IoStatus.Information);
1387
1388             AFSCompleteRequest( Irp, ntStatus);
1389         }
1390     }
1391
1392     return ntStatus;
1393 }
1394
1395 static
1396 NTSTATUS
1397 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1398                 IN PIRP Irp,
1399                 IN LARGE_INTEGER StartingByte,
1400                 IN ULONG ByteCount,
1401                 IN BOOLEAN ForceFlush)
1402 {
1403     PVOID              pSystemBuffer = NULL;
1404     NTSTATUS           ntStatus = STATUS_SUCCESS;
1405     IO_STATUS_BLOCK    iosbFlush;
1406     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1407     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1408     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1409     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1410     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1411     BOOLEAN            bMapped = FALSE;
1412     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1413     PMDL               pCurrentMdl = Irp->MdlAddress;
1414     LARGE_INTEGER      liCurrentOffset;
1415
1416     __Enter
1417     {
1418
1419         Irp->IoStatus.Information = 0;
1420
1421         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1422         {
1423
1424             __try
1425             {
1426
1427                 CcPrepareMdlWrite( pFileObject,
1428                                    &StartingByte,
1429                                    ByteCount,
1430                                    &Irp->MdlAddress,
1431                                    &Irp->IoStatus);
1432
1433                 ntStatus = Irp->IoStatus.Status;
1434             }
1435             __except( EXCEPTION_EXECUTE_HANDLER)
1436             {
1437                 ntStatus = GetExceptionCode();
1438
1439                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1440                               AFS_TRACE_LEVEL_ERROR,
1441                               "AFSCachedWrite (%08lX) Exception thrown while preparing mdl write Status %08lX\n",
1442                               Irp,
1443                               ntStatus);
1444             }
1445
1446             if( !NT_SUCCESS( ntStatus))
1447             {
1448
1449                 //
1450                 // Free up any potentially allocated mdl's
1451                 //
1452
1453                 CcMdlWriteComplete( pFileObject,
1454                                     &StartingByte,
1455                                     Irp->MdlAddress);
1456
1457                 Irp->MdlAddress = NULL;
1458
1459                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1460                               AFS_TRACE_LEVEL_ERROR,
1461                               "AFSCachedWrite (%08lX) Failed to process MDL write Status %08lX\n",
1462                               Irp,
1463                               ntStatus);
1464             }
1465
1466             try_return( ntStatus);
1467         }
1468
1469         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1470
1471         while( ulTotalLen > 0)
1472         {
1473
1474             ntStatus = STATUS_SUCCESS;
1475
1476             if( pCurrentMdl != NULL)
1477             {
1478
1479                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1480                                                               NormalPagePriority);
1481
1482                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1483
1484                 if( ulCurrentIO > ulTotalLen)
1485                 {
1486                     ulCurrentIO = ulTotalLen;
1487                 }
1488             }
1489             else
1490             {
1491
1492                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1493                                                      ulTotalLen);
1494
1495                 ulCurrentIO = ulTotalLen;
1496             }
1497
1498             if( pSystemBuffer == NULL)
1499             {
1500
1501                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1502                               AFS_TRACE_LEVEL_ERROR,
1503                               "AFSCachedWrite (%08lX) Failed to lock system buffer\n",
1504                               Irp);
1505
1506                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1507             }
1508
1509             __try
1510             {
1511
1512                 if( !CcCopyWrite( pFileObject,
1513                                   &liCurrentOffset,
1514                                   ulCurrentIO,
1515                                   TRUE,
1516                                   pSystemBuffer))
1517                 {
1518                     //
1519                     // Failed to process request.
1520                     //
1521
1522                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1523                                   AFS_TRACE_LEVEL_ERROR,
1524                                   "AFSCachedWrite (%08lX) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1525                                   Irp,
1526                                   &pFileObject->FileName,
1527                                   liCurrentOffset.QuadPart,
1528                                   Irp->IoStatus.Status);
1529
1530                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1531                 }
1532             }
1533             __except( EXCEPTION_EXECUTE_HANDLER)
1534             {
1535
1536                 ntStatus = GetExceptionCode();
1537
1538                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1539                               AFS_TRACE_LEVEL_ERROR,
1540                               "AFSCachedWrite (%08lX) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1541                               Irp,
1542                               &pFileObject->FileName,
1543                               liCurrentOffset.QuadPart,
1544                               ntStatus);
1545             }
1546
1547             if( !NT_SUCCESS( ntStatus))
1548             {
1549                 try_return( ntStatus);
1550             }
1551
1552             if( ForceFlush)
1553             {
1554
1555                 //
1556                 // We have detected a file we do a write through with.
1557                 //
1558
1559                 CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1560                              &liCurrentOffset,
1561                              ulCurrentIO,
1562                              &iosbFlush);
1563
1564                 if( !NT_SUCCESS( iosbFlush.Status))
1565                 {
1566
1567                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1568                                   AFS_TRACE_LEVEL_ERROR,
1569                                   "AFSCachedWrite (%08lX) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1570                                   Irp,
1571                                   &pFileObject->FileName,
1572                                   pFcb->ObjectInformation->FileId.Cell,
1573                                   pFcb->ObjectInformation->FileId.Volume,
1574                                   pFcb->ObjectInformation->FileId.Vnode,
1575                                   pFcb->ObjectInformation->FileId.Unique,
1576                                   iosbFlush.Status,
1577                                   iosbFlush.Information);
1578
1579                     try_return( ntStatus = iosbFlush.Status);
1580                 }
1581             }
1582
1583             if( ulTotalLen <= ulCurrentIO)
1584             {
1585                 break;
1586             }
1587
1588             liCurrentOffset.QuadPart += ulCurrentIO;
1589
1590             ulTotalLen -= ulCurrentIO;
1591
1592             pCurrentMdl = pCurrentMdl->Next;
1593         }
1594
1595 try_exit:
1596
1597         if( NT_SUCCESS( ntStatus))
1598         {
1599
1600             Irp->IoStatus.Information = ByteCount;
1601
1602             if( bSynchronousFo)
1603             {
1604
1605                 pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1606             }
1607
1608             //
1609             // If this extended the Vdl, then update it accordingly
1610             //
1611
1612             if( StartingByte.QuadPart + ByteCount > pFcb->Header.ValidDataLength.QuadPart)
1613             {
1614
1615                 pFcb->Header.ValidDataLength.QuadPart = StartingByte.QuadPart + ByteCount;
1616             }
1617
1618             if (BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1619             {
1620                 //
1621                 // Write through asked for... Set things so that we get
1622                 // flush when the worker thread next wakes up
1623                 //
1624                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1625             }
1626
1627             if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
1628             {
1629
1630                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
1631
1632                 KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
1633             }
1634         }
1635
1636         AFSCompleteRequest( Irp,
1637                             ntStatus);
1638     }
1639
1640     return ntStatus;
1641 }
1642
1643 static
1644 NTSTATUS
1645 AFSExtendingWrite( IN AFSFcb *Fcb,
1646                    IN PFILE_OBJECT FileObject,
1647                    IN LONGLONG NewLength)
1648 {
1649     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
1650     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
1651     NTSTATUS      ntStatus = STATUS_SUCCESS;
1652     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
1653
1654     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
1655     {
1656
1657         Fcb->Header.AllocationSize.QuadPart = NewLength;
1658
1659         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
1660     }
1661
1662     if( NewLength > Fcb->Header.FileSize.QuadPart)
1663     {
1664
1665         Fcb->Header.FileSize.QuadPart = NewLength;
1666
1667         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
1668     }
1669
1670     //
1671     // Tell the server
1672     //
1673
1674     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentObjectInformation->FileId,
1675                                          Fcb->ObjectInformation,
1676                                          &pCcb->AuthGroup);
1677
1678     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1679                   AFS_TRACE_LEVEL_VERBOSE,
1680                   "AFSExtendingWrite Acquiring Fcb lock %08lX EXCL %08lX\n",
1681                   &Fcb->NPFcb->Resource,
1682                   PsGetCurrentThread());
1683
1684     if (NT_SUCCESS(ntStatus))
1685     {
1686
1687         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
1688
1689         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1690
1691         //
1692         // If the file is currently cached, then let the MM know about the extension
1693         //
1694
1695         if( CcIsFileCached( FileObject))
1696         {
1697             CcSetFileSizes( FileObject,
1698                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1699         }
1700     }
1701     else
1702     {
1703         Fcb->Header.FileSize = liSaveFileSize;
1704         Fcb->Header.AllocationSize = liSaveAllocation;
1705     }
1706
1707     //
1708     // DownConvert file resource to shared
1709     //
1710     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
1711
1712     return ntStatus;
1713 }
1714
1715 NTSTATUS
1716 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
1717                IN PIRP Irp)
1718 {
1719
1720     NTSTATUS ntStatus = STATUS_SUCCESS;
1721     AFSPIOCtlIORequestCB stIORequestCB;
1722     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1723     AFSFcb *pFcb = NULL;
1724     AFSCcb *pCcb = NULL;
1725     AFSPipeIORequestCB *pIoRequest = NULL;
1726     void *pBuffer = NULL;
1727     AFSPipeIOResultCB stIoResult;
1728     ULONG ulBytesReturned = 0;
1729
1730     __Enter
1731     {
1732
1733         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1734
1735         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1736
1737         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1738                       AFS_TRACE_LEVEL_VERBOSE,
1739                       "AFSShareWrite On pipe %wZ Length %08lX\n",
1740                       &pCcb->DirectoryCB->NameInformation.FileName,
1741                       pIrpSp->Parameters.Write.Length);
1742
1743         if( pIrpSp->Parameters.Write.Length == 0)
1744         {
1745
1746             //
1747             // Nothing to do in this case
1748             //
1749
1750             try_return( ntStatus);
1751         }
1752
1753         //
1754         // Retrieve the buffer for the read request
1755         //
1756
1757         pBuffer = AFSLockSystemBuffer( Irp,
1758                                        pIrpSp->Parameters.Write.Length);
1759
1760         if( pBuffer == NULL)
1761         {
1762
1763             AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1764                           AFS_TRACE_LEVEL_ERROR,
1765                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
1766                           &pCcb->DirectoryCB->NameInformation.FileName);
1767
1768             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1769         }
1770
1771         AFSAcquireShared( &pFcb->NPFcb->Resource,
1772                           TRUE);
1773
1774         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
1775                                                                      sizeof( AFSPipeIORequestCB) +
1776                                                                                 pIrpSp->Parameters.Write.Length,
1777                                                                      AFS_GENERIC_MEMORY_14_TAG);
1778
1779         if( pIoRequest == NULL)
1780         {
1781
1782             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1783         }
1784
1785         RtlZeroMemory( pIoRequest,
1786                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
1787
1788         pIoRequest->RequestId = pCcb->RequestID;
1789
1790         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
1791
1792         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
1793
1794         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
1795                        pBuffer,
1796                        pIrpSp->Parameters.Write.Length);
1797
1798         stIoResult.BytesProcessed = 0;
1799
1800         ulBytesReturned = sizeof( AFSPipeIOResultCB);
1801
1802         //
1803         // Issue the open request to the service
1804         //
1805
1806         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
1807                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
1808                                       &pCcb->AuthGroup,
1809                                       &pCcb->DirectoryCB->NameInformation.FileName,
1810                                       NULL,
1811                                       pIoRequest,
1812                                       sizeof( AFSPipeIORequestCB) +
1813                                                 pIrpSp->Parameters.Write.Length,
1814                                       &stIoResult,
1815                                       &ulBytesReturned);
1816
1817         if( !NT_SUCCESS( ntStatus))
1818         {
1819
1820             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1821                           AFS_TRACE_LEVEL_ERROR,
1822                           "AFSShareWrite (%08lX) Failed service write Status %08lX\n",
1823                           Irp,
1824                           ntStatus);
1825
1826             try_return( ntStatus);
1827         }
1828
1829         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1830                       AFS_TRACE_LEVEL_VERBOSE,
1831                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
1832                       &pCcb->DirectoryCB->NameInformation.FileName,
1833                       stIoResult.BytesProcessed);
1834
1835         Irp->IoStatus.Information = stIoResult.BytesProcessed;
1836
1837 try_exit:
1838
1839         if( pFcb != NULL)
1840         {
1841
1842             AFSReleaseResource( &pFcb->NPFcb->Resource);
1843         }
1844
1845         if( pIoRequest != NULL)
1846         {
1847
1848             AFSExFreePool( pIoRequest);
1849         }
1850     }
1851
1852     return ntStatus;
1853 }