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.

1542 lines
38 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Cc.c
  5. Abstract:
  6. WinDbg Extension Api for examining cache manager data structures
  7. Author:
  8. Keith Kaplan [KeithKa] 17-Apr-97
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #undef CREATE_NEW
  15. #undef OPEN_EXISTING
  16. #undef FlagOn
  17. #undef WordAlign
  18. #undef LongAlign
  19. #undef QuadAlign
  20. #pragma hdrstop
  21. //
  22. // DUMP_WITH_OFFSET -- for dumping values contained in structures.
  23. //
  24. #define DUMP_WITH_OFFSET(type, ptr, element, label) \
  25. dprintf( "\n(%03x) %08x %s ", \
  26. FIELD_OFFSET(type, element), \
  27. ptr.element, \
  28. label )
  29. //
  30. // DUMP_LL_W_OFFSET -- for dumping longlongs contained in structures.
  31. //
  32. #define DUMP_LL_W_OFFSET(type, ptr, element, label) \
  33. dprintf( "\n(%03x) %I64x %s ", \
  34. FIELD_OFFSET(type, element), \
  35. ptr.element, \
  36. label )
  37. //
  38. // DUMP_EMBW_OFFSET -- for dumping addresses of values embedded in structures.
  39. //
  40. #define DUMP_EMBW_OFFSET(type, ptr, element, label) \
  41. dprintf( "\n(%03x) %08x %s ", \
  42. FIELD_OFFSET(type, element), \
  43. ptr + FIELD_OFFSET(type, element), \
  44. label )
  45. #define RM( Addr, Obj, pObj, Type, Result, label ) \
  46. (pObj) = (Type) (Addr); \
  47. if ( !ReadMemory( (DWORD) (pObj), &(Obj), sizeof( Obj ), &(Result)) ) { \
  48. if (label) { \
  49. dprintf( "Unable to read memory at %p (%s)\n", (pObj), (label) );\
  50. } else { \
  51. dprintf( "Unable to read memory at %p\n", (pObj) ); \
  52. } \
  53. return; \
  54. }
  55. //
  56. // The help strings printed out
  57. //
  58. static LPSTR Extensions[] = {
  59. "Cache Manager Debugger Extensions:\n",
  60. "bcb [addr] Dump Buffer Control Block",
  61. "scm [addr] Dump Shared Cache Map",
  62. "finddata [FileObject Offset] Find cached data at given offset in file object",
  63. "defwrites Dump deferred write queue",
  64. 0
  65. };
  66. typedef PVOID (*STRUCT_DUMP_ROUTINE)(
  67. IN ULONG64 Address,
  68. IN LONG Options,
  69. USHORT Processor,
  70. HANDLE hCurrentThread
  71. );
  72. VOID
  73. DumpBcb (
  74. IN ULONG64 Address,
  75. IN LONG Options,
  76. USHORT Processor,
  77. HANDLE hCurrentThread
  78. );
  79. VOID
  80. DumpPcm (
  81. IN ULONG64 Address,
  82. IN LONG Options,
  83. USHORT Processor,
  84. HANDLE hCurrentThread
  85. );
  86. VOID
  87. DumpScm (
  88. IN ULONG64 Address,
  89. IN LONG Options,
  90. USHORT Processor,
  91. HANDLE hCurrentThread
  92. );
  93. typedef struct {
  94. CSHORT TypeCode;
  95. char *Text;
  96. } MY_NODE_TYPE;
  97. static MY_NODE_TYPE NodeTypeCodes[] = {
  98. { CACHE_NTC_SHARED_CACHE_MAP, "Shared Cache Map" },
  99. { CACHE_NTC_PRIVATE_CACHE_MAP, "Private Cache Map" },
  100. { CACHE_NTC_BCB, "Bcb" },
  101. { CACHE_NTC_DEFERRED_WRITE, "Deferred Write" },
  102. { CACHE_NTC_MBCB, "Mbcb" },
  103. { CACHE_NTC_OBCB, "Obcb" },
  104. { CACHE_NTC_MBCB_GRANDE, "Mcb Grande" },
  105. { 0, "Unknown" }
  106. };
  107. static const char *
  108. TypeCodeGuess (
  109. IN CSHORT TypeCode
  110. )
  111. /*++
  112. Routine Description:
  113. Guess at a structure's type code
  114. Arguments:
  115. TypeCode - Type code from the data structure
  116. Return Value:
  117. None
  118. --*/
  119. {
  120. int i = 0;
  121. while (NodeTypeCodes[i].TypeCode != 0 &&
  122. NodeTypeCodes[i].TypeCode != TypeCode) {
  123. i++;
  124. }
  125. return NodeTypeCodes[i].Text;
  126. }
  127. VOID
  128. DumpBcb (
  129. IN ULONG64 Address,
  130. IN LONG Options,
  131. USHORT Processor,
  132. HANDLE hCurrentThread
  133. )
  134. /*++
  135. Routine Description:
  136. Dump a specific bcb.
  137. Arguments:
  138. Address - Gives the address of the bcb to dump
  139. Return Value:
  140. None
  141. --*/
  142. {
  143. ULONG Result, NodeTypeCode;
  144. UNREFERENCED_PARAMETER( Options );
  145. UNREFERENCED_PARAMETER( Processor );
  146. UNREFERENCED_PARAMETER( hCurrentThread );
  147. dprintf( "\n Bcb: %08p", Address );
  148. if (GetFieldValue(Address, "BCB", "NodeTypeCode", NodeTypeCode) ) {
  149. dprintf("Unable to read BCB at %p.\n", Address);
  150. return;
  151. }
  152. //
  153. // Type of a bcb must be CACHE_NTC_BCB.
  154. //
  155. if (NodeTypeCode != CACHE_NTC_BCB) {
  156. dprintf( "\nBCB signature does not match, type code is %s",
  157. TypeCodeGuess((CSHORT) NodeTypeCode ));
  158. return;
  159. } else {
  160. dprintf("Use 'dt -n BCB %p' to dump BCB", Address);
  161. return;
  162. }
  163. #if 0
  164. RM( Address, Bcb, pBcb, PBCB, Result, "Bcb" );
  165. //
  166. // Before we get into too much trouble, make sure this looks like a bcb.
  167. //
  168. //
  169. // Type of a bcb must be CACHE_NTC_BCB.
  170. //
  171. if (Bcb.NodeTypeCode != CACHE_NTC_BCB) {
  172. dprintf( "\nBCB signature does not match, type code is %s",
  173. TypeCodeGuess( Bcb.NodeTypeCode ));
  174. return;
  175. }
  176. //
  177. // Having established that this looks like a bcb, let's dump the
  178. // interesting parts.
  179. //
  180. DUMP_WITH_OFFSET( BCB, Bcb, PinCount, "PinCount " );
  181. DUMP_WITH_OFFSET( BCB, Bcb, ByteLength, "ByteLength " );
  182. DUMP_LL_W_OFFSET( BCB, Bcb, FileOffset, "FileOffset " );
  183. DUMP_LL_W_OFFSET( BCB, Bcb, BeyondLastByte, "BeyondLastByte " );
  184. DUMP_LL_W_OFFSET( BCB, Bcb, OldestLsn, "OldestLsn " );
  185. DUMP_LL_W_OFFSET( BCB, Bcb, NewestLsn, "NewestLsn " );
  186. DUMP_WITH_OFFSET( BCB, Bcb, Vacb, "Vacb " );
  187. DUMP_EMBW_OFFSET( BCB, Address, Resource, "Resource " );
  188. DUMP_WITH_OFFSET( BCB, Bcb, SharedCacheMap, "SharedCacheMap " );
  189. DUMP_WITH_OFFSET( BCB, Bcb, BaseAddress, "BaseAddress " );
  190. if (Bcb.Dirty) {
  191. dprintf( "\n Dirty" );
  192. } else {
  193. dprintf( "\n Not dirty" );
  194. }
  195. dprintf( "\n" );
  196. return;
  197. #endif
  198. }
  199. VOID
  200. DumpFindData (
  201. IN ULONG64 FileObjectAddress,
  202. IN LONG ffset,
  203. USHORT Processor,
  204. HANDLE hCurrentThread
  205. )
  206. /*++
  207. Routine Description:
  208. Dump the cache contents for a given file object at the given offset.
  209. Arguments:
  210. FileObjectAddress - Gives the address of the file object to dump
  211. Offset - Gives the offset within the file to dump
  212. Return Value:
  213. None
  214. --*/
  215. {
  216. ULONG Result;
  217. ULONG64 pFileObject;
  218. ULONG64 pScm;
  219. ULONG64 pSop;
  220. ULONG64 VacbAddr; // the address of the vacb
  221. ULONG64 *pVacbAddr;
  222. ULONG64 VacbAddrAddr; // the address of the address of the vacb
  223. ULONG64 pVacb;
  224. ULONG VacbNumber;
  225. ULONG OffsetWithinVacb;
  226. ULONG Level;
  227. ULONG Shift;
  228. ULONG OffsetForLevel;
  229. LONGLONG Offset = ffset;
  230. LONGLONG OriginalOffset = Offset;
  231. LONGLONG LevelMask;
  232. ULONG PtrSize = DBG_PTR_SIZE;
  233. ULONG Type, InVacbsOffset;
  234. ULONG64 SectionObjectPointer, SharedCacheMap, Vacbs, SectionSize_Quad;
  235. UNREFERENCED_PARAMETER( Processor );
  236. UNREFERENCED_PARAMETER( hCurrentThread );
  237. //
  238. // Before we get into too much trouble, make sure this looks like a FileObject or SCM.
  239. //
  240. if (GetFieldValue(FileObjectAddress, "FILE_OBJECT", "Type", Type)) {
  241. dprintf("Unable to read FILE_OBJECT at %p\n", FileObjectAddress);
  242. return;
  243. }
  244. //
  245. // Type must be IO_TYPE_FILE or a CACHE_NTC_SHARED_CACHE_MAP
  246. //
  247. if (Type != CACHE_NTC_SHARED_CACHE_MAP) {
  248. dprintf( "\n FindData for FileObject %08p", FileObjectAddress );
  249. if (Type != IO_TYPE_FILE) {
  250. dprintf( "\nFILE_OBJECT type signature does not match, type code is %s",
  251. TypeCodeGuess((USHORT) Type ));
  252. return;
  253. }
  254. GetFieldValue(FileObjectAddress, "FILE_OBJECT",
  255. "SectionObjectPointer", SectionObjectPointer);
  256. dprintf( " Section Object Pointers: %08p", SectionObjectPointer );
  257. if (GetFieldValue(SectionObjectPointer,
  258. "SECTION_OBJECT_POINTERS",
  259. "SharedCacheMap",
  260. SharedCacheMap)) {
  261. dprintf("Unable to read SECTION_OBJECT_POINTERS at %p\n", SectionObjectPointer);
  262. return;
  263. }
  264. dprintf( "\n Shared Cache Map: %08p", SharedCacheMap );
  265. } else {
  266. dprintf( "\n FindData for SharedCacheMap %08p", FileObjectAddress );
  267. SharedCacheMap = FileObjectAddress;
  268. }
  269. if (GetFieldValue(SharedCacheMap,
  270. "SHARED_CACHE_MAP",
  271. "Vacbs",
  272. Vacbs)) {
  273. dprintf("Unable to read SHARED_CACHE_MAP at %p\n", SharedCacheMap);
  274. return;
  275. }
  276. GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP",
  277. "SectionSize.QuadPart", SectionSize_Quad);
  278. OffsetWithinVacb = (((ULONG) Offset) & (VACB_MAPPING_GRANULARITY - 1));
  279. GetFieldOffset("SHARED_CACHE_MAP", "InitialVacbs", &InVacbsOffset);
  280. dprintf( " File Offset: %I64x ", Offset );
  281. if (Vacbs == (SharedCacheMap + InVacbsOffset)) {
  282. CHAR Buff[50];
  283. //
  284. // Small file case -- we're using one of the Vacbs in the Shared Cache Map's
  285. // embedded array.
  286. //
  287. VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT);
  288. if (VacbNumber >= PREALLOCATED_VACBS) {
  289. dprintf( "\nInvalid VacbNumber for resident Vacb" );
  290. return;
  291. }
  292. sprintf(Buff, "InitialVacbs[%d]", VacbNumber);
  293. GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP",
  294. Buff, VacbAddr);
  295. dprintf( "in VACB number %x", VacbNumber );
  296. } else if (SectionSize_Quad <= (VACB_SIZE_OF_FIRST_LEVEL)) {
  297. //
  298. // Medium file case -- we're using a single level (linear) structure to
  299. // store the Vacbs.
  300. //
  301. VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT);
  302. VacbAddrAddr = Vacbs + (VacbNumber * PtrSize);
  303. if (!ReadPointer(VacbAddrAddr, &VacbAddr)) {
  304. dprintf("Unable to read at %p\n", VacbAddrAddr);
  305. return;
  306. }
  307. // RM( VacbAddrAddr, VacbAddr, pVacbAddr, PVOID, Result, "VACB array" );
  308. dprintf( "in VACB number %x", VacbNumber );
  309. } else {
  310. //
  311. // Large file case -- multilevel Vacb storage.
  312. //
  313. Level = 0;
  314. Shift = VACB_OFFSET_SHIFT + VACB_LEVEL_SHIFT;
  315. //
  316. // Loop to calculate how many levels we have and how much we have to
  317. // shift to index into the first level.
  318. //
  319. do {
  320. Level += 1;
  321. Shift += VACB_LEVEL_SHIFT;
  322. } while (SectionSize_Quad > ((ULONG64)1 << Shift));
  323. //
  324. // Now descend the tree to the bottom level to get the caller's Vacb.
  325. //
  326. Shift -= VACB_LEVEL_SHIFT;
  327. // dprintf( "Shift: 0x%x\n", Shift );
  328. OffsetForLevel = (ULONG) (Offset >> Shift);
  329. VacbAddrAddr = Vacbs + (OffsetForLevel * PtrSize);
  330. if (!ReadPointer(VacbAddrAddr, &VacbAddr)) {
  331. dprintf("Unable to read at %p\n", VacbAddrAddr);
  332. return;
  333. }
  334. while ((VacbAddr != 0) && (Level != 0)) {
  335. Level -= 1;
  336. Offset &= ((LONGLONG)1 << Shift) - 1;
  337. Shift -= VACB_LEVEL_SHIFT;
  338. // dprintf( "Shift: 0x%x\n", Shift );
  339. OffsetForLevel = (ULONG) (Offset >> Shift);
  340. VacbAddrAddr = VacbAddr + (OffsetForLevel * PtrSize);
  341. if (!ReadPointer(VacbAddrAddr, &VacbAddr)) {
  342. dprintf("Unable to read at %p\n", VacbAddrAddr);
  343. return;
  344. }
  345. }
  346. }
  347. if (VacbAddr != 0) {
  348. ULONG64 Base;
  349. dprintf( "\n Vacb: %08p", VacbAddr );
  350. if (GetFieldValue(VacbAddr, "VACB", "BaseAddress", Base)) {
  351. dprintf("Unable to read VACB at %p.", VacbAddr);
  352. return;
  353. }
  354. dprintf( "\n Your data is at: %08p", (Base + OffsetWithinVacb) );
  355. } else {
  356. dprintf( "\n Data at offset %I64x not mapped", OriginalOffset );
  357. }
  358. dprintf( "\n" );
  359. return;
  360. }
  361. VOID
  362. DumpPcm (
  363. IN ULONG64 Address,
  364. IN LONG Options,
  365. USHORT Processor,
  366. HANDLE hCurrentThread
  367. )
  368. /*++
  369. Routine Description:
  370. Dump a specific private cache map.
  371. Arguments:
  372. Address - Gives the address of the private cache map to dump
  373. Return Value:
  374. None
  375. --*/
  376. {
  377. ULONG Result, NodeTypeCode;
  378. ULONG64 pPcm;
  379. UNREFERENCED_PARAMETER( Options );
  380. UNREFERENCED_PARAMETER( Processor );
  381. UNREFERENCED_PARAMETER( hCurrentThread );
  382. dprintf( "\n Private cache map: %08p", Address );
  383. if (GetFieldValue(Address, "PRIVATE_CACHE_MAP",
  384. "NodeTypeCode", NodeTypeCode)) {
  385. dprintf("Unable to read PRIVATE_CACHE_MAP at %p\n", Address);
  386. return;
  387. }
  388. // RM( Address, Pcm, pPcm, PPRIVATE_CACHE_MAP, Result, "PrivateCacheMap" );
  389. //
  390. // Before we get into too much trouble, make sure this looks like a private cache map.
  391. //
  392. //
  393. // Type of a private cache map must be CACHE_NTC_PRIVATE_CACHE_MAP.
  394. //
  395. if (NodeTypeCode != CACHE_NTC_PRIVATE_CACHE_MAP) {
  396. dprintf( "\nPrivate cache map signature does not match, type code is %s",
  397. TypeCodeGuess( (USHORT) NodeTypeCode ));
  398. return;
  399. } else {
  400. dprintf("Use 'dt PRIVATE_CACHE_MAP %p' to dump PCM\n", Address);
  401. return;
  402. }
  403. #if 0
  404. DUMP_WITH_OFFSET( PRIVATE_CACHE_MAP, Pcm, FileObject, "FileObject " );
  405. DUMP_LL_W_OFFSET( PRIVATE_CACHE_MAP, Pcm, FileOffset1, "FileOffset1 " );
  406. DUMP_LL_W_OFFSET( PRIVATE_CACHE_MAP, Pcm, BeyondLastByte1, "BeyondLastByte1 " );
  407. DUMP_LL_W_OFFSET( PRIVATE_CACHE_MAP, Pcm, FileOffset2, "FileOffset2 " );
  408. DUMP_LL_W_OFFSET( PRIVATE_CACHE_MAP, Pcm, BeyondLastByte2, "BeyondLastByte2 " );
  409. DUMP_EMBW_OFFSET( PRIVATE_CACHE_MAP, Address, ReadAheadSpinLock, "ReadAheadSpinLock " );
  410. DUMP_WITH_OFFSET( PRIVATE_CACHE_MAP, Pcm, ReadAheadMask, "ReadAheadMask " );
  411. dprintf( "\n ReadAhead -- " );
  412. if (Pcm.ReadAheadActive) {
  413. dprintf( "Active, " );
  414. } else {
  415. dprintf( "Not active, " );
  416. }
  417. if (Pcm.ReadAheadEnabled) {
  418. dprintf( "Enabled" );
  419. } else {
  420. dprintf( "Not enabled" );
  421. }
  422. dprintf( "\n" );
  423. #endif
  424. return;
  425. }
  426. VOID
  427. DumpScm (
  428. IN ULONG64 Address,
  429. IN LONG Options,
  430. USHORT Processor,
  431. HANDLE hCurrentThread
  432. )
  433. /*++
  434. Routine Description:
  435. Dump a specific shared cache map.
  436. Arguments:
  437. Address - Gives the address of the shared cache map to dump
  438. Return Value:
  439. None
  440. --*/
  441. {
  442. ULONG Result, NodeTypeCode;
  443. ULONG64 pScm;
  444. UNREFERENCED_PARAMETER( Options );
  445. UNREFERENCED_PARAMETER( Processor );
  446. UNREFERENCED_PARAMETER( hCurrentThread );
  447. dprintf( "\n Shared cache map: %08p", Address );
  448. if (GetFieldValue(Address, "SHARED_CACHE_MAP",
  449. "NodeTypeCode", NodeTypeCode)) {
  450. dprintf("Unable to read SHARED_CACHE_MAP at %p\n", Address);
  451. return;
  452. }
  453. // RM( Address, Scm, pScm, PSHARED_CACHE_MAP, Result, "SharedCacheMap" );
  454. //
  455. // Before we get into too much trouble, make sure this looks like a shared cache map.
  456. //
  457. //
  458. // Type of a shared cache map must be CACHE_NTC_SHARED_CACHE_MAP.
  459. //
  460. if (NodeTypeCode != CACHE_NTC_SHARED_CACHE_MAP) {
  461. dprintf( "\nShared cache map signature does not match, type code is %s",
  462. TypeCodeGuess( (USHORT) NodeTypeCode ));
  463. return;
  464. } else {
  465. dprintf("Use 'dt SHARED_CACHE_MAP %p' to dump PCM\n", Address);
  466. return;
  467. }
  468. #if 0
  469. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, OpenCount, "OpenCount " );
  470. DUMP_LL_W_OFFSET( SHARED_CACHE_MAP, Scm, FileSize, "FileSize " );
  471. DUMP_LL_W_OFFSET( SHARED_CACHE_MAP, Scm, SectionSize, "SectionSize " );
  472. DUMP_LL_W_OFFSET( SHARED_CACHE_MAP, Scm, ValidDataLength, "ValidDataLength " );
  473. DUMP_LL_W_OFFSET( SHARED_CACHE_MAP, Scm, ValidDataGoal, "ValidDataGoal " );
  474. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, FileObject, "FileObject " );
  475. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, ActiveVacb, "ActiveVacb " );
  476. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, ActivePage, "ActivePage " );
  477. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, NeedToZero, "NeedToZero " );
  478. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, NeedToZeroPage, "NeedToZeroPage " );
  479. DUMP_EMBW_OFFSET( SHARED_CACHE_MAP, Address, ActiveVacbSpinLock, "ActiveVacbSpinLock " );
  480. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, VacbActiveCount, "VacbActiveCount " );
  481. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, Mbcb, "Mbcb " );
  482. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, DirtyPages, "DirtyPages " );
  483. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, Section, "Section " );
  484. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, Status, "Status " );
  485. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, CreateEvent, "CreateEvent " );
  486. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, WaitOnActiveCount, "WaitOnActiveCount " );
  487. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, PagesToWrite, "PagesToWrite " );
  488. DUMP_LL_W_OFFSET( SHARED_CACHE_MAP, Scm, BeyondLastFlush, "BeyondLastFlush " );
  489. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, Callbacks, "Callbacks " );
  490. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, LazyWriteContext, "LazyWriteContext " );
  491. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, LogHandle, "LogHandle " );
  492. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, FlushToLsnRoutine, "FlushToLsnRoutine " );
  493. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, DirtyPageThreshold, "DirtyPageThreshold " );
  494. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, LazyWritePassCount, "LazyWritePassCount " );
  495. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, UninitializeEvent, "UninitializeEvent " );
  496. DUMP_WITH_OFFSET( SHARED_CACHE_MAP, Scm, NeedToZeroVacb, "NeedToZeroVacb " );
  497. DUMP_EMBW_OFFSET( SHARED_CACHE_MAP, Address, BcbSpinLock, "BcbSpinLock " );
  498. DUMP_EMBW_OFFSET( SHARED_CACHE_MAP, Address, Event, "Event " );
  499. DUMP_EMBW_OFFSET( SHARED_CACHE_MAP, Address, PrivateCacheMap, "PrivateCacheMap " );
  500. dprintf( "\n" );
  501. #endif
  502. return;
  503. }
  504. VOID
  505. DumpDeferredWrites (
  506. IN ULONG64 Address,
  507. IN LONG Options,
  508. USHORT Processor,
  509. HANDLE hCurrentThread
  510. )
  511. /*++
  512. Routine Description:
  513. Dump a specific shared cache map.
  514. Arguments:
  515. Address - Gives the address of the shared cache map to dump
  516. Return Value:
  517. None
  518. --*/
  519. {
  520. ULONG64 ListHeadAddr;
  521. ULONG Result;
  522. ULONG Temp;
  523. ULONG64 GlobalAddress;
  524. ULONG Value;
  525. ULONG64 CcTotalDirtyPages=0;
  526. ULONG64 CcDirtyPageThreshold=0;
  527. ULONG64 MmAvailablePages=0;
  528. ULONG64 MmThrottleTop=0;
  529. ULONG64 MmThrottleBottom=0;
  530. ULONG64 CcSingleDirtySourceDominant=0;
  531. ULONG64 CcDirtyPageHysteresisThreshold=0;
  532. ULONG64 Total;
  533. ULONG Offset;
  534. ULONG64 Flink;
  535. BOOLEAN CheckLazyWriter = FALSE;
  536. BOOLEAN CheckMappedPageWriter = FALSE;
  537. BOOLEAN CheckModifiedPageWriter = FALSE;
  538. UNREFERENCED_PARAMETER( Options );
  539. UNREFERENCED_PARAMETER( Processor );
  540. UNREFERENCED_PARAMETER( hCurrentThread );
  541. UNREFERENCED_PARAMETER( Address );
  542. dprintf( "*** Cache Write Throttle Analysis ***\n\n" );
  543. CcTotalDirtyPages = GetUlongFromAddress( GlobalAddress = GetExpression( "nt!CcTotalDirtyPages" ));
  544. CcDirtyPageThreshold = GetUlongFromAddress( GlobalAddress = GetExpression( "nt!CcDirtyPageThreshold" ));
  545. if (GlobalAddress = GetExpression( "nt!CcDirtyPageHysteresisThreshold" )) {
  546. CcDirtyPageHysteresisThreshold = GetUlongFromAddress( GlobalAddress );
  547. } else {
  548. //
  549. // Write hysteresis is new to Whistler. Assume that if the symbol or read fails
  550. // that we're dealing with a downlevel OS.
  551. //
  552. CcDirtyPageHysteresisThreshold = 0;
  553. }
  554. MmAvailablePages = GetUlongFromAddress( GlobalAddress = GetExpression( "nt!MmAvailablePages" ));
  555. MmThrottleTop = GetUlongFromAddress( GlobalAddress = GetExpression( "nt!MmThrottleTop" ));
  556. MmThrottleBottom = GetUlongFromAddress( GlobalAddress = GetExpression( "nt!MmThrottleBottom" ));
  557. if (GetFieldValue( GlobalAddress = GetExpression( "nt!MmModifiedPageListHead" ),
  558. "nt!_MMPFNLIST",
  559. "Total",
  560. Total)) {
  561. dprintf("Unable to read nt!_MMPFNLIST at %p\n", GlobalAddress);
  562. return;
  563. }
  564. if (!ReadPointer( GlobalAddress = GetExpression( "nt!CcSingleDirtySourceDominant" ),
  565. &CcSingleDirtySourceDominant)) {
  566. //
  567. // CcSingleDirtySourceDominant is present in newer builds only
  568. //
  569. if (GlobalAddress) {
  570. dprintf("Unable to read nt!CcSingleDirtySourceDominant at %p\n", GlobalAddress);
  571. return;
  572. } else {
  573. CcSingleDirtySourceDominant = 0;
  574. }
  575. }
  576. dprintf("\tCcTotalDirtyPages: %8u (%8u Kb)\n"
  577. "\tCcDirtyPageThreshold: %8u (%8u Kb)\n",
  578. (ULONG) CcTotalDirtyPages, (ULONG) CcTotalDirtyPages*_KB,
  579. (ULONG) CcDirtyPageThreshold, (ULONG) CcDirtyPageThreshold*_KB);
  580. if (CcDirtyPageHysteresisThreshold) {
  581. dprintf("\tCcDirtyPageHysteresisThreshold: %8u (%8u Kb)\n",
  582. (ULONG) CcDirtyPageHysteresisThreshold, (ULONG) CcDirtyPageHysteresisThreshold*_KB);
  583. }
  584. dprintf("\tMmAvailablePages: %8u (%8u Kb)\n"
  585. "\tMmThrottleTop: %8u (%8u Kb)\n"
  586. "\tMmThrottleBottom: %8u (%8u Kb)\n"
  587. "\tMmModifiedPageListHead.Total: %8u (%8u Kb)\n\n",
  588. (ULONG) MmAvailablePages, (ULONG) MmAvailablePages*_KB,
  589. (ULONG) MmThrottleTop, (ULONG) MmThrottleTop*_KB,
  590. (ULONG) MmThrottleBottom, (ULONG) MmThrottleBottom*_KB,
  591. (ULONG) Total, (ULONG) Total*_KB );
  592. //
  593. // Cc element of the throttle.
  594. //
  595. if (CcDirtyPageHysteresisThreshold) {
  596. if (CcSingleDirtySourceDominant) {
  597. dprintf("Active write hysteresis with CcSingleDirtySourceDominant (%p)\n",
  598. CcSingleDirtySourceDominant);
  599. //
  600. // Split this up in the rare case where the transition is occuring.
  601. //
  602. if (CcTotalDirtyPages > CcDirtyPageHysteresisThreshold) {
  603. dprintf("CcTotalDirtyPages > CcDirtyPageHysteresisThreshold, writes may be throttled\n");
  604. CheckLazyWriter = TRUE;
  605. }
  606. }
  607. }
  608. if (CcTotalDirtyPages < CcDirtyPageThreshold) {
  609. // From cc.h
  610. #define WRITE_CHARGE_THRESHOLD (64 * PageSize)
  611. if (CcTotalDirtyPages + (WRITE_CHARGE_THRESHOLD/PageSize) >= CcDirtyPageThreshold) {
  612. //
  613. // Fortunately, this is in pages, not bytes. The target's page size could be different.
  614. //
  615. dprintf("CcTotalDirtyPages within %u (max charge) pages of the threshold, writes\n"
  616. " may be throttled\n",
  617. (WRITE_CHARGE_THRESHOLD/PageSize));
  618. CheckLazyWriter = TRUE;
  619. }
  620. } else {
  621. dprintf("CcTotalDirtyPages >= CcDirtyPageThreshold, writes throttled\n");
  622. CheckLazyWriter = TRUE;
  623. }
  624. //
  625. // Mm element of the throttle.
  626. //
  627. if (MmAvailablePages <= MmThrottleTop) {
  628. if (MmAvailablePages <= MmThrottleBottom) {
  629. dprintf("MmAvailablePages <= MmThrottleTop,\n ");
  630. dprintf("and MmAvailablePages <= MmThrottleBottom, writes throttled\n ");
  631. CheckMappedPageWriter = TRUE;
  632. }
  633. if (Total >= 1000) {
  634. if (!CheckMappedPageWriter) {
  635. dprintf("MmAvailablePages <= MmThrottleTop,\n ");
  636. }
  637. dprintf("and modified page list >= 1000, writes throttled\n ");
  638. CheckModifiedPageWriter = TRUE;
  639. }
  640. }
  641. //
  642. // Suggest useful things.
  643. //
  644. if (CheckMappedPageWriter || CheckModifiedPageWriter || CheckLazyWriter) {
  645. dprintf("\nCheck these thread(s): ");
  646. if (CheckMappedPageWriter) {
  647. dprintf("MiMappedPageWriter ");
  648. }
  649. if (CheckModifiedPageWriter) {
  650. dprintf("MiModifiedPageWriter ");
  651. }
  652. if (CheckLazyWriter) {
  653. dprintf("CcWriteBehind(LazyWriter)");
  654. }
  655. dprintf("\n");
  656. if (CheckModifiedPageWriter || CheckMappedPageWriter) {
  657. dprintf("Check system process for the Mm page writers, !vm 3\n");
  658. }
  659. if (CheckLazyWriter) {
  660. dprintf("Check critical workqueue for the lazy writer, !exqueue 16\n");
  661. }
  662. } else {
  663. dprintf("Write throttles not engaged\n");
  664. }
  665. ListHeadAddr = GetExpression( "nt!CcDeferredWrites" );
  666. if (!ListHeadAddr) {
  667. dprintf( "Unable to get address of CcDeferredWrites\n" );
  668. return;
  669. }
  670. GetFieldOffset("nt!_DEFERRED_WRITE", "DeferredWriteLinks", &Offset);
  671. if (GetFieldValue( ListHeadAddr - Offset,
  672. "nt!_DEFERRED_WRITE",
  673. "DeferredWriteLinks.Flink",
  674. Flink)) {
  675. dprintf( "Cannot read nt!_DEFERRED_WRITE at %p\n", ListHeadAddr - Offset);
  676. return;
  677. }
  678. if (Flink != ListHeadAddr) {
  679. ULONG64 Next, Event;
  680. dprintf("Cc Deferred Write list: (CcDeferredWrites)\n");
  681. do {
  682. if (GetFieldValue( Flink - Offset,
  683. "nt!_DEFERRED_WRITE",
  684. "DeferredWriteLinks.Flink",
  685. Next)) {
  686. dprintf( "Cannot read nt!_DEFERRED_WRITE at %p\n", Flink - Offset);
  687. return;
  688. }
  689. InitTypeRead((Flink - Offset), nt!_DEFERRED_WRITE);
  690. dprintf( " File: %p ", ReadField(FileObject) );
  691. if (Event = ReadField(Event)) {
  692. dprintf("Event: %p\n", Event );
  693. } else {
  694. UCHAR Name[0x100];
  695. ULONG64 Displacement, PostRoutine;
  696. GetSymbol( (PostRoutine = ReadField(PostRoutine)), Name, &Displacement );
  697. dprintf("CallBack: %s (%p) ", Name, PostRoutine );
  698. dprintf("Context1: %p ", ReadField(Context1) );
  699. dprintf("Context2: %p\n", ReadField(Context2) );
  700. }
  701. if (CheckControlC()) {
  702. break;
  703. }
  704. } while ( (Flink = Next) != ListHeadAddr );
  705. dprintf( "\n" );
  706. }
  707. return;
  708. }
  709. ULONG
  710. DumpBcbList (
  711. IN PFIELD_INFO ListElement,
  712. IN PVOID Context
  713. )
  714. /*++
  715. Routine Description:
  716. Enumeration callback function for the bcblist
  717. Arguments:
  718. ListElement - Pointer to the containing record
  719. Context - Opaque context passed from the origination function
  720. Return Value:
  721. TRUE to discontinue the enumeration
  722. FALSE to continue the enumeration
  723. --*/
  724. {
  725. ULONG Signature;
  726. ULONG PinCount = 0;
  727. ULONG Dirty = 0;
  728. LONGLONG Offset = 0;
  729. LONG Options = (LONG)(ULONG_PTR) Context;
  730. if (GetFieldValue( ListElement->address, "BCB", "NodeTypeCode", Signature )) {
  731. dprintf( "Unable to read bcb at 0x%I64x\n", ListElement->address );
  732. } else {
  733. if (Signature == CACHE_NTC_BCB) {
  734. GetFieldValue( ListElement->address, "BCB", "PinCount", PinCount );
  735. GetFieldValue( ListElement->address, "BCB", "Dirty", Dirty );
  736. GetFieldValue( ListElement->address, "BCB", "FileOffset.QuadPart", Offset );
  737. if ((Options != 0) || (PinCount != 0)) {
  738. dprintf( " Bcb: %p @ 0x%I64x PinCount: 0x%x Dirty: %x\n", ListElement->address, Offset, PinCount, Dirty );
  739. }
  740. }
  741. }
  742. return FALSE;
  743. }
  744. VOID
  745. DumpLevel(
  746. ULONG64 Address,
  747. ULONG64 MaxSize,
  748. ULONG64 Offset,
  749. ULONG Options,
  750. ULONG Level,
  751. ULONG *Count,
  752. ULONG *CountActive
  753. )
  754. /*++
  755. Routine Description:
  756. Dump a vacb level recursively.
  757. Arguments:
  758. Address - Gives the address of the vacb level to dump
  759. MaxSize - the total section size
  760. Offset - Current offset within the section being dumped. Should be 0 for 1st caller
  761. Options - if non zero dump everything otherwise only dump referenced vacbs
  762. Level - how many levels of vacbs there are
  763. Count, CountActive - accumulators for counts of VACBs and active VACBs
  764. Return Value:
  765. None
  766. --*/
  767. {
  768. int Index;
  769. ULONG PtrSize;
  770. ULONG64 SubAddress;
  771. ULONG64 Overlay = 0;
  772. ULONG64 Limit;
  773. ULONG64 Increment;
  774. USHORT ActiveCount;
  775. Limit = (MaxSize - Offset) >> VACB_OFFSET_SHIFT;
  776. if (Limit > (((ULONG64) 1) << VACB_LEVEL_SHIFT) ) {
  777. Limit = (((ULONG64) 1) << VACB_LEVEL_SHIFT);
  778. }
  779. Increment = ((ULONG64) 1) << ((VACB_LEVEL_SHIFT * (Level - 1)) + VACB_OFFSET_SHIFT );
  780. PtrSize = DBG_PTR_SIZE;
  781. for (Index=0; Index < Limit; Index++ ) {
  782. if (!ReadPointer( Address + PtrSize * Index, &SubAddress )) {
  783. dprintf( "Unable to read subaddress at 0x%I64x\n", Address + PtrSize * Index );
  784. return;
  785. }
  786. if (SubAddress != 0) {
  787. if (Level == 1) {
  788. *Count = *Count + 1;
  789. if (GetFieldValue(SubAddress, "VACB", "Overlay.FileOffset.QuadPart", Overlay)) {
  790. dprintf( "Unable to read overlay at %p\n", SubAddress );
  791. return;
  792. }
  793. //
  794. // If verbose print all vacbs o.w. print any vacbs with reference count
  795. //
  796. ActiveCount = (USHORT) (Overlay & 0xFFFF);
  797. if (ActiveCount != 0) {
  798. *CountActive = *CountActive + 1;
  799. }
  800. if (ActiveCount != 0 || Options != 0) {
  801. dprintf( "%16I64x ActiveCount %u @ Vacb %p\n", (Overlay & ~(0xFFFF)), ActiveCount, SubAddress );
  802. }
  803. } else {
  804. DumpLevel( SubAddress, MaxSize, Offset + Increment * Index, Options, Level - 1, Count, CountActive );
  805. }
  806. }
  807. }
  808. }
  809. VOID
  810. DumpOpenMaps (
  811. IN ULONG64 Address,
  812. IN LONG Options,
  813. USHORT Processor,
  814. HANDLE hCurrentThread
  815. )
  816. /*++
  817. Routine Description:
  818. Dump a specific shared cache map.
  819. Arguments:
  820. Address - Gives the address of the shared cache map to dump
  821. Return Value:
  822. None
  823. --*/
  824. {
  825. ULONG64 FirstBcb;
  826. ULONGLONG SectionSize;
  827. LONG Level;
  828. LONG Shift;
  829. ULONG64 Vacbs;
  830. ULONG ActiveCount = 0, Count = 0;
  831. UNREFERENCED_PARAMETER( Options );
  832. UNREFERENCED_PARAMETER( Processor );
  833. UNREFERENCED_PARAMETER( hCurrentThread );
  834. UNREFERENCED_PARAMETER( Address );
  835. dprintf( "SharedCacheMap %p\n", Address );
  836. //
  837. // First look for mapped vacbs
  838. //
  839. if (GetFieldValue( Address, "SHARED_CACHE_MAP", "SectionSize.QuadPart", SectionSize )) {
  840. dprintf( "Unable to read sectionsize at 0x%I64x\n", Address );
  841. return;
  842. }
  843. if (GetFieldValue( Address, "SHARED_CACHE_MAP", "Vacbs", Vacbs )) {
  844. dprintf( "Unable to read vacbs at 0x%I64x\n", Address );
  845. return;
  846. }
  847. dprintf( "Section Size %I64x\n", SectionSize );
  848. //
  849. // Large file case -- multilevel Vacb storage.
  850. //
  851. Level = 0;
  852. Shift = VACB_OFFSET_SHIFT;
  853. //
  854. // Loop to calculate how many levels we have and how much we have to
  855. // shift to index into the first level.
  856. //
  857. while (SectionSize > ((ULONG64)1 << Shift)) {
  858. Level += 1;
  859. Shift += VACB_LEVEL_SHIFT;
  860. }
  861. dprintf( "Levels %d\n", Level );
  862. if (GetFieldValue( Address, "SHARED_CACHE_MAP", "VacbActiveCount", ActiveCount )) {
  863. dprintf( "Unable to read ActiveVacbCount at 0x%I64x\n", Address );
  864. return;
  865. }
  866. dprintf("VacbActiveCount %u\n\n", ActiveCount );
  867. //
  868. // Now spit out all of the Vacbs.
  869. //
  870. Count = ActiveCount = 0;
  871. DumpLevel( Vacbs, SectionSize, 0, Options, Level, &Count, &ActiveCount );
  872. dprintf( "\n" );
  873. dprintf( "Total VACBs %u Active %u\n", Count, ActiveCount );
  874. if (GetFieldValue( Address, "SHARED_CACHE_MAP", "BcbList.Flink", FirstBcb )) {
  875. dprintf( "Unable to read bcblist at 0x%I64x\n", Address );
  876. return;
  877. }
  878. ListType( "SHARED_CACHE_MAP", FirstBcb, 1, "BcbList.Flink", (PVOID)(ULONG_PTR) Options, DumpBcbList );
  879. return;
  880. }
  881. //
  882. // Entry points, parameter parsers, etc. below
  883. //
  884. static
  885. VOID
  886. ParseAndDump (
  887. IN PCHAR args,
  888. IN STRUCT_DUMP_ROUTINE DumpFunction,
  889. USHORT Processor,
  890. HANDLE hCurrentThread
  891. )
  892. /*++
  893. Routine Description:
  894. Parse command line arguments and dump an ntfs structure.
  895. Arguments:
  896. Args - String of arguments to parse.
  897. DumpFunction - Function to call with parsed arguments.
  898. Return Value: %u
  899. None
  900. --*/
  901. {
  902. ULONG64 StructToDump;
  903. LONG Options;
  904. LPSTR arg2 = args;
  905. //
  906. // If the caller specified an address then that's the item we dump
  907. //
  908. StructToDump = 0;
  909. Options = 0;
  910. if (GetExpressionEx(args,&StructToDump, &args )) {
  911. Options = (ULONG)GetExpression( args );
  912. }
  913. #ifdef CDAVIS_DEBUG
  914. if (!StructToDump){
  915. dprintf("unable to get expression %s\n",arg2);
  916. return;
  917. }
  918. #endif
  919. (*DumpFunction) ( StructToDump, Options, Processor, hCurrentThread );
  920. dprintf( "\n" );
  921. return;
  922. }
  923. static
  924. VOID
  925. PrintHelp (
  926. VOID
  927. )
  928. /*++
  929. Routine Description:
  930. Dump out one line of help for each DECLARE_API
  931. Arguments:
  932. None
  933. Return Value:
  934. None
  935. --*/
  936. {
  937. int i;
  938. for( i=0; Extensions[i]; i++ )
  939. dprintf( " %s\n", Extensions[i] );
  940. }
  941. DECLARE_API( bcb )
  942. /*++
  943. Routine Description:
  944. Dump bcb struct
  945. Arguments:
  946. arg - [Address] [options]
  947. Return Value:
  948. None
  949. --*/
  950. {
  951. ULONG dwProcessor;
  952. HANDLE hCurrentThread;
  953. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  954. dwProcessor = 0;
  955. hCurrentThread = 0;
  956. }
  957. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpBcb, (USHORT)dwProcessor, hCurrentThread );
  958. return S_OK;
  959. }
  960. DECLARE_API( cchelp )
  961. /*++
  962. Routine Description:
  963. Dump help message
  964. Arguments:
  965. None
  966. Return Value:
  967. None
  968. --*/
  969. {
  970. PrintHelp();
  971. return S_OK;
  972. }
  973. DECLARE_API( finddata )
  974. /*++
  975. Routine Description:
  976. Dump bcb struct
  977. Arguments:
  978. arg - [Address] [options]
  979. Return Value:
  980. None
  981. --*/
  982. {
  983. ULONG dwProcessor;
  984. HANDLE hCurrentThread;
  985. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  986. dwProcessor = 0;
  987. hCurrentThread = 0;
  988. }
  989. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpFindData, (USHORT)dwProcessor, hCurrentThread );
  990. return S_OK;
  991. }
  992. DECLARE_API( pcm )
  993. /*++
  994. Routine Description:
  995. Dump private cache map struct
  996. Arguments:
  997. arg - [Address] [options]
  998. Return Value:
  999. None
  1000. --*/
  1001. {
  1002. ULONG dwProcessor;
  1003. HANDLE hCurrentThread;
  1004. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1005. dwProcessor = 0;
  1006. hCurrentThread = 0;
  1007. }
  1008. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpPcm, (USHORT)dwProcessor, hCurrentThread );
  1009. return S_OK;
  1010. }
  1011. DECLARE_API( scm )
  1012. /*++
  1013. Routine Description:
  1014. Dump shared cache map struct
  1015. Arguments:
  1016. arg - [Address] [options]
  1017. Return Value:
  1018. None
  1019. --*/
  1020. {
  1021. ULONG dwProcessor;
  1022. HANDLE hCurrentThread;
  1023. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1024. dwProcessor = 0;
  1025. hCurrentThread = 0;
  1026. }
  1027. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpScm, (USHORT)dwProcessor, hCurrentThread );
  1028. return S_OK;
  1029. }
  1030. DECLARE_API( defwrites )
  1031. /*++
  1032. Routine Description:
  1033. Dump deferred write queue
  1034. Arguments:
  1035. arg - [Address] [options]
  1036. Return Value:
  1037. None
  1038. --*/
  1039. {
  1040. ULONG dwProcessor;
  1041. HANDLE hCurrentThread;
  1042. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1043. dwProcessor = 0;
  1044. hCurrentThread = 0;
  1045. }
  1046. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpDeferredWrites, (USHORT)dwProcessor, hCurrentThread );
  1047. return S_OK;
  1048. }
  1049. DECLARE_API( openmaps )
  1050. /*++
  1051. Routine Description:
  1052. Find referenced bcbs and vacbs in a cache map
  1053. Arguments:
  1054. arg - [Shared cache map address]
  1055. Return Value:
  1056. None
  1057. --*/
  1058. {
  1059. ULONG dwProcessor;
  1060. HANDLE hCurrentThread;
  1061. if (!GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread)) {
  1062. dwProcessor = 0;
  1063. hCurrentThread = 0;
  1064. }
  1065. ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpOpenMaps, (USHORT)dwProcessor, hCurrentThread );
  1066. return S_OK;
  1067. }