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