[PARTMGR] Implement support for IOCTL_STORAGE_GET_DEVICE_NUMBER (#7591)

CORE-13525

Now, sending the IOCTL_STORAGE_GET_DEVICE_NUMBER to a disk partition
correctly returns a non-zero STORAGE_DEVICE_NUMBER::PartitionNumber
value. This is used by the BTRFS filesystem driver and other modules.

When the STORAGE_DEVICE_NUMBER DeviceType member equals FILE_DEVICE_DISK,
the DeviceNumber and PartitionNumber correspond respectively to the
X and Y values in the \Device\Harddisk<X>\Partition<Y> device name.

References:
https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-ioctl_storage_get_device_number
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddstor/ni-ntddstor-ioctl_storage_get_device_number
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddstor/ns-ntddstor-_storage_device_number
This commit is contained in:
Hermès Bélusca-Maïto 2024-12-27 17:48:04 +01:00
parent e0e45ffa1a
commit dac991c056
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
2 changed files with 48 additions and 4 deletions

View file

@ -27,17 +27,26 @@ PartitionCreateDevice(
UNICODE_STRING deviceName;
UINT32 volumeNum;
// Create the partition/volume device object
volumeNum = HarddiskVolumeNextId++;
swprintf(nameBuf, L"\\Device\\HarddiskVolume%lu", volumeNum);
RtlCreateUnicodeString(&deviceName, nameBuf);
/*
* Create the partition/volume device object.
*
* Due to the fact we are also a (basic) volume manager, this device is
* ALSO a volume device. Because of this, we need to assign it a device
* name, and a specific device type for IoCreateDevice() to create a VPB
* for this device, so that a filesystem can be mounted on it.
* Once we get a separate volume manager, this partition DO can become
* anonymous, have a different device type, and without any associated VPB.
* (The attached volume, on the contrary, would require a VPB.)
*/
PDEVICE_OBJECT partitionDevice;
NTSTATUS status = IoCreateDevice(FDObject->DriverObject,
sizeof(PARTITION_EXTENSION),
&deviceName,
FILE_DEVICE_DISK,
FILE_DEVICE_DISK, // FILE_DEVICE_MASS_STORAGE,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&partitionDevice);
@ -55,6 +64,10 @@ PartitionCreateDevice(
partExt->DeviceObject = partitionDevice;
partExt->LowerDevice = FDObject;
// NOTE: See comment above.
// PFDO_EXTENSION fdoExtension = FDObject->DeviceExtension;
// partitionDevice->DeviceType = /*fdoExtension->LowerDevice*/FDObject->DeviceType;
partitionDevice->StackSize = FDObject->StackSize;
partitionDevice->Flags |= DO_DIRECT_IO;
@ -767,6 +780,27 @@ PartitionHandleDeviceControl(
status = STATUS_SUCCESS;
break;
}
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
{
PSTORAGE_DEVICE_NUMBER deviceNumber = Irp->AssociatedIrp.SystemBuffer;
if (!VerifyIrpOutBufferSize(Irp, sizeof(*deviceNumber)))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
PartMgrAcquireLayoutLock(fdoExtension);
deviceNumber->DeviceType = partExt->DeviceObject->DeviceType;
deviceNumber->DeviceNumber = fdoExtension->DiskData.DeviceNumber;
deviceNumber->PartitionNumber = partExt->DetectedNumber;
PartMgrReleaseLayoutLock(fdoExtension);
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(*deviceNumber);
break;
}
case IOCTL_STORAGE_MEDIA_REMOVAL:
{
return ForwardIrpAndForget(DeviceObject, Irp);

View file

@ -1182,10 +1182,17 @@ PartMgrAddDevice(
PAGED_CODE();
/*
* Create the disk FDO. Use FILE_DEVICE_MASS_STORAGE type (or any other
* one that is NOT FILE_DEVICE_[DISK|VIRTUAL_DISK|CD_ROM|TAPE]), so that
* IoCreateDevice() doesn't automatically create a VPB for this device,
* even if we will later want this device to inherit the type of the
* underlying PDO which can have any of the types mentioned above.
*/
NTSTATUS status = IoCreateDevice(DriverObject,
sizeof(FDO_EXTENSION),
NULL,
FILE_DEVICE_BUS_EXTENDER,
FILE_DEVICE_MASS_STORAGE,
FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);
@ -1210,6 +1217,9 @@ PartMgrAddDevice(
deviceExtension->PhysicalDiskDO = PhysicalDeviceObject;
KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE);
// Update now the device type with the actual underlying device type
deviceObject->DeviceType = deviceExtension->LowerDevice->DeviceType;
deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
// The device is initialized