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