mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 00:43:00 -05:00
sys: FspFsvrtDeleteVolume: delay delete the volume to avoid crashes in fltmgr.sys; using FspDeviceRetain() instead of ObReferenceObject() appears to completely resolve the fltmgr.sys crash
This commit is contained in:
parent
aee12e1c5f
commit
a3312ad2f1
@ -66,6 +66,10 @@ static NTSTATUS FspFsvolCreate(
|
||||
(0 == IrpSp->FileObject->RelatedFileObject ||
|
||||
0 == IrpSp->FileObject->RelatedFileObject->FsContext))
|
||||
{
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
|
||||
|
||||
IrpSp->FileObject->Vpb = FsvrtDeviceObject->Vpb;
|
||||
Irp->IoStatus.Information = FILE_OPENED;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -479,6 +479,17 @@ BOOLEAN FspValidRelativeSecurityDescriptor(
|
||||
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
||||
|
||||
/* delayed work queue */
|
||||
typedef struct
|
||||
{
|
||||
KTIMER Timer;
|
||||
KDPC Dpc;
|
||||
WORK_QUEUE_ITEM WorkQueueItem;
|
||||
} FSP_WORK_ITEM_WITH_DELAY;
|
||||
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout);
|
||||
|
||||
/* debug */
|
||||
#if DBG
|
||||
BOOLEAN HasDbgBreakPoint(const char *Function);
|
||||
|
@ -74,6 +74,7 @@ static NTSTATUS FspFsctlMountVolume(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsvrtDeleteVolume(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static WORKER_THREAD_ROUTINE FspFsvrtDeleteVolumeDelayed;
|
||||
static NTSTATUS FspFsvrtTransact(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsctlFileSystemControl(
|
||||
@ -89,6 +90,7 @@ FSP_IOCMPL_DISPATCH FspFileSystemControlComplete;
|
||||
#pragma alloc_text(PAGE, FspFsctlCreateVolume)
|
||||
#pragma alloc_text(PAGE, FspFsctlMountVolume)
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeleteVolume)
|
||||
#pragma alloc_text(PAGE, FspFsvrtDeleteVolumeDelayed)
|
||||
#pragma alloc_text(PAGE, FspFsvrtTransact)
|
||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||
#pragma alloc_text(PAGE, FspFsvrtFileSystemControl)
|
||||
@ -259,6 +261,13 @@ static NTSTATUS FspFsctlMountVolume(
|
||||
return Result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PDEVICE_OBJECT FsvolDeviceObject;
|
||||
PVPB OldVpb;
|
||||
FSP_WORK_ITEM_WITH_DELAY WorkItemWithDelay;
|
||||
} FSP_FSVRT_DELETE_VOLUME_WORK_ITEM;
|
||||
|
||||
static NTSTATUS FspFsvrtDeleteVolume(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
@ -272,8 +281,13 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
||||
ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE);
|
||||
try
|
||||
{
|
||||
PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject;
|
||||
PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject;
|
||||
PVPB OldVpb;
|
||||
BOOLEAN FreeVpb = FALSE;
|
||||
BOOLEAN DeleteVpb = FALSE;
|
||||
BOOLEAN DeleteDelayed = FALSE;
|
||||
LARGE_INTEGER DelayTimeout;
|
||||
FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = 0;
|
||||
KIRQL Irql;
|
||||
|
||||
/* access check */
|
||||
@ -282,6 +296,14 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
/* pre-allocate a work item in case we need it for delayed delete */
|
||||
WorkItem = FspAllocNonPaged(sizeof *WorkItem);
|
||||
if (0 == WorkItem)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* mark the virtual volume device as deleted */
|
||||
FsvrtDeviceExtension->Deleted = TRUE;
|
||||
|
||||
@ -302,16 +324,21 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
||||
DeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
|
||||
DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb;
|
||||
FsvrtDeviceExtension->SwapVpb = 0;
|
||||
FreeVpb = 0 == OldVpb->ReferenceCount;
|
||||
DeleteVpb = 0 == OldVpb->ReferenceCount;
|
||||
DeleteDelayed = !DeleteVpb && 0 != FsvolDeviceObject;
|
||||
if (DeleteDelayed)
|
||||
/* keep VPB around for delayed delete */
|
||||
OldVpb->ReferenceCount++;
|
||||
}
|
||||
IoReleaseVpbSpinLock(Irql);
|
||||
if (FreeVpb)
|
||||
if (DeleteDelayed)
|
||||
/* keep fsvol around for delayed delete */
|
||||
FspDeviceRetain(FsvolDeviceObject);
|
||||
else if (DeleteVpb)
|
||||
FspFreeExternal(OldVpb);
|
||||
#pragma prefast(pop)
|
||||
|
||||
/* release the file system device and virtual volume objects */
|
||||
PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject;
|
||||
PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject;
|
||||
FsvrtDeviceExtension->FsvolDeviceObject = 0;
|
||||
if (0 != FsvolDeviceObject)
|
||||
FspDeviceRelease(FsvolDeviceObject);
|
||||
@ -319,9 +346,23 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
||||
|
||||
FspFsctlDeviceVolumeDeleted(FsctlDeviceObject);
|
||||
|
||||
/* are we doing delayed delete of VPB and fsvol? */
|
||||
if (DeleteDelayed)
|
||||
{
|
||||
DelayTimeout.QuadPart = 300/*ms*/ * -10000;
|
||||
WorkItem->FsvolDeviceObject = FsvolDeviceObject;
|
||||
WorkItem->OldVpb = OldVpb;
|
||||
FspInitializeWorkItemWithDelay(&WorkItem->WorkItemWithDelay,
|
||||
FspFsvrtDeleteVolumeDelayed, WorkItem);
|
||||
FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout);
|
||||
WorkItem = 0;
|
||||
}
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:;
|
||||
exit:
|
||||
if (0 != WorkItem)
|
||||
FspFree(WorkItem);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -331,6 +372,34 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspFsvrtDeleteVolumeDelayed(PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = Context;
|
||||
BOOLEAN DeleteVpb = FALSE;
|
||||
LARGE_INTEGER DelayTimeout;
|
||||
KIRQL Irql;
|
||||
|
||||
IoAcquireVpbSpinLock(&Irql);
|
||||
ASSERT(0 != WorkItem->OldVpb->ReferenceCount);
|
||||
DeleteVpb = 1 == WorkItem->OldVpb->ReferenceCount;
|
||||
if (DeleteVpb)
|
||||
WorkItem->OldVpb->ReferenceCount = 0;
|
||||
IoReleaseVpbSpinLock(Irql);
|
||||
if (DeleteVpb)
|
||||
{
|
||||
FspFreeExternal(WorkItem->OldVpb);
|
||||
FspDeviceRelease(WorkItem->FsvolDeviceObject);
|
||||
FspFree(WorkItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
DelayTimeout.QuadPart = 300/*ms*/ * -10000;
|
||||
FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvrtTransact(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
|
@ -12,11 +12,17 @@ BOOLEAN FspValidRelativeSecurityDescriptor(
|
||||
SECURITY_INFORMATION RequiredInformation);
|
||||
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
||||
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout);
|
||||
static KDEFERRED_ROUTINE FspQueueWorkItemWithDelayDPC;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspCreateGuid)
|
||||
#pragma alloc_text(PAGE, FspValidRelativeSecurityDescriptor)
|
||||
#pragma alloc_text(PAGE, FspSecuritySubjectContextAccessCheck)
|
||||
#pragma alloc_text(PAGE, FspInitializeWorkItemWithDelay)
|
||||
#pragma alloc_text(PAGE, FspQueueWorkItemWithDelay)
|
||||
#endif
|
||||
|
||||
NTSTATUS FspCreateGuid(GUID *Guid)
|
||||
@ -74,3 +80,30 @@ NTSTATUS FspSecuritySubjectContextAccessCheck(
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KeInitializeTimer(&WorkItem->Timer);
|
||||
KeInitializeDpc(&WorkItem->Dpc, FspQueueWorkItemWithDelayDPC, WorkItem);
|
||||
ExInitializeWorkItem(&WorkItem->WorkQueueItem, Routine, Context);
|
||||
}
|
||||
|
||||
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KeSetTimer(&WorkItem->Timer, Timeout, &WorkItem->Dpc);
|
||||
}
|
||||
|
||||
static VOID FspQueueWorkItemWithDelayDPC(PKDPC Dpc,
|
||||
PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
|
||||
{
|
||||
// !PAGED_CODE();
|
||||
|
||||
FSP_WORK_ITEM_WITH_DELAY *WorkItem = DeferredContext;
|
||||
|
||||
ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user