Windows: Call CcDeferWrite rather than loop
authorRod Widdowson <rdw@steadingsoftware.com>
Mon, 18 Feb 2013 15:33:29 +0000 (10:33 -0500)
committerJeffrey Altman <jaltman@your-file-system.com>
Fri, 22 Feb 2013 21:11:40 +0000 (13:11 -0800)
If we are about to write into the cache and we do not have enough
memory we call CcDeferWrite and return STATUS_PENDING.  This allows
the cache to call us back when there is memory.

The write is performed on the IO queue which is shared wth paging
writes.  However this does not cause paging writes to block in a
memory shortage situation since the request will either be deferred
again (releasing a thread to service a paging write) or will complete
quickly.  Further we allocate all our resources upfront so we fail
fast and in the appropriate place.

Change-Id: I4efbc14a97d3b34236643973f1f8f85c7ea194a6
Reviewed-on: http://gerrit.openafs.org/9127
Reviewed-by: Rod Widdowson <rdw@steadingsoftware.com>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Peter Scott <pscott@kerneldrivers.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>

src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp
src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp
src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h
src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h

index 7372239..dbf98eb 100644 (file)
 
 #include "AFSCommon.h"
 
+static
+VOID
+AFSPostedDeferredWrite( IN PVOID Context1,
+                        IN PVOID Context2);
+
 //
 // Function: AFSInitializeWorkerPool
 //
@@ -916,11 +921,24 @@ AFSIOWorkerThread( IN PVOID Context)
                         break;
                     }
 
+                    case AFS_WORK_DEFERRED_WRITE:
+                    {
+
+                        ntStatus = AFSCommonWrite( pWorkItem->Specific.AsynchIo.Device,
+                                                   pWorkItem->Specific.AsynchIo.Irp,
+                                                   pWorkItem->Specific.AsynchIo.CallingProcess,
+                                                   TRUE);
+
+                        freeWorkItem = TRUE;
+
+                        break;
+                    }
+
                     default:
 
                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                                       AFS_TRACE_LEVEL_ERROR,
-                                      "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
+                                      "AFSIOWorkerThread Unknown request type %d\n", pWorkItem->RequestType);
 
                         break;
                 }
@@ -2734,3 +2752,145 @@ try_exit:
 
     return ntStatus;
 }
+
+NTSTATUS
+AFSDeferWrite( IN PDEVICE_OBJECT DeviceObject,
+               IN PFILE_OBJECT FileObject,
+               IN HANDLE CallingUser,
+               IN PIRP Irp,
+               IN ULONG BytesToWrite,
+               IN BOOLEAN bRetrying)
+{
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSWorkItem *pWorkItem = NULL;
+
+    __try
+    {
+
+        //
+        // Pin the user buffer (first time round only - AFSLockSystemBuffer is
+        // idempotent)
+        //
+
+        if ( NULL == AFSLockSystemBuffer( Irp, BytesToWrite ))
+        {
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
+                          AFS_TRACE_LEVEL_ERROR,
+                          "%s Could not pin user memory item\n",
+                          __FUNCTION__);
+
+            try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
+                                                                 sizeof(AFSWorkItem),
+                                                                 AFS_WORK_ITEM_TAG);
+
+        if (NULL == pWorkItem)
+        {
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
+                          AFS_TRACE_LEVEL_ERROR,
+                          "%s Failed to allocate work item\n",
+                          __FUNCTION__);
+
+            try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        RtlZeroMemory( pWorkItem,
+                       sizeof(AFSWorkItem));
+
+        pWorkItem->Size = sizeof( AFSWorkItem);
+
+        pWorkItem->RequestType = AFS_WORK_DEFERRED_WRITE;
+
+        pWorkItem->Specific.AsynchIo.CallingProcess = CallingUser;
+
+        pWorkItem->Specific.AsynchIo.Device = DeviceObject;
+
+        pWorkItem->Specific.AsynchIo.Irp = Irp;
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "%s Workitem %p\n",
+                      __FUNCTION__,
+                      pWorkItem);
+
+        CcDeferWrite( FileObject, AFSPostedDeferredWrite, pWorkItem, NULL, BytesToWrite, bRetrying);
+
+        IoMarkIrpPending(Irp);
+
+        ntStatus = STATUS_PENDING;
+    }
+    __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
+    {
+
+        AFSDbgLogMsg( 0,
+                      0,
+                      "EXCEPTION - %s \n",
+                      __FUNCTION__);
+
+        ntStatus = GetExceptionCode();
+    }
+
+try_exit:
+
+    AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
+                  AFS_TRACE_LEVEL_VERBOSE,
+                  "%s complete Status %08lX\n",
+                  __FUNCTION__,
+                  ntStatus);
+
+    if( !NT_SUCCESS( ntStatus))
+    {
+
+        if( pWorkItem != NULL)
+        {
+
+            ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
+        }
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
+                      AFS_TRACE_LEVEL_ERROR,
+                      "%s Failed to queue request Status %08lX\n",
+                      __FUNCTION__,
+                      ntStatus);
+    }
+
+    return ntStatus;
+}
+
+static
+VOID
+AFSPostedDeferredWrite( IN PVOID Context1,
+                        IN PVOID Context2)
+{
+    UNREFERENCED_PARAMETER( Context2);
+    NTSTATUS ntStatus;
+
+    AFSWorkItem *pWorkItem = (AFSWorkItem *) Context1;
+
+    AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
+                  AFS_TRACE_LEVEL_ERROR,
+                  "%s Workitem %p\n",
+                  __FUNCTION__,
+                  pWorkItem);
+
+    ntStatus = AFSQueueIOWorkerRequest( pWorkItem);
+
+    if (!NT_SUCCESS( ntStatus))
+    {
+
+        AFSCompleteRequest( pWorkItem->Specific.AsynchIo.Irp, ntStatus);
+
+        ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING | AFS_SUBSYSTEM_WORKER_PROCESSING,
+                      AFS_TRACE_LEVEL_ERROR,
+                      "%s (%p) Failed to queue request Status %08lX\n",
+                      __FUNCTION__,
+                      pWorkItem->Specific.AsynchIo.Irp,
+                      ntStatus);
+    }
+}
index 39fe479..05bf857 100644 (file)
@@ -80,7 +80,7 @@ AFSWrite( IN PDEVICE_OBJECT LibDeviceObject,
     __try
     {
 
-        ntStatus = AFSCommonWrite( AFSRDRDeviceObject, Irp, NULL);
+        ntStatus = AFSCommonWrite( AFSRDRDeviceObject, Irp, NULL, FALSE);
     }
     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
     {
@@ -94,7 +94,8 @@ AFSWrite( IN PDEVICE_OBJECT LibDeviceObject,
 NTSTATUS
 AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                 IN PIRP Irp,
-                IN HANDLE OnBehalfOf)
+                IN HANDLE OnBehalfOf,
+                IN BOOLEAN bRetry)
 {
 
     NTSTATUS           ntStatus = STATUS_SUCCESS;
@@ -115,7 +116,6 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
     BOOLEAN            bCompleteIrp = TRUE;
     BOOLEAN            bLockOK;
     HANDLE             hCallingUser = OnBehalfOf;
-    BOOLEAN            bRetry = FALSE;
     ULONGLONG          ullProcessId = (ULONGLONG)PsGetCurrentProcessId();
 
     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
@@ -402,21 +402,38 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
                 }
             }
 
-            while (!CcCanIWrite( pFileObject,
-                                 ulByteCount,
-                                 FALSE,
-                                 bRetry))
+            if (!CcCanIWrite( pFileObject,
+                              ulByteCount,
+                              FALSE,
+                              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",
+                              "AFSCommonWrite (FO: %p) CcCanIWrite says No room for Offset %0I64X Length %08lX bytes! Deferring%s\n",
                               pFileObject,
-                              ulByteCount);
+                              liStartingByte.QuadPart,
+                              ulByteCount,
+                              bRetry ? " RETRY" : "");
 
-                KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay);
+                ntStatus = AFSDeferWrite( DeviceObject, pFileObject, hCallingUser, Irp, ulByteCount, bRetry);
+
+                if ( STATUS_PENDING == ntStatus)
+                {
+
+                    bCompleteIrp = FALSE;
+                }
+                else
+                {
+
+                    AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
+                                  AFS_TRACE_LEVEL_ERROR,
+                                  "AFSCommonWrite (FO: %p) AFSDeferWrite failure Status %08lX\n",
+                                  pFileObject,
+                                  ntStatus);
+                }
+
+                try_return( ntStatus);
             }
         }
 
@@ -629,10 +646,11 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
                           AFS_TRACE_LEVEL_VERBOSE,
-                          "AFSCommonWrite (%p) Processing CACHED request Offset %I64X Len %08lX\n",
+                          "AFSCommonWrite (%p) Processing CACHED request Offset %0I64X Len %08lX%s\n",
                           Irp,
                           liStartingByte.QuadPart,
-                          ulByteCount);
+                          ulByteCount,
+                          bRetry ? " RETRY" : "");
 
             ntStatus = AFSCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount, TRUE);
 
@@ -671,10 +689,11 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
                           AFS_TRACE_LEVEL_VERBOSE,
-                          "AFSCommonWrite (%p) Processing NON-CACHED request Offset %I64X Len %08lX\n",
+                          "AFSCommonWrite (%p) Processing NON-CACHED request Offset %0I64X Len %08lX%s\n",
                           Irp,
                           liStartingByte.QuadPart,
-                          ulByteCount);
+                          ulByteCount,
+                          bRetry ? " RETRY" : "");
 
             ntStatus = AFSNonCachedWrite( DeviceObject, Irp,  liStartingByte, ulByteCount);
         }
index 41108e3..ad65527 100644 (file)
@@ -717,8 +717,9 @@ AFSShareRead( IN PDEVICE_OBJECT DeviceObject,
 
 NTSTATUS
 AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject,
-          IN PIRP Irp,
-          IN HANDLE CallingUser);
+                IN PIRP Irp,
+                IN HANDLE CallingUser,
+                IN BOOLEAN bRetry);
 
 NTSTATUS
 AFSWrite( IN PDEVICE_OBJECT DeviceObject,
@@ -732,6 +733,14 @@ NTSTATUS
 AFSShareWrite( IN PDEVICE_OBJECT DeviceObject,
                IN PIRP Irp);
 
+NTSTATUS
+AFSDeferWrite( IN PDEVICE_OBJECT DeviceObject,
+               IN PFILE_OBJECT FileObject,
+               IN HANDLE CallingUser,
+               IN PIRP Irp,
+               IN ULONG BytesToWrite,
+               IN BOOLEAN Retrying);
+
 //
 // AFSFileInfo.cpp Prototypes
 //
index 32eea3b..387b5a7 100644 (file)
@@ -118,6 +118,7 @@ NTSTATUS
 #define AFS_WORK_ENUMERATE_GLOBAL_ROOT          0x0006
 #define AFS_WORK_INVALIDATE_OBJECT              0x0007
 #define AFS_WORK_START_IOS                      0x0008
+#define AFS_WORK_DEFERRED_WRITE                 0x0009
 
 //
 // Worker request flags