mirror of
https://github.com/reactos/reactos.git
synced 2024-06-29 01:12:06 +00:00
[NTOS:PNP] Send removal IRPs to a file system device object for mounted devices
If a DeviceObject has VPB attached, it should be treated in a special way CORE-16106
This commit is contained in:
parent
62a4f9d42b
commit
8ee88d3bd5
|
@ -1494,27 +1494,96 @@ IopStopDevice(
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS **********************************************************/
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends one of the remove IRPs to the device stack
|
||||||
|
*
|
||||||
|
* If there is a mounted VPB attached to a one of the stack devices, the IRP
|
||||||
|
* should be send to a VPB's DeviceObject first (which belongs to a FS driver).
|
||||||
|
* FS driver will then forward it down to the volume device.
|
||||||
|
* While walking the device stack, the function sets (or unsets) VPB_REMOVE_PENDING flag
|
||||||
|
* thus blocking all further mounts on a soon-to-be-removed devices
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
NTSTATUS
|
||||||
|
PiIrpSendRemoveCheckVpb(
|
||||||
|
_In_ PDEVICE_OBJECT DeviceObject,
|
||||||
|
_In_ UCHAR MinorFunction)
|
||||||
|
{
|
||||||
|
KIRQL oldIrql;
|
||||||
|
|
||||||
|
ASSERT(MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE ||
|
||||||
|
MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE ||
|
||||||
|
MinorFunction == IRP_MN_SURPRISE_REMOVAL ||
|
||||||
|
MinorFunction == IRP_MN_REMOVE_DEVICE);
|
||||||
|
|
||||||
|
PDEVICE_OBJECT vpbDevObj = DeviceObject, targetDevice = DeviceObject;
|
||||||
|
|
||||||
|
// walk the device stack down, stop on a first mounted device
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (vpbDevObj->Vpb)
|
||||||
|
{
|
||||||
|
// two locks are needed here
|
||||||
|
KeWaitForSingleObject(&vpbDevObj->DeviceLock, Executive, KernelMode, FALSE, NULL);
|
||||||
|
IoAcquireVpbSpinLock(&oldIrql);
|
||||||
|
|
||||||
|
if (MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)
|
||||||
|
{
|
||||||
|
vpbDevObj->Vpb->Flags &= ~VPB_REMOVE_PENDING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vpbDevObj->Vpb->Flags |= VPB_REMOVE_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN isMounted = (_Bool)(vpbDevObj->Vpb->Flags & VPB_MOUNTED);
|
||||||
|
|
||||||
|
if (isMounted)
|
||||||
|
{
|
||||||
|
targetDevice = vpbDevObj->Vpb->DeviceObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoReleaseVpbSpinLock(oldIrql);
|
||||||
|
KeSetEvent(&vpbDevObj->DeviceLock, IO_NO_INCREMENT, FALSE);
|
||||||
|
|
||||||
|
if (isMounted)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
|
||||||
|
vpbDevObj = vpbDevObj->AttachedDevice;
|
||||||
|
KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, oldIrql);
|
||||||
|
} while (vpbDevObj);
|
||||||
|
|
||||||
|
ASSERT(targetDevice);
|
||||||
|
|
||||||
|
PVOID info;
|
||||||
|
IO_STACK_LOCATION stack = {.MajorFunction = IRP_MJ_PNP, .MinorFunction = MinorFunction};
|
||||||
|
|
||||||
|
return IopSynchronousCall(targetDevice, &stack, &info);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
IO_STACK_LOCATION Stack;
|
|
||||||
PVOID Dummy;
|
|
||||||
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
|
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
|
||||||
|
|
||||||
/* Drop all our state for this device in case it isn't really going away */
|
/* Drop all our state for this device in case it isn't really going away */
|
||||||
DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
|
DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
|
||||||
|
|
||||||
RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
|
|
||||||
Stack.MajorFunction = IRP_MJ_PNP;
|
|
||||||
Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
|
|
||||||
|
|
||||||
/* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
|
/* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
|
||||||
IopSynchronousCall(DeviceObject, &Stack, &Dummy);
|
PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_REMOVE_DEVICE);
|
||||||
|
|
||||||
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL);
|
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL);
|
||||||
ObDereferenceObject(DeviceObject);
|
LONG_PTR refCount = ObDereferenceObject(DeviceObject);
|
||||||
|
if (refCount != 0)
|
||||||
|
{
|
||||||
|
DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode->InstancePath, (INT32)refCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -1562,15 +1631,8 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
|
IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
IO_STACK_LOCATION Stack;
|
|
||||||
PVOID Dummy;
|
|
||||||
|
|
||||||
RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
|
|
||||||
Stack.MajorFunction = IRP_MJ_PNP;
|
|
||||||
Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
|
|
||||||
|
|
||||||
/* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
|
/* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
|
||||||
IopSynchronousCall(DeviceObject, &Stack, &Dummy);
|
PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_SURPRISE_REMOVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -1578,15 +1640,8 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
IO_STACK_LOCATION Stack;
|
|
||||||
PVOID Dummy;
|
|
||||||
|
|
||||||
RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
|
|
||||||
Stack.MajorFunction = IRP_MJ_PNP;
|
|
||||||
Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
|
|
||||||
|
|
||||||
/* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
|
/* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
|
||||||
IopSynchronousCall(DeviceObject, &Stack, &Dummy);
|
PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_CANCEL_REMOVE_DEVICE);
|
||||||
|
|
||||||
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL);
|
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1669,8 +1724,6 @@ NTAPI
|
||||||
IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
|
PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
|
||||||
IO_STACK_LOCATION Stack;
|
|
||||||
PVOID Dummy;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
ASSERT(DeviceNode);
|
ASSERT(DeviceNode);
|
||||||
|
@ -1678,11 +1731,7 @@ IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
|
||||||
IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
|
IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
|
||||||
&DeviceNode->InstancePath);
|
&DeviceNode->InstancePath);
|
||||||
|
|
||||||
RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
|
Status = PiIrpSendRemoveCheckVpb(DeviceObject, IRP_MN_QUERY_REMOVE_DEVICE);
|
||||||
Stack.MajorFunction = IRP_MJ_PNP;
|
|
||||||
Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
|
|
||||||
|
|
||||||
Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
|
|
||||||
|
|
||||||
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL);
|
PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue