sys: FspVolumeNotify: allow multiple outstanding calls to FspFileSystemNotifyBegin

This commit is contained in:
Bill Zissimopoulos 2022-01-15 15:46:56 +00:00
parent 73f587e674
commit 228f1d658d
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
4 changed files with 44 additions and 28 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);
@ -1298,12 +1302,18 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
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);

View File

@ -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);