mirror of
https://github.com/winfsp/winfsp.git
synced 2026-07-29 07:49:24 -05:00
sys: FspMainFileClose: fix issue #680
Instead of closing the main file handle in the dispatcher thread, close it in a system thread and wait for that close to complete in an alertable manner. This avoids a deadlock due to the file system process being forcibly terminated via NtTerminateProcess.
This commit is contained in:
+6
-2
@@ -698,14 +698,18 @@ NTSTATUS FspOplockFsctrl(
|
||||
/* utility: synchronous work queue */
|
||||
typedef struct
|
||||
{
|
||||
KEVENT Event;
|
||||
LONG RefCount;
|
||||
PWORKER_THREAD_ROUTINE Routine;
|
||||
PVOID Context;
|
||||
KEVENT Event;
|
||||
WORK_QUEUE_ITEM WorkQueueItem;
|
||||
} FSP_SYNCHRONOUS_WORK_ITEM;
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable);
|
||||
|
||||
/* utility: delayed work queue */
|
||||
typedef struct
|
||||
|
||||
+33
-3
@@ -121,6 +121,7 @@ NTSTATUS FspMainFileOpen(
|
||||
NTSTATUS FspMainFileClose(
|
||||
HANDLE MainFileHandle,
|
||||
PFILE_OBJECT MainFileObject);
|
||||
static WORKER_THREAD_ROUTINE FspMainFileCloseSynchronousWork;
|
||||
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
||||
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
|
||||
@@ -183,6 +184,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker)
|
||||
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||
#pragma alloc_text(PAGE, FspMainFileCloseSynchronousWork)
|
||||
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
||||
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
|
||||
#endif
|
||||
@@ -2803,14 +2805,42 @@ NTSTATUS FspMainFileClose(
|
||||
|
||||
if (0 != MainFileHandle)
|
||||
{
|
||||
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
||||
if (!NT_SUCCESS(Result))
|
||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *WorkItem;
|
||||
|
||||
WorkItem = DEBUGTEST(90) ?
|
||||
FspAllocateSynchronousWorkItem(FspMainFileCloseSynchronousWork, MainFileHandle) :
|
||||
0;
|
||||
if (0 != WorkItem)
|
||||
/*
|
||||
* Fix issue #680:
|
||||
* Instead of closing the main file handle in this thread, close it in a system thread
|
||||
* and wait for that close to complete in an alertable manner. This avoids a deadlock
|
||||
* due to the file system process being forcibly terminated via NtTerminateProcess.
|
||||
*/
|
||||
Result = FspExecuteSynchronousWorkItem(WorkItem, TRUE);
|
||||
else
|
||||
/*
|
||||
* Best effort: Close the main file handle in this thread.
|
||||
* Small chance of deadlock if someone is killing our file system.
|
||||
*/
|
||||
FspMainFileCloseSynchronousWork(MainFileHandle);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspMainFileCloseSynchronousWork(PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
HANDLE MainFileHandle = Context;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
||||
if (!NT_SUCCESS(Result))
|
||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
||||
}
|
||||
|
||||
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
+47
-7
@@ -115,9 +115,12 @@ NTSTATUS FspOplockFsctrl(
|
||||
POPLOCK Oplock,
|
||||
PIRP Irp,
|
||||
ULONG OpenCount);
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable);
|
||||
static WORKER_THREAD_ROUTINE FspExecuteSynchronousWorkItemRoutine;
|
||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
@@ -167,6 +170,7 @@ LONG FspCompareUnicodeString(
|
||||
#pragma alloc_text(PAGE, FspCheckOplock)
|
||||
#pragma alloc_text(PAGE, FspCheckOplockEx)
|
||||
#pragma alloc_text(PAGE, FspOplockFsctrl)
|
||||
#pragma alloc_text(PAGE, FspAllocateSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
||||
@@ -1123,27 +1127,56 @@ NTSTATUS FspOplockFsctrl(
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem;
|
||||
|
||||
SynchronousWorkItem = FspAllocNonPaged(sizeof *SynchronousWorkItem);
|
||||
if (0 != SynchronousWorkItem)
|
||||
{
|
||||
FspInitializeSynchronousWorkItem(SynchronousWorkItem, Routine, Context);
|
||||
SynchronousWorkItem->RefCount = 2; /* make it refcounted */
|
||||
}
|
||||
|
||||
return SynchronousWorkItem;
|
||||
}
|
||||
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
||||
SynchronousWorkItem->RefCount = 0; /* initialize as non-refcounted */
|
||||
SynchronousWorkItem->Routine = Routine;
|
||||
SynchronousWorkItem->Context = Context;
|
||||
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
||||
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
|
||||
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
|
||||
}
|
||||
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem)
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
||||
|
||||
NTSTATUS Result;
|
||||
Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, FALSE, 0);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
/* Alertable=TRUE requires item allocated by FspAllocateSynchronousWorkItem */
|
||||
ASSERT(!Alertable || 0 < SynchronousWorkItem->RefCount);
|
||||
|
||||
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
||||
Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, Alertable, 0);
|
||||
|
||||
if (0 < SynchronousWorkItem->RefCount)
|
||||
{
|
||||
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
|
||||
FspFree(SynchronousWorkItem);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
||||
@@ -1151,8 +1184,15 @@ static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
|
||||
|
||||
SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
|
||||
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
|
||||
|
||||
if (0 < SynchronousWorkItem->RefCount)
|
||||
{
|
||||
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
|
||||
FspFree(SynchronousWorkItem);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||
|
||||
Reference in New Issue
Block a user