Microsoft WDK 提供了DiskPerf 的代码例子,但没有说的很明白。
网络上、以及我身边的朋友,都有在询问和查找有关Windows磁盘过滤驱动的问题。
我在这篇帖子里面,写上自己对磁盘过滤驱动的理解和总结。 写的不好,请勿取笑。 大牛就漂过吧。
<<分析diskpref.sys的设备栈信息>>
kd> !drvobj diskperf
Driver object (8213c2c0) is for:
\Driver\diskperf
Driver Extension List: (id , addr)
Device Object list:
81ded020
kd> !devobj 81ded020
Device object (81ded020) is for:
\Driver\diskperf DriverObject 8213c2c0
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00000010
Vpb 81ccc1d8 DevExt 81ded0d8 DevObjExt 81ded1d8 Dope 8219e950
ExtensionFlags (0000000000)
AttachedTo (Lower) 8219e020 \Driver\PartMgr
Device queue is not busy.
kd> !devobj 8219e020
Device object (8219e020) is for:
\Driver\PartMgr DriverObject 82053cb0
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00000010
Vpb 821deb98 DevExt 8219e0d8 DevObjExt 8219e1e8 Dope 8213cc08
ExtensionFlags (0000000000)
AttachedDevice (Upper) 81ded020 \Driver\diskperf
AttachedTo (Lower) 82051030 \Driver\Disk
Device queue is not busy.
kd> !devobj 82051030
Device object (82051030) is for:
DR0 \Driver\Disk DriverObject 82053300
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00000050
Vpb 821a50b0 Dacl e132122c DevExt 820510e8 DevObjExt 82051548 Dope 81ccd418
ExtensionFlags (0000000000)
AttachedDevice (Upper) 8219e020 \Driver\PartMgr
AttachedTo (Lower) 82052a38 \Driver\vmscsi
Device queue is not busy.
kd> !devobj 82052a38
Device object (82052a38) is for:
vmscsi1Port1Path0Target0Lun0 \Driver\vmscsi DriverObject 8205e8b0
Current Irp 00000000 RefCount 0 Type 00000007 Flags 00001050
Dacl e132122c DevExt 82052af0 DevObjExt 82052fd0 Dope 82189178 DevNode 81ccb8e8
ExtensionFlags (0000000000)
AttachedDevice (Upper) 82051030 \Driver\Disk
Device queue is not busy.
Scsiport.sys:针对SCSI总线上的磁盘的端口驱动程序
Atapi.sys:针对IDE系统的端口驱动程序
这2个驱动都实现了磁盘调度算法:C-LOOK 卷参数块(VPB): 一个卷设备对象和代表该卷被挂载以后的文件系统实例(由某个文件系统驱动程序创建)之间的一个连接纽带。
包含在DEVICE_OBJECT数据结构中。
0: kd> dt _vpb 0x88469108
nt!_VPB
+0x000 Type : 10
+0x002 Size : 88
+0x004 Flags : 1 //该卷已挂载
+0x006 VolumeLabelLength : 0x14
+0x008 DeviceObject : 0x88722020 _DEVICE_OBJECT //指向被挂载的文件系统设备对象
+0x00c RealDevice : 0x8846ae20 _DEVICE_OBJECT //指向所属卷设备对象
+0x010 SerialNumber : 0x58884d3b
+0x014 ReferenceCount : 0x19
+0x018 VolumeLabel : [32] "New Volume" //文件系统驱动程序分配给该卷的名称 MountMgr.sys:挂载管理器设备驱动程序(一个功能驱动),其为以下设备分配驱动器字母:
在windows安装以后创建的动态磁盘卷和基本磁盘卷、CD-ROM、软盘驱动器和可移动设备。
其将字母分配信息存储在HKLM\SYSTEM\MountedDevices中。 下面,是DiskPerf.c代码的注释,帮助大家理解DiskPerf这个工程的代码内容。 #define INITGUID
#include "ntddk.h"
#include "ntdddisk.h"
#include "stdarg.h"
#include "stdio.h"
#include <ntddvol.h>
#include <mountdev.h>
#include "wmistr.h"
#include "wmidata.h"
#include "wmiguid.h"
#include "wmilib.h"
#include "ntstrsafe.h"
#ifdef POOL_TAGGING
#ifdef ExAllocatePool
#undef ExAllocatePool
#endif
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'frPD')
#endif
#define DISKPERF_MAXSTR 64 typedef struct _DEVICE_EXTENSION {
//
// Back pointer to device object
//
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT TargetDeviceObject;
PDEVICE_OBJECT PhysicalDeviceObject;
//
// Disk number for reference in WMI
//
ULONG DiskNumber;
//
// If device is enabled for counting always
//
LONG EnabledAlways;
//
// Use to keep track of Volume info from ntddvol.h
//
WCHAR StorageManagerName[8];
//
// Disk performance counters
// and locals used to compute counters
//
ULONG Processors;
PDISK_PERFORMANCE DiskCounters; // per processor counters
LARGE_INTEGER LastIdleClock;
LONG QueueDepth;
LONG CountersEnabled;
//
// 同步分页路径通知用
//
KEVENT PagingPathCountEvent;
LONG PagingPathCount;
//
// 物理设备名或者WMI 实例名字
//
UNICODE_STRING PhysicalDeviceName;
WCHAR PhysicalDeviceNameBuffer[DISKPERF_MAXSTR];
//
// Private context for using WmiLib
//
WMILIB_CONTEXT WmilibContext;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION)
#define PROCESSOR_COUNTERS_SIZE FIELD_OFFSET(DISK_PERFORMANCE, QueryTime)
/*
每个处理器的计数器的布局,是一个连续的内存块:
处理器1
+-----------------------+ +-----------------------+
|PROCESSOR_COUNTERS_SIZE| ... |PROCESSOR_COUNTERS_SIZE|
+-----------------------+ +-----------------------+
这里PROCESSOR_COUNTERS_SIZE比DISK_PERFORMANCE的尺寸要小,因为我们只统计实际使用的。
*/
UNICODE_STRING DiskPerfRegistryPath; //
// Function declarations
//
DRIVER_INITIALIZE DriverEntry;
DRIVER_ADD_DEVICE DiskPerfAddDevice;
DRIVER_DISPATCH DiskPerfForwardIrpSynchronous;
__drv_dispatchType(IRP_MJ_PNP)
DRIVER_DISPATCH DiskPerfDispatchPnp;
__drv_dispatchType(IRP_MJ_POWER)
DRIVER_DISPATCH DiskPerfDispatchPower;
DRIVER_DISPATCH DiskPerfSendToNextDriver;
__drv_dispatchType(IRP_MJ_CREATE)
DRIVER_DISPATCH DiskPerfCreate;
__drv_dispatchType(IRP_MJ_READ)
__drv_dispatchType(IRP_MJ_WRITE)
DRIVER_DISPATCH DiskPerfReadWrite;
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH DiskPerfDeviceControl;
__drv_dispatchType(IRP_MJ_SYSTEM_CONTROL)
DRIVER_DISPATCH DiskPerfWmi;
__drv_dispatchType(IRP_MJ_FLUSH_BUFFERS)
__drv_dispatchType(IRP_MJ_SHUTDOWN)
DRIVER_DISPATCH DiskPerfShutdownFlush;
DRIVER_DISPATCH DiskPerfStartDevice;
DRIVER_DISPATCH DiskPerfRemoveDevice;
IO_COMPLETION_ROUTINE DiskPerfIoCompletion;
IO_COMPLETION_ROUTINE DiskPerfIrpCompletion;
DRIVER_UNLOAD DiskPerfUnload; VOID
DiskPerfLogError(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG UniqueId,
IN NTSTATUS ErrorCode,
IN NTSTATUS Status
);
NTSTATUS
DiskPerfRegisterDevice(
IN PDEVICE_OBJECT DeviceObject
);
WMI_QUERY_REGINFO_CALLBACK DiskperfQueryWmiRegInfo;
WMI_QUERY_DATABLOCK_CALLBACK DiskperfQueryWmiDataBlock;
VOID
DiskPerfSyncFilterWithTarget(
IN PDEVICE_OBJECT FilterDevice,
IN PDEVICE_OBJECT TargetDevice
);
WMI_FUNCTION_CONTROL_CALLBACK DiskperfWmiFunctionControl;
VOID
DiskPerfAddCounters(
IN OUT PDISK_PERFORMANCE TotalCounters,
IN PDISK_PERFORMANCE NewCounters,
IN LARGE_INTEGER Frequency
);
#if DBG
ULONG DiskPerfDebug = 0;
VOID
DiskPerfDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
...
);
#define DebugPrint(x) DiskPerfDebugPrint x
#else
#define DebugPrint(x)
#endif
//
// Define the sections that allow for discarding (i.e. paging) some of
// the code.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, DiskPerfCreate)
#pragma alloc_text (PAGE, DiskPerfAddDevice)
#pragma alloc_text (PAGE, DiskPerfDispatchPnp)
#pragma alloc_text (PAGE, DiskPerfStartDevice)
#pragma alloc_text (PAGE, DiskPerfRemoveDevice)
#pragma alloc_text (PAGE, DiskPerfUnload)
#pragma alloc_text (PAGE, DiskPerfWmi)
#pragma alloc_text (PAGE, DiskperfQueryWmiRegInfo)
#pragma alloc_text (PAGE, DiskperfQueryWmiDataBlock)
#pragma alloc_text (PAGE, DiskPerfRegisterDevice)
#pragma alloc_text (PAGE, DiskPerfSyncFilterWithTarget)
#endif
WMIGUIDREGINFO DiskperfGuidList[] =
{
{ &DiskPerfGuid,
1,
0
}
};
#define DiskperfGuidCount (sizeof(DiskperfGuidList) / sizeof(WMIGUIDREGINFO))
#define USE_PERF_CTR
#ifdef USE_PERF_CTR
#define DiskPerfGetClock(a, b) (a) = KeQueryPerformanceCounter((b))
#else
#define DiskPerfGetClock(a, b) KeQuerySystemTime(&(a))
#endif NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
函数说明:
可安装驱动的初始化入口点。
这个方法直接被I/O管理器调用,用来创建磁盘性能驱动。这里的driver对象创建好,
然后Pnp管理器调用DiskPerfAddDevice来把它附加到启动设备上。 参数:
DriverObject – 磁盘性能驱动对象。
RegistryPath – 指向一个unicode的字符串,表示路径。也就是注册表中,驱动特定的键。 返回值:
STATUS_SUCCESS 如果成功的话
--*/
{
ULONG ulIndex;
PDRIVER_DISPATCH * dispatch;
//
// 保存注册表路径
//
DiskPerfRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
DiskPerfRegistryPath.Buffer = ExAllocatePool(
PagedPool,
DiskPerfRegistryPath.MaximumLength);
if (DiskPerfRegistryPath.Buffer != NULL)
{
RtlCopyUnicodeString(&DiskPerfRegistryPath, RegistryPath);
}
else
{
DiskPerfRegistryPath.Length = 0;
DiskPerfRegistryPath.MaximumLength = 0;
}
//
// 创建分派函数
//
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;
ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
ulIndex++, dispatch++)
{
*dispatch = DiskPerfSendToNextDriver;
}
//
// 创建设备驱动入口点
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = DiskPerfCreate;
DriverObject->MajorFunction[IRP_MJ_READ] = DiskPerfReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DiskPerfReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DiskPerfDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DiskPerfWmi;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = DiskPerfShutdownFlush;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = DiskPerfShutdownFlush;
DriverObject->MajorFunction[IRP_MJ_PNP] = DiskPerfDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = DiskPerfDispatchPower;
DriverObject->DriverExtension->AddDevice = DiskPerfAddDevice;
DriverObject->DriverUnload = DiskPerfUnload;
return(STATUS_SUCCESS);
}
#define FILTER_DEVICE_PROPOGATE_FLAGS 0
#define FILTER_DEVICE_PROPOGATE_CHARACTERISTICS (FILE_REMOVABLE_MEDIA | \
FILE_READ_ONLY_DEVICE | \
FILE_FLOPPY_DISKETTE \
)
VOID
DiskPerfSyncFilterWithTarget(
IN PDEVICE_OBJECT FilterDevice,
IN PDEVICE_OBJECT TargetDevice
)
{
ULONG propFlags;
PAGED_CODE();
//
// 把目标设备的一些有用标记复制到diskperf中。挂载管理器将查找
// diskperf对象的功能点,并且表明磁盘是可移动设备还是其他的设备
propFlags = TargetDevice->Flags & FILTER_DEVICE_PROPOGATE_FLAGS;
FilterDevice->Flags |= propFlags;
propFlags = TargetDevice->Characteristics & FILTER_DEVICE_PROPOGATE_CHARACTERISTICS;
FilterDevice->Characteristics |= propFlags; }
NTSTATUS
DiskPerfAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
方法说明:
为对应得物理设备对象(PDO=Physical Device Object)创建一个新的过滤设备对象(FiDO)。
然后把这个设备对象“粘”到驱动的堆栈上去。
参数:
DriverObject – 磁盘性能驱动对象。
PhysicalDeviceObject – 下层驱动的物理设备对象。
返回值:
NTSTATUS
--*/
{
NTSTATUS status;
PDEVICE_OBJECT filterDeviceObject;
PDEVICE_EXTENSION deviceExtension;
PWMILIB_CONTEXT wmilibContext;
PCHAR buffer;
ULONG buffersize;
PAGED_CODE();
//
// 为本设备创建一个过滤设备对象(分离)。
//
DebugPrint((2, "DiskPerfAddDevice: Driver %X Device %X\n",
DriverObject, PhysicalDeviceObject));
//注意FILE_DEVICE_DISK这个参数,这个用来表示你创建的设备需要“粘”到磁盘设备对象,
//如果这个参数弄错了,你可能就“粘”到其他地方去了。
status = IoCreateDevice(DriverObject,
DEVICE_EXTENSION_SIZE,
NULL,
FILE_DEVICE_DISK,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&filterDeviceObject);
if (!NT_SUCCESS(status))
{
DebugPrint((1, "DiskPerfAddDevice: Cannot create filterDeviceObject\n"));
return status;
}
filterDeviceObject->Flags |= DO_DIRECT_IO;
deviceExtension = (PDEVICE_EXTENSION) filterDeviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, DEVICE_EXTENSION_SIZE);
DiskPerfGetClock(deviceExtension->LastIdleClock, NULL);
DebugPrint((10, "DiskPerfAddDevice: LIC=%I64u\n",
deviceExtension->LastIdleClock));
//
// 为每个处理器分配计数器
//
// 注意:为了节省内存,我们不必为QueryTime分配额外的内存。
// 如果有额外需要的话,记录需要的额外的内存大小。
//
#if (NTDDI_VERSION >= NTDDI_WIN7)
deviceExtension->Processors = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
#elif (NTDDI_VERSION >= NTDDI_VISTA)
deviceExtension->Processors = KeQueryActiveProcessorCount(NULL);
#else
deviceExtension->Processors = KeNumberProcessors;
#endif
buffersize= PROCESSOR_COUNTERS_SIZE * deviceExtension->Processors;
buffer = (PCHAR) ExAllocatePool(NonPagedPool, buffersize);
if (buffer != NULL)
{
RtlZeroMemory(buffer, buffersize);
deviceExtension->DiskCounters = (PDISK_PERFORMANCE) buffer;
}
else
{
DiskPerfLogError(
filterDeviceObject,
513,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
}
//
// 把设备对象“粘”到设备链中最高层的设备对象中,同时返回上次的最高层设备对象,
// 这个用来在调用IoCallDriver把IRP下发的时候用。
//
deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
deviceExtension->TargetDeviceObject =
IoAttachDeviceToDeviceStack(filterDeviceObject, PhysicalDeviceObject);
if (deviceExtension->TargetDeviceObject == NULL) {
ExFreePool(deviceExtension->DiskCounters);
deviceExtension->DiskCounters = NULL;
IoDeleteDevice(filterDeviceObject);
DebugPrint((1, "DiskPerfAddDevice: Unable to attach %X to target %X\n",
filterDeviceObject, PhysicalDeviceObject));
return STATUS_NO_SUCH_DEVICE;
}
//
// 在device extension中保存过滤设备对象。
//
deviceExtension->DeviceObject = filterDeviceObject;
deviceExtension->PhysicalDeviceName.Buffer
= deviceExtension->PhysicalDeviceNameBuffer;
KeInitializeEvent(&deviceExtension->PagingPathCountEvent,
NotificationEvent, TRUE); //
// 初始化WMI库上下文
//
wmilibContext = &deviceExtension->WmilibContext;
RtlZeroMemory(wmilibContext, sizeof(WMILIB_CONTEXT));
wmilibContext->GuidCount = DiskperfGuidCount;
wmilibContext->GuidList = DiskperfGuidList;
wmilibContext->QueryWmiRegInfo = DiskperfQueryWmiRegInfo;
wmilibContext->QueryWmiDataBlock = DiskperfQueryWmiDataBlock;
wmilibContext->WmiFunctionControl = DiskperfWmiFunctionControl;
//
// 默认DO_POWER_PAGABLE
//
filterDeviceObject->Flags |= DO_POWER_PAGABLE; //
// 清除DO_DEVICE_INITIALIZING标记
//
filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
} NTSTATUS
DiskPerfDispatchPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Dispatch for PNP
Arguments:
DeviceObject - Supplies the device object.
Irp - Supplies the I/O request packet.
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PAGED_CODE();
DebugPrint((2, "DiskPerfDispatchPnp: Device %X Irp %X\n",
DeviceObject, Irp));
switch(irpSp->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// 调用StartRoutine
//
DebugPrint((3,
"DiskPerfDispatchPnp: Schedule completion for START_DEVICE"));
status = DiskPerfStartDevice(DeviceObject, Irp);
break;
case IRP_MN_REMOVE_DEVICE:
{
//
// 调用移除方法
//
DebugPrint((3,
"DiskPerfDispatchPnp: Schedule completion for REMOVE_DEVICE"));
status = DiskPerfRemoveDevice(DeviceObject, Irp);
break;
}
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
{
PIO_STACK_LOCATION irpStack;
BOOLEAN setPagable;
DebugPrint((3,
"DiskPerfDispatchPnp: Processing DEVICE_USAGE_NOTIFICATION"));
irpStack = IoGetCurrentIrpStackLocation(Irp);
if (irpStack->Parameters.UsageNotification.Type != DeviceUsageTypePaging) {
status = DiskPerfSendToNextDriver(DeviceObject, Irp);
break; // out of case statement
}
deviceExtension = DeviceObject->DeviceExtension;
//
// 等待分页路径事件
//
status = KeWaitForSingleObject(&deviceExtension->PagingPathCountEvent,
Executive, KernelMode,
FALSE, NULL);
//
// 如果移除上一次分页的设备,需要设置DO_POWER_PAGABLE
// 如果失败,则清除这个标志
//
setPagable = FALSE;
if (!irpStack->Parameters.UsageNotification.InPath &&
deviceExtension->PagingPathCount == 1 ) {
//
// removing the last paging file
// must have DO_POWER_PAGABLE bits set
//
if (DeviceObject->Flags & DO_POWER_INRUSH) {
DebugPrint((3, "DiskPerfDispatchPnp: last paging file "
"removed but DO_POWER_INRUSH set, so not "
"setting PAGABLE bit "
"for DO %p\n", DeviceObject));
} else {
DebugPrint((2, "DiskPerfDispatchPnp: Setting PAGABLE "
"bit for DO %p\n", DeviceObject));
DeviceObject->Flags |= DO_POWER_PAGABLE;
setPagable = TRUE;
}
}
//
// 同步发送irp
//
status = DiskPerfForwardIrpSynchronous(DeviceObject, Irp);
//
// 处理成功和失败的情况。
// 注意,发送到下层驱动后,irp不允许失败。
//
if (NT_SUCCESS(status))
{
IoAdjustPagingPathCount(
&deviceExtension->PagingPathCount,
irpStack->Parameters.UsageNotification.InPath);
if (irpStack->Parameters.UsageNotification.InPath)
{
if (deviceExtension->PagingPathCount == 1)
{
//
// 分页文件第1条件
//
DebugPrint((3, "DiskPerfDispatchPnp: Clearing PAGABLE bit "
"for DO %p\n", DeviceObject));
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
}
}
}
else
{
//
// 清除上文的改变
//
if (setPagable == TRUE)
{
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
setPagable = FALSE;
}
}
//
// 设置事件,以便下一个事件可以触发
//
KeSetEvent(&deviceExtension->PagingPathCountEvent,
IO_NO_INCREMENT, FALSE);
//
// complete the irp
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
break;
}
default:
DebugPrint((3,
"DiskPerfDispatchPnp: Forwarding irp"));
//
// 简单的转发所有其他的Irp
//
return DiskPerfSendToNextDriver(DeviceObject, Irp);
}
return status;
} // end DiskPerfDispatchPnp() NTSTATUS
DiskPerfIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
函数说明:
转发IRP完成方法。设置一个事件并且返回STATUS_MORE_PROCESSING_REQUIRED,
这样Irp转发的时候会等待这个事件,然后在清理工作完成后再次完成。 参数:
DeviceObject 是WMI驱动的设备对象。
Irp 就是WMI的irp
Context 是转发器等待的事件句柄 PKEVENT。
返回值:
STATUS_MORE_PORCESSING_REQUIRED
--*/
{
PKEVENT Event = (PKEVENT) Context;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
return(STATUS_MORE_PROCESSING_REQUIRED);
} NTSTATUS
DiskPerfStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明:
当收到Pnp启动Irp时调用本函数。
它将调用完成函数,初始化和注册WMI。
参数:
DeviceObject - 指向设备对象的指针
Irp – 指向irp的指针 返回值:
处理开始Irp的状态
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS status;
PAGED_CODE();
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = DiskPerfForwardIrpSynchronous(DeviceObject, Irp);
DiskPerfSyncFilterWithTarget(DeviceObject,
deviceExtension->TargetDeviceObject);
//
// 完成WMI注册
//
DiskPerfRegisterDevice(DeviceObject);
//
// Complete the Irp
//
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
} NTSTATUS
DiskPerfRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明:
当设备被移除时调用此函数。
首先将把自身从WMI反注册,删除自身前把自己从设备栈上移除。 参数:
DeviceObject – 指向设备对象的指针
Irp – 指向irp的指针 返回值:
移除设备后的状态
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PWMILIB_CONTEXT wmilibContext;
PAGED_CODE();
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//
// Remove registration with WMI first
//
IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER);
//
// 尽快把计数器清零,来把结构置为不可用
//
wmilibContext = &deviceExtension->WmilibContext;
InterlockedExchange((PLONG) &(wmilibContext->GuidCount), (LONG) 0);
RtlZeroMemory(wmilibContext, sizeof(WMILIB_CONTEXT));
status = DiskPerfForwardIrpSynchronous(DeviceObject, Irp);
if (deviceExtension->DiskCounters) {
ExFreePool(deviceExtension->DiskCounters);
}
IoDetachDevice(deviceExtension->TargetDeviceObject);
IoDeleteDevice(DeviceObject);
//
// Complete the Irp
//
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
} NTSTATUS
DiskPerfSendToNextDriver(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
当本驱动不处理某个Irp时,这个函数发送Irp到队列的下一个驱动 参数:
DeviceObject
Irp
返回值:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
} NTSTATUS
DiskPerfDispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
/*
响应电源管理
*/
PDEVICE_EXTENSION deviceExtension; #if (NTDDI_VERSION < NTDDI_VISTA)
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
return PoCallDriver(deviceExtension->TargetDeviceObject, Irp);
#else
IoSkipCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
#endif
} NTSTATUS
DiskPerfForwardIrpSynchronous(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明:
当Irp需要底层驱动优先处理的时候,把本Irp发送到下一个驱动处理。
参数:
DeviceObject
Irp
返回值:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension;
KEVENT event;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//
// 把irp堆栈拷贝到下一个设备
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// 设置完成例程
//
IoSetCompletionRoutine(Irp, DiskPerfIrpCompletion,
&event, TRUE, TRUE, TRUE);
//
// 调用更低层设备
//
status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp); //
// 等待真正完成
//
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
} NTSTATUS
DiskPerfCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明:
这个函数接受打开命令。通过状态返回建立驱动。 参数:
DeviceObject – 活动的上下文
Irp - 设备控制参数块
返回值:
NT 状态
--*/
{
PAGED_CODE();
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
} NTSTATUS
DiskPerfReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
方法说明:
这是diskperf驱动粘帖到的磁盘的读写入口点。
这个驱动收集统计信息并且设置完成方法,当请求完成时可以收集额外的信息。然后调用下层的驱动。 参数:
DeviceObject
Irp
返回值:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
#if (NTDDI_VERSION >= NTDDI_WIN7)
ULONG processor = KeGetCurrentProcessorNumberEx(NULL);
#else
ULONG processor = KeGetCurrentProcessorNumber();
#endif
PDISK_PERFORMANCE partitionCounters = NULL;
LONG queueLen;
PLARGE_INTEGER timeStamp;
//
// 因为处理器可能动态添加,确保这里有当前处理器的上下文环境。
//
if (deviceExtension->DiskCounters != NULL &&
processor < deviceExtension->Processors) {
partitionCounters = (PDISK_PERFORMANCE)
((PCHAR) deviceExtension->DiskCounters
+ (processor*PROCESSOR_COUNTERS_SIZE));
}
//
// 设备没有合适的初始化。只能盲目的传递irp
//
if (deviceExtension->CountersEnabled <= 0 ||
deviceExtension->PhysicalDeviceNameBuffer[0] == 0 ||
partitionCounters == NULL) {
return DiskPerfSendToNextDriver(DeviceObject, Irp);
}
//
// 增加队列深度计数
//
queueLen = InterlockedIncrement(&deviceExtension->QueueDepth);
//
// 把当前的堆栈拷贝到下一个堆栈
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// 当前请求开始的时间戳
//
timeStamp = (PLARGE_INTEGER) ¤tIrpStack->Parameters.Read;
DiskPerfGetClock(*timeStamp, NULL);
DebugPrint((10, "DiskPerfReadWrite: TS=%I64u\n", *timeStamp));
if (queueLen == 1)
{
partitionCounters->IdleTime.QuadPart
+= timeStamp->QuadPart -
deviceExtension->LastIdleClock.QuadPart;
deviceExtension->LastIdleClock.QuadPart = timeStamp->QuadPart;
}
//
// Set completion routine callback.
//
IoSetCompletionRoutine(Irp,
DiskPerfIoCompletion,
DeviceObject,
TRUE,
TRUE,
TRUE);
//
// 返回所有调用磁盘驱动的结果
//
return IoCallDriver(deviceExtension->TargetDeviceObject,
Irp);
} NTSTATUS
DiskPerfIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
函数说明:
完成一个IRP后,本方法从系统获取控制。
它将计算IRP开始时间和当前时间的差异,然后减小队列深度。 参数:
DeviceObject – 为IRP准备
Irp - 刚完成的I/O请求。
Context - 未使用
返回值:
IRP 的状态
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
#if (NTDDI_VERSION >= NTDDI_WIN7)
ULONG processor = KeGetCurrentProcessorNumberEx(NULL);
#else
ULONG processor = KeGetCurrentProcessorNumber();
#endif
PDISK_PERFORMANCE partitionCounters = NULL;
LARGE_INTEGER timeStampComplete;
PLARGE_INTEGER difference;
LONG queueLen;
UNREFERENCED_PARAMETER(Context);
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
//
// 当前请求完成的时间戳
//
difference = (PLARGE_INTEGER) &irpStack->Parameters.Read;
DiskPerfGetClock(timeStampComplete, NULL);
difference->QuadPart = timeStampComplete.QuadPart - difference->QuadPart;
DebugPrint((10, "DiskPerfIoCompletion: TS=%I64u diff %I64u\n",
timeStampComplete, difference->QuadPart));
//
// 减少卷的队列深度计数。
// 这个不需要自旋锁,使用Interlocked函数完成即可。
// 这是唯一合法的方法。
//
//
queueLen = InterlockedDecrement(&deviceExtension->QueueDepth);
if (queueLen < 0) { // do not over-decrement. Only happens at start
queueLen = InterlockedIncrement(&deviceExtension->QueueDepth);
}
if (queueLen == 0) {
deviceExtension->LastIdleClock = timeStampComplete;
}
//
// 更新计数器,但是,仅当在单处理器具有预分配上下文时才使用。
//
if (deviceExtension->DiskCounters != NULL &&
processor < deviceExtension->Processors) {
partitionCounters = (PDISK_PERFORMANCE)
((PCHAR) deviceExtension->DiskCounters
+ (processor*PROCESSOR_COUNTERS_SIZE));
}
if (partitionCounters == NULL) {
return STATUS_SUCCESS;
};
if (irpStack->MajorFunction == IRP_MJ_READ) {
//
// 增加这个请求的字节数。用字节来表示读取计数器。
//
partitionCounters->BytesRead.QuadPart += Irp->IoStatus.Information; //
// 增加读取请求的处理计数器。
//
partitionCounters->ReadCount++;
//
// 计算请求处理时间。
//
partitionCounters->ReadTime.QuadPart += difference->QuadPart;
DebugPrint((11, "Added RT delta %I64u total %I64u qlen=%d\n",
difference->QuadPart, partitionCounters->ReadTime.QuadPart,
queueLen));
}
else
{
//
// 增加这个请求的字节数。用字节来表示写入计数器。
//
partitionCounters->BytesWritten.QuadPart += Irp->IoStatus.Information;
//
// 增加写入请求的处理计数器。
//
partitionCounters->WriteCount++;
//
// 计算请求处理时间
//
partitionCounters->WriteTime.QuadPart += difference->QuadPart;
DebugPrint((11, "Added WT delta %I64u total %I64u qlen=%d\n",
difference->QuadPart, partitionCounters->WriteTime.QuadPart,
queueLen));
}
if (Irp->Flags & IRP_ASSOCIATED_IRP)
{
partitionCounters->SplitCount++;
}
return STATUS_SUCCESS;
} NTSTATUS
DiskPerfDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
函数说明:
设备控制分派函数,只处理磁盘性能设备控制。
所有其他的控制命令都直接发送给下层磁盘驱动。
磁盘性能驱动返回当前的性能数据快照。 参数:
DeviceObject – 活动上下文
Irp - 设备控制参数快
返回值:
返回状态。
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
DebugPrint((2, "DiskPerfDeviceControl: DeviceObject %X Irp %X\n",
DeviceObject, Irp));
if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_DISK_PERFORMANCE) {
NTSTATUS status;
//
// 校验对于性能数据来说用户缓冲区是否够大。
//
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(DISK_PERFORMANCE))
{
//
// 表示非成功状态,没有数据传输。
//
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
}
else
{
ULONG i;
PDISK_PERFORMANCE totalCounters;
PDISK_PERFORMANCE diskCounters = deviceExtension->DiskCounters;
LARGE_INTEGER frequency, perfctr;
if (diskCounters == NULL)
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
if (InterlockedCompareExchange(&deviceExtension->EnabledAlways, 1, 0) == 0)
{
InterlockedIncrement(&deviceExtension->CountersEnabled);
//
// reset per processor counters only
//
if (deviceExtension->DiskCounters != NULL)
{
RtlZeroMemory(deviceExtension->DiskCounters, PROCESSOR_COUNTERS_SIZE * deviceExtension->Processors);
}
DiskPerfGetClock(deviceExtension->LastIdleClock, NULL);
deviceExtension->QueueDepth = 0;
DebugPrint((10, "DiskPerfDeviceControl: LIC=%I64u\n", deviceExtension->LastIdleClock));
DebugPrint((3, "DiskPerfDeviceControl: Counters enabled %d\n", deviceExtension->CountersEnabled));
}
totalCounters = (PDISK_PERFORMANCE) Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(totalCounters, sizeof(DISK_PERFORMANCE));
#ifdef USE_PERF_CTR
perfctr = KeQueryPerformanceCounter(&frequency);
#endif
KeQuerySystemTime(&totalCounters->QueryTime);
for (i=0; i<deviceExtension->Processors; i++)
{
DiskPerfAddCounters(totalCounters, diskCounters, frequency);
diskCounters = (PDISK_PERFORMANCE)
((PCHAR) diskCounters + PROCESSOR_COUNTERS_SIZE);
}
totalCounters->QueueDepth = deviceExtension->QueueDepth;
if (totalCounters->QueueDepth == 0)
{
LARGE_INTEGER difference;
difference.QuadPart =
#ifdef USE_PERF_CTR
perfctr.QuadPart
#else
totalCounters->QueryTime.QuadPart
#endif
- deviceExtension->LastIdleClock.QuadPart;
if (difference.QuadPart > 0)
{
totalCounters->IdleTime.QuadPart +=
#ifdef USE_PERF_CTR
10000000 * difference.QuadPart / frequency.QuadPart;
#else
difference.QuadPart;
#endif
}
}
totalCounters->StorageDeviceNumber
= deviceExtension->DiskNumber;
RtlCopyMemory(
&totalCounters->StorageManagerName[0],
&deviceExtension->StorageManagerName[0],
8 * sizeof(WCHAR));
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(DISK_PERFORMANCE);
}
//
// Complete request.
//
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
else {
//
// 将当前的堆栈回退1。
//
Irp->CurrentLocation++,
Irp->Tail.Overlay.CurrentStackLocation++;
//传递未识别的设备控制查询到下层驱动
//
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
}
} NTSTATUS DiskPerfWmi(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明:
这个函数处理WMI的信息请求。由于磁盘性能信息是只读的,所以总是收集数据,
没有任何的事件,除非是QueryAllData,QuerySingleInstance和GetRegInfo请求支持的事件。 参数:
DeviceObject – 活动的上下文
Irp - 设备控制参数块
返回值:
返回的状态
--*/
{
PIO_STACK_LOCATION irpSp;
NTSTATUS status;
PWMILIB_CONTEXT wmilibContext;
SYSCTL_IRP_DISPOSITION disposition;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
DebugPrint((2, "DiskPerfWmi: DeviceObject %X Irp %X\n", DeviceObject, Irp));
wmilibContext = &deviceExtension->WmilibContext;
if (wmilibContext->GuidCount == 0) // wmilibContext is not valid
{
DebugPrint((3, "DiskPerfWmi: WmilibContext invalid"));
return DiskPerfSendToNextDriver(DeviceObject, Irp);
}
irpSp = IoGetCurrentIrpStackLocation(Irp);
DebugPrint((3, "DiskPerfWmi: Calling WmiSystemControl\n"));
status = WmiSystemControl(wmilibContext,
DeviceObject,
Irp,
&disposition);
switch (disposition)
{
case IrpProcessed:
{
break;
}
case IrpNotCompleted:
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
// case IrpForward:
// case IrpNotWmi:
default:
{
status = DiskPerfSendToNextDriver(DeviceObject, Irp);
break;
}
}
return(status);
} NTSTATUS
DiskPerfShutdownFlush(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
函数说明: 关闭或者刷新IRP时候调用本函数。在系统真正关闭之前或者系统刷新时发送这些IRP。 参数:
DriverObject –指向将被系统关闭的设备对象。
Irp -包含的Irp
返回值:
NT 状态
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
DebugPrint((2, "DiskPerfShutdownFlush: DeviceObject %X Irp %X\n",
DeviceObject, Irp));
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
} VOID
DiskPerfUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
函数说明:
释放所有分配的资源.。
参数:
DriverObject - 指向驱动对象。
返回值:
VOID.
--*/
{
PAGED_CODE();
UNREFERENCED_PARAMETER(DriverObject);
return;
} NTSTATUS
DiskPerfRegisterDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
函数说明:
为设备初始化合适的名字,并且向WMI注册。 参数:
DeviceObject – 指向需要初始化的设备对象。
返回值:
初始化的状态。注意:如果注册失败,DeviceExtension中的设备名称将为空。
--*/
{
NTSTATUS status;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
STORAGE_DEVICE_NUMBER number;
ULONG registrationFlag = 0;
PAGED_CODE();
DebugPrint((2, "DiskPerfRegisterDevice: DeviceObject %X\n",
DeviceObject));
deviceExtension = DeviceObject->DeviceExtension;
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// 请求设备号
//
irp = IoBuildDeviceIoControlRequest(
IOCTL_STORAGE_GET_DEVICE_NUMBER,
deviceExtension->TargetDeviceObject,
NULL,
0,
&number,
sizeof(number),
FALSE,
&event,
&ioStatus);
if (!irp)
{
DiskPerfLogError(
DeviceObject,
256,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
DebugPrint((3, "DiskPerfRegisterDevice: Fail to build irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (NT_SUCCESS(status)) {
//
// 保存设备号,作为DiskIoNotifyRoutine的参数使用。
//
deviceExtension->DiskNumber = number.DeviceNumber;
//
// 为每个分区创建设备名字
//
RtlStringCbPrintfW(
deviceExtension->PhysicalDeviceNameBuffer,
sizeof(deviceExtension->PhysicalDeviceNameBuffer),
L"\\Device\\Harddisk%d\\Partition%d",
number.DeviceNumber, number.PartitionNumber);
RtlInitUnicodeString(&deviceExtension->PhysicalDeviceName, &deviceExtension->PhysicalDeviceNameBuffer[0]);
//
// 为物理磁盘设置默认名字
//
RtlCopyMemory(
&(deviceExtension->StorageManagerName[0]),
L"PhysDisk",
8 * sizeof(WCHAR));
DebugPrint((3, "DiskPerfRegisterDevice: Device name %ws\n",
deviceExtension->PhysicalDeviceNameBuffer));
}
else
{
// request for partition's information failed, try volume
ULONG outputSize = sizeof(MOUNTDEV_NAME);
PMOUNTDEV_NAME output;
VOLUME_NUMBER volumeNumber;
ULONG nameSize;
output = ExAllocatePool(PagedPool, outputSize);
if (!output)
{
DiskPerfLogError(
DeviceObject,
257,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
deviceExtension->TargetDeviceObject, NULL, 0,
output, outputSize, FALSE, &event, &ioStatus);
if (!irp)
{
ExFreePool(output);
DiskPerfLogError(
DeviceObject,
258,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (status == STATUS_BUFFER_OVERFLOW)
{
outputSize = sizeof(MOUNTDEV_NAME) + output->NameLength;
ExFreePool(output);
output = ExAllocatePool(PagedPool, outputSize);
if (!output)
{
DiskPerfLogError(
DeviceObject,
258,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
deviceExtension->TargetDeviceObject, NULL, 0,
output, outputSize, FALSE, &event, &ioStatus);
if (!irp) {
ExFreePool(output);
DiskPerfLogError(
DeviceObject, 259,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
NULL
);
status = ioStatus.Status;
}
}
if (!NT_SUCCESS(status)) {
ExFreePool(output);
DiskPerfLogError(
DeviceObject,
260,
STATUS_SUCCESS,
IO_ERR_CONFIGURATION_ERROR);
return status;
}
//
// 我们得到卷的名字来代替磁盘数量,因此把它设置为一个虚拟值。
// 代替磁盘数量传递给用户程序。为了方便追踪,传递STORAGE_DEVICE_NUMBER结构体。
deviceExtension->DiskNumber = (ULONG)-1;
nameSize = min(output->NameLength, sizeof(deviceExtension->PhysicalDeviceNameBuffer) - sizeof(WCHAR));
RtlStringCbCopyW(deviceExtension->PhysicalDeviceNameBuffer, nameSize, output->Name);
RtlInitUnicodeString(&deviceExtension->PhysicalDeviceName, &deviceExtension->PhysicalDeviceNameBuffer[0]);
ExFreePool(output);
//
// 获取 VOLUME_NUMBER 信息
//
outputSize = sizeof(VOLUME_NUMBER);
RtlZeroMemory(&volumeNumber, sizeof(VOLUME_NUMBER));
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_VOLUME_QUERY_VOLUME_NUMBER,
deviceExtension->TargetDeviceObject, NULL, 0,
&volumeNumber,
sizeof(VOLUME_NUMBER),
FALSE, &event, &ioStatus);
if (!irp)
{
DiskPerfLogError(
DeviceObject,
265,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
status = IoCallDriver(deviceExtension->TargetDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive,
KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS(status) ||
volumeNumber.VolumeManagerName[0] == (WCHAR) UNICODE_NULL)
{
RtlCopyMemory(
&deviceExtension->StorageManagerName[0],
L"LogiDisk",
8 * sizeof(WCHAR));
if (NT_SUCCESS(status))
deviceExtension->DiskNumber = volumeNumber.VolumeNumber;
}
else
{
RtlCopyMemory(
&deviceExtension->StorageManagerName[0],
&volumeNumber.VolumeManagerName[0],
8 * sizeof(WCHAR));
deviceExtension->DiskNumber = volumeNumber.VolumeNumber;
}
DebugPrint((3, "DiskPerfRegisterDevice: Device name %ws\n",
deviceExtension->PhysicalDeviceNameBuffer));
}
status = IoWMIRegistrationControl(DeviceObject,
WMIREG_ACTION_REGISTER | registrationFlag );
if (! NT_SUCCESS(status))
{
DiskPerfLogError(
DeviceObject,
261,
STATUS_SUCCESS,
IO_ERR_INTERNAL_ERROR);
}
return status;
} VOID
DiskPerfLogError(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG UniqueId,
IN NTSTATUS ErrorCode,
IN NTSTATUS Status
)
/*++
Routine Description:
Routine to log an error with the Error Logger
Arguments:
DeviceObject - the device object responsible for the error
UniqueId - an id for the error
Status - the status of the error
Return Value:
None
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
errorLogEntry = (PIO_ERROR_LOG_PACKET)
IoAllocateErrorLogEntry(
DeviceObject,
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + sizeof(DEVICE_OBJECT))
);
if (errorLogEntry != NULL) {
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = UniqueId;
errorLogEntry->FinalStatus = Status;
//
// The following is necessary because DumpData is of type ULONG
// and DeviceObject can be more than that
//
RtlCopyMemory(
&errorLogEntry->DumpData[0],
DeviceObject,
sizeof(DEVICE_OBJECT));
errorLogEntry->DumpDataSize = sizeof(DEVICE_OBJECT);
IoWriteErrorLogEntry(errorLogEntry);
}
} NTSTATUS
DiskperfQueryWmiRegInfo(
IN PDEVICE_OBJECT DeviceObject,
OUT ULONG *RegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING *RegistryPath,
OUT PUNICODE_STRING MofResourceName,
OUT PDEVICE_OBJECT *Pdo
)
/*++
Routine Description:
This routine is a callback into the driver to retrieve information about
the guids being registered.
Implementations of this routine may be in paged memory
Arguments:
DeviceObject is the device whose registration information is needed
*RegFlags returns with a set of flags that describe all of the guids being
registered for this device. If the device wants enable and disable
collection callbacks before receiving queries for the registered
guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
the instance name is determined from the PDO associated with the
device object. Note that the PDO must have an associated devnode. If
WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
name for the device. These flags are ORed into the flags specified
by the GUIDREGINFO for each guid.
InstanceName returns with the instance name for the guids if
WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
caller will call ExFreePool with the buffer returned.
*RegistryPath returns with the registry path of the driver. This is
required
MofResourceName returns with the name of the MOF resource attached to
the binary file. If the driver does not have a mof resource attached
then this can be returned unmodified. If a value is returned then
it is NOT freed.
*Pdo returns with the device object for the PDO associated with this
device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
*RegFlags.
Return Value:
status
--*/
{
USHORT size;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
UNREFERENCED_PARAMETER(MofResourceName);
size = deviceExtension->PhysicalDeviceName.Length + sizeof(UNICODE_NULL);
InstanceName->Buffer = ExAllocatePool(PagedPool,
size);
if (InstanceName->Buffer != NULL)
{
*RegistryPath = &DiskPerfRegistryPath;
*RegFlags = WMIREG_FLAG_INSTANCE_PDO | WMIREG_FLAG_EXPENSIVE;
*Pdo = deviceExtension->PhysicalDeviceObject;
status = STATUS_SUCCESS;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return(status);
} NTSTATUS
DiskperfQueryWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG InstanceCount,
IN OUT PULONG InstanceLengthArray,
IN ULONG BufferAvail,
OUT PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to query for the contents of
all instances of a data block. When the driver has finished filling the
data block 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 data block is being queried
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
InstanceCount is the number of instnaces expected to be returned for
the data block.
InstanceLengthArray is a pointer to an array of ULONG that returns the
lengths of each instance of the data block. If this is NULL then
there was not enough space in the output buffer to fufill the request
so the irp should be completed with the buffer needed.
BufferAvail on entry has the maximum size available to write the data
blocks.
Buffer on return is filled with the returned data blocks. Note that each
instance of the data block must be aligned on a 8 byte boundry. Return Value:
status
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
ULONG sizeNeeded;
PDISK_PERFORMANCE totalCounters;
PDISK_PERFORMANCE diskCounters;
PWMI_DISK_PERFORMANCE diskPerformance;
ULONG deviceNameSize;
PWCHAR diskNamePtr;
PAGED_CODE();
UNREFERENCED_PARAMETER(InstanceIndex);
UNREFERENCED_PARAMETER(InstanceCount);
deviceExtension = DeviceObject->DeviceExtension;
if (GuidIndex == 0)
{
deviceNameSize = deviceExtension->PhysicalDeviceName.Length +
sizeof(USHORT);
sizeNeeded = ((sizeof(WMI_DISK_PERFORMANCE) + 1) & ~1) +
deviceNameSize;
diskCounters = deviceExtension->DiskCounters;
if (diskCounters == NULL)
{
status = STATUS_UNSUCCESSFUL;
}
else if (BufferAvail >= sizeNeeded)
{
//
// Update idle time if disk has been idle
//
ULONG i;
LARGE_INTEGER perfctr, frequency;
RtlZeroMemory(Buffer, sizeof(WMI_DISK_PERFORMANCE));
diskPerformance = (PWMI_DISK_PERFORMANCE)Buffer;
totalCounters = (PDISK_PERFORMANCE)diskPerformance;
KeQuerySystemTime(&totalCounters->QueryTime);
#ifdef USE_PERF_CTR
perfctr = KeQueryPerformanceCounter(&frequency);
#endif
for (i=0; i<deviceExtension->Processors; i++) {
DiskPerfAddCounters( totalCounters, diskCounters, frequency);
DebugPrint((11,
"DiskPerfQueryWmiDataBlock: R%d %I64u W%d%I64u ", i,
diskCounters->ReadTime, diskCounters->WriteTime));
diskCounters = (PDISK_PERFORMANCE)
((PCHAR)diskCounters + PROCESSOR_COUNTERS_SIZE);
}
DebugPrint((11, "\n"));
totalCounters->QueueDepth = deviceExtension->QueueDepth;
DebugPrint((9,
"QueryWmiDataBlock: Dev %X RT %I64u WT %I64u Rds %d Wts %d freq %I64u\n",
totalCounters,
totalCounters->ReadTime, totalCounters->WriteTime,
totalCounters->ReadCount, totalCounters->WriteCount,
frequency));
if (totalCounters->QueueDepth == 0) {
LARGE_INTEGER difference;
difference.QuadPart
#ifdef USE_PERF_CTR
= perfctr.QuadPart -
#else
= totalCounters->QueryTime.QuadPart -
#endif
deviceExtension->LastIdleClock.QuadPart;
if (frequency.QuadPart > 0) {
totalCounters->IdleTime.QuadPart +=
#ifdef USE_PERF_CTR
10000000 * difference.QuadPart / frequency.QuadPart;
#else
difference.QuadPart;
#endif
}
}
totalCounters->StorageDeviceNumber
= deviceExtension->DiskNumber;
RtlCopyMemory(
&totalCounters->StorageManagerName[0],
&deviceExtension->StorageManagerName[0],
8 * sizeof(WCHAR));
diskNamePtr = (PWCHAR)(Buffer +
((sizeof(DISK_PERFORMANCE) + 1) & ~1));
*diskNamePtr++ = deviceExtension->PhysicalDeviceName.Length;
RtlCopyMemory(diskNamePtr,
deviceExtension->PhysicalDeviceName.Buffer,
deviceExtension->PhysicalDeviceName.Length);
*InstanceLengthArray = sizeNeeded;
status = STATUS_SUCCESS;
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
} else {
status = STATUS_WMI_GUID_NOT_FOUND;
sizeNeeded = 0;
}
status = WmiCompleteRequest(
DeviceObject,
Irp,
status,
sizeNeeded,
IO_NO_INCREMENT);
return(status);
} NTSTATUS
DiskperfWmiFunctionControl(
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;
deviceExtension = DeviceObject->DeviceExtension;
if (GuidIndex == 0)
{
if (Function == WmiDataBlockControl) {
if (Enable) {
if (InterlockedIncrement(&deviceExtension->CountersEnabled) == 1) {
//
// Reset per processor counters to 0
//
if (deviceExtension->DiskCounters != NULL) {
RtlZeroMemory(
deviceExtension->DiskCounters,
PROCESSOR_COUNTERS_SIZE * deviceExtension->Processors);
}
DiskPerfGetClock(deviceExtension->LastIdleClock, NULL);
DebugPrint((10,
"DiskPerfWmiFunctionControl: LIC=%I64u\n",
deviceExtension->LastIdleClock));
deviceExtension->QueueDepth = 0;
DebugPrint((3, "DiskPerfWmi: Counters enabled %d\n",
deviceExtension->CountersEnabled));
}
} else {
if (InterlockedDecrement(&deviceExtension->CountersEnabled)
<= 0) {
deviceExtension->CountersEnabled = 0;
deviceExtension->QueueDepth = 0;
DebugPrint((3, "DiskPerfWmi: Counters disabled %d\n",
deviceExtension->CountersEnabled));
}
}
}
status = STATUS_SUCCESS;
} else {
status = STATUS_WMI_GUID_NOT_FOUND;
}
status = WmiCompleteRequest(
DeviceObject,
Irp,
status,
0,
IO_NO_INCREMENT);
return(status);
} VOID
DiskPerfAddCounters(
IN OUT PDISK_PERFORMANCE TotalCounters,
IN PDISK_PERFORMANCE NewCounters,
IN LARGE_INTEGER Frequency
)
{
TotalCounters->BytesRead.QuadPart += NewCounters->BytesRead.QuadPart;
TotalCounters->BytesWritten.QuadPart+= NewCounters->BytesWritten.QuadPart;
TotalCounters->ReadCount += NewCounters->ReadCount;
TotalCounters->WriteCount += NewCounters->WriteCount;
TotalCounters->SplitCount += NewCounters->SplitCount;
#ifdef USE_PERF_CTR
if (Frequency.QuadPart > 0) {
TotalCounters->ReadTime.QuadPart +=
NewCounters->ReadTime.QuadPart * 10000000 / Frequency.QuadPart;
TotalCounters->WriteTime.QuadPart +=
NewCounters->WriteTime.QuadPart * 10000000 / Frequency.QuadPart;
TotalCounters->IdleTime.QuadPart +=
NewCounters->IdleTime.QuadPart * 10000000 / Frequency.QuadPart;
}
else
#endif
{
TotalCounters->ReadTime.QuadPart += NewCounters->ReadTime.QuadPart;
TotalCounters->WriteTime.QuadPart += NewCounters->WriteTime.QuadPart;
TotalCounters->IdleTime.QuadPart += NewCounters->IdleTime.QuadPart;
}
}
#if DBG
VOID
DiskPerfDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
...
)
/*++
Routine Description:
Debug print for all DiskPerf
Arguments:
Debug print level between 0 and 3, with 3 being the most verbose.
Return Value:
None
--*/
{
va_list ap;
va_start(ap, DebugMessage); if ((DebugPrintLevel <= (DiskPerfDebug & 0x0000ffff)) ||
((1 << (DebugPrintLevel + 15)) & DiskPerfDebug)) {
DbgPrint(DebugMessage, ap);
}
va_end(ap);
}
#endif
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: