|
|
/*++
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
|