1416 lines
32 KiB
C
1416 lines
32 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
histgram.c
|
||
|
||
Abstract:
|
||
|
||
This driver monitors which disk sector are accessed and how frequently
|
||
|
||
Authors:
|
||
|
||
Stephane Plante
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
This driver is based upon the diskperf driver written by Bob Rinne and
|
||
Mike Glass.
|
||
|
||
Revision History:
|
||
|
||
01/20/1995 -- Initial Revision
|
||
|
||
--*/
|
||
|
||
#include "histgram.h"
|
||
|
||
#if DBG
|
||
ULONG HistGramDebug = 0
|
||
| HISTGRAM_CONFIGURATION
|
||
| HISTGRAM_IOCTL_SIZE_FAILURE
|
||
| HISTGRAM_IOCTL_SIZE_SUCCESS
|
||
| HISTGRAM_IOCTL_SIZE_DUMP
|
||
| HISTGRAM_IOCTL_DATA_FAILURE
|
||
// | HISTGRAM_IOCTL_DATA_SUCCESS
|
||
// | HISTGRAM_IOCTL_DATA_DUMP
|
||
// | HISTGRAM_READS
|
||
// | HISTGRAM_READS_DUMP
|
||
// | HISTGRAM_WRITES
|
||
// | HISTGRAM_WRITES_DUMP
|
||
;
|
||
UCHAR HistGramBuffer[128];
|
||
#endif
|
||
|
||
UNICODE_STRING HistGramRegistryPath;
|
||
|
||
#ifdef POOL_TAGGING
|
||
#ifdef ExAllocatePool
|
||
#undef ExAllocatePool
|
||
#endif
|
||
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'tsiH')
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the routine called by the system to initialize the disk
|
||
performance driver. The driver object is set up and then the
|
||
driver calls HistGramInitialize to attach to the boot devices.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - The disk performance driver object.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
STRING ntString;
|
||
|
||
//
|
||
// Set up the device driver entry points.
|
||
//
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = HistGramCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_READ] = HistGramReadWrite;
|
||
DriverObject->MajorFunction[IRP_MJ_WRITE] = HistGramReadWrite;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HistGramDeviceControl;
|
||
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HistGramShutdownFlush;
|
||
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = HistGramShutdownFlush;
|
||
|
||
//
|
||
// Keep a local copy of our path to the registry information
|
||
// Note: this code can break if we have a non-ansi character in out string.
|
||
//
|
||
|
||
RtlUnicodeStringToAnsiString(&ntString,RegistryPath,TRUE);
|
||
RtlAnsiStringToUnicodeString(&HistGramRegistryPath,&ntString,TRUE);
|
||
RtlFreeAnsiString(&ntString);
|
||
|
||
//
|
||
// Call the initialization routine for the first time.
|
||
//
|
||
|
||
HistGramInitialize(DriverObject, 0, 0);
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
} // DriverEntry
|
||
|
||
|
||
VOID
|
||
HistGramInitialize(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PVOID NextDisk,
|
||
IN ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Attach to new disk devices and partitions.
|
||
Set up device objects for counts and times.
|
||
If this is the first time this routine is called,
|
||
then register with the IO system to be called
|
||
after all other disk device drivers have initiated.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Histogram driver object.
|
||
NextDisk - Starting disk for this part of the initialization.
|
||
Count - Not used. Number of times this routine has been called.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PCONFIGURATION_INFORMATION configurationInformation;
|
||
CCHAR ntNameBuffer[64];
|
||
STRING ntNameString;
|
||
UNICODE_STRING ntUnicodeString;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE_OBJECT physicalDevice;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PDEVICE_EXTENSION zeroExtension;
|
||
PFILE_OBJECT fileObject;
|
||
PIRP irp;
|
||
KIRQL currentIrql;
|
||
PDRIVE_LAYOUT_INFORMATION partitionInfo;
|
||
KEVENT event;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
NTSTATUS status;
|
||
ULONG diskNumber;
|
||
ULONG partNumber;
|
||
|
||
//
|
||
// Get the configuration information.
|
||
//
|
||
|
||
configurationInformation = IoGetConfigurationInformation();
|
||
|
||
//
|
||
// Find disk devices.
|
||
//
|
||
|
||
for (diskNumber = (ULONG)NextDisk;
|
||
diskNumber < configurationInformation->DiskCount;
|
||
diskNumber++) {
|
||
|
||
//
|
||
// Create device name for the physical disk.
|
||
//
|
||
|
||
sprintf(ntNameBuffer,
|
||
"\\Device\\Harddisk%d\\Partition0",
|
||
diskNumber);
|
||
|
||
RtlInitAnsiString(&ntNameString,
|
||
ntNameBuffer);
|
||
|
||
RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
||
&ntNameString,
|
||
TRUE);
|
||
|
||
//
|
||
// Create device object for partition 0.
|
||
//
|
||
|
||
status = IoCreateDevice(DriverObject,
|
||
sizeof(DEVICE_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_DISK,
|
||
0,
|
||
FALSE,
|
||
&physicalDevice);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
continue;
|
||
}
|
||
|
||
physicalDevice->Flags |= DO_DIRECT_IO;
|
||
|
||
//
|
||
// Point device extension back at device object and remember
|
||
// the disk number.
|
||
//
|
||
|
||
deviceExtension = physicalDevice->DeviceExtension;
|
||
zeroExtension = deviceExtension;
|
||
deviceExtension->DeviceObject = physicalDevice;
|
||
deviceExtension->DiskNumber = diskNumber;
|
||
deviceExtension->LastPartitionNumber = 0;
|
||
deviceExtension->DriverObject = DriverObject;
|
||
|
||
//
|
||
// This is the physical device object.
|
||
//
|
||
|
||
deviceExtension->PhysicalDevice = physicalDevice;
|
||
|
||
//
|
||
// Set the offset for the entire disk
|
||
//
|
||
|
||
deviceExtension->PartitionOffset.QuadPart = 0;
|
||
|
||
//
|
||
// Attach to partition0. This call links the newly created
|
||
// device to the target device, returning the target device object.
|
||
//
|
||
|
||
status = IoAttachDevice(physicalDevice,
|
||
&ntUnicodeString,
|
||
&deviceExtension->TargetDeviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
IoDeleteDevice(physicalDevice);
|
||
continue;
|
||
}
|
||
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
|
||
//
|
||
// Propogate driver's alignment requirements.
|
||
//
|
||
|
||
physicalDevice->AlignmentRequirement =
|
||
deviceExtension->TargetDeviceObject->AlignmentRequirement;
|
||
|
||
//
|
||
// Initialize spinlock for performance measures.
|
||
//
|
||
|
||
KeInitializeSpinLock(&deviceExtension->Spinlock);
|
||
|
||
//
|
||
// Acquire the spinlock and set the initial status of the
|
||
// enabling flag to false
|
||
//
|
||
|
||
KeAcquireSpinLock(&deviceExtension->Spinlock,¤tIrql);
|
||
|
||
deviceExtension->HistGramEnable = FALSE;
|
||
|
||
KeReleaseSpinLock(&deviceExtension->Spinlock,currentIrql);
|
||
|
||
//
|
||
// Configure the histogram data structure
|
||
//
|
||
|
||
if (!NT_SUCCESS(HistGramConfigure(deviceExtension) ) ) {
|
||
IoDeleteDevice(physicalDevice);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Allocate buffer for drive layout.
|
||
//
|
||
|
||
partitionInfo = ExAllocatePool(NonPagedPool,
|
||
(128 * sizeof(PARTITION_INFORMATION) + 4));
|
||
|
||
if (!partitionInfo) {
|
||
IoDeleteDevice(physicalDevice);
|
||
ExFreePool(deviceExtension->DiskHist.Histogram);
|
||
ExFreePool(deviceExtension->ReqHist.Histogram);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Create IRP for get drive layout device control.
|
||
//
|
||
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT,
|
||
deviceExtension->TargetDeviceObject,
|
||
NULL,
|
||
0,
|
||
partitionInfo,
|
||
(128 * sizeof(PARTITION_INFORMATION) + 4),
|
||
FALSE,
|
||
&event,
|
||
&ioStatusBlock);
|
||
|
||
if (!irp) {
|
||
ExFreePool(partitionInfo);
|
||
ExFreePool(deviceExtension->DiskHist.Histogram);
|
||
ExFreePool(deviceExtension->ReqHist.Histogram);
|
||
IoDeleteDevice(physicalDevice);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Set the event object to the unsignaled state.
|
||
// It will be used to signal request completion.
|
||
//
|
||
|
||
KeInitializeEvent(&event,
|
||
NotificationEvent,
|
||
FALSE);
|
||
|
||
status = IoCallDriver(deviceExtension->TargetDeviceObject,
|
||
irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject(&event,
|
||
Suspended,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
|
||
status = ioStatusBlock.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(partitionInfo);
|
||
ExFreePool(deviceExtension->DiskHist.Histogram);
|
||
ExFreePool(deviceExtension->ReqHist.Histogram);
|
||
IoDeleteDevice(physicalDevice);
|
||
continue;
|
||
}
|
||
|
||
for (partNumber = 1;
|
||
partNumber < partitionInfo->PartitionCount;
|
||
partNumber++) {
|
||
|
||
//
|
||
// Create device name for partition.
|
||
//
|
||
|
||
sprintf(ntNameBuffer,
|
||
"\\Device\\Harddisk%d\\Partition%d",
|
||
diskNumber,
|
||
partNumber);
|
||
|
||
RtlInitAnsiString(&ntNameString,
|
||
ntNameBuffer);
|
||
|
||
RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
||
&ntNameString,
|
||
TRUE);
|
||
|
||
//
|
||
// Get target device object.
|
||
//
|
||
|
||
status = IoGetDeviceObjectPointer(&ntUnicodeString,
|
||
FILE_READ_ATTRIBUTES,
|
||
&fileObject,
|
||
&deviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Check if this device is already mounted.
|
||
//
|
||
|
||
if (!deviceObject->Vpb ||
|
||
(deviceObject->Vpb->Flags & VPB_MOUNTED)) {
|
||
|
||
//
|
||
// Can't attach to a device that is already mounted.
|
||
//
|
||
|
||
ObDereferenceObject(fileObject);
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
continue;
|
||
}
|
||
|
||
ObDereferenceObject(fileObject);
|
||
|
||
//
|
||
// Create device object for this partition.
|
||
//
|
||
|
||
status = IoCreateDevice(DriverObject,
|
||
sizeof(DEVICE_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_DISK,
|
||
0,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
continue;
|
||
}
|
||
|
||
deviceObject->Flags |= DO_DIRECT_IO;
|
||
|
||
//
|
||
// Point device extension back at device object and
|
||
// remember the disk number.
|
||
//
|
||
|
||
deviceExtension = deviceObject->DeviceExtension;
|
||
deviceExtension->DeviceObject = deviceObject;
|
||
deviceExtension->DiskNumber = diskNumber;
|
||
deviceExtension->DriverObject = DriverObject;
|
||
|
||
//
|
||
// Remember the starting offset of this partition
|
||
//
|
||
|
||
deviceExtension->PartitionOffset.QuadPart =
|
||
partitionInfo->PartitionEntry[partNumber-1].StartingOffset.QuadPart;
|
||
|
||
//
|
||
// Maintain the last partition number created. Put it in
|
||
// each extension just to initialize the field.
|
||
//
|
||
|
||
zeroExtension->LastPartitionNumber =
|
||
deviceExtension->LastPartitionNumber = partNumber;
|
||
|
||
//
|
||
// Store pointer to physical device.
|
||
//
|
||
|
||
deviceExtension->PhysicalDevice = physicalDevice;
|
||
|
||
//
|
||
// Attach to the partition. This call links the newly created
|
||
// device to the target device, returning the target device object.
|
||
//
|
||
|
||
status = IoAttachDevice(deviceObject,
|
||
&ntUnicodeString,
|
||
&deviceExtension->TargetDeviceObject);
|
||
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
IoDeleteDevice(deviceObject);
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Propogate driver's alignment requirements.
|
||
//
|
||
|
||
deviceObject->AlignmentRequirement =
|
||
deviceExtension->TargetDeviceObject->AlignmentRequirement;
|
||
|
||
}
|
||
|
||
ExFreePool(partitionInfo);
|
||
|
||
}
|
||
|
||
//
|
||
// Check if this is the first time this routine has been called.
|
||
//
|
||
|
||
if (!NextDisk) {
|
||
|
||
//
|
||
// Register with IO system to be called a second time after all
|
||
// other device drivers have initialized.
|
||
//
|
||
|
||
IoRegisterDriverReinitialization(DriverObject,
|
||
HistGramInitialize,
|
||
(PVOID)configurationInformation->DiskCount);
|
||
}
|
||
|
||
return;
|
||
|
||
} // end HistGramInitialize()
|
||
|
||
|
||
NTSTATUS
|
||
HistGramCreate(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine services open commands. It establishes
|
||
the driver's existance by returning status success.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Context for the activity.
|
||
Irp - The device control argument block.
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return STATUS_SUCCESS;
|
||
|
||
} // end HistGramCreate()
|
||
|
||
|
||
NTSTATUS
|
||
HistGramReadWrite(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the driver entry point for read requests
|
||
to disks to which the diskperf driver has attached.
|
||
This driver collects statistics and then sets a completion
|
||
routine so that it can collect additional information when
|
||
the request completes. Then it calls the next driver below
|
||
it.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PDEVICE_EXTENSION physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
|
||
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
KIRQL currentIrql;
|
||
ULONG start; // first bucket for the physical disk
|
||
ULONG end; // last bucket for the physical disk
|
||
ULONG reqBucket; // Points to the request length bucket to update
|
||
ULONGLONG counter;
|
||
LARGE_INTEGER reqOffset; // Start location of the request
|
||
LARGE_INTEGER reqFinish; // Final disk location of the request
|
||
NTSTATUS status;
|
||
BOOLEAN reqRead; // True if this is a read IRQ;
|
||
|
||
//
|
||
// Take into account the initial partition offset
|
||
//
|
||
|
||
reqOffset.QuadPart = deviceExtension->PartitionOffset.QuadPart;
|
||
|
||
//
|
||
// Determine what the initial variables are. Read them from the IrpStack
|
||
//
|
||
|
||
if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
|
||
reqRead = TRUE;
|
||
reqOffset.QuadPart += currentIrpStack->Parameters.Read.ByteOffset.QuadPart;
|
||
counter = currentIrpStack->Parameters.Read.Length;
|
||
reqFinish.QuadPart = reqOffset.QuadPart + counter;
|
||
} else {
|
||
reqRead = FALSE;
|
||
reqOffset.QuadPart += currentIrpStack->Parameters.Write.ByteOffset.QuadPart;
|
||
counter = currentIrpStack->Parameters.Write.Length;
|
||
reqFinish.QuadPart = reqOffset.QuadPart + counter;
|
||
}
|
||
|
||
//
|
||
// Determine which bucket the request size falls into. Use a simple
|
||
// Bit-Testing algorithm.
|
||
//
|
||
|
||
for (reqBucket = 0;counter > 1;reqBucket++, counter = (counter >> 1) );
|
||
|
||
//
|
||
// Now check to see if we have a bucket which is numbered that high.
|
||
// If we don't then we will simply have to add the number to the last
|
||
// valid bucket.
|
||
//
|
||
|
||
if (reqBucket >= physicalDisk->ReqHist.Size) {
|
||
reqBucket = (physicalDisk->ReqHist.Size - 1);
|
||
}
|
||
|
||
//
|
||
// Determine if the location on the disk falls within the area of interest
|
||
// Note that if it doesn't then we DO NOT log the accompanying request
|
||
// into its histogram
|
||
//
|
||
|
||
if (physicalDisk->DiskHist.Start.QuadPart > reqFinish.QuadPart ||
|
||
physicalDisk->DiskHist.End.QuadPart < reqOffset.QuadPart) {
|
||
|
||
goto histgramreadwriteexitpoint;
|
||
|
||
}
|
||
|
||
if (physicalDisk->DiskHist.End.QuadPart < reqFinish.QuadPart) {
|
||
|
||
reqFinish.QuadPart -= (reqFinish.QuadPart - physicalDisk->DiskHist.End.QuadPart);
|
||
|
||
}
|
||
|
||
reqOffset.QuadPart -= physicalDisk->DiskHist.Start.QuadPart;
|
||
reqFinish.QuadPart -= physicalDisk->DiskHist.Start.QuadPart;
|
||
|
||
if (reqOffset.QuadPart < 0) {
|
||
|
||
reqFinish.QuadPart -= reqOffset.QuadPart;
|
||
reqOffset.QuadPart = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Calculate the Starting Bucket for the physical device
|
||
//
|
||
|
||
start = (ULONG) ( reqOffset.QuadPart / physicalDisk->DiskHist.Granularity );
|
||
|
||
//
|
||
// Calculate the Ending Bucket for the physical device
|
||
//
|
||
|
||
end = (ULONG) ( reqFinish.QuadPart / physicalDisk->DiskHist.Granularity );
|
||
|
||
//
|
||
// Print some useful debugging information
|
||
//
|
||
|
||
#if DBG
|
||
|
||
if (reqRead) {
|
||
HistGramDebugPrint(HISTGRAM_READS,
|
||
"Histgram: Added %ld Reads [Start: %ld End %ld]\n",
|
||
(1+end-start),
|
||
start,
|
||
end);
|
||
} else {
|
||
HistGramDebugPrint(HISTGRAM_WRITES,
|
||
"Histgram: Added %ld Writes [Start: %ld End %ld]\n",
|
||
(1+end-start),
|
||
start,
|
||
end);
|
||
}
|
||
|
||
//
|
||
// Some useful asserts to make sure that everything is stable
|
||
//
|
||
|
||
ASSERT(physicalDisk->DiskHist.Histogram == NULL);
|
||
ASSERT(physicalDisk->ReqHist.Histogram == NULL);
|
||
|
||
#endif
|
||
|
||
//
|
||
// Acquired Spinlock protection
|
||
//
|
||
|
||
KeAcquireSpinLock(&physicalDisk->Spinlock,¤tIrql);
|
||
|
||
//
|
||
// Are we allowed to write to the histogram data? If not
|
||
// then we had better release the lock and exit
|
||
//
|
||
|
||
if (physicalDisk->HistGramEnable == FALSE) {
|
||
|
||
KeReleaseSpinLock(&physicalDisk->Spinlock,currentIrql);
|
||
goto histgramreadwriteexitpoint;
|
||
|
||
}
|
||
|
||
//
|
||
// Update Physical Buckets and Count
|
||
//
|
||
|
||
if (reqRead) {
|
||
|
||
physicalDisk->DiskHist.ReadCount += (1 + end - start);
|
||
physicalDisk->ReqHist.ReadCount += 1;
|
||
physicalDisk->ReqHist.Histogram[reqBucket].Reads++;
|
||
|
||
for (;start <= end; start++) {
|
||
|
||
physicalDisk->DiskHist.Histogram[start].Reads++;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
physicalDisk->DiskHist.WriteCount += (1 + end - start);
|
||
physicalDisk->ReqHist.WriteCount += 1;
|
||
physicalDisk->ReqHist.Histogram[reqBucket].Writes++;
|
||
|
||
for (;start <= end; start++) {
|
||
|
||
physicalDisk->DiskHist.Histogram[start].Writes++;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Release Spinlock protection
|
||
//
|
||
|
||
KeReleaseSpinLock(&physicalDisk->Spinlock, currentIrql);
|
||
|
||
histgramreadwriteexitpoint:
|
||
|
||
//
|
||
// Set current stack back one
|
||
//
|
||
|
||
Irp->CurrentLocation++;
|
||
Irp->Tail.Overlay.CurrentStackLocation++;
|
||
|
||
//
|
||
// Return the results of the call to the disk driver.
|
||
//
|
||
|
||
return IoCallDriver(deviceExtension->TargetDeviceObject,
|
||
Irp);
|
||
|
||
} // end HistGramReadWrite()
|
||
|
||
|
||
NTSTATUS
|
||
HistGramUpdateDriveLayout(
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called after an IOCTL to set drive layout completes.
|
||
It attempts to attach to each partition in the system. If it fails
|
||
then it is assumed that diskperf has already attached. After
|
||
the attach the new device extension is set up to point to the
|
||
device extension representing the physical disk. There are no
|
||
data items or other pointers that need to be cleaned up on a
|
||
per partition basis.
|
||
|
||
Arguments:
|
||
|
||
PhysicalDeviceObject - Pointer to device object for the disk just changed.
|
||
Irp - IRP involved.
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION physicalExtension = PhysicalDeviceObject->DeviceExtension;
|
||
PDRIVE_LAYOUT_INFORMATION partitionInfo;
|
||
PIRP irp;
|
||
KEVENT event;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
ULONG partitionNumber = physicalExtension->LastPartitionNumber;
|
||
PDEVICE_OBJECT targetObject;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
UCHAR ntDeviceName[64];
|
||
STRING ntString;
|
||
UNICODE_STRING ntUnicodeString;
|
||
PFILE_OBJECT fileObject;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Allocate Buffer for Drive Layout
|
||
//
|
||
|
||
partitionInfo = ExAllocatePool(NonPagedPool,
|
||
(128 * sizeof(PARTITION_INFORMATION) + 4 ) );
|
||
|
||
if (!partitionInfo) {
|
||
IoDeleteDevice(physicalExtension->DeviceObject);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT,
|
||
physicalExtension->TargetDeviceObject,
|
||
NULL,
|
||
0,
|
||
partitionInfo,
|
||
(128 * sizeof(PARTITION_INFORMATION) + 4),
|
||
FALSE,
|
||
&event,
|
||
&ioStatusBlock);
|
||
|
||
if (!irp) {
|
||
ExFreePool(partitionInfo);
|
||
IoDeleteDevice(physicalExtension->DeviceObject);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
KeInitializeEvent(&event,
|
||
NotificationEvent,
|
||
FALSE);
|
||
|
||
status = IoCallDriver(physicalExtension->TargetDeviceObject,
|
||
irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event,
|
||
Suspended,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
status = ioStatusBlock.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(partitionInfo);
|
||
IoDeleteDevice(physicalExtension->DeviceObject);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// Attach to any new partitions created by the set layout call.
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// Get first/next partition. Already attached to the disk,
|
||
// otherwise control would not have been passed to this driver
|
||
// on the device I/O control.
|
||
//
|
||
|
||
partitionNumber++;
|
||
|
||
//
|
||
// Create unicode NT device name.
|
||
//
|
||
|
||
sprintf(ntDeviceName,
|
||
"\\Device\\Harddisk%d\\Partition%d",
|
||
physicalExtension->DiskNumber,
|
||
partitionNumber);
|
||
|
||
RtlInitAnsiString(&ntString,
|
||
ntDeviceName);
|
||
|
||
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
||
&ntString,
|
||
TRUE);
|
||
if (!NT_SUCCESS(status)) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Get target device object.
|
||
//
|
||
|
||
status = IoGetDeviceObjectPointer(&ntUnicodeString,
|
||
FILE_READ_ATTRIBUTES,
|
||
&fileObject,
|
||
&targetObject);
|
||
|
||
//
|
||
// If this fails then it is because there is no such device
|
||
// which signals completion.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Dereference file object as these are the rules.
|
||
//
|
||
|
||
ObDereferenceObject(fileObject);
|
||
|
||
//
|
||
// Check if this device is already mounted.
|
||
//
|
||
|
||
if ((!targetObject->Vpb) || (targetObject->Vpb->Flags & VPB_MOUNTED)) {
|
||
|
||
//
|
||
// Assume this device has already been attached.
|
||
//
|
||
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Create device object for this partition.
|
||
//
|
||
|
||
status = IoCreateDevice(physicalExtension->DriverObject,
|
||
sizeof(DEVICE_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_DISK,
|
||
0,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
continue;
|
||
}
|
||
|
||
deviceObject->Flags |= DO_DIRECT_IO;
|
||
|
||
//
|
||
// Point device extension back at device object.
|
||
//
|
||
|
||
deviceExtension = deviceObject->DeviceExtension;
|
||
deviceExtension->DeviceObject = deviceObject;
|
||
|
||
//
|
||
// Store pointer to physical device and disk/driver information.
|
||
//
|
||
|
||
deviceExtension->PhysicalDevice = PhysicalDeviceObject;
|
||
deviceExtension->DiskNumber = physicalExtension->DiskNumber;
|
||
deviceExtension->DriverObject = physicalExtension->DriverObject;
|
||
deviceExtension->PartitionOffset.QuadPart =
|
||
partitionInfo->PartitionEntry[partitionNumber].StartingOffset.QuadPart;
|
||
|
||
//
|
||
// Update the highest partition number in partition zero
|
||
// and store the same value in this new extension just to initialize
|
||
// the field.
|
||
//
|
||
|
||
physicalExtension->LastPartitionNumber =
|
||
deviceExtension->LastPartitionNumber = partitionNumber;
|
||
|
||
//
|
||
// Attach to the partition. This call links the newly created
|
||
// device to the target device, returning the target device object.
|
||
//
|
||
|
||
status = IoAttachDevice(deviceObject,
|
||
&ntUnicodeString,
|
||
&deviceExtension->TargetDeviceObject);
|
||
|
||
if ((!NT_SUCCESS(status)) || (status == STATUS_OBJECT_NAME_EXISTS)) {
|
||
|
||
//
|
||
// Assume this device is already attached.
|
||
//
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Propogate driver's alignment requirements.
|
||
//
|
||
|
||
deviceObject->AlignmentRequirement =
|
||
deviceExtension->TargetDeviceObject->AlignmentRequirement;
|
||
}
|
||
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
} while (TRUE);
|
||
|
||
|
||
ExFreePool(partitionInfo);
|
||
return Irp->IoStatus.Status;
|
||
|
||
} // end HistGramUpdateDriveLayout()
|
||
|
||
|
||
|
||
NTSTATUS
|
||
HistGramDeviceControl(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This device control dispatcher handles only the disk performance
|
||
device control. All others are passed down to the disk drivers.
|
||
The disk performane device control returns a current snapshot of
|
||
the performance data.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Context for the activity.
|
||
Irp - The device control argument block.
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PDEVICE_EXTENSION physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
|
||
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
PDISK_HISTOGRAM currentHist = NULL;
|
||
KIRQL currentIrql;
|
||
NTSTATUS status;
|
||
|
||
switch(currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
||
case IOCTL_DISK_HISTOGRAM_RESET:
|
||
|
||
//
|
||
// Under spinlock protection, set flag to disable all histogram
|
||
// access and free all memory allocated for the histograms
|
||
//
|
||
|
||
KeAcquireSpinLock(&physicalDisk->Spinlock,¤tIrql);
|
||
|
||
physicalDisk->HistGramEnable = FALSE;
|
||
ExFreePool(physicalDisk->DiskHist.Histogram);
|
||
ExFreePool(physicalDisk->ReqHist.Histogram);
|
||
|
||
KeReleaseSpinLock(&physicalDisk->Spinlock,currentIrql);
|
||
|
||
//
|
||
// Reconfigure the driver. Make sure that the config routine
|
||
// doesn't get swapped out
|
||
//
|
||
|
||
HistGramConfigure(physicalDisk);
|
||
|
||
status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = 0;
|
||
break;
|
||
|
||
case IOCTL_DISK_REQUEST:
|
||
case IOCTL_DISK_HISTOGRAM:
|
||
|
||
//
|
||
// Choose which of the histograms to work on
|
||
//
|
||
|
||
if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_REQUEST) {
|
||
currentHist = &physicalDisk->ReqHist;
|
||
} else {
|
||
currentHist = &physicalDisk->DiskHist;
|
||
}
|
||
|
||
//
|
||
// Check to see if we have the minimum amount of space required for data transfer
|
||
//
|
||
|
||
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
||
DISK_HISTOGRAM_SIZE) {
|
||
|
||
//
|
||
// Indicate unsuccessful status and no data transferred.
|
||
//
|
||
|
||
HistGramDebugPrint(HISTGRAM_IOCTL_SIZE_FAILURE,
|
||
"HistGram: IOCTL_DISK_??????? FAILED [Given: %ld Req: %ld]\n",
|
||
currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
|
||
DISK_HISTOGRAM_SIZE );
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
} else {
|
||
|
||
HistGramDebugPrint(HISTGRAM_IOCTL_SIZE_DUMP,
|
||
"HistGram: IOCTL_DISK_HISTGRAM_STRUCTURE\n"
|
||
"\tGranularity:\t%ld\n"
|
||
"\tDiskSize:\t%ld(MB)\n"
|
||
"\tSize:\t\t%ld\n"
|
||
"\tReadCount:\t%ld\n"
|
||
"\tWriteCount:\t%ld\n",
|
||
currentHist->Granularity,
|
||
(ULONG) ( currentHist->DiskSize.QuadPart / ( 1024 * 1024) ),
|
||
currentHist->Size,
|
||
currentHist->ReadCount,
|
||
currentHist->WriteCount);
|
||
|
||
KeAcquireSpinLock(&physicalDisk->Spinlock, ¤tIrql);
|
||
|
||
//
|
||
// Note: we only copy as many bytes as is REQUESTED of us
|
||
//
|
||
|
||
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
|
||
currentHist,
|
||
DISK_HISTOGRAM_SIZE );
|
||
|
||
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength > DISK_HISTOGRAM_SIZE) {
|
||
if ( (currentHist->Size * HISTOGRAM_BUCKET_SIZE ) <
|
||
(currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength - DISK_HISTOGRAM_SIZE) ) {
|
||
|
||
RtlCopyMemory( ( (char *)Irp->AssociatedIrp.SystemBuffer + DISK_HISTOGRAM_SIZE ),
|
||
currentHist->Histogram,
|
||
(currentHist->Size * HISTOGRAM_BUCKET_SIZE) );
|
||
|
||
} else {
|
||
|
||
RtlCopyMemory( ( (char *)Irp->AssociatedIrp.SystemBuffer + DISK_HISTOGRAM_SIZE ),
|
||
currentHist->Histogram,
|
||
(currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength - DISK_HISTOGRAM_SIZE) );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Wipe out all data
|
||
//
|
||
|
||
RtlZeroMemory(currentHist->Histogram, (currentHist->Size * HISTOGRAM_BUCKET_SIZE) );
|
||
|
||
//
|
||
// Now that we have used them, we can reset these values
|
||
//
|
||
|
||
currentHist->WriteCount = 0;
|
||
currentHist->ReadCount = 0;
|
||
|
||
KeReleaseSpinLock(&physicalDisk->Spinlock, currentIrql);
|
||
|
||
//
|
||
// Set IRP status to success and indicate bytes transferred.
|
||
//
|
||
|
||
HistGramDebugPrint(HISTGRAM_IOCTL_SIZE_SUCCESS,
|
||
"HistGram: IOCTL_DISK_??????? SUCCESS\n");
|
||
|
||
status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
}
|
||
break;
|
||
case IOCTL_DISK_SET_DRIVE_LAYOUT: {
|
||
|
||
PIRP newIrp;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
KEVENT event;
|
||
CCHAR boost;
|
||
|
||
PDRIVE_LAYOUT_INFORMATION driveLayout =
|
||
(PDRIVE_LAYOUT_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
//
|
||
// Perform the set drive layout synchronously. Set both
|
||
// the input and output buffers as the buffer passed.
|
||
//
|
||
|
||
KeInitializeEvent(&event,
|
||
NotificationEvent,
|
||
FALSE);
|
||
|
||
newIrp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_DRIVE_LAYOUT,
|
||
deviceExtension->TargetDeviceObject,
|
||
driveLayout,
|
||
currentIrpStack->Parameters.DeviceIoControl.InputBufferLength,
|
||
driveLayout,
|
||
currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
|
||
FALSE,
|
||
&event,
|
||
&ioStatusBlock);
|
||
|
||
status = IoCallDriver(deviceExtension->TargetDeviceObject, newIrp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event,
|
||
Suspended,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
status = ioStatusBlock.Status;
|
||
|
||
}
|
||
|
||
Irp->IoStatus = ioStatusBlock;
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Process the new partition table. The work for the
|
||
// set drive layout was done synchronously because this
|
||
// routine performs synchronous activities.
|
||
//
|
||
|
||
HistGramUpdateDriveLayout(DeviceObject, Irp);
|
||
boost = IO_DISK_INCREMENT;
|
||
|
||
} else {
|
||
|
||
boost = IO_NO_INCREMENT;
|
||
|
||
}
|
||
|
||
IoCompleteRequest(Irp, boost);
|
||
return status;
|
||
}
|
||
|
||
case IOCTL_DISK_FIND_NEW_DEVICES:
|
||
//
|
||
// Copy current stack to next stack.
|
||
//
|
||
|
||
*nextIrpStack = *currentIrpStack;
|
||
|
||
//
|
||
// Ask to be called back during request completion.
|
||
//
|
||
|
||
IoSetCompletionRoutine(Irp,
|
||
HistGramNewDiskCompletion,
|
||
(PVOID)IoGetConfigurationInformation()->DiskCount,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
//
|
||
// Call target driver.
|
||
//
|
||
|
||
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
default:
|
||
|
||
//
|
||
// Set current stack back one.
|
||
//
|
||
|
||
Irp->CurrentLocation++,
|
||
Irp->Tail.Overlay.CurrentStackLocation++;
|
||
|
||
//
|
||
// Pass unrecognized device control requests
|
||
// down to next driver layer.
|
||
//
|
||
|
||
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
}
|
||
|
||
//
|
||
// Complete request
|
||
//
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return status;
|
||
|
||
} // end HistGramDeviceControl()
|
||
|
||
|
||
NTSTATUS
|
||
HistGramShutdownFlush(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called for a shutdown and flush IRPs. These are sent by the
|
||
system before it actually shuts down or when the file system does a flush.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to device object to being shutdown by system.
|
||
Irp - IRP involved.
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PDEVICE_EXTENSION physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
|
||
|
||
//
|
||
// Set current stack back one.
|
||
//
|
||
|
||
Irp->CurrentLocation++,
|
||
Irp->Tail.Overlay.CurrentStackLocation++;
|
||
|
||
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
} // end HistGramShutdownFlush()
|
||
|
||
|
||
NTSTATUS
|
||
HistGramNewDiskCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for IOCTL_DISK_FIND_NEW_DEVICES.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to device object to being shutdown by system.
|
||
Irp - IRP involved.
|
||
Context - Previous disk count.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension =
|
||
(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Find new disk devices and attach to disk and all of its partitions.
|
||
//
|
||
|
||
HistGramInitialize(DeviceObject->DriverObject, Context, 0);
|
||
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
HistGramDebugPrint(
|
||
ULONG DebugPrintMask,
|
||
PCCHAR DebugMessage,
|
||
...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Debug Print for HistGram Driver
|
||
|
||
Arguments:
|
||
|
||
ID of what is to be printed. Stored in a mask.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
|
||
va_list ap;
|
||
|
||
va_start(ap,DebugMessage);
|
||
|
||
if ((DebugPrintMask & HistGramDebug) != 0) {
|
||
|
||
vsprintf(HistGramBuffer, DebugMessage, ap);
|
||
|
||
DbgPrint(HistGramBuffer);
|
||
}
|
||
|
||
va_end(ap);
|
||
|
||
#endif
|
||
} // HistGramDebugPrint()
|