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 */
|
/* utility: synchronous work queue */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
KEVENT Event;
|
LONG RefCount;
|
||||||
PWORKER_THREAD_ROUTINE Routine;
|
PWORKER_THREAD_ROUTINE Routine;
|
||||||
PVOID Context;
|
PVOID Context;
|
||||||
|
KEVENT Event;
|
||||||
WORK_QUEUE_ITEM WorkQueueItem;
|
WORK_QUEUE_ITEM WorkQueueItem;
|
||||||
} FSP_SYNCHRONOUS_WORK_ITEM;
|
} FSP_SYNCHRONOUS_WORK_ITEM;
|
||||||
|
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||||
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
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 */
|
/* utility: delayed work queue */
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
+33
-3
@@ -121,6 +121,7 @@ NTSTATUS FspMainFileOpen(
|
|||||||
NTSTATUS FspMainFileClose(
|
NTSTATUS FspMainFileClose(
|
||||||
HANDLE MainFileHandle,
|
HANDLE MainFileHandle,
|
||||||
PFILE_OBJECT MainFileObject);
|
PFILE_OBJECT MainFileObject);
|
||||||
|
static WORKER_THREAD_ROUTINE FspMainFileCloseSynchronousWork;
|
||||||
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
||||||
VOID FspFileNodeOplockComplete(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, FspFileDescSetDirectoryMarker)
|
||||||
#pragma alloc_text(PAGE, FspMainFileOpen)
|
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||||
#pragma alloc_text(PAGE, FspMainFileClose)
|
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||||
|
#pragma alloc_text(PAGE, FspMainFileCloseSynchronousWork)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
||||||
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
|
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
|
||||||
#endif
|
#endif
|
||||||
@@ -2803,14 +2805,42 @@ NTSTATUS FspMainFileClose(
|
|||||||
|
|
||||||
if (0 != MainFileHandle)
|
if (0 != MainFileHandle)
|
||||||
{
|
{
|
||||||
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
FSP_SYNCHRONOUS_WORK_ITEM *WorkItem;
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
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;
|
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)
|
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|||||||
+47
-7
@@ -115,9 +115,12 @@ NTSTATUS FspOplockFsctrl(
|
|||||||
POPLOCK Oplock,
|
POPLOCK Oplock,
|
||||||
PIRP Irp,
|
PIRP Irp,
|
||||||
ULONG OpenCount);
|
ULONG OpenCount);
|
||||||
|
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||||
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
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;
|
static WORKER_THREAD_ROUTINE FspExecuteSynchronousWorkItemRoutine;
|
||||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||||
@@ -167,6 +170,7 @@ LONG FspCompareUnicodeString(
|
|||||||
#pragma alloc_text(PAGE, FspCheckOplock)
|
#pragma alloc_text(PAGE, FspCheckOplock)
|
||||||
#pragma alloc_text(PAGE, FspCheckOplockEx)
|
#pragma alloc_text(PAGE, FspCheckOplockEx)
|
||||||
#pragma alloc_text(PAGE, FspOplockFsctrl)
|
#pragma alloc_text(PAGE, FspOplockFsctrl)
|
||||||
|
#pragma alloc_text(PAGE, FspAllocateSynchronousWorkItem)
|
||||||
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
||||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
||||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
||||||
@@ -1123,27 +1127,56 @@ NTSTATUS FspOplockFsctrl(
|
|||||||
return Result;
|
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,
|
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
SynchronousWorkItem->RefCount = 0; /* initialize as non-refcounted */
|
||||||
SynchronousWorkItem->Routine = Routine;
|
SynchronousWorkItem->Routine = Routine;
|
||||||
SynchronousWorkItem->Context = Context;
|
SynchronousWorkItem->Context = Context;
|
||||||
|
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
||||||
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
|
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
|
||||||
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
|
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem)
|
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||||
|
BOOLEAN Alertable)
|
||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
|
||||||
|
|
||||||
NTSTATUS Result;
|
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)
|
static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
||||||
@@ -1151,8 +1184,15 @@ static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
|
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
|
||||||
|
|
||||||
SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
|
SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
|
||||||
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
|
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
|
||||||
|
|
||||||
|
if (0 < SynchronousWorkItem->RefCount)
|
||||||
|
{
|
||||||
|
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
|
||||||
|
FspFree(SynchronousWorkItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||||
|
|||||||
Reference in New Issue
Block a user