首页
社区
课程
招聘
[原创]我对Windows磁盘过滤驱动分析diskpref的理解以及技术分享
发表于: 2014-6-18 13:49 20649

[原创]我对Windows磁盘过滤驱动分析diskpref的理解以及技术分享

2014-6-18 13:49
20649

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) &currentIrpStack->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直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (11)
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
2
附件是DiskPerf.c代码。
diskperf.rar
上传的附件:
2014-6-18 13:51
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
3
[QUOTE=tianhz;1294008]附件是DiskPerf.c代码。
diskperf.rar[/QUOTE]

tianhz大哥又发大招了,顶一个...
2014-6-18 13:56
0
雪    币: 142
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
顶一个,框架应该是wdk8.0的
2014-6-18 14:38
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
是WDK7600的框架例子代码。
2014-6-18 15:36
0
雪    币: 220
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这个必须顶
2014-6-19 10:22
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hhs
7
顶大牛。。
2014-6-19 10:23
0
雪    币: 69
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
8
一直对楼主的头像印象深刻~~
2014-7-8 14:33
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
9
谢谢大家的支持
2014-9-10 14:30
0
雪    币: 3761
活跃值: (510)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark 多谢分享
2014-9-15 07:31
0
雪    币: 6509
活跃值: (2382)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
11
支持一个!
2019-4-11 13:42
0
雪    币: 22
活跃值: (192)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
mark,多谢分享
2021-8-25 18:08
0
游客
登录 | 注册 方可回帖
返回
//