1518 lines
43 KiB
C
1518 lines
43 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
perfdisk.c
|
||
|
||
Abstract:
|
||
|
||
|
||
Author:
|
||
|
||
Bob Watson (a-robw) Aug 95
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
// define the WMI Guids for this program
|
||
#ifndef INITGUID
|
||
#define INITGUID 1
|
||
#endif
|
||
|
||
//
|
||
// Force everything to be UNICODE
|
||
//
|
||
#ifndef UNICODE
|
||
#define UNICODE
|
||
#endif
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <ntexapi.h>
|
||
#include <windows.h>
|
||
#include <ole2.h>
|
||
#pragma warning ( disable : 4201 )
|
||
#include <wmium.h>
|
||
#pragma warning ( default : 4201 )
|
||
#include <wmiguid.h>
|
||
#include <winperf.h>
|
||
#if DBG
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#endif
|
||
#include <ntprfctr.h>
|
||
#include <perfutil.h>
|
||
#include <assert.h>
|
||
#include "perfdisk.h"
|
||
#include "diskmsg.h"
|
||
|
||
// define this symbol to test if diskperf has installed itself
|
||
// as an upper filter
|
||
// if this symbol is undefined, then check for diskperf before
|
||
// returning any logical disk counters
|
||
#define _DONT_CHECK_FOR_VOLUME_FILTER
|
||
|
||
#ifndef _DONT_CHECK_FOR_VOLUME_FILTER
|
||
#include <regstr.h> // for REGSTR_VAL_UPPERFILTERS
|
||
#endif
|
||
|
||
// bit field definitions for collect function flags
|
||
|
||
#define POS_COLLECT_PDISK_DATA ((DWORD)0x00000001)
|
||
#define POS_COLLECT_LDISK_DATA ((DWORD)0x00000003)
|
||
#define POS_COLLECT_IGNORE ((DWORD)0x80000000)
|
||
|
||
#define POS_COLLECT_GLOBAL_DATA ((DWORD)0x00000003)
|
||
#define POS_COLLECT_FOREIGN_DATA ((DWORD)0)
|
||
#define POS_COLLECT_COSTLY_DATA ((DWORD)0)
|
||
|
||
// global variables to this DLL
|
||
|
||
HANDLE ThisDLLHandle = NULL;
|
||
HANDLE hEventLog = NULL;
|
||
HANDLE hLibHeap = NULL;
|
||
|
||
BOOL bShownDiskPerfMessage = FALSE;
|
||
BOOL bShownDiskVolumeMessage = FALSE;
|
||
|
||
LPWSTR wszTotal = NULL;
|
||
|
||
const WCHAR cszNT4InstanceNames[] = {L"NT4 Instance Names"};
|
||
const WCHAR cszRegKeyPath[] = {L"System\\CurrentControlSet\\Services\\PerfDisk\\Performance"};
|
||
|
||
const WCHAR cszVolumeKey[] = {L"SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}"};
|
||
const WCHAR cszRefreshInterval[] = {L"VolumeSpaceRefreshInterval"};
|
||
|
||
#define DISKPERF_SERVICE_NAME L"DiskPerf"
|
||
ULONG CheckVolumeFilter();
|
||
|
||
PDRIVE_VOLUME_ENTRY pPhysDiskList = NULL;
|
||
DWORD dwNumPhysDiskListEntries = 0;
|
||
PDRIVE_VOLUME_ENTRY pVolumeList = NULL;
|
||
DWORD dwNumVolumeListEntries = 0;
|
||
DWORD dwWmiDriveCount = 0;
|
||
BOOL bRemapDriveLetters = TRUE;
|
||
DWORD dwMaxVolumeNumber = 0;
|
||
|
||
// start off with a big buffer then size according to return values
|
||
DWORD WmiBufSize = 0x10000; // this can be smaller when the Diskperf.sys
|
||
DWORD WmiAllocSize = 0x10000; // function is fixed to return the right status
|
||
LPBYTE WmiBuffer = NULL;
|
||
|
||
// variables local to this module
|
||
|
||
static POS_FUNCTION_INFO posDataFuncInfo[] = {
|
||
{LOGICAL_DISK_OBJECT_TITLE_INDEX, POS_COLLECT_LDISK_DATA, 0, CollectLDiskObjectData},
|
||
{PHYSICAL_DISK_OBJECT_TITLE_INDEX, POS_COLLECT_PDISK_DATA, 0, CollectPDiskObjectData}
|
||
};
|
||
|
||
#define POS_NUM_FUNCS (sizeof(posDataFuncInfo) / sizeof(posDataFuncInfo[1]))
|
||
|
||
static bInitOk = FALSE;
|
||
static DWORD dwOpenCount = 0;
|
||
|
||
WMIHANDLE hWmiDiskPerf = NULL;
|
||
|
||
PM_OPEN_PROC OpenDiskObject;
|
||
PM_COLLECT_PROC CollecDiskObjectData;
|
||
PM_CLOSE_PROC CloseDiskObject;
|
||
|
||
DOUBLE dSysTickTo100Ns;
|
||
|
||
#if DBG
|
||
const WCHAR cszDebugPrintLevel[] = {L"DebugPrintLevel"};
|
||
|
||
#define DEBUG_BUFFER_LENGTH MAX_PATH*2
|
||
|
||
ULONG_PTR HeapUsed = 0;
|
||
ULONG oldPLSize = 0;
|
||
ULONG oldVLSize = 0;
|
||
ULONG wszSize = 0;
|
||
|
||
ULONG PerfDiskDebug = 0;
|
||
UCHAR PerfDiskDebugBuffer[DEBUG_BUFFER_LENGTH];
|
||
|
||
#endif
|
||
|
||
|
||
BOOL
|
||
WriteNewBootTimeEntry (
|
||
LONGLONG *pBootTime
|
||
)
|
||
{
|
||
LONG lStatus;
|
||
HKEY hKeyPerfDiskPerf;
|
||
DWORD dwType, dwSize;
|
||
BOOL bReturn = FALSE;
|
||
|
||
// try to read the registry value of the last time
|
||
// this error was reported
|
||
lStatus = RegOpenKeyExW (
|
||
HKEY_LOCAL_MACHINE,
|
||
cszRegKeyPath,
|
||
(DWORD)0,
|
||
KEY_WRITE,
|
||
&hKeyPerfDiskPerf);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
// read the key value
|
||
dwType = REG_BINARY;
|
||
dwSize = sizeof (*pBootTime);
|
||
lStatus = RegSetValueExW (
|
||
hKeyPerfDiskPerf,
|
||
(LPCWSTR)L"SystemStartTimeOfLastErrorMsg",
|
||
0L, // reserved
|
||
dwType,
|
||
(LPBYTE)pBootTime,
|
||
dwSize);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
bReturn = TRUE;
|
||
} else {
|
||
// the value hasn't been written and
|
||
SetLastError (lStatus);
|
||
} // else assume the value hasn't been written and
|
||
// return FALSE
|
||
RegCloseKey (hKeyPerfDiskPerf);
|
||
} else {
|
||
// assume the value hasn't been written and
|
||
SetLastError (lStatus);
|
||
}
|
||
|
||
return bReturn;
|
||
}
|
||
BOOL
|
||
NT4NamesAreDefault ()
|
||
{
|
||
LONG lStatus;
|
||
HKEY hKeyPerfDiskPerf;
|
||
DWORD dwType, dwSize;
|
||
DWORD dwValue;
|
||
BOOL bReturn = FALSE;
|
||
|
||
// try to read the registry value of the last time
|
||
// this error was reported
|
||
lStatus = RegOpenKeyExW (
|
||
HKEY_LOCAL_MACHINE,
|
||
cszRegKeyPath,
|
||
(DWORD)0,
|
||
KEY_READ,
|
||
&hKeyPerfDiskPerf);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
// read the key value
|
||
dwType = 0;
|
||
dwSize = sizeof (dwValue);
|
||
lStatus = RegQueryValueExW (
|
||
hKeyPerfDiskPerf,
|
||
cszNT4InstanceNames,
|
||
0L, // reserved
|
||
&dwType,
|
||
(LPBYTE)&dwValue,
|
||
&dwSize);
|
||
if ((lStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
||
if (dwValue != 0) {
|
||
bReturn = TRUE;
|
||
}
|
||
} else {
|
||
// the key is not present or not accessible so
|
||
// leave default as is and
|
||
// return FALSE
|
||
}
|
||
RegCloseKey (hKeyPerfDiskPerf);
|
||
} else {
|
||
// the key could not be opened.
|
||
SetLastError (lStatus);
|
||
}
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
BOOL
|
||
SystemHasBeenRestartedSinceLastEntry (
|
||
DWORD dwReserved, // just in case we want to have multiple tests in the future
|
||
LONGLONG *pBootTime // a buffer to receive the current boot time
|
||
)
|
||
{
|
||
BOOL bReturn = TRUE;
|
||
NTSTATUS ntStatus = ERROR_SUCCESS;
|
||
SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
|
||
DWORD dwReturnedBufferSize = 0;
|
||
HKEY hKeyPerfDiskPerf;
|
||
LONG lStatus;
|
||
DWORD dwType;
|
||
DWORD dwSize;
|
||
LONGLONG llLastErrorStartTime;
|
||
|
||
DBG_UNREFERENCED_PARAMETER(dwReserved);
|
||
|
||
// get the current system boot time (as a filetime)
|
||
memset ((LPVOID)&SysTimeInfo, 0, sizeof(SysTimeInfo));
|
||
|
||
ntStatus = NtQuerySystemInformation(
|
||
SystemTimeOfDayInformation,
|
||
&SysTimeInfo,
|
||
sizeof(SysTimeInfo),
|
||
&dwReturnedBufferSize
|
||
);
|
||
|
||
if (NT_SUCCESS(ntStatus)) {
|
||
// try to read the registry value of the last time
|
||
// this error was reported
|
||
lStatus = RegOpenKeyExW (
|
||
HKEY_LOCAL_MACHINE,
|
||
cszRegKeyPath,
|
||
(DWORD)0,
|
||
KEY_READ,
|
||
&hKeyPerfDiskPerf);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
// read the key value
|
||
dwType = 0;
|
||
dwSize = sizeof (llLastErrorStartTime);
|
||
lStatus = RegQueryValueExW (
|
||
hKeyPerfDiskPerf,
|
||
(LPCWSTR)L"SystemStartTimeOfLastErrorMsg",
|
||
0L, // reserved
|
||
&dwType,
|
||
(LPBYTE)&llLastErrorStartTime,
|
||
&dwSize);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
assert (dwType == REG_BINARY); // this should be a binary type
|
||
assert (dwSize == sizeof (LONGLONG)); // and it should be 8 bytes long
|
||
// compare times
|
||
// if the times are the same, then this message has already been
|
||
// written since the last boot so we don't need to do it again.
|
||
if (SysTimeInfo.BootTime.QuadPart ==
|
||
llLastErrorStartTime) {
|
||
bReturn = FALSE;
|
||
} // else they are the different times so return FALSE
|
||
} // else assume the value hasn't been written and
|
||
// return TRUE
|
||
RegCloseKey (hKeyPerfDiskPerf);
|
||
} // else assume the value hasn't been written and
|
||
// return TRUE
|
||
|
||
// return the boot time if a buffer was passed in
|
||
if (pBootTime != NULL) {
|
||
// save the time
|
||
*pBootTime = SysTimeInfo.BootTime.QuadPart;
|
||
}
|
||
} // else assume that it has been rebooted and return TRUE
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
DllProcessAttach (
|
||
IN HANDLE DllHandle
|
||
)
|
||
/*++
|
||
|
||
Description:
|
||
|
||
perform any initialization function that apply to all object
|
||
modules
|
||
|
||
--*/
|
||
{
|
||
BOOL bReturn = TRUE;
|
||
WCHAR wszTempBuffer[512];
|
||
LONG lStatus;
|
||
DWORD dwBufferSize;
|
||
HKEY hKeyPerfDiskPerf;
|
||
|
||
LARGE_INTEGER liSysTick;
|
||
|
||
UNREFERENCED_PARAMETER(DllHandle);
|
||
|
||
// create heap for this library
|
||
if (hLibHeap == NULL) hLibHeap = HeapCreate (0, 1, 0);
|
||
assert (hLibHeap != NULL);
|
||
|
||
if (hLibHeap == NULL) {
|
||
return FALSE;
|
||
}
|
||
// open handle to the event log
|
||
if (hEventLog == NULL) hEventLog = MonOpenEventLog((LPWSTR)L"PerfDisk");
|
||
assert (hEventLog != NULL);
|
||
|
||
lStatus = GetPerflibKeyValue (
|
||
szTotalValue,
|
||
REG_SZ,
|
||
sizeof(wszTempBuffer),
|
||
(LPVOID)&wszTempBuffer[0],
|
||
DEFAULT_TOTAL_STRING_LEN,
|
||
(LPVOID)&szDefaultTotalString[0]);
|
||
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
// then a string was returned in the temp buffer
|
||
dwBufferSize = lstrlenW (wszTempBuffer) + 1;
|
||
dwBufferSize *= sizeof (WCHAR);
|
||
wszTotal = ALLOCMEM (hLibHeap, HEAP_ZERO_MEMORY, dwBufferSize);
|
||
if (wszTotal == NULL) {
|
||
// unable to allocate buffer so use static buffer
|
||
wszTotal = (LPWSTR)&szDefaultTotalString[0];
|
||
} else {
|
||
memcpy (wszTotal, wszTempBuffer, dwBufferSize);
|
||
#if DBG
|
||
HeapUsed += dwBufferSize;
|
||
wszSize = dwBufferSize;
|
||
DebugPrint((4,
|
||
"DllAttach: wszTotal add %d to %d\n",
|
||
dwBufferSize, HeapUsed));
|
||
#endif
|
||
}
|
||
} else {
|
||
// unable to get string from registry so just use static buffer
|
||
wszTotal = (LPWSTR)&szDefaultTotalString[0];
|
||
}
|
||
|
||
QueryPerformanceFrequency (&liSysTick);
|
||
dSysTickTo100Ns = (DOUBLE)liSysTick.QuadPart;
|
||
dSysTickTo100Ns /= 10000000.0;
|
||
|
||
lStatus = RegOpenKeyExW (
|
||
HKEY_LOCAL_MACHINE,
|
||
cszRegKeyPath,
|
||
(DWORD)0,
|
||
KEY_READ,
|
||
&hKeyPerfDiskPerf);
|
||
if (lStatus == ERROR_SUCCESS) {
|
||
DWORD dwType = REG_DWORD;
|
||
DWORD dwSize = sizeof(DWORD);
|
||
ULONG interval;
|
||
lStatus = RegQueryValueExW (
|
||
hKeyPerfDiskPerf,
|
||
cszRefreshInterval,
|
||
0L, // reserved
|
||
&dwType,
|
||
(LPBYTE)&interval,
|
||
&dwSize);
|
||
if ((lStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
||
g_lRefreshInterval = interval;
|
||
}
|
||
#if DBG
|
||
dwSize = sizeof(DWORD);
|
||
dwType = REG_DWORD;
|
||
lStatus = RegQueryValueExW (
|
||
hKeyPerfDiskPerf,
|
||
cszDebugPrintLevel,
|
||
0L,
|
||
&dwType,
|
||
(LPBYTE) &interval,
|
||
&dwSize);
|
||
if ((lStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
|
||
PerfDiskDebug = interval;
|
||
}
|
||
#endif
|
||
RegCloseKey (hKeyPerfDiskPerf);
|
||
}
|
||
|
||
return bReturn;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
DllProcessDetach (
|
||
IN HANDLE DllHandle
|
||
)
|
||
{
|
||
UNREFERENCED_PARAMETER(DllHandle);
|
||
|
||
if (dwOpenCount > 0) {
|
||
// then close the object now, since the DLL's being discarded
|
||
// prematurely, this is our last chance.
|
||
// this is to insure the object is closed.
|
||
dwOpenCount = 1;
|
||
CloseDiskObject();
|
||
}
|
||
|
||
if ((wszTotal != NULL) && (wszTotal != &szDefaultTotalString[0])) {
|
||
FREEMEM (hLibHeap, 0, wszTotal);
|
||
#if DBG
|
||
HeapUsed -= wszSize;
|
||
DebugPrint((4,
|
||
"DllDetach: wsz freed %d to %d\n",
|
||
wszSize, HeapUsed));
|
||
wszSize = 0;
|
||
#endif
|
||
wszTotal = NULL;
|
||
}
|
||
|
||
if (HeapDestroy (hLibHeap)) {
|
||
hLibHeap = NULL;
|
||
pVolumeList = NULL;
|
||
pPhysDiskList = NULL;
|
||
dwNumVolumeListEntries = 0;
|
||
dwNumPhysDiskListEntries = 0;
|
||
}
|
||
|
||
if (hEventLog != NULL) {
|
||
MonCloseEventLog ();
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL
|
||
__stdcall
|
||
DllInit(
|
||
IN HANDLE DLLHandle,
|
||
IN DWORD Reason,
|
||
IN LPVOID ReservedAndUnused
|
||
)
|
||
{
|
||
ReservedAndUnused;
|
||
|
||
// this will prevent the DLL from getting
|
||
// the DLL_THREAD_* messages
|
||
DisableThreadLibraryCalls (DLLHandle);
|
||
|
||
switch(Reason) {
|
||
case DLL_PROCESS_ATTACH:
|
||
return DllProcessAttach (DLLHandle);
|
||
|
||
case DLL_PROCESS_DETACH:
|
||
return DllProcessDetach (DLLHandle);
|
||
|
||
case DLL_THREAD_ATTACH:
|
||
case DLL_THREAD_DETACH:
|
||
default:
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
MapDriveLetters()
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
DWORD dwLoopCount;
|
||
PDRIVE_VOLUME_ENTRY pTempPtr;
|
||
DWORD dwDriveCount;
|
||
DWORD dwThisEntry;
|
||
PVOID pOldBuffer;
|
||
#if DBG
|
||
LONG64 startTime, endTime;
|
||
LONG elapsed;
|
||
#endif
|
||
|
||
if (pPhysDiskList != NULL) {
|
||
FREEMEM (hLibHeap, 0, pPhysDiskList);
|
||
#if DBG
|
||
HeapUsed -= oldPLSize;
|
||
DebugPrint((4,"MapDriveLetters: PL Freed %d to %d\n",
|
||
oldPLSize, HeapUsed));
|
||
oldPLSize = 0;
|
||
#endif
|
||
pPhysDiskList = NULL;
|
||
}
|
||
#ifdef DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &startTime);
|
||
DebugPrint((1, "BEGIN MapDriveLetters:\n",
|
||
status));
|
||
#endif
|
||
dwNumPhysDiskListEntries = INITIAL_NUM_VOL_LIST_ENTRIES;
|
||
|
||
// Initially allocate enough entries for drives A through Z
|
||
pPhysDiskList = (PDRIVE_VOLUME_ENTRY)ALLOCMEM (
|
||
hLibHeap, HEAP_ZERO_MEMORY,
|
||
(dwNumPhysDiskListEntries * sizeof (DRIVE_VOLUME_ENTRY)));
|
||
|
||
#if DBG
|
||
if (pPhysDiskList == NULL) {
|
||
DebugPrint((2,
|
||
"MapDriveLetters: pPhysDiskList alloc failure\n"));
|
||
}
|
||
#endif
|
||
|
||
if (pPhysDiskList != NULL) {
|
||
// try until we get a big enough buffer
|
||
#if DBG
|
||
ULONG oldsize = dwNumPhysDiskListEntries * sizeof(DRIVE_VOLUME_ENTRY);
|
||
HeapUsed += oldsize;
|
||
oldPLSize = oldsize;
|
||
DebugPrint((4, "MapDriveLetter: Alloc %d to %d\n",
|
||
oldsize, HeapUsed));
|
||
#endif
|
||
dwLoopCount = 10; // no more than 10 retries to get the right size
|
||
while ((status = BuildPhysDiskList (
|
||
hWmiDiskPerf,
|
||
pPhysDiskList,
|
||
&dwNumPhysDiskListEntries)) == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
||
DebugPrint ((3,
|
||
"MapDriveLetters: BuildPhysDiskList returns: %d, requesting %d entries\n",
|
||
status, dwNumPhysDiskListEntries));
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pPhysDiskList)) {
|
||
DebugPrint((2,
|
||
"\tERROR! pPhysDiskList %X corrupted BuildPhysDiskList\n",
|
||
pPhysDiskList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
// if ERROR_INSUFFICIENT_BUFFER, then
|
||
// dwNumPhysDiskListEntries should contain the required size
|
||
pOldBuffer = pPhysDiskList;
|
||
pPhysDiskList = (PDRIVE_VOLUME_ENTRY)REALLOCMEM (
|
||
hLibHeap, HEAP_ZERO_MEMORY,
|
||
pPhysDiskList, (dwNumPhysDiskListEntries * sizeof (DRIVE_VOLUME_ENTRY)));
|
||
|
||
if (pPhysDiskList == NULL) {
|
||
// bail if the allocation failed
|
||
DebugPrint((2,
|
||
"MapDriveLetters: pPhysDiskList realloc failure\n"));
|
||
status = ERROR_OUTOFMEMORY;
|
||
FREEMEM(hLibHeap, 0, pOldBuffer);
|
||
break;
|
||
}
|
||
#if DBG
|
||
else {
|
||
HeapUsed -= oldsize; // subtract the old size and add new size
|
||
oldPLSize = dwNumPhysDiskListEntries*sizeof(DRIVE_VOLUME_ENTRY);
|
||
HeapUsed += oldPLSize;
|
||
DebugPrint((4,
|
||
"MapDriveLetter: Realloc old %d new %d to %d\n",
|
||
oldsize, oldPLSize, HeapUsed));
|
||
}
|
||
#endif
|
||
dwLoopCount--;
|
||
if (!dwLoopCount) {
|
||
status = ERROR_OUTOFMEMORY;
|
||
break;
|
||
}
|
||
DebugPrint ((3,
|
||
"MapDriveLetters: %d retrying BuildPhysDiskList with %d entries\n",
|
||
status, dwNumPhysDiskListEntries));
|
||
}
|
||
}
|
||
|
||
else { // do not bother going any further if no memory
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
DebugPrint ((4,
|
||
"MapDriveLetters: BuildPhysDiskList returns: %d\n", status));
|
||
#if DBG
|
||
if (pPhysDiskList != NULL) {
|
||
if (!HeapValidate(hLibHeap, 0, pPhysDiskList)) {
|
||
DebugPrint((2, "\tERROR! pPhysDiskList %X corrupted after Builds\n",
|
||
pPhysDiskList));
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if (pVolumeList != NULL) {
|
||
// close any open handles
|
||
dwThisEntry = dwNumVolumeListEntries;
|
||
while (dwThisEntry != 0) {
|
||
dwThisEntry--;
|
||
if (pVolumeList[dwThisEntry].hVolume != NULL) {
|
||
NtClose (pVolumeList[dwThisEntry].hVolume);
|
||
}
|
||
}
|
||
#if DBG
|
||
HeapUsed -= oldVLSize;
|
||
DebugPrint((4,"MapDriveLetters: VL Freed %d to %d\n",
|
||
oldVLSize, HeapUsed));
|
||
oldVLSize = 0;
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "\tERROR! pVolumeList %X is corrupted before free\n",
|
||
pVolumeList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
FREEMEM (hLibHeap, 0, pVolumeList);
|
||
pVolumeList = NULL;
|
||
}
|
||
dwNumVolumeListEntries = INITIAL_NUM_VOL_LIST_ENTRIES;
|
||
|
||
// Initially allocate enough entries for letters C through Z
|
||
pVolumeList = (PDRIVE_VOLUME_ENTRY)ALLOCMEM (
|
||
hLibHeap, HEAP_ZERO_MEMORY,
|
||
(dwNumVolumeListEntries * sizeof (DRIVE_VOLUME_ENTRY)));
|
||
|
||
#if DBG
|
||
if (pVolumeList == NULL) {
|
||
DebugPrint((2,
|
||
"MapDriveLetters: pPhysVolumeList alloc failure\n"));
|
||
}
|
||
#endif
|
||
|
||
if (pVolumeList != NULL) {
|
||
// try until we get a big enough buffer
|
||
#if DBG
|
||
ULONG oldsize = dwNumVolumeListEntries * sizeof (DRIVE_VOLUME_ENTRY);
|
||
HeapUsed += oldsize;
|
||
oldVLSize = oldsize;
|
||
DebugPrint((4,
|
||
"MapDriveLetter: Add %d HeapUsed %d\n", oldsize, HeapUsed));
|
||
#endif
|
||
dwLoopCount = 10; // no more than 10 retries to get the right size
|
||
while ((status = BuildVolumeList (
|
||
pVolumeList,
|
||
&dwNumVolumeListEntries)) == ERROR_INSUFFICIENT_BUFFER) {
|
||
// if ERROR_INSUFFICIENT_BUFFER, then
|
||
|
||
DebugPrint ((3,
|
||
"MapDriveLetters: BuildVolumeList returns: %d, requesting %d entries\n",
|
||
status, dwNumVolumeListEntries));
|
||
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "\tERROR! pVolumeList %X corrupted in while\n",
|
||
pVolumeList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
// dwNumVolumeListEntries should contain the required size
|
||
pOldBuffer = pVolumeList;
|
||
pVolumeList = (PDRIVE_VOLUME_ENTRY)REALLOCMEM (
|
||
hLibHeap, HEAP_ZERO_MEMORY,
|
||
pVolumeList, (dwNumVolumeListEntries * sizeof (DRIVE_VOLUME_ENTRY)));
|
||
|
||
if (pVolumeList == NULL) {
|
||
// bail if the allocation failed
|
||
DebugPrint((2,
|
||
"MapDriveLetters: pPhysVolumeList realloc failure\n"));
|
||
status = ERROR_OUTOFMEMORY;
|
||
FREEMEM(hLibHeap, 0, pOldBuffer);
|
||
break;
|
||
}
|
||
#if DBG
|
||
else {
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "\tpVolumeList %X corrupted - realloc\n",
|
||
pVolumeList));
|
||
DbgBreakPoint();
|
||
}
|
||
HeapUsed -= oldsize; // subtract the old size and add new size
|
||
oldVLSize = dwNumVolumeListEntries*sizeof(DRIVE_VOLUME_ENTRY);
|
||
HeapUsed += oldVLSize;
|
||
DebugPrint((4,
|
||
"MapDriveLetter: Realloc old %d new %d to %d\n",
|
||
oldsize, oldVLSize, HeapUsed));
|
||
}
|
||
#endif
|
||
dwLoopCount--;
|
||
if (!dwLoopCount) {
|
||
status = ERROR_OUTOFMEMORY;
|
||
break;
|
||
}
|
||
DebugPrint ((3,
|
||
"MapDriveLetters: retrying BuildVolumeList with %d entries\n",
|
||
status, dwNumVolumeListEntries));
|
||
}
|
||
|
||
DebugPrint ((4, "MapDriveLetters: BuildVolumeList returns %d\n", status));
|
||
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "\tpVolumeList %X corrupted after build\n",
|
||
pVolumeList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
status = FindNewVolumes(
|
||
&pPhysDiskList,
|
||
&dwNumPhysDiskListEntries,
|
||
pVolumeList,
|
||
dwNumVolumeListEntries);
|
||
}
|
||
|
||
// now map the disks to their drive letters
|
||
if (status == ERROR_SUCCESS) {
|
||
status = MapLoadedDisks (
|
||
hWmiDiskPerf,
|
||
pVolumeList,
|
||
&dwNumVolumeListEntries,
|
||
&dwMaxVolumeNumber,
|
||
&dwWmiDriveCount
|
||
);
|
||
|
||
DebugPrint ((4,
|
||
"MapDriveLetters: MapLoadedDisks returns status %d %d MaxVol %d WmiDrive\n",
|
||
status, dwNumVolumeListEntries,
|
||
dwMaxVolumeNumber, dwWmiDriveCount));
|
||
}
|
||
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "\tpVolumeList %X corrupted by MapLoadedDisks\n",
|
||
pVolumeList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
// now assign drive letters to the phys disk list
|
||
dwDriveCount = 0;
|
||
status = MakePhysDiskInstanceNames (
|
||
pPhysDiskList,
|
||
dwNumPhysDiskListEntries,
|
||
&dwDriveCount,
|
||
pVolumeList,
|
||
dwNumVolumeListEntries);
|
||
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pPhysDiskList)) {
|
||
DebugPrint((2, "\tpPhysList %X corrupted by MakePhysDiskInst\n",
|
||
pPhysDiskList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
if (status == ERROR_SUCCESS) {
|
||
// then compress this into an indexed table
|
||
// save original pointer
|
||
pTempPtr = pPhysDiskList;
|
||
|
||
// the function returns the last Drive ID
|
||
// so we need to add 1 here to the count to include
|
||
// the "0" drive
|
||
dwDriveCount += 1;
|
||
|
||
DebugPrint ((4, "\tDrive count now = %d\n",
|
||
dwDriveCount));
|
||
|
||
// and allocate just enough for the actual physical drives
|
||
pPhysDiskList = (PDRIVE_VOLUME_ENTRY)ALLOCMEM (
|
||
hLibHeap, HEAP_ZERO_MEMORY,
|
||
(dwDriveCount * sizeof (DRIVE_VOLUME_ENTRY)));
|
||
|
||
if (pPhysDiskList != NULL) {
|
||
status = CompressPhysDiskTable (
|
||
pTempPtr,
|
||
dwNumPhysDiskListEntries,
|
||
pPhysDiskList,
|
||
dwDriveCount);
|
||
|
||
#if DBG
|
||
if (!HeapValidate(hLibHeap, 0, pPhysDiskList)) {
|
||
DebugPrint((2, "\tpPhysList %X corrupted by CompressPhys\n",
|
||
pPhysDiskList));
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
if (status == ERROR_SUCCESS) {
|
||
dwNumPhysDiskListEntries = dwDriveCount;
|
||
}
|
||
else { // free if cannot compress
|
||
FREEMEM(hLibHeap, 0, pPhysDiskList);
|
||
#if DBG
|
||
HeapUsed -= dwDriveCount * sizeof(DRIVE_VOLUME_ENTRY);
|
||
DebugPrint((4,
|
||
"MapDriveLetters: Compress freed %d to %d\n",
|
||
dwDriveCount*sizeof(DRIVE_VOLUME_ENTRY), HeapUsed));
|
||
#endif
|
||
pPhysDiskList = NULL;
|
||
}
|
||
} else {
|
||
DebugPrint((2,"MapDriveLetters: pPhysDiskList alloc fail for compress\n"));
|
||
status = ERROR_OUTOFMEMORY;
|
||
}
|
||
if (pTempPtr) { // Free the previous list
|
||
FREEMEM(hLibHeap, 0, pTempPtr);
|
||
#if DBG
|
||
HeapUsed -= oldPLSize;
|
||
DebugPrint((4,
|
||
"MapDriveLetters: tempPtr freed %d to %d\n",
|
||
oldPLSize, HeapUsed));
|
||
oldPLSize = 0;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
if (status == ERROR_SUCCESS) {
|
||
oldPLSize = dwDriveCount * sizeof(DRIVE_VOLUME_ENTRY);
|
||
HeapUsed += oldPLSize;
|
||
DebugPrint((4,
|
||
"MapDriveLetters: Compress add %d to %d\n",
|
||
oldPLSize, HeapUsed));
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
if (status == ERROR_SUCCESS) {
|
||
// clear the remap flag
|
||
bRemapDriveLetters = FALSE;
|
||
}
|
||
} else {
|
||
status = ERROR_OUTOFMEMORY;
|
||
}
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((1, "END MapDriveLetters: %d msec\n\n", elapsed));
|
||
#endif
|
||
|
||
// TODO: Need to keep track of different status for PhysDisk & Volumes
|
||
// If Physdisk succeeds whereas Volume fails, need to log event
|
||
// and try and continue with Physdisk counters
|
||
// TODO Post W2K: Free stuff if status != ERROR_SUCCESS
|
||
return status;
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
OpenDiskObject (
|
||
LPWSTR lpDeviceNames
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will initialize the data structures used to pass
|
||
data back to the registry
|
||
|
||
Arguments:
|
||
|
||
Pointer to object ID of each device to be opened (PerfGen)
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
LONGLONG llLastBootTime;
|
||
BOOL bWriteMessage;
|
||
#if DBG
|
||
LONG64 startTime, endTime;
|
||
LONG elapsed;
|
||
#endif
|
||
|
||
UNREFERENCED_PARAMETER (lpDeviceNames);
|
||
|
||
#ifdef DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &startTime);
|
||
DebugPrint((1, "BEGIN OpenDiskObject:\n",
|
||
status));
|
||
#endif
|
||
|
||
if (dwOpenCount == 0) {
|
||
status = WmiOpenBlock (
|
||
(GUID *)&DiskPerfGuid,
|
||
GENERIC_READ,
|
||
&hWmiDiskPerf);
|
||
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((3, "WmiOpenBlock returns: %d in %d msec after BEGIN\n",
|
||
status, elapsed));
|
||
#endif
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
// build drive map
|
||
status = MapDriveLetters();
|
||
|
||
DebugPrint((3,
|
||
"OpenDiskObject: MapDriveLetters returns: %d\n", status));
|
||
}
|
||
// determine instance name format
|
||
bUseNT4InstanceNames = NT4NamesAreDefault();
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((3,
|
||
"OpenDiskObject: NT4Names - %d msec after BEGIN\n", status));
|
||
#endif
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
bInitOk = TRUE;
|
||
}
|
||
}
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
// check to see if this is a WMI error and if so only
|
||
// write the error once per boot cycle
|
||
|
||
if (status == ERROR_WMI_GUID_NOT_FOUND) {
|
||
bWriteMessage = SystemHasBeenRestartedSinceLastEntry (
|
||
0, &llLastBootTime);
|
||
|
||
if (bWriteMessage) {
|
||
// update registry time
|
||
WriteNewBootTimeEntry (&llLastBootTime);
|
||
ReportEvent (hEventLog,
|
||
EVENTLOG_ERROR_TYPE,
|
||
0,
|
||
PERFDISK_UNABLE_QUERY_DISKPERF_INFO,
|
||
NULL,
|
||
0,
|
||
sizeof(DWORD),
|
||
NULL,
|
||
(LPVOID)&status);
|
||
} // else it's already been written
|
||
} else {
|
||
// always write other messages
|
||
ReportEvent (hEventLog,
|
||
EVENTLOG_ERROR_TYPE,
|
||
0,
|
||
PERFDISK_UNABLE_OPEN,
|
||
NULL,
|
||
0,
|
||
sizeof(DWORD),
|
||
NULL,
|
||
(LPVOID)&status);
|
||
}
|
||
} else {
|
||
dwOpenCount++;
|
||
#ifndef _DONT_CHECK_FOR_VOLUME_FILTER
|
||
if (!CheckVolumeFilter()) {
|
||
posDataFuncInfo[0].dwCollectFunctionBit |= POS_COLLECT_IGNORE;
|
||
}
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((3,
|
||
"OpenDiskObject: CheckVolFilter - %d msec after BEGIN\n", status));
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
#if DBG
|
||
if (status == ERROR_SUCCESS) {
|
||
if (pPhysDiskList) {
|
||
DebugPrint((4, "\t Validating pPhysDiskList %X at end Open\n",
|
||
pPhysDiskList));
|
||
if (!HeapValidate(hLibHeap, 0, pPhysDiskList)) {
|
||
DebugPrint((2, "OpenDiskObject: PhysDiskList heap corrupt!\n"));
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
if (pVolumeList) {
|
||
DebugPrint((4, "\t Validating pVolumeList %X at end Open\n",
|
||
pVolumeList));
|
||
if (!HeapValidate(hLibHeap, 0, pVolumeList)) {
|
||
DebugPrint((2, "OpenDiskObject: VolumeList heap corrupt!\n"));
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
if (WmiBuffer) {
|
||
DebugPrint((4, "\t Validating WmiBuffer %X at end Open\n",
|
||
WmiBuffer));
|
||
if (!HeapValidate(hLibHeap, 0, WmiBuffer)) {
|
||
DebugPrint((2, "OpenDiskObject: WmiBuffer heap corrupt!\n"));
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((1, "END OpenDiskObject: %d msec\n\n", elapsed));
|
||
#endif
|
||
return status;
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
CollectDiskObjectData (
|
||
IN LPWSTR lpValueName,
|
||
IN OUT LPVOID *lppData,
|
||
IN OUT LPDWORD lpcbTotalBytes,
|
||
IN OUT LPDWORD lpNumObjectTypes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will return the data for the processor object
|
||
|
||
Arguments:
|
||
|
||
IN LPWSTR lpValueName
|
||
pointer to a wide character string passed by registry.
|
||
|
||
IN OUT LPVOID *lppData
|
||
IN: pointer to the address of the buffer to receive the completed
|
||
PerfDataBlock and subordinate structures. This routine will
|
||
append its data to the buffer starting at the point referenced
|
||
by *lppData.
|
||
OUT: points to the first byte after the data structure added by this
|
||
routine. This routine updated the value at lppdata after appending
|
||
its data.
|
||
|
||
IN OUT LPDWORD lpcbTotalBytes
|
||
IN: the address of the DWORD that tells the size in bytes of the
|
||
buffer referenced by the lppData argument
|
||
OUT: the number of bytes added by this routine is writted to the
|
||
DWORD pointed to by this argument
|
||
|
||
IN OUT LPDWORD NumObjectTypes
|
||
IN: the address of the DWORD to receive the number of objects added
|
||
by this routine
|
||
OUT: the number of objects added by this routine is writted to the
|
||
DWORD pointed to by this argument
|
||
|
||
Returns:
|
||
|
||
0 if successful, else Win 32 error code of failure
|
||
|
||
--*/
|
||
{
|
||
LONG lReturn = ERROR_SUCCESS;
|
||
|
||
NTSTATUS Status;
|
||
|
||
// build bit mask of functions to call
|
||
|
||
DWORD dwQueryType;
|
||
DWORD FunctionCallMask = 0;
|
||
DWORD FunctionIndex;
|
||
|
||
DWORD dwNumObjectsFromFunction;
|
||
DWORD dwOrigBuffSize;
|
||
DWORD dwByteSize;
|
||
#if DBG
|
||
LONG64 startTime, endTime;
|
||
LONG elapsed;
|
||
|
||
GetSystemTimeAsFileTime((LPFILETIME) &startTime);
|
||
DebugPrint((1, "BEGIN CollectDiskObject:\n"));
|
||
#endif
|
||
|
||
if (!bInitOk) {
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
lReturn = ERROR_SUCCESS;
|
||
bShownDiskPerfMessage = TRUE;
|
||
goto COLLECT_BAIL_OUT;
|
||
}
|
||
|
||
dwQueryType = GetQueryType (lpValueName);
|
||
|
||
switch (dwQueryType) {
|
||
case QUERY_ITEMS:
|
||
for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
|
||
if (IsNumberInUnicodeList (
|
||
posDataFuncInfo[FunctionIndex].dwObjectId, lpValueName)) {
|
||
FunctionCallMask |=
|
||
posDataFuncInfo[FunctionIndex].dwCollectFunctionBit;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case QUERY_GLOBAL:
|
||
FunctionCallMask = POS_COLLECT_GLOBAL_DATA;
|
||
break;
|
||
|
||
case QUERY_FOREIGN:
|
||
FunctionCallMask = POS_COLLECT_FOREIGN_DATA;
|
||
break;
|
||
|
||
case QUERY_COSTLY:
|
||
FunctionCallMask = POS_COLLECT_COSTLY_DATA;
|
||
break;
|
||
|
||
default:
|
||
FunctionCallMask = POS_COLLECT_COSTLY_DATA;
|
||
break;
|
||
}
|
||
|
||
// collect data
|
||
|
||
// if either bit is set, collect data
|
||
if (FunctionCallMask & POS_COLLECT_GLOBAL_DATA) {
|
||
__try {
|
||
// read the data from the diskperf driver
|
||
|
||
// only one call at a time is permitted. This should be
|
||
// throttled by the perflib, but just in case we'll test it
|
||
|
||
assert (WmiBuffer == NULL);
|
||
|
||
if (WmiBuffer != NULL) {
|
||
ReportEvent (hEventLog,
|
||
EVENTLOG_ERROR_TYPE,
|
||
0,
|
||
PERFDISK_BUSY,
|
||
NULL,
|
||
0,
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
lReturn = ERROR_SUCCESS;
|
||
goto COLLECT_BAIL_OUT;
|
||
} else {
|
||
WmiBuffer = ALLOCMEM (hLibHeap, HEAP_ZERO_MEMORY, WmiAllocSize);
|
||
#if DBG
|
||
if (WmiBuffer != NULL) {
|
||
HeapUsed += WmiAllocSize;
|
||
DebugPrint((4,
|
||
"CollecDiskObjectData: WmiBuffer added %d to %d\n",
|
||
WmiAllocSize, HeapUsed));
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// the buffer pointer should NOT be null if here
|
||
|
||
if ( WmiBuffer == NULL ) {
|
||
ReportEvent (hEventLog,
|
||
EVENTLOG_WARNING_TYPE,
|
||
0,
|
||
PERFDISK_UNABLE_ALLOC_BUFFER,
|
||
NULL,
|
||
0,
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
lReturn = ERROR_SUCCESS;
|
||
goto COLLECT_BAIL_OUT;
|
||
}
|
||
|
||
WmiBufSize = WmiAllocSize;
|
||
Status = WmiQueryAllDataW (
|
||
hWmiDiskPerf,
|
||
&WmiBufSize,
|
||
WmiBuffer);
|
||
|
||
// if buffer size attempted is too big or too small, resize
|
||
if ((WmiBufSize > 0) && (WmiBufSize != WmiAllocSize)) {
|
||
WmiBuffer = REALLOCMEM (hLibHeap,
|
||
HEAP_ZERO_MEMORY,
|
||
WmiBuffer, WmiBufSize);
|
||
|
||
if (WmiBuffer == NULL) {
|
||
// reallocation failed so bail out
|
||
Status = ERROR_OUTOFMEMORY;
|
||
} else {
|
||
// if the required buffer is larger than
|
||
// originally planned, bump it up some
|
||
#if DBG
|
||
HeapUsed += (WmiBufSize - WmiAllocSize);
|
||
DebugPrint((4,
|
||
"CollectDiskObjectData: Realloc old %d new %d to %d\n",
|
||
WmiAllocSize, WmiBufSize, HeapUsed));
|
||
#endif
|
||
if (WmiBufSize > WmiAllocSize) {
|
||
WmiAllocSize = WmiBufSize;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (Status == ERROR_INSUFFICIENT_BUFFER) {
|
||
// if it didn't work because it was too small the first time
|
||
// try one more time
|
||
Status = WmiQueryAllDataW (
|
||
hWmiDiskPerf,
|
||
&WmiBufSize,
|
||
WmiBuffer);
|
||
|
||
} else {
|
||
// it either worked the fisrt time or it failed because of
|
||
// something other than a buffer size problem
|
||
}
|
||
|
||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||
DebugPrint((2, "\tWmiBuffer %X size %d set to NULL\n",
|
||
WmiBuffer, WmiAllocSize));
|
||
if (WmiBuffer != NULL) {
|
||
if (HeapValidate(hLibHeap, 0, WmiBuffer)) {
|
||
FREEMEM(hLibHeap, 0, WmiBuffer);
|
||
}
|
||
} // else we are really in trouble with WmiBuffer!!
|
||
WmiBuffer = NULL;
|
||
Status = ERROR_OUTOFMEMORY;
|
||
}
|
||
DebugPrint((3,
|
||
"WmiQueryAllData status return: %x Buffer %d bytes\n",
|
||
Status, WmiBufSize));
|
||
|
||
} else {
|
||
// no data required so these counter objects must not be in
|
||
// the query list
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
lReturn = ERROR_SUCCESS;
|
||
goto COLLECT_BAIL_OUT;
|
||
}
|
||
|
||
if (Status == ERROR_SUCCESS) {
|
||
*lpNumObjectTypes = 0;
|
||
dwOrigBuffSize = dwByteSize = *lpcbTotalBytes;
|
||
*lpcbTotalBytes = 0;
|
||
|
||
for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
|
||
if (posDataFuncInfo[FunctionIndex].dwCollectFunctionBit &
|
||
POS_COLLECT_IGNORE)
|
||
continue;
|
||
|
||
if (posDataFuncInfo[FunctionIndex].dwCollectFunctionBit &
|
||
FunctionCallMask) {
|
||
dwNumObjectsFromFunction = 0;
|
||
lReturn = (*posDataFuncInfo[FunctionIndex].pCollectFunction) (
|
||
lppData,
|
||
&dwByteSize,
|
||
&dwNumObjectsFromFunction);
|
||
|
||
if (lReturn == ERROR_SUCCESS) {
|
||
*lpNumObjectTypes += dwNumObjectsFromFunction;
|
||
*lpcbTotalBytes += dwByteSize;
|
||
dwOrigBuffSize -= dwByteSize;
|
||
dwByteSize = dwOrigBuffSize;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
#if DBG
|
||
dwQueryType = HeapValidate(hLibHeap, 0, WmiBuffer);
|
||
DebugPrint((4,
|
||
"CollectDiskObjectData: Index %d HeapValid %d lReturn %d\n",
|
||
FunctionIndex, dwQueryType, lReturn));
|
||
if (!dwQueryType)
|
||
DbgBreakPoint();
|
||
#endif
|
||
}
|
||
} else {
|
||
ReportEvent (hEventLog,
|
||
EVENTLOG_WARNING_TYPE,
|
||
0,
|
||
PERFDISK_UNABLE_QUERY_DISKPERF_INFO,
|
||
NULL,
|
||
0,
|
||
sizeof(DWORD),
|
||
NULL,
|
||
(LPVOID)&Status);
|
||
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
lReturn = ERROR_SUCCESS;
|
||
}
|
||
|
||
// *lppData is updated by each function
|
||
// *lpcbTotalBytes is updated after each successful function
|
||
// *lpNumObjects is updated after each successful function
|
||
|
||
COLLECT_BAIL_OUT:
|
||
if (WmiBuffer != NULL) {
|
||
FREEMEM (hLibHeap, 0, WmiBuffer);
|
||
#if DBG
|
||
HeapUsed -= WmiBufSize;
|
||
DebugPrint((4, "CollectDiskObjectData: Freed %d to %d\n",
|
||
WmiBufSize, HeapUsed));
|
||
#endif
|
||
WmiBuffer = NULL;
|
||
}
|
||
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((1, "END CollectDiskObject: %d msec\n\n", elapsed));
|
||
#endif
|
||
return lReturn;
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
CloseDiskObject (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine closes the open handles to the Signal Gen counters.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
DWORD dwThisEntry;
|
||
#if DBG
|
||
LONG64 startTime, endTime;
|
||
LONG elapsed;
|
||
|
||
GetSystemTimeAsFileTime((LPFILETIME) &startTime);
|
||
DebugPrint((1, "BEGIN CloseDiskObject:\n"));
|
||
#endif
|
||
|
||
if (--dwOpenCount == 0) {
|
||
if (pVolumeList != NULL) {
|
||
// close handles in volume list
|
||
dwThisEntry = dwNumVolumeListEntries;
|
||
while (dwThisEntry != 0) {
|
||
dwThisEntry--;
|
||
if (pVolumeList[dwThisEntry].hVolume != NULL) {
|
||
NtClose (pVolumeList[dwThisEntry].hVolume);
|
||
}
|
||
if (pVolumeList[dwThisEntry].DeviceName.Buffer) {
|
||
FREEMEM(hLibHeap, 0,
|
||
pVolumeList[dwThisEntry].DeviceName.Buffer);
|
||
}
|
||
}
|
||
FREEMEM (hLibHeap, 0, pVolumeList);
|
||
#if DBG
|
||
HeapUsed -= oldVLSize;
|
||
DebugPrint((4, "CloseDiskObject: Freed VL %d to %d\n",
|
||
oldVLSize, HeapUsed));
|
||
oldVLSize = 0;
|
||
#endif
|
||
pVolumeList = NULL;
|
||
dwNumVolumeListEntries = 0;
|
||
}
|
||
if (pPhysDiskList != NULL) {
|
||
FREEMEM (hLibHeap, 0, pPhysDiskList);
|
||
#if DBG
|
||
HeapUsed -= oldPLSize;
|
||
DebugPrint((4, "CloseDiskObject: Freed PL %d to %d\n",
|
||
oldVLSize, HeapUsed));
|
||
oldPLSize = 0;
|
||
#endif
|
||
pPhysDiskList = NULL;
|
||
dwNumPhysDiskListEntries = 0;
|
||
}
|
||
// close PDisk object
|
||
if (hWmiDiskPerf != NULL) {
|
||
status = WmiCloseBlock (hWmiDiskPerf);
|
||
hWmiDiskPerf = NULL;
|
||
}
|
||
}
|
||
#if DBG
|
||
GetSystemTimeAsFileTime((LPFILETIME) &endTime);
|
||
elapsed = (LONG) ((endTime - startTime) / 10000);
|
||
DebugPrint((1, "END CloseDiskObject %d msec\n\n", elapsed));
|
||
#endif
|
||
return status;
|
||
|
||
}
|
||
|
||
#ifndef _DONT_CHECK_FOR_VOLUME_FILTER
|
||
ULONG
|
||
CheckVolumeFilter(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks to see if diskperf is set to be an upper filter
|
||
for Storage Volumes
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE if there is a filter
|
||
|
||
--*/
|
||
{
|
||
WCHAR Buffer[MAX_PATH+1];
|
||
WCHAR *string = Buffer;
|
||
DWORD dwSize = sizeof(Buffer);
|
||
ULONG stringLength, diskperfLen, result, status;
|
||
HKEY hKey;
|
||
|
||
status = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
cszVolumeKey,
|
||
(DWORD) 0,
|
||
KEY_QUERY_VALUE,
|
||
&hKey
|
||
);
|
||
if (status != ERROR_SUCCESS) {
|
||
return FALSE;
|
||
}
|
||
|
||
status = RegQueryValueExW(
|
||
hKey,
|
||
(LPCWSTR)REGSTR_VAL_UPPERFILTERS,
|
||
NULL,
|
||
NULL,
|
||
(LPBYTE) Buffer,
|
||
&dwSize);
|
||
if (status != ERROR_SUCCESS) {
|
||
RegCloseKey(hKey);
|
||
return FALSE;
|
||
}
|
||
|
||
stringLength = wcslen(string);
|
||
|
||
diskperfLen = wcslen((LPCWSTR)DISKPERF_SERVICE_NAME);
|
||
|
||
result = FALSE;
|
||
while(stringLength != 0) {
|
||
|
||
if (diskperfLen == stringLength) {
|
||
if(_wcsicmp(string, (LPCWSTR)DISKPERF_SERVICE_NAME) == 0) {
|
||
result = TRUE;
|
||
break;
|
||
}
|
||
} else {
|
||
string += stringLength + 1;
|
||
stringLength = wcslen(string);
|
||
}
|
||
}
|
||
RegCloseKey(hKey);
|
||
return result;
|
||
}
|
||
#endif
|
||
|
||
#if DBG
|
||
VOID
|
||
PerfDiskDebugPrint(
|
||
ULONG DebugPrintLevel,
|
||
PCCHAR DebugMessage,
|
||
...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Debug print for all PerfDisk
|
||
|
||
Arguments:
|
||
|
||
Debug print level between 0 and 3, with 3 being the most verbose.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
va_list ap;
|
||
|
||
if ((DebugPrintLevel <= (PerfDiskDebug & 0x0000ffff)) ||
|
||
((1 << (DebugPrintLevel + 15)) & PerfDiskDebug)) {
|
||
DbgPrint("%d:Perfdisk!", GetCurrentThreadId());
|
||
}
|
||
else
|
||
return;
|
||
|
||
va_start(ap, DebugMessage);
|
||
|
||
|
||
if ((DebugPrintLevel <= (PerfDiskDebug & 0x0000ffff)) ||
|
||
((1 << (DebugPrintLevel + 15)) & PerfDiskDebug)) {
|
||
|
||
_vsnprintf((LPSTR)PerfDiskDebugBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
|
||
|
||
DbgPrint((LPSTR)PerfDiskDebugBuffer);
|
||
}
|
||
|
||
va_end(ap);
|
||
|
||
}
|
||
#endif
|