Source code of Windows XP (NT5)
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.

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