From 11aa3e09e591b325e80c5d4a420051923f121b82 Mon Sep 17 00:00:00 2001 From: Rod Widdowson Date: Mon, 18 Feb 2013 10:33:29 -0500 Subject: [PATCH] Windows: Call CcDeferWrite rather than loop 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 Tested-by: BuildBot Reviewed-by: Peter Scott Reviewed-by: Jeffrey Altman --- src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp | 162 +++++++++++++++++- src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp | 51 ++++-- .../afsrdr/kernel/lib/Include/AFSCommon.h | 13 +- .../afsrdr/kernel/lib/Include/AFSDefines.h | 1 + 4 files changed, 208 insertions(+), 19 deletions(-) diff --git a/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp b/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp index 7372239f3..dbf98eb30 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp @@ -38,6 +38,11 @@ #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); + } +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp index 39fe47986..05bf85711 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp @@ -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); } diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h index 41108e359..ad65527f5 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h @@ -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 // diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h index 32eea3b30..387b5a7e5 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h @@ -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 -- 2.39.5