From ccd4bb869c2217a646b6c69552510be89318b77e Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 10 Feb 2017 12:39:53 -0800 Subject: [PATCH] Experimental fix for github issue #45 --- src/sys/close.c | 12 +++++++++++- src/sys/device.c | 11 +++++++++++ src/sys/driver.h | 1 + src/sys/file.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/sys/close.c b/src/sys/close.c index 06cbec82..5b7ec200 100644 --- a/src/sys/close.c +++ b/src/sys/close.c @@ -80,8 +80,18 @@ static NTSTATUS FspFsvolClose( FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */ FspFileNodeDereference(FileNode); + /* if we are closing files in the context of a rename make it synchronous */ + if (FspFsvolDeviceFileRenameIsAcquiredExclusive(FsvolDeviceObject)) + { + /* acquire ownership of the Request */ + Request->Hint = (UINT_PTR)Irp; + FspIrpSetRequest(Irp, Request); + + return FSP_STATUS_IOQ_POST_BEST_EFFORT; + } + /* - * Post as a BestEffort work request. This allows us to complete our own IRP + * Post as a BestEffort WORK request. This allows us to complete our own IRP * and return immediately. */ FspIopPostWorkRequestBestEffort(FsvolDeviceObject, Request); diff --git a/src/sys/device.c b/src/sys/device.c index 5c776179..ed5f802a 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -41,6 +41,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner); VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner); +BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject); NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject, @@ -80,6 +81,7 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspFsvolDeviceFileRenameSetOwner) #pragma alloc_text(PAGE, FspFsvolDeviceFileRenameRelease) #pragma alloc_text(PAGE, FspFsvolDeviceFileRenameReleaseOwner) +#pragma alloc_text(PAGE, FspFsvolDeviceFileRenameIsAcquiredExclusive) #pragma alloc_text(PAGE, FspFsvolDeviceLockContextTable) #pragma alloc_text(PAGE, FspFsvolDeviceUnlockContextTable) #pragma alloc_text(PAGE, FspFsvolDeviceCopyContextList) @@ -574,6 +576,15 @@ VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Own ExReleaseResourceForThreadLite(&FsvolDeviceExtension->FileRenameResource, (ERESOURCE_THREAD)Owner); } +BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + return ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->FileRenameResource); +} + VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject) { PAGED_CODE(); diff --git a/src/sys/driver.h b/src/sys/driver.h index 15b1c756..b7847b8d 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1064,6 +1064,7 @@ VOID FspFsvolDeviceFileRenameAcquireExclusive(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner); VOID FspFsvolDeviceFileRenameRelease(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceFileRenameReleaseOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner); +BOOLEAN FspFsvolDeviceFileRenameIsAcquiredExclusive(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceLockContextTable(PDEVICE_OBJECT DeviceObject); VOID FspFsvolDeviceUnlockContextTable(PDEVICE_OBJECT DeviceObject); NTSTATUS FspFsvolDeviceCopyContextList(PDEVICE_OBJECT DeviceObject, diff --git a/src/sys/file.c b/src/sys/file.c index 5821b5eb..eb9f2604 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -1243,6 +1243,50 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp } } + /* flush and purge cleaned up but still open files affected by rename (github issue #45) */ + { + PIRP TopLevelIrp; + IO_STATUS_BLOCK IoStatus; + + /* reset the top-level IRP to avoid deadlock on the FileNodes' resources */ + TopLevelIrp = IoGetTopLevelIrp(); + IoSetTopLevelIrp(0); + + /* enumerate in reverse order so that files are flushed before containing directories */ + for ( + DescendantFileNodeIndex = DescendantFileNodeCount - 1; + DescendantFileNodeCount > DescendantFileNodeIndex; + DescendantFileNodeIndex--) + { + DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; + HasHandles = (UINT_PTR)DescendantFileNode & 1; + DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7); + + if (HasHandles) + continue; + if (CheckingOldName && + (DescendantFileNode->FileName.Length <= FileName->Length || + L'\\' != DescendantFileNode->FileName.Buffer[FileName->Length / sizeof(WCHAR)])) + continue; + if (MmDoesFileHaveUserWritableReferences(&DescendantFileNode->NonPaged->SectionObjectPointers)) + continue; + + /* + * There are no handles and no writable user mappings. [Ideally we would want to know + * that there are no handles and no user mappings, period. Is there an DDI/method to + * do that?] There may be a read-only user mapping, but in this case CcFlushCache + * should be a no-op and MmForceSectionClosed will fail (which is fine). + */ + + ASSERT(DescendantFileNode != FileNode && DescendantFileNode->MainFileNode != FileNode); + + FspCcFlushCache(&DescendantFileNode->NonPaged->SectionObjectPointers, 0, 0, &IoStatus); + MmForceSectionClosed(&DescendantFileNode->NonPaged->SectionObjectPointers, FALSE); + } + + IoSetTopLevelIrp(TopLevelIrp); + } + /* break any Batch or Handle oplocks on descendants */ Result = STATUS_SUCCESS; for (