mirror of
https://github.com/reactos/reactos.git
synced 2024-12-26 17:14:41 +00:00
[PARTMGR] Trigger mount points removal when a partition/volume is deleted (#7034)
CORE-18139
When a partition is created, PartMgr notifies the volume manager
(FTDisk on Windows <= 2003, VolMgr on Vista+) of its presence.
(Note that currently in ReactOS, our partmgr does the job of both
PartMgr *AND* VolMgr.)
The VolMgr then sends a `GUID_DEVINTERFACE_VOLUME` PnP notification,
which is handled by the mount manager (MountMgr) as part of a
`GUID_DEVICE_INTERFACE_ARRIVAL` notification:
```
MountMgr!MountMgrMountedDeviceNotification -> MountMgrMountedDeviceArrival
followed by
MountMgr!MountMgrTargetDeviceNotification
```
When a partition is deleted, via e.g. Disk Management or DiskPart,
it can be observed, on Windows, that the PartMgr gets notified by
the PnP manager, as part of QueryDeviceRelations. Before actually
removing the partition, it notifies the VolMgr. The latter invalidates
any volume mounted on that partition (`*PartitionRemoved*` functions
for basic volumes), then requests (`*DeleteMountPoints` function)
the MountMgr to delete all the mount points associated to the volume:
```
VolMgr!*DeleteMountPoints
-> MountMgr!MountMgrDeviceControl -> MountMgrDeletePoints
```
**** THIS is the new functionality that is implemented for ReactOS ****
**** in the present commit. ****
Following this, a subsequent PnP notification is sent, which calls
```
MountMgr!MountMgrTargetDeviceNotification
-> MountMgr!MountMgrMountedDeviceRemoval
```
(Note that this observation somewhat invalidates the modification
made in ReactOS commit 62a4f9d42b
: our MountMgr placed in Windows
*WOULD* receive a `GUID_TARGET_DEVICE_REMOVE_COMPLETE` target-device
notification...)
Finally, a `GUID_DEVICE_INTERFACE_REMOVAL` PnP notification is sent
to the MountMgr:
```
MountMgr!MountMgrMountedDeviceNotification
-> MountMgr!MountMgrMountedDeviceRemoval
```
This commit is contained in:
parent
465b9cef25
commit
9e07d0cc74
1 changed files with 115 additions and 4 deletions
|
@ -122,15 +122,15 @@ PartitionHandleStartDevice(
|
|||
|
||||
INFO("Symlink created %wZ -> %wZ\n", &partitionSymlink, &PartExt->DeviceName);
|
||||
|
||||
// our partition device will have two interfaces:
|
||||
// Our partition device will have two interfaces:
|
||||
// GUID_DEVINTERFACE_PARTITION and GUID_DEVINTERFACE_VOLUME
|
||||
// the former one is used to notify mountmgr about new device
|
||||
// (aka. MOUNTDEV_MOUNTED_DEVICE_GUID).
|
||||
// The latter one is used to notify MountMgr about the new volume.
|
||||
|
||||
status = IoRegisterDeviceInterface(PartExt->DeviceObject,
|
||||
&GUID_DEVINTERFACE_PARTITION,
|
||||
NULL,
|
||||
&interfaceName);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
return status;
|
||||
|
@ -152,7 +152,6 @@ PartitionHandleStartDevice(
|
|||
&GUID_DEVINTERFACE_VOLUME,
|
||||
NULL,
|
||||
&interfaceName);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
return status;
|
||||
|
@ -173,6 +172,105 @@ PartitionHandleStartDevice(
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Notifies MountMgr to delete all mount points
|
||||
* associated with the given volume.
|
||||
*
|
||||
* @note This should belong to volmgr.sys and act on a PVOLUME_EXTENSION.
|
||||
**/
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
VolumeDeleteMountPoints(
|
||||
_In_ PPARTITION_EXTENSION PartExt)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING MountMgr;
|
||||
ULONG InputSize, OutputSize;
|
||||
LOGICAL Retry;
|
||||
PUNICODE_STRING DeviceName;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
PMOUNTMGR_MOUNT_POINT InputBuffer = NULL;
|
||||
PMOUNTMGR_MOUNT_POINTS OutputBuffer = NULL;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Get the device pointer to the MountMgr */
|
||||
RtlInitUnicodeString(&MountMgr, MOUNTMGR_DEVICE_NAME);
|
||||
Status = IoGetDeviceObjectPointer(&MountMgr,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
&FileObject,
|
||||
&DeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
/* Setup the volume device name for deleting its mount points */
|
||||
DeviceName = &PartExt->DeviceName;
|
||||
|
||||
/* Allocate the input buffer */
|
||||
InputSize = sizeof(*InputBuffer) + DeviceName->Length;
|
||||
InputBuffer = ExAllocatePoolWithTag(PagedPool, InputSize, TAG_PARTMGR);
|
||||
if (!InputBuffer)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
/* Fill it in */
|
||||
RtlZeroMemory(InputBuffer, sizeof(*InputBuffer));
|
||||
InputBuffer->DeviceNameOffset = sizeof(*InputBuffer);
|
||||
InputBuffer->DeviceNameLength = DeviceName->Length;
|
||||
RtlCopyMemory(&InputBuffer[1], DeviceName->Buffer, DeviceName->Length);
|
||||
|
||||
/*
|
||||
* IOCTL_MOUNTMGR_DELETE_POINTS needs a large-enough scratch output buffer
|
||||
* to work with. (It uses it to query the mount points, before deleting
|
||||
* them.) Start with a guessed size and call the IOCTL. If the buffer is
|
||||
* not big enough, use the value retrieved in MOUNTMGR_MOUNT_POINTS::Size
|
||||
* to re-allocate a larger buffer and call the IOCTL once more.
|
||||
*/
|
||||
OutputSize = max(PAGE_SIZE, sizeof(*OutputBuffer));
|
||||
for (Retry = 0; Retry < 2; ++Retry)
|
||||
{
|
||||
OutputBuffer = ExAllocatePoolWithTag(PagedPool, OutputSize, TAG_PARTMGR);
|
||||
if (!OutputBuffer)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Call the MountMgr to delete the drive letter */
|
||||
Status = IssueSyncIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
|
||||
DeviceObject,
|
||||
InputBuffer,
|
||||
InputSize,
|
||||
OutputBuffer,
|
||||
OutputSize,
|
||||
FALSE);
|
||||
|
||||
/* Adjust the allocation size if it was too small */
|
||||
if (Status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
OutputSize = OutputBuffer->Size;
|
||||
ExFreePoolWithTag(OutputBuffer, TAG_PARTMGR);
|
||||
continue;
|
||||
}
|
||||
/* Success or failure: stop the loop */
|
||||
break;
|
||||
}
|
||||
|
||||
Quit:
|
||||
if (OutputBuffer)
|
||||
ExFreePoolWithTag(OutputBuffer, TAG_PARTMGR);
|
||||
if (InputBuffer)
|
||||
ExFreePoolWithTag(InputBuffer, TAG_PARTMGR);
|
||||
if (FileObject)
|
||||
ObDereferenceObject(FileObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PartitionHandleRemove(
|
||||
|
@ -220,6 +318,19 @@ PartitionHandleRemove(
|
|||
|
||||
if (PartExt->VolumeInterfaceName.Buffer)
|
||||
{
|
||||
/* Notify MountMgr to delete all associated mount points.
|
||||
* MountMgr does not automatically remove these in order to support
|
||||
* drive letter persistence for online/offline volume transitions,
|
||||
* or volumes arrival/removal on removable devices. */
|
||||
status = VolumeDeleteMountPoints(PartExt);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
ERR("VolumeDeleteMountPoints(%wZ) failed with status 0x%08lx\n",
|
||||
&PartExt->DeviceName, status);
|
||||
/* Failure isn't major, continue proceeding with volume removal */
|
||||
}
|
||||
|
||||
/* Notify MountMgr of volume removal */
|
||||
status = IoSetDeviceInterfaceState(&PartExt->VolumeInterfaceName, FALSE);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue