4204 lines
117 KiB
C
4204 lines
117 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
partmgr.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This driver manages hides partitions from user mode, allowing access
|
|||
|
only from other device drivers. This driver implements a notification
|
|||
|
protocol for other drivers that want to be alerted of changes to the
|
|||
|
partitions in the system.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Norbert Kusters 18-Apr-1997
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define RTL_USE_AVL_TABLES 0
|
|||
|
|
|||
|
#include <ntosp.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <ntddvol.h>
|
|||
|
#include <ntdddisk.h>
|
|||
|
#include <initguid.h>
|
|||
|
#include <volmgr.h>
|
|||
|
#include <wmikm.h>
|
|||
|
#include <wmilib.h>
|
|||
|
#include <pmwmireg.h>
|
|||
|
#include <pmwmicnt.h>
|
|||
|
#include <partmgr.h>
|
|||
|
#include <ntiologc.h>
|
|||
|
#include <ioevent.h>
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmReadPartitionTableEx(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmWritePartitionTableEx(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmTakePartition(
|
|||
|
IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmGivePartition(
|
|||
|
IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmFindPartition(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN ULONG PartitionNumber,
|
|||
|
OUT PPARTITION_LIST_ENTRY *PartitionEntry
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDeviceRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmRemoveDevice(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmCreateClose(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPnp(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPower(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmPowerNotify (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PVOID WorkItem
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmAddDevice(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmVolumeManagerNotification(
|
|||
|
IN PVOID NotificationStructure,
|
|||
|
IN PVOID DriverExtension
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmNotifyPartitions(
|
|||
|
IN PDEVICE_EXTENSION DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmBuildDependantVolumeRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
OUT PDEVICE_RELATIONS *Relations
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDependantVolumeList(
|
|||
|
IN PDEVICE_OBJECT VolumeManager,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo,
|
|||
|
OUT PDEVICE_RELATIONS *DependantVolumes
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryRemovalRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmStartPartition(
|
|||
|
IN PDEVICE_OBJECT Partition
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmRemovePartition(
|
|||
|
IN PPARTITION_LIST_ENTRY Partition
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmDeviceControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmGetPartitionInformation(
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
OUT PLONGLONG PartitionOffset,
|
|||
|
OUT PLONGLONG PartitionLength
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmDiskGrowPartition(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmCheckForUnclaimedPartitions(
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmChangePartitionIoctl(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PPARTITION_LIST_ENTRY Partition,
|
|||
|
IN ULONG IoctlCode
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmEjectVolumeManagers(
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmAddSignatures(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX Layout
|
|||
|
);
|
|||
|
|
|||
|
RTL_GENERIC_COMPARE_RESULTS
|
|||
|
PmTableSignatureCompareRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID First,
|
|||
|
IN PVOID Second
|
|||
|
);
|
|||
|
|
|||
|
RTL_GENERIC_COMPARE_RESULTS
|
|||
|
PmTableGuidCompareRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID First,
|
|||
|
IN PVOID Second
|
|||
|
);
|
|||
|
|
|||
|
PVOID
|
|||
|
PmTableAllocateRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN CLONG Size
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmTableFreeRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID Buffer
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDiskSignature(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmReadWrite(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmIoCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS PmWmi(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmWmiFunctionControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN WMIENABLEDISABLECONTROL Function,
|
|||
|
IN BOOLEAN Enable
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmDriverReinit(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PVOID DriverExtension,
|
|||
|
IN ULONG Count
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PmIsRedundantPath(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDEVICE_EXTENSION WinningExtension,
|
|||
|
IN ULONG Signature,
|
|||
|
IN GUID* Guid
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PmLogError(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDEVICE_EXTENSION WinningExtension,
|
|||
|
IN NTSTATUS SpecificIoStatus
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
PmQueryRegistrySignature(
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT, DriverEntry)
|
|||
|
#pragma alloc_text(PAGE, PmTakePartition)
|
|||
|
#pragma alloc_text(PAGE, PmGivePartition)
|
|||
|
#pragma alloc_text(PAGE, PmFindPartition)
|
|||
|
#pragma alloc_text(PAGE, PmQueryDeviceRelations)
|
|||
|
#pragma alloc_text(PAGE, PmRemoveDevice)
|
|||
|
#pragma alloc_text(PAGE, PmCreateClose)
|
|||
|
#pragma alloc_text(PAGE, PmPnp)
|
|||
|
#pragma alloc_text(PAGE, PmAddDevice)
|
|||
|
#pragma alloc_text(PAGE, PmVolumeManagerNotification)
|
|||
|
#pragma alloc_text(PAGE, PmNotifyPartitions)
|
|||
|
#pragma alloc_text(PAGE, PmBuildDependantVolumeRelations)
|
|||
|
#pragma alloc_text(PAGE, PmQueryDependantVolumeList)
|
|||
|
#pragma alloc_text(PAGE, PmQueryRemovalRelations)
|
|||
|
#pragma alloc_text(PAGE, PmStartPartition)
|
|||
|
#pragma alloc_text(PAGE, PmDeviceControl)
|
|||
|
#pragma alloc_text(PAGE, PmGetPartitionInformation)
|
|||
|
#pragma alloc_text(PAGE, PmDiskGrowPartition)
|
|||
|
#pragma alloc_text(PAGE, PmCheckForUnclaimedPartitions)
|
|||
|
#pragma alloc_text(PAGE, PmChangePartitionIoctl)
|
|||
|
#pragma alloc_text(PAGE, PmEjectVolumeManagers)
|
|||
|
#pragma alloc_text(PAGE, PmAddSignatures)
|
|||
|
#pragma alloc_text(PAGE, PmTableSignatureCompareRoutine)
|
|||
|
#pragma alloc_text(PAGE, PmTableGuidCompareRoutine)
|
|||
|
#pragma alloc_text(PAGE, PmTableAllocateRoutine)
|
|||
|
#pragma alloc_text(PAGE, PmTableFreeRoutine)
|
|||
|
#pragma alloc_text(PAGE, PmQueryDiskSignature)
|
|||
|
#pragma alloc_text(PAGE, PmWmi)
|
|||
|
#pragma alloc_text(PAGE, PmWmiFunctionControl)
|
|||
|
#pragma alloc_text(PAGE, PmReadPartitionTableEx)
|
|||
|
#pragma alloc_text(PAGE, PmWritePartitionTableEx)
|
|||
|
#pragma alloc_text(PAGE, PmDriverReinit)
|
|||
|
#pragma alloc_text(PAGE, PmIsRedundantPath)
|
|||
|
#pragma alloc_text(PAGE, PmLogError)
|
|||
|
#pragma alloc_text(PAGE, PmQueryRegistrySignature)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPassThrough(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatch for IRP_MJ_PNP_POWER.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmSignalCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Event
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will signal the event given as context.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Event - Supplies the event to signal.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmTakePartition(
|
|||
|
IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine passes the given partition to the given volume manager
|
|||
|
and waits to see if the volume manager accepts the partition. A success
|
|||
|
status indicates that the volume manager has accepted the partition.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VolumeManager - Supplies a volume manager.
|
|||
|
|
|||
|
Partition - Supplies a partition.
|
|||
|
|
|||
|
WholeDiskPdo - Supplies the whole disk PDO.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KEVENT event;
|
|||
|
VOLMGR_PARTITION_INFORMATION input;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
if (!VolumeManagerEntry) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
input.PartitionDeviceObject = Partition;
|
|||
|
input.WholeDiskPdo = WholeDiskPdo;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_PARTITION_REMOVED,
|
|||
|
VolumeManagerEntry->VolumeManager,
|
|||
|
&input, sizeof(input), NULL, 0, TRUE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
}
|
|||
|
|
|||
|
VolumeManagerEntry->RefCount--;
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
VolumeManagerEntry->VolumeManager = NULL;
|
|||
|
ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
|
|||
|
VolumeManagerEntry->VolumeManagerFileObject = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmGivePartition(
|
|||
|
IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine passes the given partition to the given volume manager
|
|||
|
and waits to see if the volume manager accepts the partition. A success
|
|||
|
status indicates that the volume manager has accepted the partition.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VolumeManager - Supplies a volume manager.
|
|||
|
|
|||
|
Partition - Supplies a partition.
|
|||
|
|
|||
|
WholeDiskPdo - Supplies the whole disk PDO.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
KEVENT event;
|
|||
|
VOLMGR_PARTITION_INFORMATION input;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
status = IoGetDeviceObjectPointer(
|
|||
|
&VolumeManagerEntry->VolumeManagerName, FILE_READ_DATA,
|
|||
|
&VolumeManagerEntry->VolumeManagerFileObject,
|
|||
|
&VolumeManagerEntry->VolumeManager);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
input.PartitionDeviceObject = Partition;
|
|||
|
input.WholeDiskPdo = WholeDiskPdo;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_PARTITION_ARRIVED,
|
|||
|
VolumeManagerEntry->VolumeManager,
|
|||
|
&input, sizeof(input),
|
|||
|
NULL, 0, TRUE, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
VolumeManagerEntry->VolumeManager = NULL;
|
|||
|
ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
|
|||
|
VolumeManagerEntry->VolumeManagerFileObject = NULL;
|
|||
|
}
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
VolumeManagerEntry->RefCount++;
|
|||
|
} else {
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
VolumeManagerEntry->VolumeManager = NULL;
|
|||
|
ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
|
|||
|
VolumeManagerEntry->VolumeManagerFileObject = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmFindPartition(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN ULONG PartitionNumber,
|
|||
|
OUT PPARTITION_LIST_ENTRY* Partition
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PLIST_ENTRY l;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
STORAGE_DEVICE_NUMBER deviceNumber;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
ASSERT(Partition);
|
|||
|
*Partition = NULL;
|
|||
|
|
|||
|
for (l = Extension->PartitionList.Flink; l != &Extension->PartitionList;
|
|||
|
l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|||
|
partition->TargetObject, NULL, 0,
|
|||
|
&deviceNumber,
|
|||
|
sizeof(deviceNumber), FALSE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(partition->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status) &&
|
|||
|
PartitionNumber == deviceNumber.PartitionNumber) {
|
|||
|
|
|||
|
*Partition = partition;
|
|||
|
return status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmChangePartitionIoctl(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PPARTITION_LIST_ENTRY Partition,
|
|||
|
IN ULONG IoctlCode
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PVOLMGR_LIST_ENTRY volumeEntry;
|
|||
|
KEVENT event;
|
|||
|
VOLMGR_PARTITION_INFORMATION input;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
volumeEntry = Partition->VolumeManagerEntry;
|
|||
|
if (!volumeEntry) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
input.PartitionDeviceObject = Partition->TargetObject;
|
|||
|
input.WholeDiskPdo = Partition->WholeDiskPdo;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IoctlCode, volumeEntry->VolumeManager, &input, sizeof(input),
|
|||
|
NULL, 0, TRUE, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(volumeEntry->VolumeManager, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmStartPartition(
|
|||
|
IN PDEVICE_OBJECT Partition
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
KEVENT event;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
irp = IoAllocateIrp(Partition->StackSize, FALSE);
|
|||
|
if (!irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|||
|
irpSp->MajorFunction = IRP_MJ_PNP;
|
|||
|
irpSp->MinorFunction = IRP_MN_START_DEVICE;
|
|||
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|||
|
IoSetCompletionRoutine(irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
|
|||
|
|
|||
|
IoCallDriver(Partition, irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
status = irp->IoStatus.Status;
|
|||
|
|
|||
|
IoFreeIrp(irp);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDeviceRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine processes the query device relations request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX newLayout;
|
|||
|
KEVENT event;
|
|||
|
PDEVICE_RELATIONS deviceRelations;
|
|||
|
PLIST_ENTRY l, b;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
ULONG i;
|
|||
|
PDO_EXTENSION driverExtension;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
|
|||
|
IoCallDriver(Extension->TargetObject, Irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
|
|||
|
|
|||
|
if (Extension->SignaturesNotChecked) {
|
|||
|
|
|||
|
status = PmReadPartitionTableEx(Extension->TargetObject,
|
|||
|
&newLayout);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&Extension->DriverExtension->Mutex,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
PmAddSignatures(Extension, newLayout);
|
|||
|
Extension->SignaturesNotChecked = FALSE;
|
|||
|
KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
ExFreePool(newLayout);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// First notify clients of partitions that have gone away.
|
|||
|
//
|
|||
|
|
|||
|
driverExtension = Extension->DriverExtension;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
|
|||
|
for (l = Extension->PartitionList.Flink; l != &Extension->PartitionList;
|
|||
|
l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
for (i = 0; i < deviceRelations->Count; i++) {
|
|||
|
if (partition->TargetObject == deviceRelations->Objects[i]) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i < deviceRelations->Count) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
PmTakePartition(partition->VolumeManagerEntry,
|
|||
|
partition->TargetObject, partition->WholeDiskPdo);
|
|||
|
|
|||
|
//
|
|||
|
// We're pretending to be pnp. Send a remove to the partition
|
|||
|
// object so it can delete it.
|
|||
|
//
|
|||
|
|
|||
|
PmRemovePartition(partition);
|
|||
|
|
|||
|
b = l->Blink;
|
|||
|
RemoveEntryList(l);
|
|||
|
l = b;
|
|||
|
|
|||
|
ExFreePool(partition);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Then notify clients of new partitions.
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < deviceRelations->Count; i++) {
|
|||
|
|
|||
|
for (l = Extension->PartitionList.Flink;
|
|||
|
l != &Extension->PartitionList; l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
if (deviceRelations->Objects[i] == partition->TargetObject) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (l != &Extension->PartitionList) {
|
|||
|
|
|||
|
//
|
|||
|
// Must attempt to start the partition even if it is in our list
|
|||
|
// because it may be stopped and need restarting.
|
|||
|
//
|
|||
|
|
|||
|
PmStartPartition(deviceRelations->Objects[i]);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (Extension->DriverExtension->PastReinit) {
|
|||
|
|
|||
|
//
|
|||
|
// Now that this partition is owned by the partition manager
|
|||
|
// make sure that nobody can open it another way.
|
|||
|
//
|
|||
|
|
|||
|
deviceRelations->Objects[i]->Flags |= DO_DEVICE_INITIALIZING;
|
|||
|
}
|
|||
|
|
|||
|
status = PmStartPartition(deviceRelations->Objects[i]);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
partition = ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
sizeof(PARTITION_LIST_ENTRY),
|
|||
|
PARTMGR_TAG_PARTITION_ENTRY);
|
|||
|
if (!partition) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
partition->TargetObject = deviceRelations->Objects[i];
|
|||
|
partition->WholeDiskPdo = Extension->Pdo;
|
|||
|
partition->VolumeManagerEntry = NULL;
|
|||
|
InsertHeadList(&Extension->PartitionList, &partition->ListEntry);
|
|||
|
|
|||
|
if (Extension->IsRedundantPath) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
for (l = driverExtension->VolumeManagerList.Flink;
|
|||
|
l != &driverExtension->VolumeManagerList; l = l->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
status = PmGivePartition(volmgrEntry,
|
|||
|
partition->TargetObject,
|
|||
|
partition->WholeDiskPdo);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
partition->VolumeManagerEntry = volmgrEntry;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
deviceRelations->Count = 0;
|
|||
|
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmTakeWholeDisk(
|
|||
|
IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine alerts the volume manager that the given PDO is going away.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VolumeManager - Supplies a volume manager.
|
|||
|
|
|||
|
WholeDiskPdo - Supplies the whole disk PDO.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
KEVENT event;
|
|||
|
VOLMGR_WHOLE_DISK_INFORMATION input;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
|
|||
|
if (!VolumeManagerEntry) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
status = IoGetDeviceObjectPointer(
|
|||
|
&VolumeManagerEntry->VolumeManagerName, FILE_READ_DATA,
|
|||
|
&VolumeManagerEntry->VolumeManagerFileObject,
|
|||
|
&VolumeManagerEntry->VolumeManager);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
input.WholeDiskPdo = WholeDiskPdo;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_WHOLE_DISK_REMOVED,
|
|||
|
VolumeManagerEntry->VolumeManager,
|
|||
|
&input, sizeof(input), NULL, 0, TRUE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
VolumeManagerEntry->VolumeManager = NULL;
|
|||
|
ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
|
|||
|
VolumeManagerEntry->VolumeManagerFileObject = NULL;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
}
|
|||
|
|
|||
|
if (!VolumeManagerEntry->RefCount) {
|
|||
|
VolumeManagerEntry->VolumeManager = NULL;
|
|||
|
ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
|
|||
|
VolumeManagerEntry->VolumeManagerFileObject = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmNotifyPartitions(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine notifies each partition stolen by the partmgr that it is
|
|||
|
about to be removed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PLIST_ENTRY l;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
KEVENT event;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|||
|
|
|||
|
KeWaitForSingleObject(&Extension->DriverExtension->Mutex, Executive,
|
|||
|
KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
for(l = Extension->PartitionList.Flink;
|
|||
|
l != &(Extension->PartitionList);
|
|||
|
l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp,
|
|||
|
PmSignalCompletion,
|
|||
|
&event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
|
|||
|
status = IoCallDriver(partition->TargetObject, Irp);
|
|||
|
|
|||
|
if(status == STATUS_PENDING) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&event,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if(!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmRemoveDevice(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine processes the query device relations request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Irp - Supplies the I/O request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDO_EXTENSION driverExtension = Extension->DriverExtension;
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
|||
|
PLIST_ENTRY l;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
if (Extension->RemoveProcessed) {
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
Extension->RemoveProcessed = TRUE;
|
|||
|
|
|||
|
Extension->IsStarted = FALSE;
|
|||
|
|
|||
|
PmAddSignatures(Extension, NULL);
|
|||
|
|
|||
|
for (l = Extension->PartitionList.Flink;
|
|||
|
l != &Extension->PartitionList; l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
PmTakePartition(partition->VolumeManagerEntry,
|
|||
|
partition->TargetObject, NULL);
|
|||
|
}
|
|||
|
|
|||
|
status = PmNotifyPartitions(Extension, Irp);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
|
|||
|
while (!IsListEmpty(&Extension->PartitionList)) {
|
|||
|
l = RemoveHeadList(&Extension->PartitionList);
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
ExFreePool(partition);
|
|||
|
}
|
|||
|
|
|||
|
for (l = driverExtension->VolumeManagerList.Flink;
|
|||
|
l != &driverExtension->VolumeManagerList; l = l->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
PmTakeWholeDisk(volmgrEntry, Extension->Pdo);
|
|||
|
}
|
|||
|
|
|||
|
RemoveEntryList(&Extension->ListEntry);
|
|||
|
|
|||
|
if (Extension->WmilibContext != NULL) { // just to be safe
|
|||
|
IoWMIRegistrationControl(Extension->DeviceObject,
|
|||
|
WMIREG_ACTION_DEREGISTER);
|
|||
|
ExFreePool(Extension->WmilibContext);
|
|||
|
Extension->WmilibContext = NULL;
|
|||
|
PmWmiCounterDisable(&Extension->PmWmiCounterContext,
|
|||
|
TRUE, TRUE);
|
|||
|
Extension->CountersEnabled = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmPowerNotify (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PVOID PublicWorkItem
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine notifies volume managers about changes in
|
|||
|
the power state of the given disk.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
PublicWorkItem - Supplies the public work item
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PDO_EXTENSION driverExtension = deviceExtension->DriverExtension;
|
|||
|
KEVENT event;
|
|||
|
KIRQL irql;
|
|||
|
LIST_ENTRY q;
|
|||
|
PLIST_ENTRY l;
|
|||
|
BOOLEAN empty;
|
|||
|
PPM_POWER_WORK_ITEM privateWorkItem;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
VOLMGR_POWER_STATE input;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
|
|||
|
if (IsListEmpty(&deviceExtension->PowerQueue)) {
|
|||
|
empty = TRUE;
|
|||
|
} else {
|
|||
|
empty = FALSE;
|
|||
|
q = deviceExtension->PowerQueue;
|
|||
|
InitializeListHead(&deviceExtension->PowerQueue);
|
|||
|
}
|
|||
|
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
|
|||
|
|
|||
|
if (empty) {
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
IoFreeWorkItem((PIO_WORKITEM) PublicWorkItem);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
q.Flink->Blink = &q;
|
|||
|
q.Blink->Flink = &q;
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
while (!IsListEmpty(&q)) {
|
|||
|
|
|||
|
l = RemoveHeadList(&q);
|
|||
|
privateWorkItem = CONTAINING_RECORD(l, PM_POWER_WORK_ITEM, ListEntry);
|
|||
|
|
|||
|
for (l = deviceExtension->PartitionList.Flink;
|
|||
|
l != &deviceExtension->PartitionList; l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
if (!partition->VolumeManagerEntry) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
input.PartitionDeviceObject = partition->TargetObject;
|
|||
|
input.WholeDiskPdo = partition->WholeDiskPdo;
|
|||
|
input.PowerState = privateWorkItem->DevicePowerState;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_INTERNAL_VOLMGR_SET_POWER_STATE,
|
|||
|
partition->VolumeManagerEntry->VolumeManager,
|
|||
|
&input, sizeof(input), NULL, 0, TRUE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
status = IoCallDriver(partition->VolumeManagerEntry->VolumeManager,
|
|||
|
irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
}
|
|||
|
KeClearEvent(&event);
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(privateWorkItem);
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
IoFreeWorkItem((PIO_WORKITEM) PublicWorkItem);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPowerCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles completion of an IRP_MN_SET_POWER irp.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Context - Not used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PIO_WORKITEM publicWorkItem;
|
|||
|
PPM_POWER_WORK_ITEM privateWorkItem;
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER &&
|
|||
|
irpStack->MinorFunction == IRP_MN_SET_POWER);
|
|||
|
ASSERT(irpStack->Parameters.Power.Type == DevicePowerState);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
publicWorkItem = IoAllocateWorkItem(DeviceObject);
|
|||
|
if (!publicWorkItem) {
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
privateWorkItem = (PPM_POWER_WORK_ITEM) ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
sizeof(PM_POWER_WORK_ITEM),
|
|||
|
PARTMGR_TAG_POWER_WORK_ITEM);
|
|||
|
if (!privateWorkItem) {
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
IoFreeWorkItem(publicWorkItem);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
privateWorkItem->DevicePowerState =
|
|||
|
irpStack->Parameters.Power.State.DeviceState;
|
|||
|
|
|||
|
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
|
|||
|
InsertTailList(&deviceExtension->PowerQueue, &privateWorkItem->ListEntry);
|
|||
|
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
|
|||
|
|
|||
|
IoQueueWorkItem(publicWorkItem, PmPowerNotify, DelayedWorkQueue,
|
|||
|
publicWorkItem);
|
|||
|
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPower(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatch for IRP_MJ_POWER.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_EXTENSION deviceExtension =
|
|||
|
(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|||
|
if (!NT_SUCCESS (status)) {
|
|||
|
PoStartNextPowerIrp (Irp);
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
if (irpSp->MinorFunction == IRP_MN_SET_POWER &&
|
|||
|
irpSp->Parameters.Power.Type == DevicePowerState) {
|
|||
|
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmPowerCompletion, NULL, TRUE,
|
|||
|
TRUE, TRUE);
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
PoCallDriver(deviceExtension->TargetObject, Irp);
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
status = PoCallDriver(deviceExtension->TargetObject, Irp);
|
|||
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryRemovalRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine processes the query removal relations request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
KEVENT event;
|
|||
|
PDEVICE_RELATIONS deviceRelations;
|
|||
|
PLIST_ENTRY l, b;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
ULONG i;
|
|||
|
PDO_EXTENSION driverExtension;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
|
|||
|
IoCallDriver(Extension->TargetObject, Irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
if (status != Irp->IoStatus.Status) {
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return PmBuildDependantVolumeRelations(Extension,
|
|||
|
&((PDEVICE_RELATIONS) Irp->IoStatus.Information));
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PmIsRedundantPath(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDEVICE_EXTENSION WinningExtension,
|
|||
|
IN ULONG Signature,
|
|||
|
IN GUID* Guid
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PDO_EXTENSION driverExtension = Extension->DriverExtension;
|
|||
|
PDEVICE_EXTENSION extension = WinningExtension;
|
|||
|
PGUID_TABLE_ENTRY guidEntry;
|
|||
|
PSIGNATURE_TABLE_ENTRY sigEntry;
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
DISK_GEOMETRY geometry, geometry2;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG bufferSize;
|
|||
|
ULONG readSize;
|
|||
|
PVOID buffer;
|
|||
|
LARGE_INTEGER byteOffset;
|
|||
|
PULONG signature;
|
|||
|
BOOLEAN isRedundant;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|||
|
Extension->TargetObject, NULL, 0,
|
|||
|
&geometry, sizeof(geometry), FALSE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(Extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|||
|
extension->TargetObject, NULL, 0,
|
|||
|
&geometry2, sizeof(geometry2), FALSE,
|
|||
|
&event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (geometry2.BytesPerSector > geometry.BytesPerSector) {
|
|||
|
geometry.BytesPerSector = geometry2.BytesPerSector;
|
|||
|
}
|
|||
|
|
|||
|
byteOffset.QuadPart = 0;
|
|||
|
readSize = 512;
|
|||
|
if (readSize < geometry.BytesPerSector) {
|
|||
|
readSize = geometry.BytesPerSector;
|
|||
|
}
|
|||
|
|
|||
|
bufferSize = 2*readSize;
|
|||
|
buffer = ExAllocatePoolWithTag(NonPagedPool, bufferSize < PAGE_SIZE ?
|
|||
|
PAGE_SIZE : bufferSize,
|
|||
|
PARTMGR_TAG_IOCTL_BUFFER);
|
|||
|
if (!buffer) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, Extension->TargetObject,
|
|||
|
buffer, readSize, &byteOffset, &event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(Extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, extension->TargetObject,
|
|||
|
(PCHAR) buffer + readSize, readSize,
|
|||
|
&byteOffset, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (RtlCompareMemory(buffer, (PCHAR) buffer + readSize, readSize) !=
|
|||
|
readSize) {
|
|||
|
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
signature = (PULONG) ((PCHAR) buffer + 0x1B8);
|
|||
|
(*signature)++;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, Extension->TargetObject,
|
|||
|
buffer, readSize, &byteOffset, &event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(Extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, extension->TargetObject,
|
|||
|
(PCHAR) buffer + readSize, readSize,
|
|||
|
&byteOffset, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
status = IoCallDriver(extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (RtlCompareMemory(buffer, (PCHAR) buffer + readSize, readSize) !=
|
|||
|
readSize) {
|
|||
|
|
|||
|
ExFreePool(buffer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
(*signature)--;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, Extension->TargetObject,
|
|||
|
buffer, readSize, &byteOffset, &event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
status = IoCallDriver(Extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(buffer);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(buffer);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmLogError(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDEVICE_EXTENSION WinningExtension,
|
|||
|
IN NTSTATUS SpecificIoStatus
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
STORAGE_DEVICE_NUMBER deviceNumber, winningDeviceNumber;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
WCHAR buffer1[30], buffer2[30];
|
|||
|
UNICODE_STRING number, winningNumber;
|
|||
|
ULONG extraSpace;
|
|||
|
PIO_ERROR_LOG_PACKET errorLogPacket;
|
|||
|
PWCHAR p;
|
|||
|
GUID_IO_DISK_CLONE_ARRIVAL_INFORMATION diskCloneArrivalInfo;
|
|||
|
UCHAR notificationBuffer[sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) + sizeof(GUID_IO_DISK_CLONE_ARRIVAL_INFORMATION)];
|
|||
|
PTARGET_DEVICE_CUSTOM_NOTIFICATION notification = (PTARGET_DEVICE_CUSTOM_NOTIFICATION) notificationBuffer;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|||
|
Extension->TargetObject, NULL, 0,
|
|||
|
&deviceNumber, sizeof(deviceNumber),
|
|||
|
FALSE, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(Extension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|||
|
WinningExtension->TargetObject, NULL,
|
|||
|
0, &winningDeviceNumber,
|
|||
|
sizeof(winningDeviceNumber),
|
|||
|
FALSE, &event, &ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(WinningExtension->TargetObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
swprintf(buffer1, L"%d", deviceNumber.DeviceNumber);
|
|||
|
RtlInitUnicodeString(&number, buffer1);
|
|||
|
swprintf(buffer2, L"%d", winningDeviceNumber.DeviceNumber);
|
|||
|
RtlInitUnicodeString(&winningNumber, buffer2);
|
|||
|
extraSpace = number.Length + winningNumber.Length + 2*sizeof(WCHAR);
|
|||
|
extraSpace += sizeof(IO_ERROR_LOG_PACKET);
|
|||
|
if (extraSpace > 0xFF) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
errorLogPacket = (PIO_ERROR_LOG_PACKET)
|
|||
|
IoAllocateErrorLogEntry(Extension->DeviceObject,
|
|||
|
(UCHAR) extraSpace);
|
|||
|
if (!errorLogPacket) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
errorLogPacket->ErrorCode = SpecificIoStatus;
|
|||
|
errorLogPacket->SequenceNumber = 0;
|
|||
|
errorLogPacket->FinalStatus = 0;
|
|||
|
errorLogPacket->UniqueErrorValue = 0;
|
|||
|
errorLogPacket->DumpDataSize = 0;
|
|||
|
errorLogPacket->RetryCount = 0;
|
|||
|
errorLogPacket->NumberOfStrings = 2;
|
|||
|
errorLogPacket->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
|
|||
|
p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET));
|
|||
|
RtlCopyMemory(p, number.Buffer, number.Length);
|
|||
|
p[number.Length/sizeof(WCHAR)] = 0;
|
|||
|
p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET) +
|
|||
|
number.Length + sizeof(WCHAR));
|
|||
|
RtlCopyMemory(p, winningNumber.Buffer, winningNumber.Length);
|
|||
|
p[winningNumber.Length/sizeof(WCHAR)] = 0;
|
|||
|
|
|||
|
IoWriteErrorLogEntry(errorLogPacket);
|
|||
|
|
|||
|
if (SpecificIoStatus == IO_WARNING_DUPLICATE_SIGNATURE) {
|
|||
|
diskCloneArrivalInfo.DiskNumber = deviceNumber.DeviceNumber;
|
|||
|
notification->Version = 1;
|
|||
|
notification->Size = (USHORT)
|
|||
|
(FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION,
|
|||
|
CustomDataBuffer) +
|
|||
|
sizeof(diskCloneArrivalInfo));
|
|||
|
RtlCopyMemory(¬ification->Event, &GUID_IO_DISK_CLONE_ARRIVAL,
|
|||
|
sizeof(GUID_IO_DISK_CLONE_ARRIVAL));
|
|||
|
notification->FileObject = NULL;
|
|||
|
notification->NameBufferOffset = -1;
|
|||
|
RtlCopyMemory(notification->CustomDataBuffer, &diskCloneArrivalInfo,
|
|||
|
sizeof(diskCloneArrivalInfo));
|
|||
|
|
|||
|
IoReportTargetDeviceChangeAsynchronous(WinningExtension->Pdo,
|
|||
|
notification, NULL, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
PmQueryRegistrySignature(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks a registry value for an MBR signature to be used
|
|||
|
for the bad signature case. This is to facilitate OEM pre-install.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A valid signature or 0.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG zero, signature;
|
|||
|
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
zero = 0;
|
|||
|
signature = 0;
|
|||
|
|
|||
|
RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
|
|||
|
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|||
|
queryTable[0].Name = L"BootDiskSig";
|
|||
|
queryTable[0].EntryContext = &signature;
|
|||
|
queryTable[0].DefaultType = REG_DWORD;
|
|||
|
queryTable[0].DefaultData = &zero;
|
|||
|
queryTable[0].DefaultLength = sizeof(ULONG);
|
|||
|
|
|||
|
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|||
|
L"\\Registry\\Machine\\System\\Setup",
|
|||
|
queryTable, NULL, NULL);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
signature = zero;
|
|||
|
}
|
|||
|
|
|||
|
RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|||
|
L"\\Registry\\Machine\\System\\Setup",
|
|||
|
L"BootDiskSig");
|
|||
|
|
|||
|
return signature;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmAddSignatures(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX Layout
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds the disk and partition signature to their
|
|||
|
respective tables. If a collision is detected, the signatures are
|
|||
|
changed and written back out.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDO_EXTENSION driverExtension = Extension->DriverExtension;
|
|||
|
PLIST_ENTRY l;
|
|||
|
PSIGNATURE_TABLE_ENTRY s;
|
|||
|
PGUID_TABLE_ENTRY g;
|
|||
|
SIGNATURE_TABLE_ENTRY sigEntry;
|
|||
|
GUID_TABLE_ENTRY guidEntry;
|
|||
|
NTSTATUS status;
|
|||
|
PVOID nodeOrParent, nodeOrParent2;
|
|||
|
TABLE_SEARCH_RESULT searchResult, searchResult2;
|
|||
|
UUID uuid;
|
|||
|
PULONG p;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
while (!IsListEmpty(&Extension->SignatureList)) {
|
|||
|
l = RemoveHeadList(&Extension->SignatureList);
|
|||
|
s = CONTAINING_RECORD(l, SIGNATURE_TABLE_ENTRY, ListEntry);
|
|||
|
RtlDeleteElementGenericTable(&driverExtension->SignatureTable, s);
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&Extension->GuidList)) {
|
|||
|
l = RemoveHeadList(&Extension->GuidList);
|
|||
|
g = CONTAINING_RECORD(l, GUID_TABLE_ENTRY, ListEntry);
|
|||
|
RtlDeleteElementGenericTable(&driverExtension->GuidTable, g);
|
|||
|
}
|
|||
|
|
|||
|
if (!Layout) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (Layout->PartitionStyle == PARTITION_STYLE_MBR) {
|
|||
|
|
|||
|
if (!Layout->PartitionCount && !Layout->Mbr.Signature) {
|
|||
|
// RAW disk. No signature to validate.
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (Layout->PartitionCount > 0 &&
|
|||
|
Layout->PartitionEntry[0].PartitionLength.QuadPart > 0 &&
|
|||
|
Layout->PartitionEntry[0].StartingOffset.QuadPart == 0) {
|
|||
|
|
|||
|
// Super floppy. No signature to validate.
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
sigEntry.Signature = Layout->Mbr.Signature;
|
|||
|
s = RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->SignatureTable, &sigEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
if (s || !sigEntry.Signature ||
|
|||
|
Extension->DriverExtension->BootDiskSig) {
|
|||
|
|
|||
|
if (s) {
|
|||
|
if (PmIsRedundantPath(Extension, s->Extension,
|
|||
|
sigEntry.Signature, NULL)) {
|
|||
|
|
|||
|
PmLogError(Extension, s->Extension,
|
|||
|
IO_WARNING_DUPLICATE_PATH);
|
|||
|
|
|||
|
Extension->IsRedundantPath = TRUE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PmLogError(Extension, s->Extension,
|
|||
|
IO_WARNING_DUPLICATE_SIGNATURE);
|
|||
|
}
|
|||
|
|
|||
|
if (Extension->DriverExtension->BootDiskSig) {
|
|||
|
Layout->Mbr.Signature =
|
|||
|
Extension->DriverExtension->BootDiskSig;
|
|||
|
Extension->DriverExtension->BootDiskSig = 0;
|
|||
|
} else {
|
|||
|
status = ExUuidCreate(&uuid);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
p = (PULONG) &uuid;
|
|||
|
Layout->Mbr.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
|
|||
|
}
|
|||
|
sigEntry.Signature = Layout->Mbr.Signature;
|
|||
|
|
|||
|
if (driverExtension->PastReinit) {
|
|||
|
status = PmWritePartitionTableEx(Extension->TargetObject,
|
|||
|
Layout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
} else {
|
|||
|
Extension->DiskSignature = Layout->Mbr.Signature;
|
|||
|
}
|
|||
|
|
|||
|
RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->SignatureTable, &sigEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
}
|
|||
|
|
|||
|
s = RtlInsertElementGenericTableFull(&driverExtension->SignatureTable,
|
|||
|
&sigEntry, sizeof(sigEntry), NULL,
|
|||
|
nodeOrParent, searchResult);
|
|||
|
if (!s) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InsertTailList(&Extension->SignatureList, &s->ListEntry);
|
|||
|
s->Extension = Extension;
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(Layout->PartitionStyle == PARTITION_STYLE_GPT);
|
|||
|
|
|||
|
if (Layout->PartitionStyle != PARTITION_STYLE_GPT) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (Extension->DriverExtension->PastReinit) {
|
|||
|
|
|||
|
p = (PULONG) &Layout->Gpt.DiskId;
|
|||
|
sigEntry.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
|
|||
|
guidEntry.Guid = Layout->Gpt.DiskId;
|
|||
|
|
|||
|
s = RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->SignatureTable, &sigEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
g = RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
&nodeOrParent2, &searchResult2);
|
|||
|
if (s || g || !sigEntry.Signature) {
|
|||
|
|
|||
|
if (g) {
|
|||
|
if (PmIsRedundantPath(Extension, g->Extension, 0,
|
|||
|
&guidEntry.Guid)) {
|
|||
|
|
|||
|
PmLogError(Extension, g->Extension,
|
|||
|
IO_WARNING_DUPLICATE_PATH);
|
|||
|
|
|||
|
Extension->IsRedundantPath = TRUE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PmLogError(Extension, g->Extension,
|
|||
|
IO_WARNING_DUPLICATE_SIGNATURE);
|
|||
|
}
|
|||
|
|
|||
|
status = ExUuidCreate(&uuid);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Layout->Gpt.DiskId = uuid;
|
|||
|
status = PmWritePartitionTableEx(Extension->TargetObject, Layout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
p = (PULONG) &Layout->Gpt.DiskId;
|
|||
|
sigEntry.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
|
|||
|
guidEntry.Guid = Layout->Gpt.DiskId;
|
|||
|
|
|||
|
RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->SignatureTable, &sigEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
&nodeOrParent2, &searchResult2);
|
|||
|
}
|
|||
|
|
|||
|
s = RtlInsertElementGenericTableFull(
|
|||
|
&driverExtension->SignatureTable, &sigEntry,
|
|||
|
sizeof(sigEntry), NULL, nodeOrParent, searchResult);
|
|||
|
if (!s) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InsertTailList(&Extension->SignatureList, &s->ListEntry);
|
|||
|
s->Extension = Extension;
|
|||
|
|
|||
|
g = RtlInsertElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
sizeof(guidEntry), NULL, nodeOrParent2, searchResult2);
|
|||
|
if (!g) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InsertTailList(&Extension->GuidList, &g->ListEntry);
|
|||
|
g->Extension = Extension;
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < Layout->PartitionCount; i++) {
|
|||
|
|
|||
|
p = (PULONG) &Layout->PartitionEntry[i].Gpt.PartitionId;
|
|||
|
sigEntry.Signature = p[0] | p[1] | p[2] | p[3];
|
|||
|
guidEntry.Guid = Layout->PartitionEntry[i].Gpt.PartitionId;
|
|||
|
|
|||
|
g = RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
if (g || !sigEntry.Signature) {
|
|||
|
|
|||
|
status = ExUuidCreate(&uuid);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Layout->PartitionEntry[i].Gpt.PartitionId = uuid;
|
|||
|
status = PmWritePartitionTableEx(Extension->TargetObject, Layout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
guidEntry.Guid = Layout->PartitionEntry[i].Gpt.PartitionId;
|
|||
|
|
|||
|
RtlLookupElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
&nodeOrParent, &searchResult);
|
|||
|
}
|
|||
|
|
|||
|
g = RtlInsertElementGenericTableFull(
|
|||
|
&driverExtension->GuidTable, &guidEntry,
|
|||
|
sizeof(guidEntry), NULL, nodeOrParent, searchResult);
|
|||
|
if (!g) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InsertTailList(&Extension->GuidList, &g->ListEntry);
|
|||
|
g->Extension = Extension;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmPnp(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatch for IRP_MJ_PNP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
KEVENT event;
|
|||
|
NTSTATUS status, status2;
|
|||
|
PDEVICE_OBJECT targetObject;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
|||
|
|
|||
|
if (irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION &&
|
|||
|
irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
|
|||
|
|
|||
|
ULONG count;
|
|||
|
BOOLEAN setPagable;
|
|||
|
|
|||
|
//
|
|||
|
// synchronize these irps.
|
|||
|
//
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->PagingPathCountEvent,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
//
|
|||
|
// if removing last paging device, need to set DO_POWER_PAGABLE
|
|||
|
// bit here, and possible re-set it below on failure.
|
|||
|
//
|
|||
|
|
|||
|
setPagable = FALSE;
|
|||
|
if (!irpSp->Parameters.UsageNotification.InPath &&
|
|||
|
extension->PagingPathCount == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// removing a paging file. if last removal,
|
|||
|
// must have DO_POWER_PAGABLE bits set
|
|||
|
//
|
|||
|
|
|||
|
if (extension->PagingPathCount == 0) {
|
|||
|
if (!(DeviceObject->Flags & DO_POWER_INRUSH)) {
|
|||
|
DeviceObject->Flags |= DO_POWER_PAGABLE;
|
|||
|
setPagable = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// send the irp synchronously
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
|
|||
|
status = IoCallDriver(extension->TargetObject, Irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// now deal with the failure and success cases.
|
|||
|
// note that we are not allowed to fail the irp
|
|||
|
// once it is sent to the lower drivers.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
IoAdjustPagingPathCount(
|
|||
|
&extension->PagingPathCount,
|
|||
|
irpSp->Parameters.UsageNotification.InPath);
|
|||
|
|
|||
|
if (irpSp->Parameters.UsageNotification.InPath) {
|
|||
|
|
|||
|
if (extension->PagingPathCount == 1) {
|
|||
|
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// cleanup the changes done above
|
|||
|
//
|
|||
|
|
|||
|
if (setPagable == TRUE) {
|
|||
|
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
|
|||
|
setPagable = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set the event so the next one can occur.
|
|||
|
//
|
|||
|
|
|||
|
KeSetEvent(&extension->PagingPathCountEvent,
|
|||
|
IO_NO_INCREMENT, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// and complete the irp
|
|||
|
//
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
switch (irpSp->MinorFunction) {
|
|||
|
|
|||
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|||
|
switch (irpSp->Parameters.QueryDeviceRelations.Type) {
|
|||
|
case BusRelations:
|
|||
|
status = PmQueryDeviceRelations(extension, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case RemovalRelations:
|
|||
|
status = PmQueryRemovalRelations(extension, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IRP_MN_START_DEVICE:
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event,
|
|||
|
TRUE, TRUE, TRUE);
|
|||
|
IoCallDriver(extension->TargetObject, Irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (extension->TargetObject->Characteristics&
|
|||
|
FILE_REMOVABLE_MEDIA) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status2 = PmReadPartitionTableEx(extension->TargetObject,
|
|||
|
&layout);
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
extension->IsStarted = TRUE;
|
|||
|
if (NT_SUCCESS(status2)) {
|
|||
|
PmAddSignatures(extension, layout);
|
|||
|
ExFreePool(layout);
|
|||
|
} else {
|
|||
|
extension->SignaturesNotChecked = TRUE;
|
|||
|
}
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Register its existence with WMI
|
|||
|
//
|
|||
|
PmRegisterDevice(DeviceObject);
|
|||
|
break;
|
|||
|
|
|||
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|||
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|||
|
case IRP_MN_STOP_DEVICE:
|
|||
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|||
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|||
|
status = PmNotifyPartitions(extension, Irp);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
|
|||
|
case IRP_MN_SURPRISE_REMOVAL:
|
|||
|
case IRP_MN_REMOVE_DEVICE:
|
|||
|
|
|||
|
//
|
|||
|
// Notify all the children of their imminent removal.
|
|||
|
//
|
|||
|
|
|||
|
PmRemoveDevice(extension, Irp);
|
|||
|
targetObject = extension->TargetObject;
|
|||
|
|
|||
|
if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
|
|||
|
status = IoAcquireRemoveLock (&extension->RemoveLock, Irp);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
IoReleaseRemoveLockAndWait(&extension->RemoveLock, Irp);
|
|||
|
IoDetachDevice(targetObject);
|
|||
|
IoDeleteDevice(extension->DeviceObject);
|
|||
|
}
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(targetObject, Irp);
|
|||
|
|
|||
|
default:
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmAddDevice(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates and initializes a new FDO for the corresponding
|
|||
|
PDO.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies the FTDISK driver object.
|
|||
|
|
|||
|
PhysicalDeviceObject - Supplies the physical device object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_OBJECT attachedDevice;
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
PDEVICE_EXTENSION extension;
|
|||
|
|
|||
|
attachedDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
|
|||
|
if (attachedDevice) {
|
|||
|
if (attachedDevice->Characteristics&FILE_REMOVABLE_MEDIA) {
|
|||
|
ObDereferenceObject(attachedDevice);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
ObDereferenceObject(attachedDevice);
|
|||
|
}
|
|||
|
|
|||
|
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
|
|||
|
NULL, FILE_DEVICE_DISK, 0, FALSE, &deviceObject);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|||
|
|
|||
|
//
|
|||
|
// the storage stack explicitly requires DO_POWER_PAGABLE to be
|
|||
|
// set in all filter drivers *unless* DO_POWER_INRUSH is set.
|
|||
|
// this is true even if the attached device doesn't set DO_POWER_PAGABLE
|
|||
|
//
|
|||
|
if (attachedDevice->Flags & DO_POWER_INRUSH) {
|
|||
|
deviceObject->Flags |= DO_POWER_INRUSH;
|
|||
|
} else {
|
|||
|
deviceObject->Flags |= DO_POWER_PAGABLE;
|
|||
|
}
|
|||
|
|
|||
|
extension = deviceObject->DeviceExtension;
|
|||
|
RtlZeroMemory(extension, sizeof(DEVICE_EXTENSION));
|
|||
|
extension->DeviceObject = deviceObject;
|
|||
|
extension->DriverExtension = IoGetDriverObjectExtension(DriverObject,
|
|||
|
PmAddDevice);
|
|||
|
extension->TargetObject =
|
|||
|
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
|
|||
|
if (!extension->TargetObject) {
|
|||
|
IoDeleteDevice(deviceObject);
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
extension->Pdo = PhysicalDeviceObject;
|
|||
|
InitializeListHead(&extension->PartitionList);
|
|||
|
KeInitializeEvent(&extension->PagingPathCountEvent,
|
|||
|
SynchronizationEvent, TRUE);
|
|||
|
InitializeListHead(&extension->SignatureList);
|
|||
|
InitializeListHead(&extension->GuidList);
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex, Executive,
|
|||
|
KernelMode, FALSE, NULL);
|
|||
|
InsertTailList(&extension->DriverExtension->DeviceExtensionList,
|
|||
|
&extension->ListEntry);
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
deviceObject->AlignmentRequirement =
|
|||
|
extension->TargetObject->AlignmentRequirement;
|
|||
|
|
|||
|
extension->PhysicalDeviceName.Buffer
|
|||
|
= extension->PhysicalDeviceNameBuffer;
|
|||
|
|
|||
|
// Allocate WMI library context
|
|||
|
|
|||
|
extension->WmilibContext =
|
|||
|
ExAllocatePoolWithTag(PagedPool, sizeof(WMILIB_CONTEXT),
|
|||
|
PARTMGR_TAG_PARTITION_ENTRY);
|
|||
|
if (extension->WmilibContext != NULL)
|
|||
|
{
|
|||
|
RtlZeroMemory(extension->WmilibContext, sizeof(WMILIB_CONTEXT));
|
|||
|
extension->WmilibContext->GuidCount = DiskperfGuidCount;
|
|||
|
extension->WmilibContext->GuidList = DiskperfGuidList;
|
|||
|
extension->WmilibContext->QueryWmiRegInfo = PmQueryWmiRegInfo;
|
|||
|
extension->WmilibContext->QueryWmiDataBlock = PmQueryWmiDataBlock;
|
|||
|
extension->WmilibContext->WmiFunctionControl = PmWmiFunctionControl;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeSpinLock(&extension->SpinLock);
|
|||
|
InitializeListHead(&extension->PowerQueue);
|
|||
|
|
|||
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
IoInitializeRemoveLock (&extension->RemoveLock, PARTMGR_TAG_REMOVE_LOCK,
|
|||
|
2, 5);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmUnload(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine unloads.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies the driver object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDO_EXTENSION driverExtension;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
|
|||
|
while (deviceObject = DriverObject->DeviceObject) {
|
|||
|
IoDeleteDevice(deviceObject);
|
|||
|
}
|
|||
|
|
|||
|
driverExtension = IoGetDriverObjectExtension(DriverObject, PmAddDevice);
|
|||
|
if (driverExtension) {
|
|||
|
IoUnregisterPlugPlayNotification(driverExtension->NotificationEntry);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmVolumeManagerNotification(
|
|||
|
IN PVOID NotificationStructure,
|
|||
|
IN PVOID DriverExtension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called whenever a volume comes or goes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NotificationStructure - Supplies the notification structure.
|
|||
|
|
|||
|
RootExtension - Supplies the root extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_INTERFACE_CHANGE_NOTIFICATION notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
|
|||
|
PDO_EXTENSION driverExtension = (PDO_EXTENSION) DriverExtension;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
NTSTATUS status;
|
|||
|
PLIST_ENTRY l, ll;
|
|||
|
PDEVICE_EXTENSION extension;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
PMWMICOUNTERLIB_CONTEXT input;
|
|||
|
PIRP irp;
|
|||
|
KEVENT event;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
PFILE_OBJECT fileObject;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
if (IsEqualGUID(¬ification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
|
|||
|
|
|||
|
for (l = driverExtension->VolumeManagerList.Flink;
|
|||
|
l != &driverExtension->VolumeManagerList; l = l->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
if (RtlEqualUnicodeString(notification->SymbolicLinkName,
|
|||
|
&volmgrEntry->VolumeManagerName,
|
|||
|
TRUE)) {
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
volmgrEntry = (PVOLMGR_LIST_ENTRY)
|
|||
|
ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
sizeof(VOLMGR_LIST_ENTRY),
|
|||
|
PARTMGR_TAG_VOLUME_ENTRY
|
|||
|
);
|
|||
|
if (!volmgrEntry) {
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
volmgrEntry->VolumeManagerName.Length =
|
|||
|
notification->SymbolicLinkName->Length;
|
|||
|
volmgrEntry->VolumeManagerName.MaximumLength =
|
|||
|
volmgrEntry->VolumeManagerName.Length + sizeof(WCHAR);
|
|||
|
volmgrEntry->VolumeManagerName.Buffer = ExAllocatePoolWithTag(
|
|||
|
PagedPool, volmgrEntry->VolumeManagerName.MaximumLength,
|
|||
|
PARTMGR_TAG_VOLUME_ENTRY);
|
|||
|
if (!volmgrEntry->VolumeManagerName.Buffer) {
|
|||
|
ExFreePool(volmgrEntry);
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
RtlCopyMemory(volmgrEntry->VolumeManagerName.Buffer,
|
|||
|
notification->SymbolicLinkName->Buffer,
|
|||
|
volmgrEntry->VolumeManagerName.Length);
|
|||
|
volmgrEntry->VolumeManagerName.Buffer[
|
|||
|
volmgrEntry->VolumeManagerName.Length/sizeof(WCHAR)] = 0;
|
|||
|
|
|||
|
volmgrEntry->RefCount = 0;
|
|||
|
InsertTailList(&driverExtension->VolumeManagerList,
|
|||
|
&volmgrEntry->ListEntry);
|
|||
|
volmgrEntry->VolumeManager = NULL;
|
|||
|
volmgrEntry->VolumeManagerFileObject = NULL;
|
|||
|
|
|||
|
status = IoGetDeviceObjectPointer(&volmgrEntry->VolumeManagerName,
|
|||
|
FILE_READ_DATA, &fileObject,
|
|||
|
&deviceObject);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
input.PmWmiCounterEnable = PmWmiCounterEnable;
|
|||
|
input.PmWmiCounterDisable = PmWmiCounterDisable;
|
|||
|
input.PmWmiCounterIoStart = PmWmiCounterIoStart;
|
|||
|
input.PmWmiCounterIoComplete = PmWmiCounterIoComplete;
|
|||
|
input.PmWmiCounterQuery = PmWmiCounterQuery;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_INTERNAL_VOLMGR_PMWMICOUNTERLIB_CONTEXT,
|
|||
|
deviceObject, &input, sizeof(input), NULL, 0, TRUE,
|
|||
|
&event, &ioStatus);
|
|||
|
|
|||
|
if (irp) {
|
|||
|
status = IoCallDriver(deviceObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ObDereferenceObject(fileObject);
|
|||
|
}
|
|||
|
|
|||
|
for (l = driverExtension->DeviceExtensionList.Flink;
|
|||
|
l != &driverExtension->DeviceExtensionList; l = l->Flink) {
|
|||
|
|
|||
|
extension = CONTAINING_RECORD(l, DEVICE_EXTENSION, ListEntry);
|
|||
|
|
|||
|
if (extension->IsRedundantPath) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
for (ll = extension->PartitionList.Flink;
|
|||
|
ll != &extension->PartitionList; ll = ll->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(ll, PARTITION_LIST_ENTRY,
|
|||
|
ListEntry);
|
|||
|
|
|||
|
if (!partition->VolumeManagerEntry) {
|
|||
|
status = PmGivePartition(volmgrEntry,
|
|||
|
partition->TargetObject,
|
|||
|
partition->WholeDiskPdo);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
partition->VolumeManagerEntry = volmgrEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else if (IsEqualGUID(¬ification->Event,
|
|||
|
&GUID_DEVICE_INTERFACE_REMOVAL)) {
|
|||
|
|
|||
|
for (l = driverExtension->VolumeManagerList.Flink;
|
|||
|
l != &driverExtension->VolumeManagerList; l = l->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
if (RtlEqualUnicodeString(&volmgrEntry->VolumeManagerName,
|
|||
|
notification->SymbolicLinkName, TRUE)) {
|
|||
|
|
|||
|
if (!volmgrEntry->RefCount) {
|
|||
|
RemoveEntryList(l);
|
|||
|
ExFreePool(volmgrEntry->VolumeManagerName.Buffer);
|
|||
|
ExFreePool(volmgrEntry);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmGetPartitionInformation(
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
OUT PLONGLONG PartitionOffset,
|
|||
|
OUT PLONGLONG PartitionLength
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
PARTITION_INFORMATION partInfo;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
|
|||
|
Partition, NULL, 0, &partInfo,
|
|||
|
sizeof(partInfo), FALSE, &event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|||
|
irpSp->FileObject = FileObject;
|
|||
|
|
|||
|
status = IoCallDriver(Partition, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
*PartitionOffset = partInfo.StartingOffset.QuadPart;
|
|||
|
*PartitionLength = partInfo.PartitionLength.QuadPart;
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmDriverReinit(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PVOID DriverExtension,
|
|||
|
IN ULONG Count
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PDO_EXTENSION driverExtension = DriverExtension;
|
|||
|
PLIST_ENTRY l, ll;
|
|||
|
PDEVICE_EXTENSION extension;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
InterlockedExchange(&driverExtension->PastReinit, TRUE);
|
|||
|
|
|||
|
for (l = driverExtension->DeviceExtensionList.Flink;
|
|||
|
l != &driverExtension->DeviceExtensionList; l = l->Flink) {
|
|||
|
|
|||
|
extension = CONTAINING_RECORD(l, DEVICE_EXTENSION, ListEntry);
|
|||
|
|
|||
|
if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!extension->IsStarted) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
for (ll = extension->PartitionList.Flink;
|
|||
|
ll != &extension->PartitionList; ll = ll->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(ll, PARTITION_LIST_ENTRY,
|
|||
|
ListEntry);
|
|||
|
|
|||
|
partition->TargetObject->Flags |= DO_DEVICE_INITIALIZING;
|
|||
|
}
|
|||
|
|
|||
|
status = PmReadPartitionTableEx(extension->TargetObject, &layout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (extension->DiskSignature) {
|
|||
|
if (layout->PartitionStyle == PARTITION_STYLE_MBR) {
|
|||
|
layout->Mbr.Signature = extension->DiskSignature;
|
|||
|
PmWritePartitionTableEx(extension->TargetObject, layout);
|
|||
|
}
|
|||
|
extension->DiskSignature = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (layout->PartitionStyle == PARTITION_STYLE_GPT) {
|
|||
|
PmAddSignatures(extension, layout);
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(layout);
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmBootDriverReinit(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PVOID DriverExtension,
|
|||
|
IN ULONG Count
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
IoRegisterDriverReinitialization(DriverObject, PmDriverReinit,
|
|||
|
DriverExtension);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmCheckForUnclaimedPartitions(
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PDO_EXTENSION driverExtension = extension->DriverExtension;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
PLIST_ENTRY l, ll;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
if (extension->IsRedundantPath) {
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
for (l = extension->PartitionList.Flink; l != &extension->PartitionList;
|
|||
|
l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
if (partition->VolumeManagerEntry) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
for (ll = driverExtension->VolumeManagerList.Flink;
|
|||
|
ll != &driverExtension->VolumeManagerList; ll = ll->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(ll, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
status = PmGivePartition(volmgrEntry,
|
|||
|
partition->TargetObject,
|
|||
|
partition->WholeDiskPdo);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
partition->VolumeManagerEntry = volmgrEntry;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ll == &driverExtension->VolumeManagerList) {
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmDiskGrowPartition(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDISK_GROW_PARTITION input;
|
|||
|
NTSTATUS status;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
KEVENT event;
|
|||
|
|
|||
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(DISK_GROW_PARTITION)) {
|
|||
|
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex, Executive,
|
|||
|
KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
input = (PDISK_GROW_PARTITION) Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
status = PmFindPartition(extension, input->PartitionNumber, &partition);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
status = PmChangePartitionIoctl(extension, partition,
|
|||
|
IOCTL_INTERNAL_VOLMGR_QUERY_CHANGE_PARTITION);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
|
|||
|
IoCallDriver(extension->TargetObject, Irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PmChangePartitionIoctl(extension, partition,
|
|||
|
IOCTL_INTERNAL_VOLMGR_PARTITION_CHANGED);
|
|||
|
} else {
|
|||
|
PmChangePartitionIoctl(extension, partition,
|
|||
|
IOCTL_INTERNAL_VOLMGR_CANCEL_CHANGE_PARTITION);
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmEjectVolumeManagers(
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine goes through the list of partitions for the given disk
|
|||
|
and takes the partition away from the owning volume managers. It then
|
|||
|
goes through initial arbitration for each partition on the volume.
|
|||
|
|
|||
|
This has the effect that each volume manager forgets any cached disk
|
|||
|
information and then start fresh on the disk as it may have been changed
|
|||
|
by another cluster member.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PDO_EXTENSION driverExtension = extension->DriverExtension;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
PLIST_ENTRY l;
|
|||
|
PVOLMGR_LIST_ENTRY volmgrEntry;
|
|||
|
|
|||
|
KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
|
|||
|
FALSE, NULL);
|
|||
|
|
|||
|
for (l = extension->PartitionList.Flink; l != &extension->PartitionList;
|
|||
|
l = l->Flink) {
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
if (!partition->VolumeManagerEntry) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
PmTakePartition(partition->VolumeManagerEntry,
|
|||
|
partition->TargetObject, NULL);
|
|||
|
|
|||
|
partition->VolumeManagerEntry = NULL;
|
|||
|
}
|
|||
|
|
|||
|
for (l = driverExtension->VolumeManagerList.Flink;
|
|||
|
l != &driverExtension->VolumeManagerList; l = l->Flink) {
|
|||
|
|
|||
|
volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
|
|||
|
PmTakeWholeDisk(volmgrEntry, extension->Pdo);
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&driverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDiskSignature(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the disk signature for the disk. If the
|
|||
|
volume is not an MBR disk then this call will fail.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PPARTMGR_DISK_SIGNATURE partSig = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
|||
|
|
|||
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|||
|
sizeof(PARTMGR_DISK_SIGNATURE)) {
|
|||
|
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = sizeof(PARTMGR_DISK_SIGNATURE);
|
|||
|
|
|||
|
if (extension->DiskSignature) {
|
|||
|
partSig->Signature = extension->DiskSignature;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
status = PmReadPartitionTableEx(extension->TargetObject, &layout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
if (layout->PartitionStyle != PARTITION_STYLE_MBR) {
|
|||
|
ExFreePool(layout);
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
partSig->Signature = layout->Mbr.Signature;
|
|||
|
|
|||
|
ExFreePool(layout);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmDeviceControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatch for IRP_MJ_PNP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
KEVENT event;
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVE_LAYOUT_INFORMATION layout;
|
|||
|
PDRIVE_LAYOUT_INFORMATION_EX newLayout;
|
|||
|
|
|||
|
if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|||
|
case IOCTL_DISK_SET_DRIVE_LAYOUT:
|
|||
|
case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:
|
|||
|
case IOCTL_DISK_CREATE_DISK:
|
|||
|
case IOCTL_DISK_DELETE_DRIVE_LAYOUT:
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
extension->SignaturesNotChecked = TRUE;
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE,
|
|||
|
TRUE, TRUE);
|
|||
|
IoCallDriver(extension->TargetObject, Irp);
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status = PmReadPartitionTableEx(extension->TargetObject,
|
|||
|
&newLayout);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
PmAddSignatures(extension, newLayout);
|
|||
|
extension->SignaturesNotChecked = FALSE;
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
ExFreePool(newLayout);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS:
|
|||
|
status = PmCheckForUnclaimedPartitions(DeviceObject);
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_GROW_PARTITION:
|
|||
|
status = PmDiskGrowPartition(DeviceObject, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_PARTMGR_EJECT_VOLUME_MANAGERS:
|
|||
|
status = PmEjectVolumeManagers(DeviceObject);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_PERFORMANCE:
|
|||
|
//
|
|||
|
// Verify user buffer is large enough for the performance data.
|
|||
|
//
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|||
|
sizeof(DISK_PERFORMANCE)) {
|
|||
|
|
|||
|
//
|
|||
|
// Indicate unsuccessful status and no data transferred.
|
|||
|
//
|
|||
|
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
}
|
|||
|
else if (!(extension->CountersEnabled)) {
|
|||
|
if (!PmQueryEnableAlways(DeviceObject)) {
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
if (status == STATUS_SUCCESS) {
|
|||
|
PmWmiCounterQuery(extension->PmWmiCounterContext,
|
|||
|
(PDISK_PERFORMANCE) Irp->AssociatedIrp.SystemBuffer,
|
|||
|
L"Partmgr ",
|
|||
|
extension->DiskNumber);
|
|||
|
Irp->IoStatus.Information = sizeof(DISK_PERFORMANCE);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_DISK_PERFORMANCE_OFF:
|
|||
|
//
|
|||
|
// Turns off counting
|
|||
|
//
|
|||
|
if (extension->CountersEnabled) {
|
|||
|
if (InterlockedCompareExchange(&extension->EnableAlways, 0, 1) == 1) {
|
|||
|
if (!PmWmiCounterDisable(&extension->PmWmiCounterContext, FALSE, FALSE)) {
|
|||
|
extension->CountersEnabled = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_PARTMGR_QUERY_DISK_SIGNATURE:
|
|||
|
case IOCTL_DISK_GET_DRIVE_LAYOUT:
|
|||
|
case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
|
|||
|
if (extension->SignaturesNotChecked) {
|
|||
|
|
|||
|
status = PmReadPartitionTableEx(extension->TargetObject,
|
|||
|
&newLayout);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&extension->DriverExtension->Mutex,
|
|||
|
Executive, KernelMode, FALSE, NULL);
|
|||
|
PmAddSignatures(extension, newLayout);
|
|||
|
extension->SignaturesNotChecked = FALSE;
|
|||
|
KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
ExFreePool(newLayout);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|||
|
IOCTL_PARTMGR_QUERY_DISK_SIGNATURE) {
|
|||
|
|
|||
|
status = PmQueryDiskSignature(DeviceObject, Irp);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Fall through.
|
|||
|
|
|||
|
default:
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
RTL_GENERIC_COMPARE_RESULTS
|
|||
|
PmTableSignatureCompareRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID First,
|
|||
|
IN PVOID Second
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PSIGNATURE_TABLE_ENTRY f = First;
|
|||
|
PSIGNATURE_TABLE_ENTRY s = Second;
|
|||
|
|
|||
|
if (f->Signature < s->Signature) {
|
|||
|
return GenericLessThan;
|
|||
|
}
|
|||
|
|
|||
|
if (f->Signature > s->Signature) {
|
|||
|
return GenericGreaterThan;
|
|||
|
}
|
|||
|
|
|||
|
return GenericEqual;
|
|||
|
}
|
|||
|
|
|||
|
RTL_GENERIC_COMPARE_RESULTS
|
|||
|
PmTableGuidCompareRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID First,
|
|||
|
IN PVOID Second
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PGUID_TABLE_ENTRY f = First;
|
|||
|
PGUID_TABLE_ENTRY s = Second;
|
|||
|
PULONGLONG p1, p2;
|
|||
|
|
|||
|
p1 = (PULONGLONG) &f->Guid;
|
|||
|
p2 = (PULONGLONG) &s->Guid;
|
|||
|
|
|||
|
if (p1[0] < p2[0]) {
|
|||
|
return GenericLessThan;
|
|||
|
}
|
|||
|
|
|||
|
if (p1[0] > p2[0]) {
|
|||
|
return GenericGreaterThan;
|
|||
|
}
|
|||
|
|
|||
|
if (p1[1] < p2[1]) {
|
|||
|
return GenericLessThan;
|
|||
|
}
|
|||
|
|
|||
|
if (p1[1] > p2[1]) {
|
|||
|
return GenericGreaterThan;
|
|||
|
}
|
|||
|
|
|||
|
return GenericEqual;
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
PmTableAllocateRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN CLONG Size
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
return ExAllocatePoolWithTag(PagedPool, Size, PARTMGR_TAG_TABLE_ENTRY);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PmTableFreeRoutine(
|
|||
|
IN PRTL_GENERIC_TABLE Table,
|
|||
|
IN PVOID Buffer
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
ExFreePool(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the entry point for the driver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies the driver object.
|
|||
|
|
|||
|
RegistryPath - Supplies the registry path for this driver.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
NTSTATUS status;
|
|||
|
PDO_EXTENSION driverExtension;
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
|
|||
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
|||
|
DriverObject->MajorFunction[i] = PmPassThrough;
|
|||
|
}
|
|||
|
|
|||
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PmDeviceControl;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_PNP] = PmPnp;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_POWER] = PmPower;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PmWmi;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_READ] = PmReadWrite;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = PmReadWrite;
|
|||
|
|
|||
|
DriverObject->DriverExtension->AddDevice = PmAddDevice;
|
|||
|
DriverObject->DriverUnload = PmUnload;
|
|||
|
|
|||
|
status = IoAllocateDriverObjectExtension(DriverObject, PmAddDevice,
|
|||
|
sizeof(DO_EXTENSION),
|
|||
|
&driverExtension);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
driverExtension->DiskPerfRegistryPath.MaximumLength =
|
|||
|
RegistryPath->Length + sizeof(UNICODE_NULL);
|
|||
|
driverExtension->DiskPerfRegistryPath.Buffer =
|
|||
|
ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
driverExtension->DiskPerfRegistryPath.MaximumLength,
|
|||
|
PARTMGR_TAG_PARTITION_ENTRY);
|
|||
|
if (driverExtension->DiskPerfRegistryPath.Buffer != NULL)
|
|||
|
{
|
|||
|
RtlCopyUnicodeString(&driverExtension->DiskPerfRegistryPath,
|
|||
|
RegistryPath);
|
|||
|
} else {
|
|||
|
driverExtension->DiskPerfRegistryPath.Length = 0;
|
|||
|
driverExtension->DiskPerfRegistryPath.MaximumLength = 0;
|
|||
|
}
|
|||
|
|
|||
|
driverExtension->DriverObject = DriverObject;
|
|||
|
InitializeListHead(&driverExtension->VolumeManagerList);
|
|||
|
InitializeListHead(&driverExtension->DeviceExtensionList);
|
|||
|
KeInitializeMutex(&driverExtension->Mutex, 0);
|
|||
|
driverExtension->PastReinit = FALSE;
|
|||
|
|
|||
|
RtlInitializeGenericTable(&driverExtension->SignatureTable,
|
|||
|
PmTableSignatureCompareRoutine,
|
|||
|
PmTableAllocateRoutine,
|
|||
|
PmTableFreeRoutine, driverExtension);
|
|||
|
|
|||
|
RtlInitializeGenericTable(&driverExtension->GuidTable,
|
|||
|
PmTableGuidCompareRoutine,
|
|||
|
PmTableAllocateRoutine,
|
|||
|
PmTableFreeRoutine, driverExtension);
|
|||
|
|
|||
|
IoRegisterBootDriverReinitialization(DriverObject, PmBootDriverReinit,
|
|||
|
driverExtension);
|
|||
|
|
|||
|
status = IoRegisterPlugPlayNotification(
|
|||
|
EventCategoryDeviceInterfaceChange,
|
|||
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|||
|
(PVOID) &VOLMGR_VOLUME_MANAGER_GUID, DriverObject,
|
|||
|
PmVolumeManagerNotification, driverExtension,
|
|||
|
&driverExtension->NotificationEntry);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
driverExtension->BootDiskSig = PmQueryRegistrySignature();
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmBuildDependantVolumeRelations(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
OUT PDEVICE_RELATIONS *Relations
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds a list of volumes which are dependant on a given
|
|||
|
physical disk. This list can be used for reporting removal relations
|
|||
|
to the pnp system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension for the pm filter.
|
|||
|
|
|||
|
Relations - Supplies a location to store the relations list.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG partitionCount;
|
|||
|
PIRP irp;
|
|||
|
PDEVICE_RELATIONS relationsList;
|
|||
|
PDEVICE_RELATIONS combinedList;
|
|||
|
|
|||
|
ULONG dependantVolumeCount = 0;
|
|||
|
|
|||
|
PLIST_ENTRY l;
|
|||
|
PPARTITION_LIST_ENTRY partition;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
KEVENT event;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
KeWaitForSingleObject(&Extension->DriverExtension->Mutex, Executive,
|
|||
|
KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Count the number of partitions we know about. If there aren't any then
|
|||
|
// there aren't any relations either.
|
|||
|
//
|
|||
|
|
|||
|
for(l = Extension->PartitionList.Flink, partitionCount = 0;
|
|||
|
l != &(Extension->PartitionList);
|
|||
|
l = l->Flink, partitionCount++);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the relations list.
|
|||
|
//
|
|||
|
|
|||
|
relationsList = ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
(sizeof(DEVICE_RELATIONS) +
|
|||
|
(sizeof(PDEVICE_RELATIONS) * partitionCount)),
|
|||
|
PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
|
|||
|
|
|||
|
if(relationsList== NULL) {
|
|||
|
KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(relationsList, (sizeof(DEVICE_RELATIONS) +
|
|||
|
sizeof(PDEVICE_OBJECT) * partitionCount));
|
|||
|
|
|||
|
if(partitionCount == 0) {
|
|||
|
*Relations = relationsList;
|
|||
|
KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|||
|
|
|||
|
for(l = Extension->PartitionList.Flink, i = 0, dependantVolumeCount = 0;
|
|||
|
l != &(Extension->PartitionList);
|
|||
|
l = l->Flink, i++) {
|
|||
|
|
|||
|
PDEVICE_RELATIONS dependantVolumes;
|
|||
|
|
|||
|
partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Check to make sure the volume has a volume manager. If it doesn't
|
|||
|
// then just skip to the next one.
|
|||
|
//
|
|||
|
|
|||
|
if(partition->VolumeManagerEntry == NULL) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
status = PmQueryDependantVolumeList(
|
|||
|
partition->VolumeManagerEntry->VolumeManager,
|
|||
|
partition->TargetObject,
|
|||
|
partition->WholeDiskPdo,
|
|||
|
&dependantVolumes);
|
|||
|
|
|||
|
if(!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Error getting this list. We'll need to release the lists from
|
|||
|
// the other partitions.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
dependantVolumeCount += dependantVolumes->Count;
|
|||
|
relationsList->Objects[i] = (PDEVICE_OBJECT) dependantVolumes;
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
|
|||
|
|
|||
|
relationsList->Count = i;
|
|||
|
|
|||
|
if(NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a new device relations list which can hold all the dependant
|
|||
|
// volumes for all the partitions.
|
|||
|
//
|
|||
|
|
|||
|
combinedList = ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
(sizeof(DEVICE_RELATIONS) +
|
|||
|
(sizeof(PDEVICE_OBJECT) * dependantVolumeCount)),
|
|||
|
PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
|
|||
|
} else {
|
|||
|
combinedList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if(combinedList != NULL) {
|
|||
|
|
|||
|
RtlZeroMemory(combinedList,
|
|||
|
(sizeof(DEVICE_RELATIONS) +
|
|||
|
(sizeof(PDEVICE_OBJECT) * dependantVolumeCount)));
|
|||
|
|
|||
|
//
|
|||
|
// For each partition list ...
|
|||
|
//
|
|||
|
|
|||
|
for(i = 0; i < relationsList->Count; i++) {
|
|||
|
|
|||
|
PDEVICE_RELATIONS volumeList;
|
|||
|
ULONG j;
|
|||
|
|
|||
|
volumeList = (PDEVICE_RELATIONS) relationsList->Objects[i];
|
|||
|
|
|||
|
//
|
|||
|
// We might have skipped this volume above. If we did the object
|
|||
|
// list should be NULL;
|
|||
|
//
|
|||
|
|
|||
|
if(volumeList == NULL) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For each dependant volume in that list ...
|
|||
|
//
|
|||
|
|
|||
|
for(j = 0; j < volumeList->Count; j++) {
|
|||
|
|
|||
|
PDEVICE_OBJECT volume;
|
|||
|
ULONG k;
|
|||
|
|
|||
|
volume = volumeList->Objects[j];
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if there's a duplicate in our combined list.
|
|||
|
//
|
|||
|
|
|||
|
for(k = 0; k < combinedList->Count; k++) {
|
|||
|
if(combinedList->Objects[k] == volume) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(k == combinedList->Count) {
|
|||
|
|
|||
|
//
|
|||
|
// We found no match - shove this object onto the end of
|
|||
|
// the set.
|
|||
|
//
|
|||
|
|
|||
|
combinedList->Objects[k] = volume;
|
|||
|
combinedList->Count++;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// We've got a spare reference to this device object.
|
|||
|
// release it.
|
|||
|
//
|
|||
|
|
|||
|
ObDereferenceObject(volume);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the list.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(volumeList);
|
|||
|
relationsList->Objects[i] = NULL;
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// For each partition list ...
|
|||
|
//
|
|||
|
|
|||
|
for(i = 0; i < relationsList->Count; i++) {
|
|||
|
|
|||
|
PDEVICE_RELATIONS volumeList;
|
|||
|
ULONG j;
|
|||
|
|
|||
|
volumeList = (PDEVICE_RELATIONS) relationsList->Objects[i];
|
|||
|
|
|||
|
//
|
|||
|
// For each dependant volume in that list ...
|
|||
|
//
|
|||
|
|
|||
|
for(j = 0; j < volumeList->Count; j++) {
|
|||
|
|
|||
|
PDEVICE_OBJECT volume;
|
|||
|
|
|||
|
volume = volumeList->Objects[j];
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the volume.
|
|||
|
//
|
|||
|
|
|||
|
ObDereferenceObject(volume);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the list.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(volumeList);
|
|||
|
relationsList->Objects[i] = NULL;
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the list of lists.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(relationsList);
|
|||
|
|
|||
|
*Relations = combinedList;
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmQueryDependantVolumeList(
|
|||
|
IN PDEVICE_OBJECT VolumeManager,
|
|||
|
IN PDEVICE_OBJECT Partition,
|
|||
|
IN PDEVICE_OBJECT WholeDiskPdo,
|
|||
|
OUT PDEVICE_RELATIONS *DependantVolumes
|
|||
|
)
|
|||
|
{
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
VOLMGR_PARTITION_INFORMATION input;
|
|||
|
VOLMGR_DEPENDANT_VOLUMES_INFORMATION output;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(DependantVolumes != NULL);
|
|||
|
|
|||
|
if (!VolumeManager) {
|
|||
|
*DependantVolumes = ExAllocatePoolWithTag(PagedPool,
|
|||
|
sizeof(DEVICE_RELATIONS),
|
|||
|
PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
|
|||
|
if (*DependantVolumes == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
(*DependantVolumes)->Count = 0;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
input.PartitionDeviceObject = Partition;
|
|||
|
input.WholeDiskPdo = WholeDiskPdo;
|
|||
|
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_INTERNAL_VOLMGR_REFERENCE_DEPENDANT_VOLUMES, VolumeManager,
|
|||
|
&input, sizeof(input), &output, sizeof(output), TRUE, &event,
|
|||
|
&ioStatus);
|
|||
|
|
|||
|
if (!irp) {
|
|||
|
*DependantVolumes = NULL;
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(VolumeManager, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
*DependantVolumes = output.DependantVolumeReferences;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmRemovePartition(
|
|||
|
IN PPARTITION_LIST_ENTRY Partition
|
|||
|
)
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
KEVENT event;
|
|||
|
|
|||
|
PIO_STACK_LOCATION nextStack;
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
irp = IoAllocateIrp(Partition->TargetObject->StackSize, FALSE);
|
|||
|
|
|||
|
if(irp == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|||
|
|
|||
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|||
|
|
|||
|
nextStack->MajorFunction = IRP_MJ_PNP;
|
|||
|
nextStack->MinorFunction = IRP_MN_REMOVE_DEVICE;
|
|||
|
|
|||
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|||
|
|
|||
|
IoSetCompletionRoutine(irp,
|
|||
|
PmSignalCompletion,
|
|||
|
&event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
|
|||
|
IoCallDriver(Partition->TargetObject, irp);
|
|||
|
|
|||
|
KeWaitForSingleObject(&event,
|
|||
|
KernelMode,
|
|||
|
Executive,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
status = irp->IoStatus.Status;
|
|||
|
|
|||
|
IoFreeIrp(irp);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmReadWrite(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatch for IRP_MJ_READ & _WRITE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
|
|||
|
Irp - Supplies the IO request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION extension =
|
|||
|
(PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
if (extension->CountersEnabled || extension->PhysicalDiskIoNotifyRoutine) {
|
|||
|
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
|
|||
|
|
|||
|
*nextIrpStack = *currentIrpStack;
|
|||
|
|
|||
|
if (extension->CountersEnabled) {
|
|||
|
PmWmiCounterIoStart(extension->PmWmiCounterContext,
|
|||
|
(PLARGE_INTEGER) ¤tIrpStack->Parameters.Read);
|
|||
|
}
|
|||
|
else { // need to calculate response time for tracing
|
|||
|
PmWmiGetClock(
|
|||
|
*((PLARGE_INTEGER)¤tIrpStack->Parameters.Read), NULL);
|
|||
|
}
|
|||
|
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
IoSetCompletionRoutine(Irp, PmIoCompletion, DeviceObject,
|
|||
|
TRUE, TRUE, TRUE);
|
|||
|
IoCallDriver(extension->TargetObject, Irp);
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(extension->TargetObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmIoCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will get control from the system at the completion of an IRP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - for the IRP.
|
|||
|
|
|||
|
Irp - The I/O request that just completed.
|
|||
|
|
|||
|
Context - Not used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The IRP status.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PPHYSICAL_DISK_IO_NOTIFY_ROUTINE notifyRoutine;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Context);
|
|||
|
|
|||
|
if (deviceExtension->CountersEnabled) {
|
|||
|
PmWmiCounterIoComplete(deviceExtension->PmWmiCounterContext, Irp,
|
|||
|
(PLARGE_INTEGER) &irpStack->Parameters.Read);
|
|||
|
}
|
|||
|
|
|||
|
notifyRoutine = deviceExtension->PhysicalDiskIoNotifyRoutine;
|
|||
|
if (notifyRoutine) {
|
|||
|
#ifdef NTPERF
|
|||
|
//
|
|||
|
// For now, only NTPERF needs this for tracing. Remove ifdef if it
|
|||
|
// is required for tracing in retail build
|
|||
|
//
|
|||
|
if (deviceExtension->CountersEnabled) {
|
|||
|
DISK_PERFORMANCE PerfCounters;
|
|||
|
PmWmiCounterQuery(deviceExtension->PmWmiCounterContext,
|
|||
|
&PerfCounters,
|
|||
|
L"Partmgr ",
|
|||
|
deviceExtension->DiskNumber);
|
|||
|
(*notifyRoutine) (deviceExtension->DiskNumber, Irp, &PerfCounters);
|
|||
|
} else {
|
|||
|
(*notifyRoutine) (deviceExtension->DiskNumber, Irp, NULL);
|
|||
|
}
|
|||
|
#else
|
|||
|
if (!deviceExtension->CountersEnabled) {
|
|||
|
LARGE_INTEGER completeTime;
|
|||
|
PLARGE_INTEGER response;
|
|||
|
response = (PLARGE_INTEGER) &irpStack->Parameters.Read;
|
|||
|
PmWmiGetClock(completeTime, NULL);
|
|||
|
response->QuadPart = completeTime.QuadPart - response->QuadPart;
|
|||
|
}
|
|||
|
(*notifyRoutine) (deviceExtension->DiskNumber, Irp, NULL);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmWmi(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles any WMI requests for information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Context for the activity.
|
|||
|
|
|||
|
Irp - The device control argument block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
NTSTATUS status;
|
|||
|
SYSCTL_IRP_DISPOSITION disposition;
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
if (irpSp->MinorFunction == IRP_MN_SET_TRACE_NOTIFY)
|
|||
|
{
|
|||
|
PVOID buffer = irpSp->Parameters.WMI.Buffer;
|
|||
|
ULONG bufferSize = irpSp->Parameters.WMI.BufferSize;
|
|||
|
|
|||
|
if (bufferSize < sizeof(PPHYSICAL_DISK_IO_NOTIFY_ROUTINE))
|
|||
|
{
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
} else {
|
|||
|
#ifdef NTPERF
|
|||
|
//
|
|||
|
// For NTPERF Build, automatically turn on counters for tracing
|
|||
|
//
|
|||
|
if ((deviceExtension->PhysicalDiskIoNotifyRoutine == NULL) &&
|
|||
|
(*((PVOID *)buffer) != NULL)) {
|
|||
|
PmWmiCounterEnable(&deviceExtension->PmWmiCounterContext);
|
|||
|
deviceExtension->CountersEnabled = TRUE;
|
|||
|
} else
|
|||
|
if ((deviceExtension->PhysicalDiskIoNotifyRoutine != NULL) &&
|
|||
|
(*((PVOID *)buffer) == NULL)) {
|
|||
|
deviceExtension->CountersEnabled =
|
|||
|
PmWmiCounterDisable(&deviceExtension->PmWmiCounterContext,
|
|||
|
FALSE, FALSE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
deviceExtension->PhysicalDiskIoNotifyRoutine
|
|||
|
= (PPHYSICAL_DISK_IO_NOTIFY_ROUTINE)
|
|||
|
*((PVOID *)buffer);
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|||
|
} else {
|
|||
|
if (deviceExtension->WmilibContext == NULL) {
|
|||
|
disposition = IrpForward;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
else {
|
|||
|
status = WmiSystemControl(deviceExtension->WmilibContext,
|
|||
|
DeviceObject,
|
|||
|
Irp,
|
|||
|
&disposition);
|
|||
|
}
|
|||
|
switch (disposition)
|
|||
|
{
|
|||
|
case IrpProcessed:
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IrpNotCompleted:
|
|||
|
{
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
{
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
status = IoCallDriver(deviceExtension->TargetObject, Irp);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return(status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmWmiFunctionControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN WMIENABLEDISABLECONTROL Function,
|
|||
|
IN BOOLEAN Enable
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to query for enabling or
|
|||
|
disabling events and data collection. When the driver has finished it
|
|||
|
must call WmiCompleteRequest to complete the irp. The driver can return
|
|||
|
STATUS_PENDING if the irp cannot be completed immediately.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose events or data collection are being
|
|||
|
enabled or disabled
|
|||
|
|
|||
|
Irp is the Irp that makes this request
|
|||
|
|
|||
|
GuidIndex is the index into the list of guids provided when the
|
|||
|
device registered
|
|||
|
|
|||
|
Function differentiates between event and data collection operations
|
|||
|
|
|||
|
Enable indicates whether to enable or disable
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_EXTENSION deviceExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
if (GuidIndex == 0)
|
|||
|
{
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
if (Function == WmiDataBlockControl) {
|
|||
|
if (!Enable) {
|
|||
|
deviceExtension->CountersEnabled =
|
|||
|
PmWmiCounterDisable(&deviceExtension->PmWmiCounterContext,
|
|||
|
FALSE, FALSE);
|
|||
|
} else
|
|||
|
if (NT_SUCCESS(status =
|
|||
|
PmWmiCounterEnable(&deviceExtension->PmWmiCounterContext))) {
|
|||
|
deviceExtension->CountersEnabled = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
status = WmiCompleteRequest(
|
|||
|
DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
0,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmReadPartitionTableEx(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine reads the partition table for the disk.
|
|||
|
|
|||
|
The partition list is built in nonpaged pool that is allocated by this
|
|||
|
routine. It is the caller's responsability to free this memory when it
|
|||
|
is finished with the data.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer for device object for this disk.
|
|||
|
|
|||
|
DriveLayout - Pointer to the pointer that will return the patition list.
|
|||
|
This buffer is allocated in nonpaged pool by this routine. It is
|
|||
|
the responsability of the caller to free this memory if this
|
|||
|
routine is successful.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
Status.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
PIRP Irp;
|
|||
|
KEVENT Event;
|
|||
|
PVOID IoCtlBuffer;
|
|||
|
ULONG IoCtlBufferSize;
|
|||
|
ULONG NewAllocationSize;
|
|||
|
ULONG NumTries;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize locals.
|
|||
|
//
|
|||
|
|
|||
|
NumTries = 0;
|
|||
|
IoCtlBuffer = NULL;
|
|||
|
IoCtlBufferSize = 0;
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the IOCTL buffer.
|
|||
|
//
|
|||
|
|
|||
|
IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
PAGE_SIZE,
|
|||
|
PARTMGR_TAG_IOCTL_BUFFER);
|
|||
|
|
|||
|
if (!IoCtlBuffer) {
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
IoCtlBufferSize = PAGE_SIZE;
|
|||
|
|
|||
|
//
|
|||
|
// First try to get the partition table by issuing an IOCTL.
|
|||
|
//
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the event is reset.
|
|||
|
//
|
|||
|
|
|||
|
KeClearEvent(&Event);
|
|||
|
|
|||
|
//
|
|||
|
// Build an IOCTL Irp.
|
|||
|
//
|
|||
|
|
|||
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
|||
|
DeviceObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
IoCtlBuffer,
|
|||
|
IoCtlBufferSize,
|
|||
|
FALSE,
|
|||
|
&Event,
|
|||
|
&IoStatus);
|
|||
|
if (!Irp) {
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call the driver.
|
|||
|
//
|
|||
|
|
|||
|
Status = IoCallDriver(DeviceObject, Irp);
|
|||
|
|
|||
|
if (Status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&Event,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Update status.
|
|||
|
//
|
|||
|
|
|||
|
Status = IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// We got it!
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != STATUS_BUFFER_TOO_SMALL) {
|
|||
|
|
|||
|
//
|
|||
|
// It is a real error.
|
|||
|
//
|
|||
|
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Resize IOCTL buffer. We should not enter the loop with a
|
|||
|
// NULL buffer.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(IoCtlBuffer && IoCtlBufferSize);
|
|||
|
|
|||
|
NewAllocationSize = IoCtlBufferSize * 2;
|
|||
|
|
|||
|
ExFreePool(IoCtlBuffer);
|
|||
|
IoCtlBufferSize = 0;
|
|||
|
|
|||
|
IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
NewAllocationSize,
|
|||
|
PARTMGR_TAG_IOCTL_BUFFER);
|
|||
|
|
|||
|
if (!IoCtlBuffer) {
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
IoCtlBufferSize = NewAllocationSize;
|
|||
|
|
|||
|
//
|
|||
|
// Try again with the new buffer but do not loop forever.
|
|||
|
//
|
|||
|
|
|||
|
NumTries++;
|
|||
|
|
|||
|
if (NumTries > 32) {
|
|||
|
Status = STATUS_UNSUCCESSFUL;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// If we came here we should have acquired the partition tables in
|
|||
|
// IoCtlBuffer.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
ASSERT(IoCtlBuffer && IoCtlBufferSize);
|
|||
|
|
|||
|
//
|
|||
|
// Set the output parameter and clear IoCtlBuffer so we don't free
|
|||
|
// it when we are cleaning up.
|
|||
|
//
|
|||
|
|
|||
|
(*DriveLayout) = (PDRIVE_LAYOUT_INFORMATION_EX) IoCtlBuffer;
|
|||
|
|
|||
|
IoCtlBuffer = NULL;
|
|||
|
IoCtlBufferSize = 0;
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
cleanup:
|
|||
|
|
|||
|
if (IoCtlBuffer) {
|
|||
|
ASSERT(IoCtlBufferSize);
|
|||
|
ExFreePool(IoCtlBuffer);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we were not successful with the IOCTL, pass the request off
|
|||
|
// to IoReadPartitionTableEx.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
Status = IoReadPartitionTableEx(DeviceObject,
|
|||
|
DriveLayout);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PmWritePartitionTableEx(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
ULONG layoutSize;
|
|||
|
KEVENT event;
|
|||
|
PIRP irp;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
|
|||
|
DriveLayout->PartitionCount*sizeof(PARTITION_INFORMATION_EX);
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
|
|||
|
DeviceObject, DriveLayout,
|
|||
|
layoutSize, NULL, 0, FALSE, &event,
|
|||
|
&ioStatus);
|
|||
|
if (!irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
status = IoCallDriver(DeviceObject, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|