Windows: Track AuthGroup in Context Control Block
[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
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             bForceFlush = TRUE;
337         }
338
339         if( (!bPagingIo && !bNonCachedIo))
340         {
341
342             if( pFileObject->PrivateCacheMap == NULL)
343             {
344
345                 __try
346                 {
347
348                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
349                                   AFS_TRACE_LEVEL_VERBOSE,
350                                   "AFSCommonWrite Initialize caching on Fcb %08lX FileObject %08lX\n",
351                                   pFcb,
352                                   pFileObject);
353
354                     CcInitializeCacheMap( pFileObject,
355                                           (PCC_FILE_SIZES)&pFcb->Header.AllocationSize,
356                                           FALSE,
357                                           AFSLibCacheManagerCallbacks,
358                                           pFcb);
359
360                     CcSetReadAheadGranularity( pFileObject,
361                                                READ_AHEAD_GRANULARITY);
362
363                 }
364                 __except( EXCEPTION_EXECUTE_HANDLER)
365                 {
366
367                     ntStatus = GetExceptionCode();
368
369                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
370                                   AFS_TRACE_LEVEL_ERROR,
371                                   "AFSCommonWrite (%08lX) Exception thrown while initializing cache map Status %08lX\n",
372                                   Irp,
373                                   ntStatus);
374                 }
375
376                 if( !NT_SUCCESS( ntStatus))
377                 {
378
379                     try_return( ntStatus);
380                 }
381             }
382         }
383
384         while (!bNonCachedIo && !CcCanIWrite( pFileObject,
385                                               ulByteCount,
386                                               FALSE,
387                                               bRetry))
388         {
389             static const LONGLONG llWriteDelay = (LONGLONG)-100000;
390             bRetry = TRUE;
391             KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay);
392         }
393
394         //
395         // Save off the PID if this is not a paging IO
396         //
397
398         if( !bPagingIo &&
399             ( pFcb->Specific.File.ExtentRequestProcessId == 0 ||
400               ( PsGetCurrentProcessId() != AFSSysProcess &&
401                 pFcb->Specific.File.ExtentRequestProcessId != (ULONGLONG)PsGetCurrentProcessId())))
402         {
403
404             pFcb->Specific.File.ExtentRequestProcessId = (ULONGLONG)PsGetCurrentProcessId();
405
406             if( pFcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)AFSSysProcess)
407             {
408                 AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING,
409                               AFS_TRACE_LEVEL_WARNING,
410                               "%s Setting LastWriterExtentProcessId to system process for Fcb %p\n",
411                               __FUNCTION__,
412                               pFcb);
413             }
414
415             pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS;
416         }
417
418         //
419         // We should be ready to go.  So first of all ask for the extents
420         // Provoke a get of the extents - if we need to.
421         //
422
423         /*
424         if( !bPagingIo && !bNonCachedIo)
425         {
426
427             ntStatus = AFSRequestExtentsAsync( pFcb, pCcb, &liStartingByte, ulByteCount);
428
429             if (!NT_SUCCESS(ntStatus))
430             {
431
432                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
433                               AFS_TRACE_LEVEL_ERROR,
434                               "AFSCommonWrite (%08lX) Failed to request extents Status %08lX\n",
435                               Irp,
436                               ntStatus);
437
438                 try_return( ntStatus );
439             }
440         }
441         */
442
443         //
444         // If they are not mapped and we are the Lazy Writer then just
445         // say "not now"
446         //
447         if (!bMapped && pFcb->Specific.File.LazyWriterThread == PsGetCurrentThread())
448         {
449
450             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
451                           AFS_TRACE_LEVEL_VERBOSE,
452                           "AFSCommonWrite (%08lX) Failing lazy writer for unmapped request\n",
453                           Irp);
454
455             try_return ( ntStatus = STATUS_FILE_LOCK_CONFLICT);
456         }
457
458         //
459         // Take locks
460         //
461         //   - if Paging then we need to nothing (the precalls will
462         //     have acquired the paging resource), for clarity we will collect
463         //     the paging resource
464         //   - If extending Write then take the fileresource EX (EOF will change, Allocation will only move out)
465         //   - Otherwise we collect the file shared, check against extending and
466         //
467
468         bLockOK = FALSE;
469
470         do
471         {
472
473             if( !bPagingIo)
474             {
475
476                 bExtendingWrite = (((liStartingByte.QuadPart + ulByteCount) >=
477                                     pFcb->Header.FileSize.QuadPart) ||
478                                    (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
479                                     liStartingByte.HighPart == -1)) ;
480             }
481
482             if( bPagingIo)
483             {
484
485                 //ASSERT( NULL != OnBehalfOf || ExIsResourceAcquiredLite( &pNPFcb->Resource ));
486
487                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
488                               AFS_TRACE_LEVEL_VERBOSE,
489                               "AFSCommonWrite Acquiring Fcb PagingIo lock %08lX SHARED %08lX\n",
490                               &pNPFcb->PagingResource,
491                               PsGetCurrentThread());
492
493                 AFSAcquireShared( &pNPFcb->PagingResource,
494                                   TRUE);
495
496                 bReleasePaging = TRUE;
497
498                 //
499                 // We have the correct lock - we cannot have the wrong one
500                 //
501                 bLockOK = TRUE;
502             }
503             else if( bExtendingWrite)
504             {
505                 //
506                 // Check for lock inversion
507                 //
508
509                 ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
510
511                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
512                               AFS_TRACE_LEVEL_VERBOSE,
513                               "AFSCommonWrite Acquiring Fcb lock %08lX EXCL %08lX\n",
514                               &pNPFcb->Resource,
515                               PsGetCurrentThread());
516
517                 AFSAcquireExcl( &pNPFcb->Resource,
518                                 TRUE);
519
520                 if (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
521                     liStartingByte.HighPart == -1)
522                 {
523                     if (pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart)
524                     {
525                         liStartingByte = pFcb->Header.ValidDataLength;
526                     }
527                     else
528                     {
529                         liStartingByte = pFcb->Header.FileSize;
530                     }
531                 }
532                 bReleaseMain = TRUE;
533
534                 //
535                 // We have the correct lock - even if we don't end up truncating
536                 //
537                 bLockOK = TRUE;
538             }
539             else
540             {
541                 ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
542
543                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
544                               AFS_TRACE_LEVEL_VERBOSE,
545                               "AFSCommonWrite Acquiring Fcb lock %08lX SHARED %08lX\n",
546                               &pNPFcb->Resource,
547                               PsGetCurrentThread());
548
549                 AFSAcquireShared( &pNPFcb->Resource,
550                                   TRUE);
551
552                 bReleaseMain = TRUE;
553
554                 //
555                 // Have things moved?  Are we extending? If so, the the lock isn't OK
556                 //
557                 bLockOK = (liStartingByte.QuadPart + ulByteCount) < pFcb->Header.FileSize.QuadPart;
558
559                 if (!bLockOK)
560                 {
561                     AFSReleaseResource( &pNPFcb->Resource);
562                     bReleaseMain = FALSE;
563                 }
564             }
565         }
566         while (!bLockOK);
567
568         //
569         // Check the BR locks on the file.
570         //
571
572         if( !bPagingIo &&
573             !FsRtlCheckLockForWriteAccess( &pFcb->Specific.File.FileLock,
574                                            Irp))
575         {
576
577             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
578                           AFS_TRACE_LEVEL_ERROR,
579                           "AFSCommonWrite (%08lX) Request failed due to lock conflict\n",
580                           Irp);
581
582             try_return( ntStatus = STATUS_FILE_LOCK_CONFLICT);
583         }
584
585         if( bExtendingWrite)
586         {
587
588             ntStatus = AFSExtendingWrite( pFcb, pFileObject, (liStartingByte.QuadPart + ulByteCount));
589
590             if( !NT_SUCCESS(ntStatus))
591             {
592
593                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
594                               AFS_TRACE_LEVEL_ERROR,
595                               "AFSCommonWrite (%08lX) Failed extending write request Status %08lX\n",
596                               Irp,
597                               ntStatus);
598
599                 try_return( ntStatus );
600             }
601         }
602
603         //
604         // Fire off the request as appropriate
605         //
606         bCompleteIrp = FALSE;
607
608         if( !bPagingIo &&
609             !bNonCachedIo)
610         {
611
612             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
613                           AFS_TRACE_LEVEL_VERBOSE,
614                           "AFSCommonWrite (%08lX) Processing CACHED request Offset %I64X Len %08lX\n",
615                           Irp,
616                           liStartingByte.QuadPart,
617                           ulByteCount);
618
619             ntStatus = AFSCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount, bForceFlush);
620
621         }
622         else
623         {
624
625             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
626                           AFS_TRACE_LEVEL_VERBOSE,
627                           "AFSCommonWrite (%08lX) Processing NON-CACHED request Offset %I64X Len %08lX\n",
628                           Irp,
629                           liStartingByte.QuadPart,
630                           ulByteCount);
631
632             ntStatus = AFSNonCachedWrite( DeviceObject, Irp,  liStartingByte, ulByteCount);
633         }
634
635 try_exit:
636
637         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
638                       AFS_TRACE_LEVEL_VERBOSE,
639                       "AFSCommonWrite (%08lX) Process complete Status %08lX\n",
640                       Irp,
641                       ntStatus);
642
643         ObDereferenceObject(pFileObject);
644
645         if( bReleaseMain)
646         {
647
648             AFSReleaseResource( &pNPFcb->Resource);
649         }
650
651         if( bReleasePaging)
652         {
653
654             AFSReleaseResource( &pNPFcb->PagingResource);
655         }
656
657         if( bCompleteIrp)
658         {
659
660             AFSCompleteRequest( Irp,
661                                 ntStatus);
662         }
663     }
664
665     return ntStatus;
666 }
667
668 NTSTATUS
669 AFSIOCtlWrite( IN PDEVICE_OBJECT DeviceObject,
670                IN PIRP Irp)
671 {
672
673     NTSTATUS ntStatus = STATUS_SUCCESS;
674     AFSPIOCtlIORequestCB stIORequestCB;
675     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
676     AFSFcb *pFcb = NULL;
677     AFSCcb *pCcb = NULL;
678     AFSPIOCtlIOResultCB stIOResultCB;
679     ULONG ulBytesReturned = 0;
680     AFSFileID stParentFID;
681
682     __Enter
683     {
684
685         RtlZeroMemory( &stIORequestCB,
686                        sizeof( AFSPIOCtlIORequestCB));
687
688         if( pIrpSp->Parameters.Write.Length == 0)
689         {
690
691             //
692             // Nothing to do in this case
693             //
694
695             try_return( ntStatus);
696         }
697
698         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
699
700         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
701
702         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
703                       AFS_TRACE_LEVEL_VERBOSE,
704                       "AFSIOCtlWrite Acquiring Fcb lock %08lX SHARED %08lX\n",
705                       &pFcb->NPFcb->Resource,
706                       PsGetCurrentThread());
707
708         AFSAcquireShared( &pFcb->NPFcb->Resource,
709                           TRUE);
710
711         //
712         // Get the parent fid to pass to the cm
713         //
714
715         RtlZeroMemory( &stParentFID,
716                        sizeof( AFSFileID));
717
718         if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
719         {
720
721             //
722             // The parent directory FID of the node
723             //
724
725             stParentFID = pFcb->ObjectInformation->ParentObjectInformation->FileId;
726         }
727
728         //
729         // Set the control block up
730         //
731
732         stIORequestCB.RequestId = pCcb->RequestID;
733
734         if( pFcb->ObjectInformation->VolumeCB != NULL)
735         {
736             stIORequestCB.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
737         }
738
739         //
740         // Lock down the buffer
741         //
742
743         stIORequestCB.MappedBuffer = AFSMapToService( Irp,
744                                                       pIrpSp->Parameters.Write.Length);
745
746         if( stIORequestCB.MappedBuffer == NULL)
747         {
748
749             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
750         }
751
752         stIORequestCB.BufferLength = pIrpSp->Parameters.Write.Length;
753
754         stIOResultCB.BytesProcessed = 0;
755
756         ulBytesReturned = sizeof( AFSPIOCtlIOResultCB);
757
758         //
759         // Issue the request to the service
760         //
761
762         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_WRITE,
763                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
764                                       &pCcb->AuthGroup,
765                                       NULL,
766                                       &stParentFID,
767                                       (void *)&stIORequestCB,
768                                       sizeof( AFSPIOCtlIORequestCB),
769                                       &stIOResultCB,
770                                       &ulBytesReturned);
771
772         if( !NT_SUCCESS( ntStatus))
773         {
774
775             try_return( ntStatus);
776         }
777
778         //
779         // Update the length written
780         //
781
782         Irp->IoStatus.Information = stIOResultCB.BytesProcessed;
783
784 try_exit:
785
786         if( stIORequestCB.MappedBuffer != NULL)
787         {
788
789             AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer,
790                                          Irp->MdlAddress);
791         }
792
793         if( pFcb != NULL)
794         {
795
796             AFSReleaseResource( &pFcb->NPFcb->Resource);
797         }
798     }
799
800     return ntStatus;
801 }
802
803 //
804 // This function is called when we know we have to read from the AFS Cache.
805 //
806 // It ensures that we have exents for the entirety of the write and
807 // then pins the extents into memory (meaning that although we may
808 // add we will not remove).  Then it creates a scatter gather write
809 // and fires off the IRPs
810 //
811 static
812 NTSTATUS
813 AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject,
814                    IN PIRP Irp,
815                    IN LARGE_INTEGER StartingByte,
816                    IN ULONG ByteCount)
817 {
818     NTSTATUS           ntStatus = STATUS_UNSUCCESSFUL;
819     VOID              *pSystemBuffer = NULL;
820     BOOLEAN            bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
821     BOOLEAN            bLocked = FALSE;
822     BOOLEAN            bCompleteIrp = TRUE;
823     BOOLEAN            bExtentsMapped = FALSE;
824     AFSGatherIo       *pGatherIo = NULL;
825     AFSIoRun          *pIoRuns = NULL;
826     AFSIoRun           stIoRuns[AFS_MAX_STACK_IO_RUNS];
827     ULONG              extentsCount = 0, runCount = 0;
828     AFSExtent         *pStartExtent = NULL;
829     AFSExtent         *pIgnoreExtent = NULL;
830     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
831     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
832     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
833     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
834     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
835     AFSDeviceExt      *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension;
836     ULONG              ulRequestCount = 0;
837     LARGE_INTEGER      liCurrentTime, liLastRequestTime;
838     AFSDeviceExt      *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
839     PFILE_OBJECT       pCacheFileObject = NULL;
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 10 seconds of 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 );
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         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1169                       AFS_TRACE_LEVEL_VERBOSE,
1170                       "AFSNonCachedWrite Releasing(2) Fcb extents lock %08lX SHARED %08lX\n",
1171                       &pFcb->NPFcb->Specific.File.ExtentsResource,
1172                       PsGetCurrentThread());
1173
1174         AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1175         bLocked = FALSE;
1176
1177         pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool,
1178                                                              sizeof( AFSGatherIo),
1179                                                              AFS_GATHER_TAG);
1180
1181         if (NULL == pGatherIo)
1182         {
1183
1184             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1185                           AFS_TRACE_LEVEL_ERROR,
1186                           "AFSNonCachedWrite (%08lX) Failed to allocate IO gather block\n",
1187                           Irp);
1188
1189             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1190                           AFS_TRACE_LEVEL_VERBOSE,
1191                           "AFSNonCachedWrite Acquiring(1) Fcb extents lock %08lX SHARED %08lX\n",
1192                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1193                           PsGetCurrentThread());
1194
1195             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1196                               TRUE);
1197             bLocked = TRUE;
1198
1199             AFSDereferenceActiveExtents( pStartExtent,
1200                                          extentsCount);
1201
1202             try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES );
1203         }
1204
1205         RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo ));
1206
1207         //
1208         // Initialize count to 1, that was we won't get an early
1209         // completion if the first irp completes before the second is
1210         // queued.
1211         //
1212         pGatherIo->Count = 1;
1213         pGatherIo->Status = STATUS_SUCCESS;
1214         pGatherIo->MasterIrp = Irp;
1215         pGatherIo->Synchronous = TRUE;
1216         pGatherIo->CompleteMasterIrp = FALSE;
1217
1218         bCompleteIrp = TRUE;
1219
1220         if( pGatherIo->Synchronous)
1221         {
1222             KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE );
1223         }
1224
1225 #if GEN_MD5
1226         //
1227         // Setup the MD5 for each extent
1228         //
1229
1230         AFSSetupMD5Hash( pFcb,
1231                          pStartExtent,
1232                          extentsCount,
1233                          pSystemBuffer,
1234                          &StartingByte,
1235                          ByteCount);
1236 #endif
1237
1238         //
1239         // Pre-emptively set up the count
1240         //
1241
1242         Irp->IoStatus.Information = ByteCount;
1243
1244         ntStatus = AFSQueueStartIos( pCacheFileObject,
1245                                      IRP_MJ_WRITE,
1246                                      IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API,
1247                                      pIoRuns,
1248                                      runCount,
1249                                      pGatherIo);
1250
1251         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1252                       AFS_TRACE_LEVEL_VERBOSE,
1253                       "AFSNonCachedWrite (%08lX) AFSStartIos completed Status %08lX\n",
1254                       Irp,
1255                       ntStatus);
1256
1257         if( !NT_SUCCESS( ntStatus))
1258         {
1259
1260             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1261                           AFS_TRACE_LEVEL_VERBOSE,
1262                           "AFSNonCachedWrite Acquiring(2) Fcb extents lock %08lX SHARED %08lX\n",
1263                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1264                           PsGetCurrentThread());
1265
1266             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1267                               TRUE);
1268             bLocked = TRUE;
1269
1270             AFSDereferenceActiveExtents( pStartExtent,
1271                                          extentsCount);
1272
1273             try_return( ntStatus);
1274         }
1275
1276         //
1277         // Wait for completion of All IOs we started.
1278         //
1279
1280         ntStatus = KeWaitForSingleObject( &pGatherIo->Event,
1281                                           Executive,
1282                                           KernelMode,
1283                                           FALSE,
1284                                           NULL);
1285
1286         if( NT_SUCCESS( ntStatus))
1287         {
1288
1289             ntStatus = pGatherIo->Status;
1290         }
1291
1292         if( !NT_SUCCESS( ntStatus))
1293         {
1294
1295             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1296                           AFS_TRACE_LEVEL_VERBOSE,
1297                           "AFSNonCachedWrite Acquiring(3) Fcb extents lock %08lX SHARED %08lX\n",
1298                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1299                           PsGetCurrentThread());
1300
1301             AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource,
1302                               TRUE);
1303             bLocked = TRUE;
1304
1305             AFSDereferenceActiveExtents( pStartExtent,
1306                                          extentsCount);
1307
1308             try_return( ntStatus);
1309         }
1310
1311         //
1312         // Since this is dirty we can mark the extents dirty now.
1313         // AFSMarkDirty will dereference the extents.  Do not call
1314         // AFSDereferenceActiveExtents() in this code path.
1315         //
1316
1317         AFSMarkDirty( pFcb,
1318                       pStartExtent,
1319                       extentsCount,
1320                       &StartingByte);
1321
1322         if (!bPagingIo)
1323         {
1324             //
1325             // This was an uncached user write - tell the server to do
1326             // the flush when the worker thread next wakes up
1327             //
1328             pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1329         }
1330
1331         //
1332         // All done
1333         //
1334
1335 try_exit:
1336
1337         if( pCacheFileObject != NULL)
1338         {
1339             AFSReleaseCacheFileObject( pCacheFileObject);
1340         }
1341
1342         AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1343                       AFS_TRACE_LEVEL_VERBOSE,
1344                       "AFSNonCachedWrite (%08lX) Completed request Status %08lX\n",
1345                       Irp,
1346                       ntStatus);
1347
1348         if (NT_SUCCESS(ntStatus) &&
1349             !bPagingIo &&
1350             bSynchronousFo)
1351         {
1352
1353             pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1354         }
1355
1356         if( bLocked)
1357         {
1358
1359             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1360                           AFS_TRACE_LEVEL_VERBOSE,
1361                           "AFSNonCachedWrite Releasing Fcb extents lock %08lX SHARED %08lX\n",
1362                           &pFcb->NPFcb->Specific.File.ExtentsResource,
1363                           PsGetCurrentThread());
1364
1365             AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource );
1366         }
1367
1368         if( pGatherIo)
1369         {
1370             AFSExFreePool(pGatherIo);
1371         }
1372
1373         if( NULL != pIoRuns &&
1374             stIoRuns != pIoRuns)
1375         {
1376             AFSExFreePool(pIoRuns);
1377         }
1378
1379         if( bCompleteIrp)
1380         {
1381
1382             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1383                           AFS_TRACE_LEVEL_VERBOSE,
1384                           "AFSNonCachedWrite Completing Irp %08lX Status %08lX Info %08lX\n",
1385                           Irp,
1386                           ntStatus,
1387                           Irp->IoStatus.Information);
1388
1389             AFSCompleteRequest( Irp, ntStatus);
1390         }
1391     }
1392
1393     return ntStatus;
1394 }
1395
1396 static
1397 NTSTATUS
1398 AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
1399                 IN PIRP Irp,
1400                 IN LARGE_INTEGER StartingByte,
1401                 IN ULONG ByteCount,
1402                 IN BOOLEAN ForceFlush)
1403 {
1404     PVOID              pSystemBuffer = NULL;
1405     NTSTATUS           ntStatus = STATUS_SUCCESS;
1406     IO_STATUS_BLOCK    iosbFlush;
1407     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1408     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
1409     AFSFcb            *pFcb = (AFSFcb *)pFileObject->FsContext;
1410     AFSCcb            *pCcb = (AFSCcb *)pFileObject->FsContext2;
1411     BOOLEAN            bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
1412     BOOLEAN            bMapped = FALSE;
1413     ULONG              ulCurrentIO = 0, ulTotalLen = ByteCount;
1414     PMDL               pCurrentMdl = Irp->MdlAddress;
1415     LARGE_INTEGER      liCurrentOffset;
1416
1417     __Enter
1418     {
1419
1420         Irp->IoStatus.Information = 0;
1421
1422         if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL))
1423         {
1424
1425             __try
1426             {
1427
1428                 CcPrepareMdlWrite( pFileObject,
1429                                    &StartingByte,
1430                                    ByteCount,
1431                                    &Irp->MdlAddress,
1432                                    &Irp->IoStatus);
1433
1434                 ntStatus = Irp->IoStatus.Status;
1435             }
1436             __except( EXCEPTION_EXECUTE_HANDLER)
1437             {
1438                 ntStatus = GetExceptionCode();
1439
1440                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1441                               AFS_TRACE_LEVEL_ERROR,
1442                               "AFSCachedWrite (%08lX) Exception thrown while preparing mdl write Status %08lX\n",
1443                               Irp,
1444                               ntStatus);
1445             }
1446
1447             if( !NT_SUCCESS( ntStatus))
1448             {
1449
1450                 //
1451                 // Free up any potentially allocated mdl's
1452                 //
1453
1454                 CcMdlWriteComplete( pFileObject,
1455                                     &StartingByte,
1456                                     Irp->MdlAddress);
1457
1458                 Irp->MdlAddress = NULL;
1459
1460                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1461                               AFS_TRACE_LEVEL_ERROR,
1462                               "AFSCachedWrite (%08lX) Failed to process MDL write Status %08lX\n",
1463                               Irp,
1464                               ntStatus);
1465             }
1466
1467             try_return( ntStatus);
1468         }
1469
1470         liCurrentOffset.QuadPart = StartingByte.QuadPart;
1471
1472         while( ulTotalLen > 0)
1473         {
1474
1475             ntStatus = STATUS_SUCCESS;
1476
1477             if( pCurrentMdl != NULL)
1478             {
1479
1480                 pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl,
1481                                                               NormalPagePriority);
1482
1483                 ulCurrentIO = MmGetMdlByteCount( pCurrentMdl);
1484
1485                 if( ulCurrentIO > ulTotalLen)
1486                 {
1487                     ulCurrentIO = ulTotalLen;
1488                 }
1489             }
1490             else
1491             {
1492
1493                 pSystemBuffer = AFSLockSystemBuffer( Irp,
1494                                                      ulTotalLen);
1495
1496                 ulCurrentIO = ulTotalLen;
1497             }
1498
1499             if( pSystemBuffer == NULL)
1500             {
1501
1502                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1503                               AFS_TRACE_LEVEL_ERROR,
1504                               "AFSCachedWrite (%08lX) Failed to lock system buffer\n",
1505                               Irp);
1506
1507                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1508             }
1509
1510             __try
1511             {
1512
1513                 if( !CcCopyWrite( pFileObject,
1514                                   &liCurrentOffset,
1515                                   ulCurrentIO,
1516                                   TRUE,
1517                                   pSystemBuffer))
1518                 {
1519                     //
1520                     // Failed to process request.
1521                     //
1522
1523                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1524                                   AFS_TRACE_LEVEL_ERROR,
1525                                   "AFSCachedWrite (%08lX) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n",
1526                                   Irp,
1527                                   &pFileObject->FileName,
1528                                   liCurrentOffset.QuadPart,
1529                                   Irp->IoStatus.Status);
1530
1531                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
1532                 }
1533             }
1534             __except( EXCEPTION_EXECUTE_HANDLER)
1535             {
1536
1537                 ntStatus = GetExceptionCode();
1538
1539                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1540                               AFS_TRACE_LEVEL_ERROR,
1541                               "AFSCachedWrite (%08lX) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n",
1542                               Irp,
1543                               &pFileObject->FileName,
1544                               liCurrentOffset.QuadPart,
1545                               ntStatus);
1546             }
1547
1548             if( !NT_SUCCESS( ntStatus))
1549             {
1550                 try_return( ntStatus);
1551             }
1552
1553             if( ForceFlush)
1554             {
1555
1556                 //
1557                 // We have detected a file we do a write through with.
1558                 //
1559
1560                 CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
1561                              &liCurrentOffset,
1562                              ulCurrentIO,
1563                              &iosbFlush);
1564
1565                 if( !NT_SUCCESS( iosbFlush.Status))
1566                 {
1567
1568                     AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
1569                                   AFS_TRACE_LEVEL_ERROR,
1570                                   "AFSCachedWrite (%08lX) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
1571                                   Irp,
1572                                   &pFileObject->FileName,
1573                                   pFcb->ObjectInformation->FileId.Cell,
1574                                   pFcb->ObjectInformation->FileId.Volume,
1575                                   pFcb->ObjectInformation->FileId.Vnode,
1576                                   pFcb->ObjectInformation->FileId.Unique,
1577                                   iosbFlush.Status,
1578                                   iosbFlush.Information);
1579
1580                     try_return( ntStatus = iosbFlush.Status);
1581                 }
1582             }
1583
1584             if( ulTotalLen <= ulCurrentIO)
1585             {
1586                 break;
1587             }
1588
1589             liCurrentOffset.QuadPart += ulCurrentIO;
1590
1591             ulTotalLen -= ulCurrentIO;
1592
1593             pCurrentMdl = pCurrentMdl->Next;
1594         }
1595
1596 try_exit:
1597
1598         if( NT_SUCCESS( ntStatus))
1599         {
1600
1601             Irp->IoStatus.Information = ByteCount;
1602
1603             if( bSynchronousFo)
1604             {
1605
1606                 pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount;
1607             }
1608
1609             //
1610             // If this extended the Vdl, then update it accordingly
1611             //
1612
1613             if( StartingByte.QuadPart + ByteCount > pFcb->Header.ValidDataLength.QuadPart)
1614             {
1615
1616                 pFcb->Header.ValidDataLength.QuadPart = StartingByte.QuadPart + ByteCount;
1617             }
1618
1619             if (BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
1620             {
1621                 //
1622                 // Write through asked for... Set things so that we get
1623                 // flush when the worker thread next wakes up
1624                 //
1625                 pFcb->Specific.File.LastServerFlush.QuadPart = 0;
1626             }
1627
1628             if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
1629             {
1630
1631                 SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME);
1632
1633                 KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime);
1634             }
1635         }
1636
1637         AFSCompleteRequest( Irp,
1638                             ntStatus);
1639     }
1640
1641     return ntStatus;
1642 }
1643
1644 static
1645 NTSTATUS
1646 AFSExtendingWrite( IN AFSFcb *Fcb,
1647                    IN PFILE_OBJECT FileObject,
1648                    IN LONGLONG NewLength)
1649 {
1650     LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize;
1651     LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize;
1652     NTSTATUS      ntStatus = STATUS_SUCCESS;
1653     AFSCcb       *pCcb = (AFSCcb *)FileObject->FsContext2;
1654
1655     if( NewLength > Fcb->Header.AllocationSize.QuadPart)
1656     {
1657
1658         Fcb->Header.AllocationSize.QuadPart = NewLength;
1659
1660         Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize;
1661     }
1662
1663     if( NewLength > Fcb->Header.FileSize.QuadPart)
1664     {
1665
1666         Fcb->Header.FileSize.QuadPart = NewLength;
1667
1668         Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize;
1669     }
1670
1671     //
1672     // Tell the server
1673     //
1674
1675     ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentObjectInformation->FileId,
1676                                          Fcb->ObjectInformation,
1677                                          &pCcb->AuthGroup);
1678
1679     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1680                   AFS_TRACE_LEVEL_VERBOSE,
1681                   "AFSExtendingWrite Acquiring Fcb lock %08lX EXCL %08lX\n",
1682                   &Fcb->NPFcb->Resource,
1683                   PsGetCurrentThread());
1684
1685     if (NT_SUCCESS(ntStatus))
1686     {
1687
1688         KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime);
1689
1690         SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1691
1692         //
1693         // If the file is currently cached, then let the MM know about the extension
1694         //
1695
1696         if( CcIsFileCached( FileObject))
1697         {
1698             CcSetFileSizes( FileObject,
1699                             (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1700         }
1701     }
1702     else
1703     {
1704         Fcb->Header.FileSize = liSaveFileSize;
1705         Fcb->Header.AllocationSize = liSaveAllocation;
1706     }
1707
1708     //
1709     // DownConvert file resource to shared
1710     //
1711     ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource);
1712
1713     return ntStatus;
1714 }
1715
1716 NTSTATUS
1717 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
1718                IN PIRP Irp)
1719 {
1720
1721     NTSTATUS ntStatus = STATUS_SUCCESS;
1722     AFSPIOCtlIORequestCB stIORequestCB;
1723     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
1724     AFSFcb *pFcb = NULL;
1725     AFSCcb *pCcb = NULL;
1726     AFSPipeIORequestCB *pIoRequest = NULL;
1727     void *pBuffer = NULL;
1728     AFSPipeIOResultCB stIoResult;
1729     ULONG ulBytesReturned = 0;
1730
1731     __Enter
1732     {
1733
1734         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1735
1736         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1737
1738         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1739                       AFS_TRACE_LEVEL_VERBOSE,
1740                       "AFSShareWrite On pipe %wZ Length %08lX\n",
1741                       &pCcb->DirectoryCB->NameInformation.FileName,
1742                       pIrpSp->Parameters.Write.Length);
1743
1744         if( pIrpSp->Parameters.Write.Length == 0)
1745         {
1746
1747             //
1748             // Nothing to do in this case
1749             //
1750
1751             try_return( ntStatus);
1752         }
1753
1754         //
1755         // Retrieve the buffer for the read request
1756         //
1757
1758         pBuffer = AFSLockSystemBuffer( Irp,
1759                                        pIrpSp->Parameters.Write.Length);
1760
1761         if( pBuffer == NULL)
1762         {
1763
1764             AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1765                           AFS_TRACE_LEVEL_ERROR,
1766                           "AFSShareWrite Failed to map buffer on pipe %wZ\n",
1767                           &pCcb->DirectoryCB->NameInformation.FileName);
1768
1769             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1770         }
1771
1772         AFSAcquireShared( &pFcb->NPFcb->Resource,
1773                           TRUE);
1774
1775         pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool,
1776                                                                      sizeof( AFSPipeIORequestCB) +
1777                                                                                 pIrpSp->Parameters.Write.Length,
1778                                                                      AFS_GENERIC_MEMORY_14_TAG);
1779
1780         if( pIoRequest == NULL)
1781         {
1782
1783             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1784         }
1785
1786         RtlZeroMemory( pIoRequest,
1787                        sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length);
1788
1789         pIoRequest->RequestId = pCcb->RequestID;
1790
1791         pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId;
1792
1793         pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length;
1794
1795         RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)),
1796                        pBuffer,
1797                        pIrpSp->Parameters.Write.Length);
1798
1799         stIoResult.BytesProcessed = 0;
1800
1801         ulBytesReturned = sizeof( AFSPipeIOResultCB);
1802
1803         //
1804         // Issue the open request to the service
1805         //
1806
1807         ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE,
1808                                       AFS_REQUEST_FLAG_SYNCHRONOUS,
1809                                       &pCcb->AuthGroup,
1810                                       &pCcb->DirectoryCB->NameInformation.FileName,
1811                                       NULL,
1812                                       pIoRequest,
1813                                       sizeof( AFSPipeIORequestCB) +
1814                                                 pIrpSp->Parameters.Write.Length,
1815                                       &stIoResult,
1816                                       &ulBytesReturned);
1817
1818         if( !NT_SUCCESS( ntStatus))
1819         {
1820
1821             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1822                           AFS_TRACE_LEVEL_ERROR,
1823                           "AFSShareWrite (%08lX) Failed service write Status %08lX\n",
1824                           Irp,
1825                           ntStatus);
1826
1827             try_return( ntStatus);
1828         }
1829
1830         AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
1831                       AFS_TRACE_LEVEL_VERBOSE,
1832                       "AFSShareWrite Completed on pipe %wZ Length read %08lX\n",
1833                       &pCcb->DirectoryCB->NameInformation.FileName,
1834                       stIoResult.BytesProcessed);
1835
1836         Irp->IoStatus.Information = stIoResult.BytesProcessed;
1837
1838 try_exit:
1839
1840         if( pFcb != NULL)
1841         {
1842
1843             AFSReleaseResource( &pFcb->NPFcb->Resource);
1844         }
1845
1846         if( pIoRequest != NULL)
1847         {
1848
1849             AFSExFreePool( pIoRequest);
1850         }
1851     }
1852
1853     return ntStatus;
1854 }