From 6fb1078e08d4077fb0602f97b1a83bcd72f55db8 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 7 Mar 2012 06:54:54 -0800 Subject: [PATCH] Windows: Wait for memory allocation if necessary The kernel has a limited pool of memory. If there is no memory available to satisfy a request, that request will fail initially with a STATUS_OUT_OF_RESOURCES error which in most cases is exposed to the user-mode application as STATUS_ACCESS_DENIED. This can produce inconsistent results. This patchset introduces an Event object, MemoryAvailableEvent, which is signalled when the redirector deallocates memory. This should in many cases permit requests to succeed where they otherwise would have failed immediately. The WaitingForMemoryCount field tracks the number of threads that are waiting for memory to become available. A subsequent patch could use this value to accelerate the tear down of cached data. To avoid deadlocks, blocking threads will only wait for a maximum of 30 seconds at a time. As long as the redirector continues to free memory, the thread can re-queue itself. However, if a timeout occurs, the allocation request will fail. Change-Id: I0aa549be3852b31b68d7b42ecab4ca982c75f6ba Reviewed-on: http://gerrit.openafs.org/6886 Tested-by: Jeffrey Altman Reviewed-by: Jeffrey Altman --- .../afsrdr/common/AFSRedirCommonStructs.h | 8 ++ src/WINNT/afsrdr/kernel/fs/AFSGeneric.cpp | 111 +++++++++++++++--- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/WINNT/afsrdr/common/AFSRedirCommonStructs.h b/src/WINNT/afsrdr/common/AFSRedirCommonStructs.h index 6adfad8b3..48da85055 100644 --- a/src/WINNT/afsrdr/common/AFSRedirCommonStructs.h +++ b/src/WINNT/afsrdr/common/AFSRedirCommonStructs.h @@ -556,6 +556,14 @@ typedef struct _AFS_DEVICE_EXTENSION KEVENT OutstandingServiceRequestEvent; + // + // Out of memory signalling + // + + LONG WaitingForMemoryCount; + + KEVENT MemoryAvailableEvent; + } Control; struct diff --git a/src/WINNT/afsrdr/kernel/fs/AFSGeneric.cpp b/src/WINNT/afsrdr/kernel/fs/AFSGeneric.cpp index d296e8b55..b92444f38 100644 --- a/src/WINNT/afsrdr/kernel/fs/AFSGeneric.cpp +++ b/src/WINNT/afsrdr/kernel/fs/AFSGeneric.cpp @@ -773,6 +773,12 @@ AFSInitializeControlDevice() NotificationEvent, TRUE); + pDeviceExt->Specific.Control.WaitingForMemoryCount = 0; + + KeInitializeEvent( &pDeviceExt->Specific.Control.MemoryAvailableEvent, + NotificationEvent, + TRUE); + ExInitializeResourceLite( &pDeviceExt->Specific.Control.LibraryQueueLock); pDeviceExt->Specific.Control.LibraryQueueHead = NULL; @@ -1308,32 +1314,86 @@ AFSExAllocatePoolWithTag( IN POOL_TYPE PoolType, IN ULONG Tag) { + AFSDeviceExt *pControlDevExt = NULL; void *pBuffer = NULL; + BOOLEAN bTimeout = FALSE; + LARGE_INTEGER liTimeout; + NTSTATUS ntStatus; - pBuffer = ExAllocatePoolWithTag( PoolType, - NumberOfBytes, - Tag); + // + // Attempt to allocation memory from the system. If the allocation fails + // wait up to 30 seconds for the AFS redirector to free some memory. As + // long as the wait does not timeout, continue to retry the allocation. + // If the wait does timeout, attempt to allocate one more time in case + // memory was freed by another driver. Otherwise, fail the request. + // - if( pBuffer == NULL) + if ( AFSDeviceObject) { - AFSDbgLogMsg( 0, - 0, - "AFSExAllocatePoolWithTag failure Type %08lX Size %08lX Tag %08lX %08lX\n", - PoolType, - NumberOfBytes, - Tag, - PsGetCurrentThread()); + pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; + } - switch ( Tag ) { + while( pBuffer == NULL) + { - case AFS_GENERIC_MEMORY_21_TAG: - case AFS_GENERIC_MEMORY_22_TAG: - // AFSDumpTraceFiles -- do nothing; - break; + pBuffer = ExAllocatePoolWithTag( PoolType, + NumberOfBytes, + Tag); - default: - AFSBreakPoint(); + if( pBuffer == NULL) + { + + if ( bTimeout || pControlDevExt == NULL) + { + + AFSDbgLogMsg( 0, + 0, + "AFSExAllocatePoolWithTag failure Type %08lX Size %08lX Tag %08lX %08lX\n", + PoolType, + NumberOfBytes, + Tag, + PsGetCurrentThread()); + + switch ( Tag ) { + + case AFS_GENERIC_MEMORY_21_TAG: + case AFS_GENERIC_MEMORY_22_TAG: + // AFSDumpTraceFiles -- do nothing; + break; + + default: + AFSBreakPoint(); + } + + break; + } + + + // + // Wait up to 30 seconds for a memory deallocation + // + + liTimeout.QuadPart = -(30 *AFS_ONE_SECOND); + + if( InterlockedIncrement( &pControlDevExt->Specific.Control.WaitingForMemoryCount) == 1) + { + KeClearEvent( &pControlDevExt->Specific.Control.MemoryAvailableEvent); + } + + ntStatus = KeWaitForSingleObject( &pControlDevExt->Specific.Control.MemoryAvailableEvent, + Executive, + KernelMode, + FALSE, + &liTimeout); + + if( ntStatus == STATUS_TIMEOUT) + { + + bTimeout = TRUE; + } + + InterlockedDecrement( &pControlDevExt->Specific.Control.WaitingForMemoryCount); } } @@ -1344,8 +1404,23 @@ void AFSExFreePool( IN void *Buffer) { + AFSDeviceExt *pControlDevExt = NULL; + + if ( AFSDeviceObject) + { + + pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; + } + ExFreePool( Buffer); + if ( pControlDevExt) + { + + KeSetEvent( &pControlDevExt->Specific.Control.MemoryAvailableEvent, + 0, + FALSE); + } return; } -- 2.39.5