From 7068836e6bab73e9edcb2c84727b92b25e1a6109 Mon Sep 17 00:00:00 2001 From: Rod Widdowson Date: Sun, 20 Oct 2013 14:29:35 -0400 Subject: [PATCH] Windows: EOF for Synchronous Deferred Writes on XP/2003 The Windows IO Manager is not supposed to issue multiple outstanding cached writes to a file system for a synchronous file object. To do so would risk out of order application of writes that extend the end of file and in turn risk data corruption. It turns out that on Server 2003 SP2 and more than likely XP and 2000 as well, if a file system returns STATUS_PENDING because a write was deferred due to the Windows Cache Manager failing CcCanIWrite(), the IO Manager will happily continue issue subsequent write requests. On OSes older than Vista disable the use of deferred writes and sit in a spin loop waiting for the Windows cache manager to make room. This is much less efficient and increases the write latency but it is safe. Change-Id: Ic47d62749bdb4d0475661967fcbfd25834f21a72 Reviewed-on: http://gerrit.openafs.org/10351 Tested-by: BuildBot Reviewed-by: Jeffrey Altman --- src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp | 90 ++++++++++++++++-------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp index 328ca8428..05a715d07 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp @@ -415,39 +415,73 @@ AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject, } } - if (!CcCanIWrite( pFileObject, - ulByteCount, - FALSE, - bRetry)) - { + // + // 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) + { - 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" : "")); + while (!CcCanIWrite( pFileObject, + ulByteCount, + FALSE, + bRetry)) + { + static const LONGLONG llWriteDelay = (LONGLONG)-100000; + bRetry = TRUE; - ntStatus = AFSDeferWrite( DeviceObject, pFileObject, hCallingUser, Irp, ulByteCount, bRetry); + 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); - if ( STATUS_PENDING == ntStatus) - { + KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay); + } + } + else + { - bCompleteIrp = FALSE; - } - else - { + if (!CcCanIWrite( pFileObject, + ulByteCount, + FALSE, + bRetry)) + { - AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING, - AFS_TRACE_LEVEL_ERROR, - "AFSCommonWrite (FO: %p) AFSDeferWrite failure Status %08lX\n", - pFileObject, - ntStatus)); - } + 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" : "")); - try_return( ntStatus); - } + 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); + } + } } // @@ -723,7 +757,7 @@ try_exit: if ( !bPagingIo) { - if( bSynchronousFo) + if( bSynchronousFo) { pFileObject->CurrentByteOffset.QuadPart = liStartingByte.QuadPart + ulByteCount; -- 2.39.5