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