Windows: AFSCommonWrite add bWriteToEndOfFile var
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSWrite.cpp
index dbe4f75..3fcdbbd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
- * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Your File System, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,8 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
     BOOLEAN            bReleasePaging = FALSE;
     BOOLEAN            bExtendingWrite = FALSE;
     BOOLEAN            bSynchronousFo = FALSE;
+    BOOLEAN           bWriteToEndOfFile = FALSE;
+    BOOLEAN           bWait = FALSE;
     BOOLEAN            bCompleteIrp = TRUE;
     BOOLEAN            bForceFlush = FALSE;
     BOOLEAN            bLockOK;
@@ -177,6 +179,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
         liStartingByte = pIrpSp->Parameters.Write.ByteOffset;
         bPagingIo      = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO);
         bNonCachedIo   = BooleanFlagOn( Irp->Flags, IRP_NOCACHE);
+       bWait          = IoIsOperationSynchronous( Irp);
         ulByteCount    = pIrpSp->Parameters.Write.Length;
         bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO);
 
@@ -354,7 +357,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
             if( pFileObject->PrivateCacheMap == NULL)
             {
 
-                AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
+               AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
                               AFS_TRACE_LEVEL_VERBOSE,
                               "AFSCommonWrite Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
                               &pNPFcb->SectionObjectResource,
@@ -386,7 +389,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                     CcSetDirtyPageThreshold( pFileObject,
                                              AFS_DIRTY_CHUNK_THRESHOLD * pDeviceExt->Specific.RDR.MaximumRPCLength / 4096);
                 }
-                __except( EXCEPTION_EXECUTE_HANDLER)
+               __except( EXCEPTION_EXECUTE_HANDLER)
                 {
 
                     ntStatus = GetExceptionCode();
@@ -398,7 +401,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                                   ntStatus));
                 }
 
-                AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
+               AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
                               AFS_TRACE_LEVEL_VERBOSE,
                               "AFSCommonWrite Releasing Fcb SectionObject lock %p EXCL %08lX\n",
                               &pNPFcb->SectionObjectResource,
@@ -415,39 +418,73 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                 }
             }
 
-            if (!CcCanIWrite( pFileObject,
-                              ulByteCount,
-                              FALSE,
-                              bRetry))
-            {
-
-                AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
-                              AFS_TRACE_LEVEL_WARNING,
-                              "AFSCommonWrite (FO: %p) CcCanIWrite says No room for Offset %0I64X Length %08lX bytes! Deferring%s\n",
-                              pFileObject,
-                              liStartingByte.QuadPart,
-                              ulByteCount,
-                              bRetry ? " RETRY" : ""));
-
-                ntStatus = AFSDeferWrite( DeviceObject, pFileObject, hCallingUser, Irp, ulByteCount, bRetry);
-
-                if ( STATUS_PENDING == ntStatus)
-                {
-
-                    bCompleteIrp = FALSE;
-                }
-                else
-                {
-
-                    AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
-                                  AFS_TRACE_LEVEL_ERROR,
-                                  "AFSCommonWrite (FO: %p) AFSDeferWrite failure Status %08lX\n",
-                                  pFileObject,
-                                  ntStatus));
-                }
-
-                try_return( ntStatus);
-            }
+           //
+           // On versions of Microsoft Windows older than Vista the IO Manager
+           // will issue multiple outstanding writes on a synchronous file object
+           // if one of the cached writes completes with STATUS_PENDING.  This can
+           // result in the writes being completed out of order which can corrupt
+           // the end of file marker.  On OS versions older than Vista use a spin
+           // loop instead of deferring the write.
+           //
+
+           if ( bSynchronousFo &&
+                AFSRtlSysVersion.dwMajorVersion < 6)
+           {
+
+               while (!CcCanIWrite( pFileObject,
+                                    ulByteCount,
+                                    bWait && !bRetry,
+                                    bRetry))
+               {
+                   static const LONGLONG llWriteDelay = (LONGLONG)-100000;
+                   bRetry = TRUE;
+
+                   AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
+                                 AFS_TRACE_LEVEL_WARNING,
+                                 "AFSCommonWrite (FO: %p) CcCanIWrite says No room for %u bytes! Retry in 10ms\n",
+                                 pFileObject,
+                                 ulByteCount);
+
+                   KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay);
+               }
+           }
+           else
+           {
+
+               if (!CcCanIWrite( pFileObject,
+                                 ulByteCount,
+                                 bWait && !bRetry,
+                                 bRetry))
+               {
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
+                                 AFS_TRACE_LEVEL_WARNING,
+                                 "AFSCommonWrite (FO: %p) CcCanIWrite says No room for Offset %0I64X Length %08lX bytes! Deferring%s\n",
+                                 pFileObject,
+                                 liStartingByte.QuadPart,
+                                 ulByteCount,
+                                 bRetry ? " RETRY" : ""));
+
+                   ntStatus = AFSDeferWrite( DeviceObject, pFileObject, hCallingUser, Irp, ulByteCount, bRetry);
+
+                   if ( STATUS_PENDING == ntStatus)
+                   {
+
+                       bCompleteIrp = FALSE;
+                   }
+                   else
+                   {
+
+                       AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
+                                     AFS_TRACE_LEVEL_ERROR,
+                                     "AFSCommonWrite (FO: %p) AFSDeferWrite failure Status %08lX\n",
+                                     pFileObject,
+                                     ntStatus));
+                   }
+
+                   try_return( ntStatus);
+               }
+           }
         }
 
         //
@@ -511,10 +548,12 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
             else
             {
 
-                bExtendingWrite = (((liStartingByte.QuadPart + ulByteCount) >=
-                                     pFcb->Header.FileSize.QuadPart) ||
-                                    (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
-                                      liStartingByte.HighPart == -1)) ;
+               bWriteToEndOfFile = liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
+                                   liStartingByte.HighPart == -1;
+
+               bExtendingWrite = ( bWriteToEndOfFile ||
+                                   ((liStartingByte.QuadPart + ulByteCount) >=
+                                     pFcb->Header.FileSize.QuadPart));
 
                 if( bExtendingWrite || bNonCachedIo)
                 {
@@ -522,6 +561,11 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                     // Check for lock inversion
                     //
 
+                   //
+                   // For bExtendingWrite the PagingResource is needed to protect
+                   // the CcSetFileSizes call in AFSExtendingWrite
+                   //
+
                     ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource ));
 
                     AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
@@ -535,7 +579,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
                     bReleaseMain = TRUE;
 
-                    AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
+                   AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
                                   AFS_TRACE_LEVEL_VERBOSE,
                                   "AFSCommonWrite Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
                                   &pNPFcb->SectionObjectResource,
@@ -546,8 +590,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
                     bReleaseSectionObject = TRUE;
 
-                    if (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE &&
-                         liStartingByte.HighPart == -1)
+                   if ( bWriteToEndOfFile)
                     {
                         if (pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart)
                         {
@@ -579,7 +622,7 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
                     bReleaseMain = TRUE;
 
-                    AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
+                   AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
                                   AFS_TRACE_LEVEL_VERBOSE,
                                   "AFSCommonWrite Acquiring Fcb SectionObject lock %p SHARED %08lX\n",
                                   &pNPFcb->SectionObjectResource,
@@ -597,6 +640,17 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
                     if (!bLockOK)
                     {
+
+                       AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
+                                     AFS_TRACE_LEVEL_VERBOSE,
+                                     "AFSCommonWrite Releasing Fcb SectionObject lock %p SHARED %08lX\n",
+                                     &pNPFcb->SectionObjectResource,
+                                     PsGetCurrentThread()));
+
+                       AFSReleaseResource( &pNPFcb->SectionObjectResource);
+
+                       bReleaseSectionObject = FALSE;
+
                         AFSReleaseResource( &pNPFcb->Resource);
 
                         bReleaseMain = FALSE;
@@ -630,6 +684,10 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
                 ntStatus = AFSExtendingWrite( pFcb, pFileObject, (liStartingByte.QuadPart + ulByteCount));
 
+               //
+               // Fcb->NPFcb->Resource is now held SHARED
+               //
+
                 if( !NT_SUCCESS(ntStatus))
                 {
 
@@ -654,7 +712,8 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
         {
 
             //
-            // Main and SectionObject resources held Shared
+           // Main resource held Shared
+           // SectionObject resource held exclusive if extending write
             //
 
             AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
@@ -697,19 +756,21 @@ try_exit:
                       Irp,
                       ntStatus));
 
-        if ( NT_SUCCESS( ntStatus))
+       if ( NT_SUCCESS( ntStatus) &&
+            ntStatus != STATUS_PENDING)
         {
             if ( !bPagingIo)
             {
 
-                if( bSynchronousFo)
+               if( bSynchronousFo)
                 {
 
                     pFileObject->CurrentByteOffset.QuadPart = liStartingByte.QuadPart + ulByteCount;
                 }
 
                 //
-                // If this extended the Vdl, then update it accordingly
+                // If this extended the VDL, then update it accordingly.
+                // Increasing the VDL does not require a call to CcSetFileSizes.
                 //
 
                 if( liStartingByte.QuadPart + ulByteCount > pFcb->Header.ValidDataLength.QuadPart)
@@ -728,11 +789,81 @@ try_exit:
             }
         }
 
+       if ( ntStatus != STATUS_PENDING &&
+            !bPagingIo && bNonCachedIo && CcIsFileCached( pFileObject) &&
+             pNPFcb->SectionObjectPointers.DataSectionObject != NULL &&
+             bReleaseSectionObject)
+        {
+            //
+            // Regardless of whether or not the a non-paging non-cached write
+            // succeeds or fails, if the file is cached the contents of the
+            // cache are no longer up to date.  A CcPurgeCacheSection must be
+            // performed to force subsequent cached reads to obtain the data
+            // from the service.
+            //
+            // The Fcb Resource is dropped in order to permit filters that perform
+            // an open via a worker thread in response to a purge to do so without
+            // deadlocking.  The SectionObjectResource is held across the purge to
+            // prevent racing with other cache operations.
+            //
+
+            if( bReleaseMain)
+            {
+
+                AFSReleaseResource( &pNPFcb->Resource);
+
+                bReleaseMain = FALSE;
+            }
+
+           __try
+            {
+
+               if ( !CcPurgeCacheSection( &pNPFcb->SectionObjectPointers,
+                                          &liStartingByte,
+                                          ulByteCount,
+                                          FALSE))
+               {
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
+                                 AFS_TRACE_LEVEL_WARNING,
+                                 "AFSCommonWrite CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
+                                 pFcb->ObjectInformation->FileId.Cell,
+                                 pFcb->ObjectInformation->FileId.Volume,
+                                 pFcb->ObjectInformation->FileId.Vnode,
+                                 pFcb->ObjectInformation->FileId.Unique));
+
+                   SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
+               }
+           }
+           __except( EXCEPTION_EXECUTE_HANDLER)
+           {
+
+               DWORD ntStatus2 = GetExceptionCode();
+
+               AFSDbgTrace(( 0,
+                             0,
+                             "EXCEPTION - AFSCommonWrite CcPurgeCacheSection failed FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
+                              pFcb->ObjectInformation->FileId.Cell,
+                              pFcb->ObjectInformation->FileId.Volume,
+                              pFcb->ObjectInformation->FileId.Vnode,
+                             pFcb->ObjectInformation->FileId.Unique,
+                             ntStatus2));
+
+                SetFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
+            }
+        }
+
         ObDereferenceObject(pFileObject);
 
         if( bReleaseSectionObject)
         {
 
+           AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
+                         AFS_TRACE_LEVEL_VERBOSE,
+                         "AFSCommonWrite Releasing Fcb SectionObject lock %p EXCL/SHARED %08lX\n",
+                         &pNPFcb->SectionObjectResource,
+                         PsGetCurrentThread()));
+
             AFSReleaseResource( &pNPFcb->SectionObjectResource);
         }
 
@@ -1723,7 +1854,7 @@ AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
 
                 ntStatus = Irp->IoStatus.Status;
             }
-            __except( EXCEPTION_EXECUTE_HANDLER)
+           __except( EXCEPTION_EXECUTE_HANDLER)
             {
                 ntStatus = GetExceptionCode();
 
@@ -1821,7 +1952,7 @@ AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
                     try_return( ntStatus = STATUS_UNSUCCESSFUL);
                 }
             }
-            __except( EXCEPTION_EXECUTE_HANDLER)
+           __except( EXCEPTION_EXECUTE_HANDLER)
             {
 
                 ntStatus = GetExceptionCode();
@@ -1844,31 +1975,49 @@ AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject,
                 BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH)))
             {
 
-                //
-                // We have detected a file we do a write through with.
-                //
-
-                CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
-                             &liCurrentOffset,
-                             ulCurrentIO,
-                             &iosbFlush);
-
-                if( !NT_SUCCESS( iosbFlush.Status))
+               __try
+               {
+                   //
+                   // We have detected a file we do a write through with.
+                   //
+
+                   CcFlushCache(&pFcb->NPFcb->SectionObjectPointers,
+                                 &liCurrentOffset,
+                                 ulCurrentIO,
+                                 &iosbFlush);
+
+                   if( !NT_SUCCESS( iosbFlush.Status))
+                   {
+
+                       AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
+                                     AFS_TRACE_LEVEL_ERROR,
+                                     "AFSCachedWrite (%p) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
+                                     Irp,
+                                     &pFileObject->FileName,
+                                     pFcb->ObjectInformation->FileId.Cell,
+                                     pFcb->ObjectInformation->FileId.Volume,
+                                     pFcb->ObjectInformation->FileId.Vnode,
+                                     pFcb->ObjectInformation->FileId.Unique,
+                                     iosbFlush.Status,
+                                     iosbFlush.Information));
+
+                       try_return( ntStatus = iosbFlush.Status);
+                   }
+               }
+               __except( EXCEPTION_EXECUTE_HANDLER)
                 {
 
+                   ntStatus = GetExceptionCode();
+
                     AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
                                   AFS_TRACE_LEVEL_ERROR,
-                                  "AFSCachedWrite (%p) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
+                                 "AFSCachedWrite (%p) CcFlushCache Threw exception %wZ @ %0I64X Status %08lX\n",
                                   Irp,
                                   &pFileObject->FileName,
-                                  pFcb->ObjectInformation->FileId.Cell,
-                                  pFcb->ObjectInformation->FileId.Volume,
-                                  pFcb->ObjectInformation->FileId.Vnode,
-                                  pFcb->ObjectInformation->FileId.Unique,
-                                  iosbFlush.Status,
-                                  iosbFlush.Information));
-
-                    try_return( ntStatus = iosbFlush.Status);
+                                 liCurrentOffset.QuadPart,
+                                 ntStatus));
+
+                   try_return( ntStatus);
                 }
             }
 
@@ -1909,6 +2058,10 @@ try_exit:
     return ntStatus;
 }
 
+//
+// Called with Fcb->NPFcb->SectionObjectResource and Fcb->NPFcb->Resource held
+//
+
 static
 NTSTATUS
 AFSExtendingWrite( IN AFSFcb *Fcb,
@@ -1954,6 +2107,9 @@ AFSExtendingWrite( IN AFSFcb *Fcb,
         //
         // If the file is currently cached, then let the MM know about the extension
         //
+       // The CcSetFileSizes call should be made with only the PagingResource held
+       // which we are currently not holding.
+       //
 
         if( CcIsFileCached( FileObject))
         {
@@ -1993,8 +2149,6 @@ AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
     __Enter
     {
 
-        pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
-
         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
 
         AFSDbgTrace(( AFS_SUBSYSTEM_PIPE_PROCESSING,
@@ -2031,6 +2185,8 @@ AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
         }
 
+       pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
+
         AFSAcquireShared( &pFcb->NPFcb->Resource,
                           TRUE);