b774a521de246025892550a27ca10b4276916a5e
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSWrite.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSWrite.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 static
42 NTSTATUS
43 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
44                 IN PIRP Irp,
45                 IN LARGE_INTEGER StartingByte,
46                 IN ULONG ByteCount,
47                 IN BOOLEAN ForceFlush);
48 static
49 NTSTATUS
50 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
51                    IN PIRP Irp,
52                    IN LARGE_INTEGER StartingByte,
53                    IN ULONG ByteCount);
54
55 static
56 NTSTATUS
57 AFSExtendingWrite( IN AFSFcb *Fcb,
58                    IN PFILE_OBJECT FileObject,
59                    IN LONGLONG NewLength);
60
61 //
62 // Function: AFSWrite
63 //
64 // Description:
65 //
66 //      This is the dispatch handler for the IRP_MJ_WRITE request
67 //
68 // Return:
69 //
70 //      A status is returned for the function
71 //
72 NTSTATUS
73 AFSWrite( IN PDEVICE_OBJECT LibDeviceObject,
74           IN PIRP Irp)
75 {
76
77     NTSTATUS ntStatus = STATUS_SUCCESS;
78
79     __try
80     {
81
82         ntStatus = AFSCommonWrite( AFSRDRDeviceObject, Irp, NULL);
83     }
84     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
85     {
86
87         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
88     }
89
90     return ntStatus;
91 }
92
93 NTSTATUS
94 AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
95                 IN PIRP Irp,
96                 IN HANDLE OnBehalfOf)
97 {
98
99     NTSTATUS           ntStatus = STATUS_SUCCESS;
100     AFSDeviceExt      *pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
101     IO_STACK_LOCATION *pIrpSp;
102     AFSFcb            *pFcb = NULL;
103     AFSCcb            *pCcb = NULL;
104     AFSNonPagedFcb    *pNPFcb = NULL;
105     ULONG              ulByteCount = 0;
106     LARGE_INTEGER      liStartingByte;
107     PFILE_OBJECT       pFileObject;
108     BOOLEAN            bPagingIo = FALSE;
109     BOOLEAN            bNonCachedIo = FALSE;
110     BOOLEAN            bReleaseMain = FALSE;
111     BOOLEAN            bReleasePaging = FALSE;
112     BOOLEAN            bExtendingWrite = FALSE;
113     BOOLEAN            bCompleteIrp = TRUE;
114     BOOLEAN            bLockOK;
115     BOOLEAN            bMapped = TRUE;
116     HANDLE             hCallingUser = OnBehalfOf;
117     ULONG              ulExtensionLength = 0;
118     BOOLEAN            bRetry = FALSE;
119     ULONGLONG          ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
120
121     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
122
123     __Enter
124     {
125
126         pFileObject = pIrpSp->FileObject;
127
128         //
129         // Extract the fileobject references
130         //
131
132         pFcb = (AFSFcb *)pFileObject->FsContext;
133         pCcb = (AFSCcb *)pFileObject->FsContext2;
134
135         ObReferenceObject( pFileObject);
136
137         if( pFcb == NULL)
138         {
139
140             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
141                           AFS_TRACE_LEVEL_ERROR,
142                           "AFSCommonWrite Attempted write (%08lX) when pFcb == NULL\n",
143                           Irp);
144
145             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
146         }
147
148         pNPFcb = pFcb->NPFcb;
149
150         //
151         // If we are in shutdown mode then fail the request
152         //
153
154         if( BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
155         {
156
157             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
158                           AFS_TRACE_LEVEL_WARNING,
159                           "AFSCommonWrite (%08lX) Open request after shutdown\n",
160                           Irp);
161
162             try_return( ntStatus = STATUS_TOO_LATE);
163         }
164
165         liStartingByte = pIrpSp->Parameters.Write.ByteOffset;
166         bPagingIo      = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
167         bNonCachedIo   = BooleanFlagOn( Irp->Flags, IRP_NOCACHE);
168         ulByteCount    = pIrpSp->Parameters.Write.Length;
169
170         if( pFcb->Header.NodeTypeCode != AFS_IOCTL_FCB &&
171             pFcb->Header.NodeTypeCode != AFS_FILE_FCB  &&
172             pFcb->Header.NodeTypeCode != AFS_SPECIAL_SHARE_FCB)
173         {
174
175             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
176                           AFS_TRACE_LEVEL_ERROR,
177                           "AFSCommonWrite Attempted write (%08lX) on an invalid node type %08lX\n",
178                           Irp,
179                           pFcb->Header.NodeTypeCode);
180
181             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
182         }
183
184         //
185         // If this is a write against an IOCtl node then handle it
186         // in a different pathway
187         //
188
189         if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB)
190         {
191
192             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
193                           AFS_TRACE_LEVEL_VERBOSE,
194                           "AFSCommonWrite (%08lX) Processing file (PIOCTL) Offset %I64X Length %08lX Irp Flags %08lX\n",
195                           Irp,
196                           liStartingByte.QuadPart,
197                           ulByteCount,
198                           Irp->Flags);
199
200             ntStatus = AFSIOCtlWrite( DeviceObject,
201                                       Irp);
202
203             try_return( ntStatus);
204         }
205         else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
206         {
207
208             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
209                           AFS_TRACE_LEVEL_VERBOSE,
210                           "AFSCommonWrite (%08lX) Processing file (SHARE) Offset %I64X Length %08lX Irp Flags %08lX\n",
211                           Irp,
212                           liStartingByte.QuadPart,
213                           ulByteCount,
214                           Irp->Flags);
215
216             ntStatus = AFSShareWrite( DeviceObject,
217                                       Irp);
218
219             try_return( ntStatus);
220         }
221
222         //
223         // Is the Cache not there yet?  Exit.
224         //
225         if( !BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE) &&
226             NULL == pDeviceExt->Specific.RDR.CacheFileObject)
227         {
228
229             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
230                           AFS_TRACE_LEVEL_ERROR,
231                           "AFSCommonWrite (%08lX) Request failed due to AFS cache closed\n",
232                           Irp);
233
234             try_return( ntStatus = STATUS_TOO_LATE );
235         }
236
237         if( pFcb->ObjectInformation->VolumeCB != NULL &&
238             BooleanFlagOn( pFcb->ObjectInformation->VolumeCB->VolumeInformation.Characteristics, FILE_READ_ONLY_DEVICE))
239         {
240
241             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
242                           AFS_TRACE_LEVEL_ERROR,
243                           "AFSCommonWrite (%08lX) Request failed due to read only volume\n",
244                           Irp);
245
246             try_return( ntStatus = STATUS_ACCESS_DENIED);
247         }
248
249         //
250         // We need to know on whose behalf we have been called (which
251         // we will eventually tell to the server - for non paging
252         // writes).  If we were posted then we were told.  If this is
253         // the first time we saw the irp then we grab it now.
254         //
255         if( NULL == OnBehalfOf )
256         {
257
258             hCallingUser = PsGetCurrentProcessId();
259         }
260         else
261         {
262
263             hCallingUser = OnBehalfOf;
264         }
265
266         //
267         // Check for zero length write
268         //
269
270         if( ulByteCount == 0)
271         {
272
273             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
274                           AFS_TRACE_LEVEL_VERBOSE,
275                           "AFSCommonWrite (%08lX) Request completed due to zero length\n",
276                           Irp);
277
278             try_return( ntStatus);
279         }
280
281         //
282         // Is this Fcb valid???
283         //
284
285         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID))
286         {
287
288             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
289                           AFS_TRACE_LEVEL_ERROR,
290                           "AFSCommonWrite (%08lX) Failing request due to INVALID fcb\n",
291                           Irp);
292
293             Irp->IoStatus.Information = 0;
294
295             try_return( ntStatus = STATUS_FILE_DELETED);
296         }
297
298         if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED) ||
299             BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
300         {
301
302             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
303                           AFS_TRACE_LEVEL_ERROR,
304                           "AFSCommonWrite (%08lX) Request failed due to file deleted\n",
305                           Irp);
306
307             try_return( ntStatus = STATUS_FILE_DELETED);
308         }
309
310         if( FlagOn( pIrpSp->MinorFunction, IRP_MN_COMPLETE))
311         {
312
313             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
314                           AFS_TRACE_LEVEL_VERBOSE,
315                           "AFSCommonWrite (%08lX) IRP_MN_COMPLETE being processed\n",
316                           Irp);
317
318             CcMdlWriteComplete(pFileObject, &pIrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress);
319
320             //
321             // Mdl is now Deallocated
322             //
323
324             Irp->MdlAddress = NULL;
325
326             try_return( ntStatus = STATUS_SUCCESS );
327         }
328
329         //
330         // If we get a non cached IO for a cached file we should do a purge.
331         // For now we will just promote to cached
332         //
333         if( NULL != pFileObject->SectionObjectPointer->DataSectionObject && !bPagingIo && bNonCachedIo)
334         {
335             bNonCachedIo = FALSE;
336         }
337
338         if( (!bPagingIo && !bNonCachedIo))
339         {
340
341             if( pFileObject->PrivateCacheMap == NULL)
342             {
343
344                 __try
345                 {
346
347                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
348                                   AFS_TRACE_LEVEL_VERBOSE,
349                                   "AFSCommonWrite Initialize caching on Fcb %08lX FileObject %08lX\n",
350                                   pFcb,
351                                   pFileObject);
352
353                     CcInitializeCacheMap( pFileObject,
354                                           (PCC_FILE_SIZES)&pFcb->Header.AllocationSize,
355                                           FALSE,
356                                           AFSLibCacheManagerCallbacks,
357                                           pFcb);
358
359                     CcSetReadAheadGranularity( pFileObject,
360                                                pDeviceExt->Specific.RDR.MaximumRPCLength);
361
362                     CcSetDirtyPageThreshold( pFileObject,
363                                              AFS_DIRTY_CHUNK_THRESHOLD * pDeviceExt->Specific.RDR.MaximumRPCLength);
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, TRUE);
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             AFSExFreePoolWithTag(pGatherIo, AFS_GATHER_TAG);
1376         }
1377
1378         if( NULL != pIoRuns &&
1379             stIoRuns != pIoRuns)
1380         {
1381             AFSExFreePoolWithTag(pIoRuns, AFS_IO_RUN_TAG);
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     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1661                   AFS_TRACE_LEVEL_VERBOSE,
1662                   "AFSExtendingWrite Acquiring Fcb PagingIo lock %08lX EXCL %08lX\n",
1663                   &Fcb->NPFcb->PagingResource,
1664                   PsGetCurrentThread());
1665
1666     AFSAcquireExcl( &Fcb->NPFcb->PagingResource,
1667                     TRUE);
1668
1669     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
1670     {
1671
1672         Fcb->Header.AllocationSize.QuadPart = NewLength;
1673
1674         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
1675     }
1676
1677     if( NewLength > Fcb->Header.FileSize.QuadPart)
1678     {
1679
1680         Fcb->Header.FileSize.QuadPart = NewLength;
1681
1682         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
1683     }
1684
1685     //
1686     // Tell the server
1687     //
1688
1689     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentObjectInformation->FileId,
1690                                          Fcb->ObjectInformation,
1691                                          &pCcb->AuthGroup);
1692
1693     if (NT_SUCCESS(ntStatus))
1694     {
1695
1696         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
1697
1698         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1699
1700         //
1701         // If the file is currently cached, then let the MM know about the extension
1702         //
1703
1704         if( CcIsFileCached( FileObject))
1705         {
1706             CcSetFileSizes( FileObject,
1707                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1708         }
1709     }
1710     else
1711     {
1712         Fcb->Header.FileSize = liSaveFileSize;
1713         Fcb->Header.AllocationSize = liSaveAllocation;
1714     }
1715
1716     AFSReleaseResource( &Fcb->NPFcb->PagingResource);
1717
1718     //
1719     // DownConvert file resource to shared
1720     //
1721     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
1722
1723     return ntStatus;
1724 }
1725
1726 NTSTATUS
1727 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
1728                IN PIRP Irp)
1729 {
1730
1731     NTSTATUS ntStatus = STATUS_SUCCESS;
1732     AFSPIOCtlIORequestCB stIORequestCB;
1733     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1734     AFSFcb *pFcb = NULL;
1735     AFSCcb *pCcb = NULL;
1736     AFSPipeIORequestCB *pIoRequest = NULL;
1737     void *pBuffer = NULL;
1738     AFSPipeIOResultCB stIoResult;
1739     ULONG ulBytesReturned = 0;
1740
1741     __Enter
1742     {
1743
1744         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1745
1746         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1747
1748         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1749                       AFS_TRACE_LEVEL_VERBOSE,
1750                       "AFSShareWrite On pipe %wZ Length %08lX\n",
1751                       &pCcb->DirectoryCB->NameInformation.FileName,
1752                       pIrpSp->Parameters.Write.Length);
1753
1754         if( pIrpSp->Parameters.Write.Length == 0)
1755         {
1756
1757             //
1758             // Nothing to do in this case
1759             //
1760
1761             try_return( ntStatus);
1762         }
1763
1764         //
1765         // Retrieve the buffer for the read request
1766         //
1767
1768         pBuffer = AFSLockSystemBuffer( Irp,
1769                                        pIrpSp->Parameters.Write.Length);
1770
1771         if( pBuffer == NULL)
1772         {
1773
1774             AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1775                           AFS_TRACE_LEVEL_ERROR,
1776                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
1777                           &pCcb->DirectoryCB->NameInformation.FileName);
1778
1779             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1780         }
1781
1782         AFSAcquireShared( &pFcb->NPFcb->Resource,
1783                           TRUE);
1784
1785         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
1786                                                                      sizeof( AFSPipeIORequestCB) +
1787                                                                                 pIrpSp->Parameters.Write.Length,
1788                                                                      AFS_GENERIC_MEMORY_14_TAG);
1789
1790         if( pIoRequest == NULL)
1791         {
1792
1793             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1794         }
1795
1796         RtlZeroMemory( pIoRequest,
1797                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
1798
1799         pIoRequest->RequestId = pCcb->RequestID;
1800
1801         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
1802
1803         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
1804
1805         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
1806                        pBuffer,
1807                        pIrpSp->Parameters.Write.Length);
1808
1809         stIoResult.BytesProcessed = 0;
1810
1811         ulBytesReturned = sizeof( AFSPipeIOResultCB);
1812
1813         //
1814         // Issue the open request to the service
1815         //
1816
1817         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
1818                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
1819                                       &pCcb->AuthGroup,
1820                                       &pCcb->DirectoryCB->NameInformation.FileName,
1821                                       NULL,
1822                                       pIoRequest,
1823                                       sizeof( AFSPipeIORequestCB) +
1824                                                 pIrpSp->Parameters.Write.Length,
1825                                       &stIoResult,
1826                                       &ulBytesReturned);
1827
1828         if( !NT_SUCCESS( ntStatus))
1829         {
1830
1831             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1832                           AFS_TRACE_LEVEL_ERROR,
1833                           "AFSShareWrite (%08lX) Failed service write Status %08lX\n",
1834                           Irp,
1835                           ntStatus);
1836
1837             try_return( ntStatus);
1838         }
1839
1840         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1841                       AFS_TRACE_LEVEL_VERBOSE,
1842                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
1843                       &pCcb->DirectoryCB->NameInformation.FileName,
1844                       stIoResult.BytesProcessed);
1845
1846         Irp->IoStatus.Information = stIoResult.BytesProcessed;
1847
1848 try_exit:
1849
1850         if( pFcb != NULL)
1851         {
1852
1853             AFSReleaseResource( &pFcb->NPFcb->Resource);
1854         }
1855
1856         if( pIoRequest != NULL)
1857         {
1858
1859             AFSExFreePoolWithTag( pIoRequest, AFS_GENERIC_MEMORY_14_TAG);
1860         }
1861     }
1862
1863     return ntStatus;
1864 }