diff --git a/src/sys/driver.h b/src/sys/driver.h index f800d563..e52949c2 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1363,6 +1363,24 @@ BOOLEAN FspFsvolDeviceFileRenameTryAcquireExclusive(PDEVICE_OBJECT DeviceObject) return ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->FileRenameResource, FALSE); } static inline +VOID FspFsvolDeviceFileRenameAcquireSharedStarveExclusive(PDEVICE_OBJECT DeviceObject) +{ + /* + * Acquire the file rename resource shared, but starve (ignore) any QUEUED + * exclusive waiter. Used by FspVolumeNotifyWork: a notify session opened by + * FspFileSystemNotifyBegin already holds this resource shared (via owner + * pointer) and intentionally defers renames until FspFileSystemNotifyEnd. A + * plain ExAcquireResourceSharedLite here would honor a concurrently queued + * exclusive rename waiter and block -- but the very work item that blocks is + * the one that must run FspFileSystemNotifyEnd processing to release the + * session and let that rename proceed, so the two self-deadlock. Starving the + * queued exclusive waiter is safe: the rename stays blocked behind the shared + * holders either way, so name stability across the notify is preserved. + */ + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + ExAcquireSharedStarveExclusive(&FsvolDeviceExtension->FileRenameResource, TRUE); +} +static inline VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner) { FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); diff --git a/src/sys/volume.c b/src/sys/volume.c index 4f6c2576..eb8c3e1a 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -1499,7 +1499,15 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0) BOOLEAN Unlock = FALSE; NTSTATUS Result; - FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject); + /* + * Starve queued exclusive (rename) waiters here to avoid a self-deadlock: + * the enclosing FspFileSystemNotifyBegin/End session already holds this + * resource shared, and a rename that queues exclusive mid-session would + * otherwise block this work item -- the same work item that must release + * the session (FspVolumeNotifyLock count) and unblock that rename. See + * FspFsvolDeviceFileRenameAcquireSharedStarveExclusive. + */ + FspFsvolDeviceFileRenameAcquireSharedStarveExclusive(FsvolDeviceObject); /* iterate over notify information and invalidate/notify each file */ for (; (PUINT8)NotifyInfo + sizeof(NotifyInfo->Size) <= NotifyInfoEnd;