Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

517 lines
21 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. logidisk.c
  5. Abstract:
  6. This file implements a Performance Object that presents
  7. Logical Disk Performance object data
  8. Created:
  9. Bob Watson 22-Oct-1996
  10. Revision History
  11. --*/
  12. //
  13. // Include Files
  14. //
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #pragma warning ( disable : 4201 )
  19. #include <ntdddisk.h>
  20. #include <windows.h>
  21. #include <ole2.h>
  22. #include <wmium.h>
  23. #pragma warning ( default : 4201 )
  24. #include <assert.h>
  25. #include <winperf.h>
  26. #include <ntprfctr.h>
  27. #define PERF_HEAP hLibHeap
  28. #include <perfutil.h>
  29. #include "perfdisk.h"
  30. #include "diskmsg.h"
  31. #include "datalogi.h"
  32. DWORD APIENTRY
  33. CollectLDiskObjectData(
  34. IN OUT LPVOID *lppData,
  35. IN OUT LPDWORD lpcbTotalBytes,
  36. IN OUT LPDWORD lpNumObjectTypes
  37. )
  38. /*++
  39. Routine Description:
  40. This routine will return the data for the logical disk object
  41. Arguments:
  42. IN OUT LPVOID *lppData
  43. IN: pointer to the address of the buffer to receive the completed
  44. PerfDataBlock and subordinate structures. This routine will
  45. append its data to the buffer starting at the point referenced
  46. by *lppData.
  47. OUT: points to the first byte after the data structure added by this
  48. routine. This routine updated the value at lppdata after appending
  49. its data.
  50. IN OUT LPDWORD lpcbTotalBytes
  51. IN: the address of the DWORD that tells the size in bytes of the
  52. buffer referenced by the lppData argument
  53. OUT: the number of bytes added by this routine is writted to the
  54. DWORD pointed to by this argument
  55. IN OUT LPDWORD NumObjectTypes
  56. IN: the address of the DWORD to receive the number of objects added
  57. by this routine
  58. OUT: the number of objects added by this routine is writted to the
  59. DWORD pointed to by this argument
  60. Returns:
  61. 0 if successful, else Win 32 error code of failure
  62. --*/
  63. {
  64. PLDISK_DATA_DEFINITION pLogicalDiskDataDefinition;
  65. DWORD TotalLen; // Length of the total return block
  66. LDISK_COUNTER_DATA lcdTotal;
  67. DWORD dwStatus = ERROR_SUCCESS;
  68. PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition;
  69. PWNODE_ALL_DATA WmiDiskInfo;
  70. DISK_PERFORMANCE *pDiskPerformance; // Disk driver returns counters here
  71. PWCHAR wszInstanceName;
  72. DWORD dwInstanceNameOffset;
  73. DWORD dwNumLogicalDisks;
  74. WCHAR wszTempName[MAX_PATH];
  75. WORD wNameLength;
  76. WCHAR wszDriveName[MAX_PATH];
  77. DWORD dwDriveNameSize;
  78. PLDISK_COUNTER_DATA pLCD;
  79. BOOL bMoreEntries;
  80. DWORD dwReturn = ERROR_SUCCESS;
  81. LONGLONG llTemp;
  82. DWORD dwTemp;
  83. PDRIVE_VOLUME_ENTRY pVolume;
  84. LONGLONG TotalBytes;
  85. LONGLONG FreeBytes;
  86. DWORD dwCurrentWmiObjCount = 0;
  87. DWORD dwRemapCount = 10;
  88. DOUBLE dReadTime, dWriteTime, dTransferTime;
  89. //
  90. // Check for sufficient space for Logical Disk object
  91. // type definition
  92. //
  93. do {
  94. dwNumLogicalDisks = 0;
  95. // make sure the drive letter map is up-to-date
  96. if (bRemapDriveLetters) {
  97. dwStatus = MapDriveLetters();
  98. // MapDriveLetters clears the remap flag when successful
  99. if (dwStatus != ERROR_SUCCESS) {
  100. *lpcbTotalBytes = (DWORD) 0;
  101. *lpNumObjectTypes = (DWORD) 0;
  102. return dwStatus;
  103. }
  104. }
  105. pLogicalDiskDataDefinition = (LDISK_DATA_DEFINITION *) *lppData;
  106. // clear the accumulator structure
  107. memset (&lcdTotal, 0, sizeof(lcdTotal));
  108. //
  109. // Define Logical Disk data block
  110. //
  111. TotalLen = sizeof (LDISK_DATA_DEFINITION);
  112. if ( *lpcbTotalBytes < TotalLen ) {
  113. *lpcbTotalBytes = (DWORD) 0;
  114. *lpNumObjectTypes = (DWORD) 0;
  115. return ERROR_MORE_DATA;
  116. }
  117. memmove(pLogicalDiskDataDefinition,
  118. &LogicalDiskDataDefinition,
  119. sizeof(LDISK_DATA_DEFINITION));
  120. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  121. &pLogicalDiskDataDefinition[1];
  122. WmiDiskInfo = (PWNODE_ALL_DATA)WmiBuffer;
  123. // make sure the structure is valid
  124. if (WmiDiskInfo->WnodeHeader.BufferSize < sizeof(WNODE_ALL_DATA)) {
  125. bMoreEntries = FALSE;
  126. // just to make sure someone notices on a checked build
  127. assert (WmiDiskInfo->WnodeHeader.BufferSize >= sizeof(WNODE_ALL_DATA));
  128. } else {
  129. // make sure there are some entries to return
  130. bMoreEntries =
  131. (WmiDiskInfo->InstanceCount > 0) ? TRUE : FALSE;
  132. }
  133. while (bMoreEntries) {
  134. ULONG64 StorageManagerName[2];
  135. pDiskPerformance = (PDISK_PERFORMANCE)(
  136. (PUCHAR)WmiDiskInfo + WmiDiskInfo->DataBlockOffset);
  137. dwInstanceNameOffset = (sizeof(DISK_PERFORMANCE)+1) & ~1;
  138. wNameLength = *(WORD *)((LPBYTE)pDiskPerformance +
  139. dwInstanceNameOffset);
  140. if (wNameLength > 0) {
  141. wszInstanceName = (LPWSTR)((LPBYTE)pDiskPerformance +
  142. dwInstanceNameOffset + sizeof(WORD));
  143. // copy to local buffer for processing
  144. if (wNameLength >= MAX_PATH)
  145. wNameLength = MAX_PATH-1; // truncate if necessary
  146. // copy text
  147. memcpy (wszTempName, wszInstanceName, wNameLength);
  148. // then null terminate
  149. wNameLength /= 2;
  150. wszTempName[wNameLength] = 0;
  151. memcpy(&StorageManagerName[0],
  152. &pDiskPerformance->StorageManagerName[0],
  153. 2*sizeof(ULONG64));
  154. DebugPrint((4,
  155. "PERFDISK: Logical Disk Instance: %ws\n", wszTempName));
  156. // see if this is a Physical Drive
  157. if (!IsPhysicalDrive(pDiskPerformance)) {
  158. // it's not so get the name of it for this instance
  159. dwDriveNameSize = sizeof (wszDriveName)
  160. / sizeof(wszDriveName[0]);
  161. dwStatus = GetDriveNameString (
  162. wszTempName,
  163. (DWORD)wNameLength,
  164. pVolumeList,
  165. dwNumVolumeListEntries,
  166. wszDriveName,
  167. &dwDriveNameSize,
  168. (LPCWSTR) &StorageManagerName[0],
  169. pDiskPerformance->StorageDeviceNumber,
  170. &pVolume);
  171. if (dwStatus != ERROR_SUCCESS) {
  172. // just so we have a name
  173. if (SUCCEEDED(StringCchCopyW(&wszDriveName[0],
  174. MAX_PATH, &wszTempName[0]))) {
  175. dwDriveNameSize = lstrlenW(wszDriveName);
  176. }
  177. else {
  178. dwDriveNameSize = MAX_PATH-1;
  179. }
  180. }
  181. if (pVolume != NULL && pVolume->bOffLine) {
  182. DebugPrint((1,"\t loaded as %ws, offline\n", wszDriveName));
  183. }
  184. else {
  185. DebugPrint((4, "\t loaded as %ws\n", wszDriveName));
  186. TotalLen =
  187. // space already used
  188. (DWORD)((PCHAR) pPerfInstanceDefinition -
  189. (PCHAR) pLogicalDiskDataDefinition)
  190. // + estimate of this instance
  191. + sizeof(PERF_INSTANCE_DEFINITION)
  192. + (dwDriveNameSize + 1) * sizeof(WCHAR) ;
  193. TotalLen = QWORD_MULTIPLE (TotalLen);
  194. TotalLen += sizeof(LDISK_COUNTER_DATA);
  195. TotalLen = QWORD_MULTIPLE (TotalLen);
  196. if ( *lpcbTotalBytes < TotalLen ) {
  197. *lpcbTotalBytes = (DWORD) 0;
  198. *lpNumObjectTypes = (DWORD) 0;
  199. dwReturn = ERROR_MORE_DATA;
  200. break;
  201. }
  202. MonBuildInstanceDefinition(
  203. pPerfInstanceDefinition,
  204. (PVOID *) &pLCD,
  205. 0, 0, // no parent
  206. (DWORD)-1,// no unique ID
  207. &wszDriveName[0]);
  208. // insure quadword alignment of the data structure
  209. assert (((DWORD)(pLCD) & 0x00000007) == 0);
  210. // Set up pointer for data collection
  211. // the QueueDepth counter is only a byte so clear the unused bytes
  212. pDiskPerformance->QueueDepth &= 0x000000FF;
  213. //
  214. // Format and collect Physical data
  215. //
  216. lcdTotal.DiskCurrentQueueLength += pDiskPerformance->QueueDepth;
  217. pLCD->DiskCurrentQueueLength = pDiskPerformance->QueueDepth;
  218. llTemp = pDiskPerformance->ReadTime.QuadPart +
  219. pDiskPerformance->WriteTime.QuadPart;
  220. // these values are read in 100 NS units but are expected
  221. // to be in sys perf freq (tick) units for the Sec/op ctrs
  222. // so convert them here
  223. dReadTime = (DOUBLE)(pDiskPerformance->ReadTime.QuadPart);
  224. dWriteTime = (DOUBLE)(pDiskPerformance->WriteTime.QuadPart);
  225. dTransferTime = (DOUBLE)(llTemp);
  226. dReadTime *= dSysTickTo100Ns;
  227. dWriteTime *= dSysTickTo100Ns;
  228. dTransferTime *= dSysTickTo100Ns;
  229. pLCD->DiskTime = llTemp;
  230. pLCD->DiskAvgQueueLength = llTemp;
  231. lcdTotal.DiskAvgQueueLength += llTemp;
  232. lcdTotal.DiskTime += llTemp;
  233. pLCD->DiskReadTime = pDiskPerformance->ReadTime.QuadPart;
  234. pLCD->DiskReadQueueLength = pDiskPerformance->ReadTime.QuadPart;
  235. lcdTotal.DiskReadTime += pDiskPerformance->ReadTime.QuadPart;
  236. lcdTotal.DiskReadQueueLength += pDiskPerformance->ReadTime.QuadPart;
  237. pLCD->DiskWriteTime = pDiskPerformance->WriteTime.QuadPart;
  238. pLCD->DiskWriteQueueLength = pDiskPerformance->WriteTime.QuadPart;
  239. lcdTotal.DiskWriteTime += pDiskPerformance->WriteTime.QuadPart;
  240. lcdTotal.DiskWriteQueueLength += pDiskPerformance->WriteTime.QuadPart;
  241. pLCD->DiskAvgTime = (LONGLONG)dTransferTime;
  242. lcdTotal.DiskAvgTime += (LONGLONG)dTransferTime;
  243. dwTemp = pDiskPerformance->ReadCount +
  244. pDiskPerformance->WriteCount;
  245. lcdTotal.DiskTransfersBase1 += dwTemp;
  246. pLCD->DiskTransfersBase1 = dwTemp;
  247. lcdTotal.DiskAvgReadTime += (LONGLONG)dReadTime;
  248. pLCD->DiskAvgReadTime = (LONGLONG)dReadTime;
  249. lcdTotal.DiskReadsBase1 += pDiskPerformance->ReadCount;
  250. pLCD->DiskReadsBase1 = pDiskPerformance->ReadCount;
  251. lcdTotal.DiskAvgWriteTime += (LONGLONG)dWriteTime;
  252. pLCD->DiskAvgWriteTime = (LONGLONG)dWriteTime;
  253. lcdTotal.DiskWritesBase1 += pDiskPerformance->WriteCount;
  254. pLCD->DiskWritesBase1 = pDiskPerformance->WriteCount;
  255. lcdTotal.DiskTransfers += dwTemp;
  256. pLCD->DiskTransfers = dwTemp;
  257. lcdTotal.DiskReads += pDiskPerformance->ReadCount;
  258. pLCD->DiskReads = pDiskPerformance->ReadCount;
  259. lcdTotal.DiskWrites += pDiskPerformance->WriteCount;
  260. pLCD->DiskWrites = pDiskPerformance->WriteCount;
  261. llTemp = pDiskPerformance->BytesRead.QuadPart +
  262. pDiskPerformance->BytesWritten.QuadPart;
  263. lcdTotal.DiskBytes += llTemp;
  264. pLCD->DiskBytes = llTemp;
  265. lcdTotal.DiskReadBytes += pDiskPerformance->BytesRead.QuadPart;
  266. pLCD->DiskReadBytes = pDiskPerformance->BytesRead.QuadPart;
  267. lcdTotal.DiskWriteBytes += pDiskPerformance->BytesWritten.QuadPart;
  268. pLCD->DiskWriteBytes = pDiskPerformance->BytesWritten.QuadPart;
  269. lcdTotal.DiskAvgBytes += llTemp;
  270. pLCD->DiskAvgBytes = llTemp;
  271. lcdTotal.DiskTransfersBase2 += dwTemp;
  272. pLCD->DiskTransfersBase2 = dwTemp;
  273. lcdTotal.DiskAvgReadBytes += pDiskPerformance->BytesRead.QuadPart;
  274. pLCD->DiskAvgReadBytes = pDiskPerformance->BytesRead.QuadPart;
  275. lcdTotal.DiskReadsBase2 += pDiskPerformance->ReadCount;
  276. pLCD->DiskReadsBase2 = pDiskPerformance->ReadCount;
  277. lcdTotal.DiskAvgWriteBytes += pDiskPerformance->BytesWritten.QuadPart;
  278. pLCD->DiskAvgWriteBytes = pDiskPerformance->BytesWritten.QuadPart;
  279. lcdTotal.DiskWritesBase2 += pDiskPerformance->WriteCount;
  280. pLCD->DiskWritesBase2 = pDiskPerformance->WriteCount;
  281. pLCD->IdleTime = pDiskPerformance->IdleTime.QuadPart;
  282. lcdTotal.IdleTime += pDiskPerformance->IdleTime.QuadPart;
  283. pLCD->SplitCount = pDiskPerformance->SplitCount;
  284. lcdTotal.SplitCount += pDiskPerformance->SplitCount;
  285. pLCD->DiskTimeTimestamp = pDiskPerformance->QueryTime.QuadPart;
  286. lcdTotal.DiskTimeTimestamp += pDiskPerformance->QueryTime.QuadPart;
  287. if (pVolume != NULL) {
  288. TotalBytes = pVolume->TotalBytes;
  289. FreeBytes = pVolume->FreeBytes;
  290. // First two yield percentage of free space;
  291. // last is for raw count of free space in megabytes
  292. lcdTotal.DiskFreeMbytes1 +=
  293. pLCD->DiskFreeMbytes1 = (DWORD)FreeBytes;
  294. lcdTotal.DiskTotalMbytes +=
  295. pLCD->DiskTotalMbytes = (DWORD)TotalBytes;
  296. lcdTotal.DiskFreeMbytes2 +=
  297. pLCD->DiskFreeMbytes2 = (DWORD)FreeBytes;
  298. } else {
  299. if (dwStatus != ERROR_SUCCESS) {
  300. if (!bShownDiskVolumeMessage) {
  301. bShownDiskVolumeMessage = ReportEvent (hEventLog,
  302. EVENTLOG_WARNING_TYPE,
  303. 0,
  304. PERFDISK_UNABLE_QUERY_VOLUME_INFO,
  305. NULL,
  306. 0,
  307. sizeof(DWORD),
  308. NULL,
  309. (LPVOID)&dwStatus);
  310. }
  311. }
  312. // Cannot get space information
  313. pLCD->DiskFreeMbytes1 = 0;
  314. pLCD->DiskTotalMbytes = 0;
  315. pLCD->DiskFreeMbytes2 = 0;
  316. }
  317. // bump pointers in Perf Data Block
  318. dwNumLogicalDisks ++;
  319. pLCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (LDISK_COUNTER_DATA));
  320. pPerfInstanceDefinition = (PPERF_INSTANCE_DEFINITION)&pLCD[1];
  321. }
  322. } else {
  323. // this is a physical drive entry so skip it
  324. #if _DBG_PRINT_INSTANCES
  325. OutputDebugStringW ((LPCWSTR)L" (skipped)");
  326. #endif
  327. }
  328. // count the number of items returned
  329. dwCurrentWmiObjCount++;
  330. } else {
  331. // 0 length name string so skip
  332. }
  333. // bump pointers inside WMI data block
  334. if (WmiDiskInfo->WnodeHeader.Linkage != 0) {
  335. // continue
  336. WmiDiskInfo = (PWNODE_ALL_DATA) (
  337. (LPBYTE)WmiDiskInfo + WmiDiskInfo->WnodeHeader.Linkage);
  338. } else {
  339. // this is the end of the line
  340. bMoreEntries = FALSE;
  341. }
  342. } // end for each volume
  343. // see if number of WMI objects returned is different from
  344. // the last time the instance table was built, if so then
  345. // remap the letters and redo the instances
  346. if (dwCurrentWmiObjCount != dwWmiDriveCount) {
  347. DebugPrint((1, "CollectLDisk: Remap Current %d Drive %d\n",
  348. dwCurrentWmiObjCount, dwWmiDriveCount));
  349. bRemapDriveLetters = TRUE;
  350. dwRemapCount--;
  351. }
  352. } while (bRemapDriveLetters && dwRemapCount);
  353. if (dwNumLogicalDisks > 0) {
  354. // see if there's room for the TOTAL entry....
  355. TotalLen =
  356. // space already used
  357. (DWORD)((PCHAR) pPerfInstanceDefinition -
  358. (PCHAR) pLogicalDiskDataDefinition)
  359. // + estimate of this instance
  360. + sizeof(PERF_INSTANCE_DEFINITION)
  361. + (lstrlenW(wszTotal) + 1) * sizeof(WCHAR) ;
  362. TotalLen = QWORD_MULTIPLE (TotalLen);
  363. TotalLen += sizeof(LDISK_COUNTER_DATA);
  364. TotalLen = QWORD_MULTIPLE (TotalLen);
  365. if ( *lpcbTotalBytes < TotalLen ) {
  366. *lpcbTotalBytes = (DWORD) 0;
  367. *lpNumObjectTypes = (DWORD) 0;
  368. dwReturn = ERROR_MORE_DATA;
  369. } else {
  370. // normalize the total times
  371. lcdTotal.DiskTime /= dwNumLogicalDisks;
  372. lcdTotal.DiskReadTime /= dwNumLogicalDisks;
  373. lcdTotal.DiskWriteTime /= dwNumLogicalDisks;
  374. lcdTotal.IdleTime /= dwNumLogicalDisks;
  375. lcdTotal.DiskTimeTimestamp /= dwNumLogicalDisks;
  376. MonBuildInstanceDefinition(
  377. pPerfInstanceDefinition,
  378. (PVOID *) &pLCD,
  379. 0,
  380. 0,
  381. (DWORD)-1,
  382. wszTotal);
  383. // update the total counters
  384. // insure quadword alignment of the data structure
  385. assert (((DWORD)(pLCD) & 0x00000007) == 0);
  386. memcpy (pLCD, &lcdTotal, sizeof (lcdTotal));
  387. pLCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof(LDISK_COUNTER_DATA));
  388. // and update the "next byte" pointer
  389. pPerfInstanceDefinition = (PPERF_INSTANCE_DEFINITION)&pLCD[1];
  390. // update pointer to next available buffer...
  391. pLogicalDiskDataDefinition->DiskObjectType.NumInstances =
  392. dwNumLogicalDisks + 1; // add 1 for "Total" disk
  393. }
  394. } else {
  395. // there are no instances so adjust the pointer for the
  396. // rest of the code
  397. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  398. &pLogicalDiskDataDefinition[1];
  399. }
  400. if (dwReturn == ERROR_SUCCESS) {
  401. *lpcbTotalBytes =
  402. pLogicalDiskDataDefinition->DiskObjectType.TotalByteLength =
  403. QWORD_MULTIPLE(
  404. (DWORD)((PCHAR) pPerfInstanceDefinition -
  405. (PCHAR) pLogicalDiskDataDefinition));
  406. #if DBG
  407. // sanity check on buffer size estimates
  408. if (*lpcbTotalBytes > TotalLen ) {
  409. DbgPrint ("\nPERFDISK: Logical Disk Perf Ctr. Instance Size Underestimated:");
  410. DbgPrint ("\nPERFDISK: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  411. }
  412. #endif
  413. *lppData = (LPVOID) (((LPBYTE) pLogicalDiskDataDefinition) + (* lpcbTotalBytes));
  414. *lpNumObjectTypes = 1;
  415. }
  416. return dwReturn;
  417. }