diff --git a/src/sys/device.c b/src/sys/device.c index 1b270594..93be7902 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -419,7 +419,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync); if (!NT_SUCCESS(Result)) return Result; - FspWgroupInitialize(&FsvolDeviceExtension->VolumeNotifyWgroup); + ExInitializeFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); InitializeListHead(&FsvolDeviceExtension->NotifyList); FsvolDeviceExtension->InitDoneNotify = 1; diff --git a/src/sys/driver.h b/src/sys/driver.h index 39e29473..69f0eee8 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1190,8 +1190,8 @@ typedef struct KSPIN_LOCK InfoSpinLock; UINT64 InfoExpirationTime; FSP_FSCTL_VOLUME_INFO VolumeInfo; - LONG VolumeNotifyLock; - FSP_WGROUP VolumeNotifyWgroup; + FAST_MUTEX VolumeNotifyMutex; + LONG VolumeNotifyCount; PNOTIFY_SYNC NotifySync; LIST_ENTRY NotifyList; FSP_STATISTICS *Statistics; diff --git a/src/sys/volume.c b/src/sys/volume.c index bbc42484..3b105bda 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -476,10 +476,12 @@ static VOID FspVolumeDeleteNoLock( FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject); } - /* release the volume notify lock if held (so that any pending rename will abort) */ - FspWgroupSignalPermanently(&FsvolDeviceExtension->VolumeNotifyWgroup); - if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1)) - FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject); + ExAcquireFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); + if (1 <= FsvolDeviceExtension->VolumeNotifyCount) + FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, + &FsvolDeviceExtension->VolumeNotifyCount); + FsvolDeviceExtension->VolumeNotifyCount = -1; + ExReleaseFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); /* release the volume device object */ FspDeviceDereference(FsvolDeviceObject); @@ -1122,7 +1124,6 @@ NTSTATUS FspVolumeNotify( ASSERT(0 != IrpSp->FileObject->FsContext2); PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); PVOID InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer; ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = 0; @@ -1158,7 +1159,6 @@ NTSTATUS FspVolumeNotify( ExInitializeWorkItem(&NotifyWorkItem->WorkItem, FspVolumeNotifyWork, NotifyWorkItem); NotifyWorkItem->FsvolDeviceObject = FsvolDeviceObject; - FspWgroupIncrement(&FsvolDeviceExtension->VolumeNotifyWgroup); ExQueueWorkItem(&NotifyWorkItem->WorkItem, DelayedWorkQueue); return STATUS_SUCCESS; @@ -1177,11 +1177,6 @@ static NTSTATUS FspVolumeNotifyLock( { PAGED_CODE(); - NTSTATUS Result; - - if (!FspDeviceReference(FsvolDeviceObject)) - return STATUS_CANCELLED; - /* * Acquire the rename lock shared to disallow concurrent RENAME's. * @@ -1190,19 +1185,28 @@ static NTSTATUS FspVolumeNotifyLock( * that the file is not open and not invalidate its caches, whereas the * file has simply changed name. */ - Result = STATUS_CANT_WAIT; - if (FspFsvolDeviceFileRenameTryAcquireShared(FsvolDeviceObject)) - { - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); - if (0 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 1, 0)) + if (!FspDeviceReference(FsvolDeviceObject)) + return STATUS_CANCELLED; + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + NTSTATUS Result = STATUS_SUCCESS; + + ExAcquireFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); + if (0 == FsvolDeviceExtension->VolumeNotifyCount) + { + if (FspFsvolDeviceFileRenameTryAcquireShared(FsvolDeviceObject)) { - FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, FsvolDeviceObject); - Result = STATUS_SUCCESS; + FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, + &FsvolDeviceExtension->VolumeNotifyCount); + FsvolDeviceExtension->VolumeNotifyCount++; } else - FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); + Result = STATUS_CANT_WAIT; } + else if (0 < FsvolDeviceExtension->VolumeNotifyCount) + FsvolDeviceExtension->VolumeNotifyCount++; + ExReleaseFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); FspDeviceDereference(FsvolDeviceObject); @@ -1297,13 +1301,19 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0) FspFree(FullFileName.Buffer); FspFree(NotifyWorkItem); - - FspWgroupDecrement(&FsvolDeviceExtension->VolumeNotifyWgroup); + if (Unlock) { - FspWgroupWait(&FsvolDeviceExtension->VolumeNotifyWgroup, KernelMode, FALSE, 0); - if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1)) - FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject); + ExAcquireFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); + if (1 == FsvolDeviceExtension->VolumeNotifyCount) + { + FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, + &FsvolDeviceExtension->VolumeNotifyCount); + FsvolDeviceExtension->VolumeNotifyCount--; + } + else if (1 < FsvolDeviceExtension->VolumeNotifyCount) + FsvolDeviceExtension->VolumeNotifyCount--; + ExReleaseFastMutex(&FsvolDeviceExtension->VolumeNotifyMutex); } FspDeviceDereference(FsvolDeviceObject); diff --git a/tst/winfsp-tests/notify-test.c b/tst/winfsp-tests/notify-test.c index 47b19a4f..b4d194fd 100644 --- a/tst/winfsp-tests/notify-test.c +++ b/tst/winfsp-tests/notify-test.c @@ -38,7 +38,7 @@ void notify_abandon_dotest(ULONG Flags) ASSERT(STATUS_SUCCESS == Result); Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0); - ASSERT(STATUS_CANT_WAIT == Result); + ASSERT(STATUS_SUCCESS == Result); memfs_stop(memfs); } @@ -111,6 +111,8 @@ void notify_abandon_rename_test(void) notify_abandon_rename_dotest(MemfsNet, L"\\\\memfs\\share"); } +/* OBSOLETE: it is now possible to have multiple outstanding NotifyBegin() calls. */ +#if 0 static void notify_timeout_dotest(ULONG Flags) { @@ -150,6 +152,7 @@ void notify_timeout_test(void) if (WinFspNetTests) notify_timeout_dotest(MemfsNet); } +#endif static void notify_change_dotest(ULONG Flags) @@ -453,7 +456,10 @@ void notify_tests(void) TEST(notify_abandon_test); TEST(notify_abandon_rename_test); +/* OBSOLETE: it is now possible to have multiple outstanding NotifyBegin() calls. */ +#if 0 TEST(notify_timeout_test); +#endif TEST(notify_change_test); TEST(notify_open_change_test); TEST(notify_dirnotify_test);