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.

5100 lines
129 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vfdeadlock.c
  5. Abstract:
  6. Detect deadlocks in arbitrary kernel synchronization objects.
  7. Author:
  8. Jordan Tigani (jtigani) 2-May-2000
  9. Silviu Calinoiu (silviuc) 9-May-2000
  10. Revision History:
  11. Silviu Calinoiu (silviuc) 30-Sep-2000
  12. Rewrote garbage collection of resources since now we have support
  13. from ExFreePool.
  14. Got rid of the ref/deref scheme for threads.
  15. Major optimization work.
  16. --*/
  17. /*++
  18. The Deadlock Verifier
  19. The deadlock verifier is used to detect potential deadlocks. It does this
  20. by acquiring the history of how resources are acquired and trying to figure
  21. out on the fly if there are any potential lock hierarchy issues. The algorithms
  22. for finding cycles in the lock dependency graph is totally "blind". This means
  23. that if a driver acquires lock A then B in one place and lock B then A in
  24. another this will be triggered as a deadlock issue. This will happen even if you
  25. can build a proof based on other contextual factors that the deadlock can never
  26. happen.
  27. The deadlock verifier assumes there are four operations during the lifetime
  28. of a resource: initialize(), acquire(), release() and free(). The only one that
  29. is caught 100% of the time is free() due to special support from the kernel
  30. pool manager. The other ones can be missed if the operations are performed
  31. by an unverified driver or by kernel with kernel verifier disabled. The most
  32. typical of these misses is the initialize(). For example the kernel initializes
  33. a resource and then passes it to a driver to be used in acquire()/releae() cycles.
  34. This situation is covered 100% by the deadlock verifier. It will never complain
  35. about "resource uninitialized" issues.
  36. Missing acquire() or release() operations is trickier to deal with.
  37. This can happen if the a verified driver acquires a resource and then another
  38. driver that is not verified releases it or viceversa. This is in and on itself
  39. a very bad programming practive and therefore the deadlock verifier will flag
  40. these issues. As a side note we cannot do too much about working around them
  41. given that we would like to. Also, because missing acquire() or release()
  42. operations puts deadlock verifier internal structures into inconsistent
  43. states these failures are difficult to debug.
  44. The deadlock verifier stores the lock dependency graph using three types
  45. of structures: THREAD, RESOURCE, NODE.
  46. For every active thread in the system that holds at least one resource
  47. the package maintains a THREAD structure. This gets created when a thread
  48. acquires first resource and gets destroyed when thread releases the last
  49. resource. If a thread does not hold any resource it will not have a
  50. corresponding THREAD structure.
  51. For every resource in the system there is a RESOURCE structure. This is created
  52. when Initialize() is called in a verified driver or we first encounter an
  53. Acquire() in a verified driver. Note that a resource can be initialized in
  54. an unverified driver and then passed to a verified driver for use. Therefore
  55. we can encounter Acquire() operations for resources that are not in the
  56. deadlock verifier database. The resource gets deleted from the database when
  57. the memory containing it is freed either because ExFreePool gets called or
  58. Every acquisition of a resource is modeled by a NODE structure. When a thread
  59. acquires resource B while holding A the deadlock verifier will create a NODE
  60. for B and link it to the node for A.
  61. There are three important functions that make the interface with the outside
  62. world.
  63. VfDeadlockInitializeResource hook for resource initialization
  64. VfDeadlockAcquireResource hook for resource acquire
  65. VfDeadlockReleaseResource hook for resource release
  66. VerifierDeadlockFreePool hook called from ExFreePool for every free()
  67. --*/
  68. #include "vfdef.h"
  69. //
  70. // *TO DO* LIST
  71. //
  72. // [-] Hook KeTryAcquireSpinLock
  73. // [-] Implement dynamic reset scheme for weird situations
  74. // [-] Implement Strict and VeryStrict scheme.
  75. //
  76. //
  77. // Enable/disable the deadlock detection package. This can be used
  78. // to disable temporarily the deadlock detection package.
  79. //
  80. BOOLEAN ViDeadlockDetectionEnabled;
  81. //
  82. // If true we will complain about release() without acquire() or acquire()
  83. // while we think the resource is still owned. This can happen legitimately
  84. // if a lock is shared between drivers and for example acquire() happens in
  85. // an unverified driver and release() in a verified one or viceversa. The
  86. // safest thing would be to enable this checks only if kernel verifier and
  87. // dirver verifier for all drivers are enabled.
  88. //
  89. BOOLEAN ViDeadlockStrict;
  90. //
  91. // If true we will complain about uninitialized and double initialized
  92. // resources. If false we resolve quitely these issues on the fly by
  93. // simulating an initialize ourselves during the acquire() operation.
  94. // This can happen legitimately if the resource is initialized in an
  95. // unverified driver and passed to a verified one to be used. Therefore
  96. // the safest thing would be to enable this only if kernel verifier and
  97. // all driver verifier for all dirvers are enabled.
  98. //
  99. BOOLEAN ViDeadlockVeryStrict;
  100. //
  101. // The way to deal with release() without acquire() issues is to reset
  102. // the deadlock verifier completely. Here we keep a counter of how often
  103. // does this happen.
  104. //
  105. ULONG ViDeadlockResets;
  106. //
  107. // If this is true only spinlocks are verified. All other resources
  108. // are just ignored.
  109. //
  110. BOOLEAN ViDeadlockVerifyOnlySpinlocks;
  111. ULONG ViVerifyOnlySpinlocksFromRegistry;
  112. //
  113. // AgeWindow is used while trimming the graph nodes that have not
  114. // been accessed in a while. If the global age minus the age of the node
  115. // is bigger than the age window then the node is a candidate for trimming.
  116. //
  117. // The TrimThreshold variable controls if the trimming will start for a
  118. // resource. As long as a resource has less than TrimThreshold nodes we will
  119. // not apply the ageing algorithm to trim nodes for that resource.
  120. //
  121. ULONG ViDeadlockAgeWindow = 2000;
  122. ULONG ViDeadlockTrimThreshold = 128;
  123. //
  124. // Various deadlock verification flags flags
  125. //
  126. // Recursive aquisition ok: mutexes can be recursively acquired
  127. //
  128. // No initialization function: if resource type does not have such a function
  129. // we cannot expect that in acquire() the resource is already initialized
  130. // by a previous call to initialize(). Fast mutexes are like this.
  131. //
  132. // Reverse release ok: release is not done in the same order as acquire
  133. //
  134. // Reinitialize ok: sometimes they reinitialize the resource.
  135. //
  136. // Note that a resource might appear as uninitialized if it is initialized
  137. // in an unverified driver and then passed to a verified driver that calls
  138. // acquire(). This is for instance the case with device extensions that are
  139. // allocated by the kernel but used by a particular driver.
  140. //
  141. // silviuc: based on this maybe we should drop the whole not initialized thing?
  142. //
  143. #define VI_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK 0x0001
  144. #define VI_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION 0x0002
  145. #define VI_DEADLOCK_FLAG_REVERSE_RELEASE_OK 0x0004
  146. #define VI_DEADLOCK_FLAG_REINITIALIZE_OK 0x0008
  147. //
  148. // Specific verification flags for each resource type. The
  149. // indeces in the vector match the values for the enumeration
  150. // type VI_DEADLOCK_RESOURCE_TYPE from ntos\inc\verifier.h.
  151. //
  152. ULONG ViDeadlockResourceTypeInfo[VfDeadlockTypeMaximum] =
  153. {
  154. // ViDeadlockUnknown //
  155. 0,
  156. // ViDeadlockMutex//
  157. VI_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK |
  158. 0,
  159. // ViDeadlockFastMutex //
  160. VI_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION |
  161. 0,
  162. // ViDeadlockFastMutexUnsafe //
  163. VI_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION |
  164. VI_DEADLOCK_FLAG_REVERSE_RELEASE_OK |
  165. 0,
  166. // ViDeadlockSpinLock //
  167. VI_DEADLOCK_FLAG_REVERSE_RELEASE_OK |
  168. VI_DEADLOCK_FLAG_REINITIALIZE_OK |
  169. 0,
  170. // ViDeadlockQueuedSpinLock //
  171. VI_DEADLOCK_FLAG_NO_INITIALIZATION_FUNCTION |
  172. 0,
  173. };
  174. NTSYSAPI
  175. USHORT
  176. NTAPI
  177. RtlCaptureStackBackTrace(
  178. IN ULONG FramesToSkip,
  179. IN ULONG FramesToCapture,
  180. OUT PVOID *BackTrace,
  181. OUT PULONG BackTraceHash
  182. );
  183. //
  184. // Control debugging behavior. A zero value means bugcheck for every failure.
  185. //
  186. ULONG ViDeadlockDebug;
  187. //
  188. // Various health indicators
  189. //
  190. struct {
  191. ULONG AllocationFailures : 1;
  192. ULONG KernelVerifierEnabled : 1;
  193. ULONG DriverVerifierForAllEnabled : 1;
  194. ULONG SequenceNumberOverflow : 1;
  195. ULONG DeadlockParticipantsOverflow : 1;
  196. ULONG ResourceNodeCountOverflow : 1;
  197. ULONG Reserved : 15;
  198. } ViDeadlockState;
  199. //
  200. // Maximum number of locks acceptable to be hold simultaneously
  201. //
  202. ULONG ViDeadlockSimultaneousLocksLimit = 10;
  203. //
  204. // Deadlock verifier specific issues (bugs)
  205. //
  206. // SELF_DEADLOCK
  207. //
  208. // Acquiring the same resource recursively.
  209. //
  210. // DEADLOCK_DETECTED
  211. //
  212. // Plain deadlock. Need the previous information
  213. // messages to build a deadlock proof.
  214. //
  215. // UNINITIALIZED_RESOURCE
  216. //
  217. // Acquiring a resource that was never initialized.
  218. //
  219. // UNEXPECTED_RELEASE
  220. //
  221. // Releasing a resource which is not the last one
  222. // acquired by the current thread. Spinlocks are handled like this
  223. // in a few drivers. It is not a bug per se.
  224. //
  225. // UNEXPECTED_THREAD
  226. //
  227. // Current thread does not have any resources acquired. This may be legit if
  228. // we acquire in one thread and release in another. This would be bad programming
  229. // practice but not a crash waiting to happen per se.
  230. //
  231. // MULTIPLE_INITIALIZATION
  232. //
  233. // Attempting to initialize a second time the same resource.
  234. //
  235. // THREAD_HOLDS_RESOURCES
  236. //
  237. // Thread was killed while holding resources or a resource is being
  238. // deleted while holding resources.
  239. //
  240. #define VI_DEADLOCK_ISSUE_SELF_DEADLOCK 0x1000
  241. #define VI_DEADLOCK_ISSUE_DEADLOCK_DETECTED 0x1001
  242. #define VI_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE 0x1002
  243. #define VI_DEADLOCK_ISSUE_UNEXPECTED_RELEASE 0x1003
  244. #define VI_DEADLOCK_ISSUE_UNEXPECTED_THREAD 0x1004
  245. #define VI_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION 0x1005
  246. #define VI_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES 0x1006
  247. #define VI_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE 0x1007
  248. //
  249. // Performance counters read from registry.
  250. //
  251. ULONG ViSearchedNodesLimitFromRegistry;
  252. ULONG ViRecursionDepthLimitFromRegistry;
  253. //
  254. // Water marks for the cache of freed structures.
  255. //
  256. #define VI_DEADLOCK_MAX_FREE_THREAD 0x10
  257. #define VI_DEADLOCK_MAX_FREE_NODE 0x40
  258. #define VI_DEADLOCK_MAX_FREE_RESOURCE 0x20
  259. WORK_QUEUE_ITEM ViTrimDeadlockPoolWorkItem;
  260. //
  261. // Amount of memory preallocated if kernel verifier
  262. // is enabled. If kernel verifier is enabled no memory
  263. // is ever allocated from kernel pool except in the
  264. // DeadlockDetectionInitialize() routine.
  265. //
  266. ULONG ViDeadlockReservedThreads = 0x200;
  267. ULONG ViDeadlockReservedNodes = 0x4000;
  268. ULONG ViDeadlockReservedResources = 0x2000;
  269. //
  270. // Block types that can be allocated.
  271. //
  272. typedef enum {
  273. ViDeadlockUnknown = 0,
  274. ViDeadlockResource,
  275. ViDeadlockNode,
  276. ViDeadlockThread
  277. } VI_DEADLOCK_ALLOC_TYPE;
  278. //
  279. // VI_DEADLOCK_GLOBALS
  280. //
  281. #define VI_DEADLOCK_HASH_BINS 0x1F
  282. PVI_DEADLOCK_GLOBALS ViDeadlockGlobals;
  283. //
  284. // Default maximum recursion depth for the deadlock
  285. // detection algorithm. This can be overridden by registry.
  286. //
  287. #define VI_DEADLOCK_MAXIMUM_DEGREE 4
  288. //
  289. // Default maximum number of searched nodes for the deadlock
  290. // detection algorithm. This can be overridden by registry.
  291. //
  292. #define VI_DEADLOCK_MAXIMUM_SEARCH 1000
  293. //
  294. // Verifier deadlock detection pool tag.
  295. //
  296. #define VI_DEADLOCK_TAG 'kclD'
  297. /////////////////////////////////////////////////////////////////////
  298. /////////////////////////////// Internal deadlock detection functions
  299. /////////////////////////////////////////////////////////////////////
  300. VOID
  301. VfDeadlockDetectionInitialize (
  302. );
  303. VOID
  304. VfDeadlockDetectionCleanup (
  305. );
  306. VOID
  307. ViDeadlockDetectionReset (
  308. );
  309. PLIST_ENTRY
  310. ViDeadlockDatabaseHash(
  311. IN PLIST_ENTRY Database,
  312. IN PVOID Address
  313. );
  314. BOOLEAN
  315. ViDeadlockIsDriverInList (
  316. PUNICODE_STRING BigString,
  317. PUNICODE_STRING Match
  318. );
  319. PVI_DEADLOCK_RESOURCE
  320. ViDeadlockSearchResource(
  321. IN PVOID ResourceAddress
  322. );
  323. BOOLEAN
  324. ViDeadlockSimilarNode (
  325. IN PVOID Resource,
  326. IN BOOLEAN TryNode,
  327. IN PVI_DEADLOCK_NODE Node
  328. );
  329. BOOLEAN
  330. ViDeadlockCanProceed (
  331. IN PVOID Resource, OPTIONAL
  332. IN PVOID CallAddress, OPTIONAL
  333. IN VI_DEADLOCK_RESOURCE_TYPE Type OPTIONAL
  334. );
  335. BOOLEAN
  336. ViDeadlockAnalyze(
  337. IN PVOID ResourceAddress,
  338. IN PVI_DEADLOCK_NODE CurrentNode,
  339. IN BOOLEAN FirstCall,
  340. IN ULONG Degree
  341. );
  342. PVI_DEADLOCK_THREAD
  343. ViDeadlockSearchThread (
  344. PKTHREAD Thread
  345. );
  346. PVI_DEADLOCK_THREAD
  347. ViDeadlockAddThread (
  348. PKTHREAD Thread,
  349. PVOID ReservedThread
  350. );
  351. VOID
  352. ViDeadlockDeleteThread (
  353. PVI_DEADLOCK_THREAD Thread,
  354. BOOLEAN Cleanup
  355. );
  356. BOOLEAN
  357. ViDeadlockAddResource(
  358. IN PVOID Resource,
  359. IN VI_DEADLOCK_RESOURCE_TYPE Type,
  360. IN PVOID Caller,
  361. IN PVOID ReservedResource
  362. );
  363. PVOID
  364. ViDeadlockAllocate (
  365. VI_DEADLOCK_ALLOC_TYPE Type
  366. );
  367. VOID
  368. ViDeadlockFree (
  369. PVOID Object,
  370. VI_DEADLOCK_ALLOC_TYPE Type
  371. );
  372. VOID
  373. ViDeadlockTrimPoolCache (
  374. VOID
  375. );
  376. VOID
  377. ViDeadlockTrimPoolCacheWorker (
  378. PVOID
  379. );
  380. PVOID
  381. ViDeadlockAllocateFromPoolCache (
  382. PULONG Count,
  383. ULONG MaximumCount,
  384. PLIST_ENTRY List,
  385. SIZE_T Offset
  386. );
  387. VOID
  388. ViDeadlockFreeIntoPoolCache (
  389. PVOID Object,
  390. PULONG Count,
  391. PLIST_ENTRY List,
  392. SIZE_T Offset
  393. );
  394. VOID
  395. ViDeadlockReportIssue (
  396. ULONG_PTR Param1,
  397. ULONG_PTR Param2,
  398. ULONG_PTR Param3,
  399. ULONG_PTR Param4
  400. );
  401. VOID
  402. ViDeadlockAddParticipant(
  403. PVI_DEADLOCK_NODE Node
  404. );
  405. VOID
  406. ViDeadlockDeleteResource (
  407. PVI_DEADLOCK_RESOURCE Resource,
  408. BOOLEAN Cleanup
  409. );
  410. VOID
  411. ViDeadlockDeleteNode (
  412. PVI_DEADLOCK_NODE Node,
  413. BOOLEAN Cleanup
  414. );
  415. ULONG
  416. ViDeadlockNodeLevel (
  417. PVI_DEADLOCK_NODE Node
  418. );
  419. BOOLEAN
  420. ViDeadlockCertify(
  421. VOID
  422. );
  423. BOOLEAN
  424. ViDeadlockDetectionIsLockedAlready (
  425. );
  426. VOID
  427. ViDeadlockDetectionLock (
  428. PKIRQL OldIrql
  429. );
  430. VOID
  431. ViDeadlockDetectionUnlock (
  432. KIRQL OldIrql
  433. );
  434. VOID
  435. ViDeadlockCheckThreadConsistency (
  436. PVI_DEADLOCK_THREAD Thread,
  437. BOOLEAN Recursion
  438. );
  439. VOID
  440. ViDeadlockCheckNodeConsistency (
  441. PVI_DEADLOCK_NODE Node,
  442. BOOLEAN Recursion
  443. );
  444. VOID
  445. ViDeadlockCheckResourceConsistency (
  446. PVI_DEADLOCK_RESOURCE Resource,
  447. BOOLEAN Recursion
  448. );
  449. PVI_DEADLOCK_THREAD
  450. ViDeadlockCheckThreadReferences (
  451. PVI_DEADLOCK_NODE Node
  452. );
  453. BOOLEAN
  454. ViIsThreadInsidePagingCodePaths (
  455. );
  456. VOID
  457. ViDeadlockCheckDuplicatesAmongChildren (
  458. PVI_DEADLOCK_NODE Parent,
  459. PVI_DEADLOCK_NODE Child
  460. );
  461. VOID
  462. ViDeadlockCheckDuplicatesAmongRoots (
  463. PVI_DEADLOCK_NODE Root
  464. );
  465. LOGICAL
  466. ViDeadlockSimilarNodes (
  467. PVI_DEADLOCK_NODE NodeA,
  468. PVI_DEADLOCK_NODE NodeB
  469. );
  470. VOID
  471. ViDeadlockMergeNodes (
  472. PVI_DEADLOCK_NODE NodeTo,
  473. PVI_DEADLOCK_NODE NodeFrom
  474. );
  475. VOID
  476. ViDeadlockTrimResources (
  477. PLIST_ENTRY HashList
  478. );
  479. VOID
  480. ViDeadlockForgetResourceHistory (
  481. PVI_DEADLOCK_RESOURCE Resource,
  482. ULONG TrimThreshold,
  483. ULONG AgeThreshold
  484. );
  485. VOID
  486. ViDeadlockCheckStackLimits (
  487. );
  488. #ifdef ALLOC_PRAGMA
  489. #pragma alloc_text(PAGEVRFY, VfDeadlockDetectionInitialize)
  490. #pragma alloc_text(PAGEVRFY, VfDeadlockInitializeResource)
  491. #pragma alloc_text(PAGEVRFY, VfDeadlockAcquireResource)
  492. #pragma alloc_text(PAGEVRFY, VfDeadlockReleaseResource)
  493. #pragma alloc_text(PAGEVRFY, VfDeadlockDeleteMemoryRange)
  494. #pragma alloc_text(PAGEVRFY, VfDeadlockDetectionCleanup)
  495. #pragma alloc_text(PAGEVRFY, ViDeadlockDetectionReset)
  496. #pragma alloc_text(PAGEVRFY, ViDeadlockDetectionLock)
  497. #pragma alloc_text(PAGEVRFY, ViDeadlockDetectionUnlock)
  498. #pragma alloc_text(PAGEVRFY, ViDeadlockDetectionIsLockedAlready)
  499. #pragma alloc_text(PAGEVRFY, ViDeadlockCanProceed)
  500. #pragma alloc_text(PAGEVRFY, ViDeadlockAnalyze)
  501. #pragma alloc_text(PAGEVRFY, ViDeadlockDatabaseHash)
  502. #pragma alloc_text(PAGEVRFY, ViDeadlockSearchResource)
  503. #pragma alloc_text(PAGEVRFY, ViDeadlockSimilarNode)
  504. #pragma alloc_text(PAGEVRFY, ViDeadlockSearchThread)
  505. #pragma alloc_text(PAGEVRFY, ViDeadlockAddThread)
  506. #pragma alloc_text(PAGEVRFY, ViDeadlockDeleteThread)
  507. #pragma alloc_text(PAGEVRFY, ViDeadlockAddResource)
  508. #pragma alloc_text(PAGEVRFY, ViDeadlockAllocate)
  509. #pragma alloc_text(PAGEVRFY, ViDeadlockFree)
  510. #pragma alloc_text(PAGEVRFY, ViDeadlockTrimPoolCache)
  511. #pragma alloc_text(PAGEVRFY, ViDeadlockTrimPoolCacheWorker)
  512. #pragma alloc_text(PAGEVRFY, ViDeadlockAllocateFromPoolCache)
  513. #pragma alloc_text(PAGEVRFY, ViDeadlockFreeIntoPoolCache)
  514. #pragma alloc_text(PAGEVRFY, ViDeadlockReportIssue)
  515. #pragma alloc_text(PAGEVRFY, ViDeadlockAddParticipant)
  516. #pragma alloc_text(PAGEVRFY, ViDeadlockDeleteResource)
  517. #pragma alloc_text(PAGEVRFY, ViDeadlockDeleteNode)
  518. #pragma alloc_text(PAGEVRFY, ViDeadlockNodeLevel)
  519. #pragma alloc_text(PAGEVRFY, ViDeadlockCertify)
  520. #pragma alloc_text(PAGEVRFY, VerifierDeadlockFreePool)
  521. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckResourceConsistency)
  522. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckThreadConsistency)
  523. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckNodeConsistency)
  524. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckThreadReferences)
  525. #pragma alloc_text(PAGEVRFY, VfDeadlockBeforeCallDriver)
  526. #pragma alloc_text(PAGEVRFY, VfDeadlockAfterCallDriver)
  527. #pragma alloc_text(PAGEVRFY, ViIsThreadInsidePagingCodePaths)
  528. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckDuplicatesAmongChildren)
  529. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckDuplicatesAmongRoots)
  530. #pragma alloc_text(PAGEVRFY, ViDeadlockSimilarNodes)
  531. #pragma alloc_text(PAGEVRFY, ViDeadlockMergeNodes)
  532. #pragma alloc_text(PAGEVRFY, ViDeadlockTrimResources)
  533. #pragma alloc_text(PAGEVRFY, ViDeadlockForgetResourceHistory)
  534. #pragma alloc_text(PAGEVRFY, ViDeadlockCheckStackLimits)
  535. #endif
  536. /////////////////////////////////////////////////////////////////////
  537. /////////////////////////////////////// Lock/unlock deadlock verifier
  538. /////////////////////////////////////////////////////////////////////
  539. //
  540. // Global `deadlock lock database' lock
  541. //
  542. KSPIN_LOCK ViDeadlockDatabaseLock;
  543. PKTHREAD ViDeadlockDatabaseOwner;
  544. VOID
  545. ViDeadlockDetectionLock (
  546. PKIRQL OldIrql
  547. )
  548. {
  549. KeAcquireSpinLock(&ViDeadlockDatabaseLock, (OldIrql));
  550. ViDeadlockDatabaseOwner = KeGetCurrentThread ();
  551. }
  552. VOID
  553. ViDeadlockDetectionUnlock (
  554. KIRQL OldIrql
  555. )
  556. {
  557. ViDeadlockDatabaseOwner = NULL;
  558. KeReleaseSpinLock(&ViDeadlockDatabaseLock, OldIrql);
  559. }
  560. BOOLEAN
  561. ViDeadlockDetectionIsLockedAlready (
  562. )
  563. {
  564. PVOID CurrentThread;
  565. PVOID CurrentOwner;
  566. ASSERT (ViDeadlockGlobals);
  567. ASSERT (ViDeadlockDetectionEnabled);
  568. //
  569. // Figure out if are in a recursive call into the deadlock verifier.
  570. // This can happen if we try to allocate/free pool while we execute
  571. // code in the deadlock verifier.
  572. //
  573. // silviuc: can this be done instead with a simple read ?
  574. //
  575. CurrentThread = (PVOID) KeGetCurrentThread();
  576. CurrentOwner = InterlockedCompareExchangePointer (&ViDeadlockDatabaseOwner,
  577. CurrentThread,
  578. CurrentThread);
  579. if (CurrentOwner == CurrentThread) {
  580. return TRUE;
  581. }
  582. else {
  583. return FALSE;
  584. }
  585. }
  586. /////////////////////////////////////////////////////////////////////
  587. ///////////////////// Initialization and deadlock database management
  588. /////////////////////////////////////////////////////////////////////
  589. PLIST_ENTRY
  590. ViDeadlockDatabaseHash(
  591. IN PLIST_ENTRY Database,
  592. IN PVOID Address
  593. )
  594. /*++
  595. Routine Description:
  596. This routine hashes the resource address into the deadlock database.
  597. The hash bin is represented by a list entry.
  598. NOTE -- be careful modifying the method used for hashing --
  599. we currently hash based on the PFN or page number of
  600. the address given. This knowledge is used to optimize
  601. the number of hash bins needed to look through
  602. in order to delete addresses. For example, suppose
  603. the address was 0x1020. This is PFN 1 and if we were
  604. deleting addresses 0x1020-0x1040, we'd only have to
  605. look in a single hash bin to find and remove the
  606. address. Read VfDeadlockDeleteMemoryRange() for more details.
  607. Arguments:
  608. ResourceAddress: Address of the resource that is being hashed
  609. Return Value:
  610. PLIST_ENTRY -- the list entry associated with the hash bin we land in.
  611. --*/
  612. {
  613. return Database + ((((ULONG_PTR)Address)>> PAGE_SHIFT) % VI_DEADLOCK_HASH_BINS);
  614. }
  615. VOID
  616. VfDeadlockDetectionInitialize(
  617. IN LOGICAL VerifyAllDrivers,
  618. IN LOGICAL VerifyKernel
  619. )
  620. /*++
  621. Routine Description:
  622. This routine initializes the data structures necessary for detecting
  623. deadlocks in kernel synchronization objects.
  624. Arguments:
  625. VerifyAllDrivers - Supplies TRUE if we are verifying all drivers.
  626. VerifyKernel - Supplies TRUE if we are verifying the kernel.
  627. Return Value:
  628. None. If successful ViDeadlockGlobals will point to a fully initialized
  629. structure.
  630. Environment:
  631. System initialization only.
  632. --*/
  633. {
  634. ULONG I;
  635. SIZE_T TableSize;
  636. PLIST_ENTRY Current;
  637. PVOID Block;
  638. //
  639. // Allocate the globals structure. ViDeadlockGlobals value is
  640. // used to figure out if the whole initialization was successful
  641. // or not.
  642. //
  643. ViDeadlockGlobals = ExAllocatePoolWithTag (NonPagedPool,
  644. sizeof (VI_DEADLOCK_GLOBALS),
  645. VI_DEADLOCK_TAG);
  646. if (ViDeadlockGlobals == NULL) {
  647. goto Failed;
  648. }
  649. RtlZeroMemory (ViDeadlockGlobals, sizeof (VI_DEADLOCK_GLOBALS));
  650. ExInitializeWorkItem (&ViTrimDeadlockPoolWorkItem,
  651. ViDeadlockTrimPoolCacheWorker,
  652. NULL);
  653. //
  654. // Allocate hash tables for resources and threads.
  655. //
  656. TableSize = sizeof (LIST_ENTRY) * VI_DEADLOCK_HASH_BINS;
  657. ViDeadlockGlobals->ResourceDatabase = ExAllocatePoolWithTag (NonPagedPool,
  658. TableSize,
  659. VI_DEADLOCK_TAG);
  660. if (!ViDeadlockGlobals->ResourceDatabase) {
  661. return;
  662. }
  663. ViDeadlockGlobals->ThreadDatabase = ExAllocatePoolWithTag (NonPagedPool,
  664. TableSize,
  665. VI_DEADLOCK_TAG);
  666. if (!ViDeadlockGlobals->ThreadDatabase) {
  667. goto Failed;
  668. }
  669. //
  670. // Initialize the free lists.
  671. //
  672. InitializeListHead(&ViDeadlockGlobals->FreeResourceList);
  673. InitializeListHead(&ViDeadlockGlobals->FreeThreadList);
  674. InitializeListHead(&ViDeadlockGlobals->FreeNodeList);
  675. //
  676. // Initialize hash bins and database lock.
  677. //
  678. for (I = 0; I < VI_DEADLOCK_HASH_BINS; I += 1) {
  679. InitializeListHead(&(ViDeadlockGlobals->ResourceDatabase[I]));
  680. InitializeListHead(&ViDeadlockGlobals->ThreadDatabase[I]);
  681. }
  682. KeInitializeSpinLock (&ViDeadlockDatabaseLock);
  683. //
  684. // Did user request only spin locks? This relieves the
  685. // memory consumption.
  686. //
  687. if (ViVerifyOnlySpinlocksFromRegistry) {
  688. ViDeadlockVerifyOnlySpinlocks = TRUE;
  689. }
  690. //
  691. // Initialize deadlock analysis parameters
  692. //
  693. ViDeadlockGlobals->RecursionDepthLimit = (ViRecursionDepthLimitFromRegistry) ?
  694. ViRecursionDepthLimitFromRegistry :
  695. VI_DEADLOCK_MAXIMUM_DEGREE;
  696. ViDeadlockGlobals->SearchedNodesLimit = (ViSearchedNodesLimitFromRegistry) ?
  697. ViSearchedNodesLimitFromRegistry :
  698. VI_DEADLOCK_MAXIMUM_SEARCH;
  699. //
  700. // Preallocate all resources if kernel verifier is enabled.
  701. //
  702. if (VerifyKernel) {
  703. PVOID Block;
  704. for (I = 0; I < ViDeadlockReservedThreads; I += 1) {
  705. Block = ExAllocatePoolWithTag( NonPagedPool,
  706. sizeof (VI_DEADLOCK_THREAD),
  707. VI_DEADLOCK_TAG);
  708. if (Block == NULL) {
  709. goto Failed;
  710. }
  711. ViDeadlockGlobals->BytesAllocated += sizeof (VI_DEADLOCK_THREAD);
  712. ViDeadlockGlobals->Threads[0] += 1;
  713. ViDeadlockFree (Block, ViDeadlockThread);
  714. }
  715. for (I = 0; I < ViDeadlockReservedNodes; I += 1) {
  716. Block = ExAllocatePoolWithTag( NonPagedPool,
  717. sizeof (VI_DEADLOCK_NODE),
  718. VI_DEADLOCK_TAG);
  719. if (Block == NULL) {
  720. goto Failed;
  721. }
  722. ViDeadlockGlobals->BytesAllocated += sizeof (VI_DEADLOCK_NODE);
  723. ViDeadlockGlobals->Nodes[0] += 1;
  724. ViDeadlockFree (Block, ViDeadlockNode);
  725. }
  726. for (I = 0; I < ViDeadlockReservedResources; I += 1) {
  727. Block = ExAllocatePoolWithTag( NonPagedPool,
  728. sizeof (VI_DEADLOCK_RESOURCE),
  729. VI_DEADLOCK_TAG);
  730. if (Block == NULL) {
  731. goto Failed;
  732. }
  733. ViDeadlockGlobals->BytesAllocated += sizeof (VI_DEADLOCK_RESOURCE);
  734. ViDeadlockGlobals->Resources[0] += 1;
  735. ViDeadlockFree (Block, ViDeadlockResource);
  736. }
  737. }
  738. //
  739. // Mark that everything went fine and return
  740. //
  741. if (VerifyKernel) {
  742. ViDeadlockState.KernelVerifierEnabled = 1;
  743. }
  744. if (VerifyAllDrivers) {
  745. ViDeadlockState.DriverVerifierForAllEnabled = 1;
  746. ViDeadlockStrict = TRUE;
  747. if (ViDeadlockState.KernelVerifierEnabled == 1) {
  748. //
  749. // silviuc: The VeryStrict option is unfunctional right now because
  750. // KeInitializeSpinLock is a kernel routine and therefore
  751. // cannot be hooked for kernel locks.
  752. //
  753. // ViDeadlockVeryStrict = TRUE;
  754. }
  755. }
  756. ViDeadlockDetectionEnabled = TRUE;
  757. return;
  758. Failed:
  759. //
  760. // Cleanup if any of our allocations failed
  761. //
  762. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  763. while (Current != &(ViDeadlockGlobals->FreeNodeList)) {
  764. Block = (PVOID) CONTAINING_RECORD (Current,
  765. VI_DEADLOCK_NODE,
  766. FreeListEntry);
  767. Current = Current->Flink;
  768. ExFreePool (Block);
  769. }
  770. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  771. while (Current != &(ViDeadlockGlobals->FreeResourceList)) {
  772. Block = (PVOID) CONTAINING_RECORD (Current,
  773. VI_DEADLOCK_RESOURCE,
  774. FreeListEntry);
  775. Current = Current->Flink;
  776. ExFreePool (Block);
  777. }
  778. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  779. while (Current != &(ViDeadlockGlobals->FreeThreadList)) {
  780. Block = (PVOID) CONTAINING_RECORD (Current,
  781. VI_DEADLOCK_THREAD,
  782. FreeListEntry);
  783. Current = Current->Flink;
  784. ExFreePool (Block);
  785. }
  786. if (NULL != ViDeadlockGlobals->ResourceDatabase) {
  787. ExFreePool(ViDeadlockGlobals->ResourceDatabase);
  788. }
  789. if (NULL != ViDeadlockGlobals->ThreadDatabase) {
  790. ExFreePool(ViDeadlockGlobals->ThreadDatabase);
  791. }
  792. if (NULL != ViDeadlockGlobals) {
  793. ExFreePool(ViDeadlockGlobals);
  794. //
  795. // Important to set this to null for failure because it is
  796. // used to figure out if the package got initialized or not.
  797. //
  798. ViDeadlockGlobals = NULL;
  799. }
  800. return;
  801. }
  802. VOID
  803. VfDeadlockDetectionCleanup (
  804. )
  805. /*++
  806. Routine Description:
  807. This routine tears down all deadlock verifier internal structures.
  808. Arguments:
  809. None.
  810. Return Value:
  811. None.
  812. --*/
  813. {
  814. ULONG Index;
  815. PLIST_ENTRY Current;
  816. PVI_DEADLOCK_RESOURCE Resource;
  817. PVI_DEADLOCK_THREAD Thread;
  818. PVOID Block;
  819. //
  820. // If we are not initialized then nothing to do.
  821. //
  822. if (ViDeadlockGlobals == NULL) {
  823. return;
  824. }
  825. //
  826. // Iterate all resources and delete them. This will also delete
  827. // all nodes associated with resources.
  828. //
  829. for (Index = 0; Index < VI_DEADLOCK_HASH_BINS; Index += 1) {
  830. Current = ViDeadlockGlobals->ResourceDatabase[Index].Flink;
  831. while (Current != &(ViDeadlockGlobals->ResourceDatabase[Index])) {
  832. Resource = CONTAINING_RECORD (Current,
  833. VI_DEADLOCK_RESOURCE,
  834. HashChainList);
  835. Current = Current->Flink;
  836. ViDeadlockDeleteResource (Resource, TRUE);
  837. }
  838. }
  839. //
  840. // Iterate all threads and delete them.
  841. //
  842. for (Index = 0; Index < VI_DEADLOCK_HASH_BINS; Index += 1) {
  843. Current = ViDeadlockGlobals->ThreadDatabase[Index].Flink;
  844. while (Current != &(ViDeadlockGlobals->ThreadDatabase[Index])) {
  845. Thread = CONTAINING_RECORD (Current,
  846. VI_DEADLOCK_THREAD,
  847. ListEntry);
  848. Current = Current->Flink;
  849. ViDeadlockDeleteThread (Thread, TRUE);
  850. }
  851. }
  852. //
  853. // Everything should be in the pool caches by now.
  854. //
  855. ASSERT (ViDeadlockGlobals->BytesAllocated == 0);
  856. //
  857. // Free pool caches.
  858. //
  859. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  860. while (Current != &(ViDeadlockGlobals->FreeNodeList)) {
  861. Block = (PVOID) CONTAINING_RECORD (Current,
  862. VI_DEADLOCK_NODE,
  863. FreeListEntry);
  864. Current = Current->Flink;
  865. ExFreePool (Block);
  866. }
  867. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  868. while (Current != &(ViDeadlockGlobals->FreeResourceList)) {
  869. Block = (PVOID) CONTAINING_RECORD (Current,
  870. VI_DEADLOCK_RESOURCE,
  871. FreeListEntry);
  872. Current = Current->Flink;
  873. ExFreePool (Block);
  874. }
  875. Current = ViDeadlockGlobals->FreeNodeList.Flink;
  876. while (Current != &(ViDeadlockGlobals->FreeThreadList)) {
  877. Block = (PVOID) CONTAINING_RECORD (Current,
  878. VI_DEADLOCK_THREAD,
  879. FreeListEntry);
  880. Current = Current->Flink;
  881. ExFreePool (Block);
  882. }
  883. //
  884. // Free databases and global structure
  885. //
  886. ExFreePool (ViDeadlockGlobals->ResourceDatabase);
  887. ExFreePool (ViDeadlockGlobals->ThreadDatabase);
  888. ExFreePool(ViDeadlockGlobals);
  889. ViDeadlockGlobals = NULL;
  890. ViDeadlockDetectionEnabled = FALSE;
  891. }
  892. VOID
  893. ViDeadlockDetectionReset (
  894. )
  895. /*++
  896. Routine Description:
  897. This routine resets all internal deadlock verifier structures. All nodes,
  898. resources, threads are forgotten. They will all go into free pool caches
  899. ready to be used in a new life cycle.
  900. The function is usually called with the deadlock verifier lock held.
  901. It will not touch the lock at all therefore the caller will still
  902. hold the lock after return.
  903. Arguments:
  904. None.
  905. Return Value:
  906. None.
  907. --*/
  908. {
  909. ULONG Index;
  910. PLIST_ENTRY Current;
  911. PVI_DEADLOCK_RESOURCE Resource;
  912. PVI_DEADLOCK_THREAD Thread;
  913. //
  914. // If we are not initialized or not enabled then nothing to do.
  915. //
  916. if (ViDeadlockGlobals == NULL || ViDeadlockDetectionEnabled == FALSE) {
  917. return;
  918. }
  919. ASSERT (ViDeadlockDatabaseOwner == KeGetCurrentThread());
  920. //
  921. // Iterate all resources and delete them. This will also delete
  922. // all nodes associated with resources.
  923. //
  924. for (Index = 0; Index < VI_DEADLOCK_HASH_BINS; Index += 1) {
  925. Current = ViDeadlockGlobals->ResourceDatabase[Index].Flink;
  926. while (Current != &(ViDeadlockGlobals->ResourceDatabase[Index])) {
  927. Resource = CONTAINING_RECORD (Current,
  928. VI_DEADLOCK_RESOURCE,
  929. HashChainList);
  930. Current = Current->Flink;
  931. ViDeadlockDeleteResource (Resource, TRUE);
  932. }
  933. }
  934. //
  935. // Iterate all threads and delete them.
  936. //
  937. for (Index = 0; Index < VI_DEADLOCK_HASH_BINS; Index += 1) {
  938. Current = ViDeadlockGlobals->ThreadDatabase[Index].Flink;
  939. while (Current != &(ViDeadlockGlobals->ThreadDatabase[Index])) {
  940. Thread = CONTAINING_RECORD (Current,
  941. VI_DEADLOCK_THREAD,
  942. ListEntry);
  943. Current = Current->Flink;
  944. ViDeadlockDeleteThread (Thread, TRUE);
  945. }
  946. }
  947. //
  948. // Everything should be in the pool caches by now.
  949. //
  950. ASSERT (ViDeadlockGlobals->BytesAllocated == 0);
  951. //
  952. // Update counters and forget past failures.
  953. //
  954. ViDeadlockGlobals->AllocationFailures = 0;
  955. ViDeadlockResets += 1;
  956. }
  957. BOOLEAN
  958. ViDeadlockCanProceed (
  959. IN PVOID Resource, OPTIONAL
  960. IN PVOID CallAddress, OPTIONAL
  961. IN VI_DEADLOCK_RESOURCE_TYPE Type OPTIONAL
  962. )
  963. /*++
  964. Routine Description:
  965. This routine is called by deadlock verifier exports (initialize,
  966. acquire, release) to figure out if deadlock verification should
  967. proceed for the current operation. There are several reasons
  968. why the return should be false. We failed to initialize the
  969. deadlock verifier package or the caller is an amnestied driver
  970. or the deadlock verification is temporarily disabled, etc.
  971. Arguments:
  972. Resource - address of the kernel resource operated upon
  973. CallAddress - address of the caller for the operation
  974. Return Value:
  975. True if deadlock verification should proceed for the current
  976. operation.
  977. Environment:
  978. Internal. Called by deadlock verifier exports.
  979. --*/
  980. {
  981. //
  982. // From ntos\mm\mi.h - this lock is acquired with
  983. // KeTryAcquireSpinLock which cannot be hooked for
  984. // kernel code.
  985. //
  986. extern KSPIN_LOCK MmExpansionLock;
  987. UNREFERENCED_PARAMETER (CallAddress);
  988. //
  989. // Skip if package not initialized
  990. //
  991. if (ViDeadlockGlobals == NULL) {
  992. return FALSE;
  993. }
  994. //
  995. // Skip is package is disabled
  996. //
  997. if (! ViDeadlockDetectionEnabled) {
  998. return FALSE;
  999. }
  1000. //
  1001. // Skip if operation happens above DPC level. This avoids a case
  1002. // where KeAcquireSpinlockRaiseToSynch is used to acquire a spinlock.
  1003. // During lock release when we need to acquire the deadlock verifier lock
  1004. // driver verifier will complain about lowering the IRQL. Since this is a
  1005. // very uncommon interface it is not worth for now to add the code to
  1006. // actually verify operations on this lock (MmProtectedPteLock). That would
  1007. // require first to add thunking code in driver verifier for raisetosynch
  1008. // interface.
  1009. //
  1010. if (KeGetCurrentIrql() > DISPATCH_LEVEL) {
  1011. return FALSE;
  1012. }
  1013. //
  1014. // Check if anybody switched the stack.
  1015. //
  1016. ViDeadlockCheckStackLimits ();
  1017. //
  1018. // If it is only as spinlock affair then skip.
  1019. //
  1020. if (Type != VfDeadlockUnknown) {
  1021. if (ViDeadlockVerifyOnlySpinlocks && Type != VfDeadlockSpinLock) {
  1022. return FALSE;
  1023. }
  1024. }
  1025. //
  1026. // We do not check the deadlock verifier lock
  1027. //
  1028. if (Resource == &ViDeadlockDatabaseLock) {
  1029. return FALSE;
  1030. }
  1031. //
  1032. // Skip kernel locks acquired with KeTryAcquireSpinLock
  1033. //
  1034. if (Resource == &MmExpansionLock) {
  1035. return FALSE;
  1036. }
  1037. //
  1038. // Figure out if are in a recursive call into the deadlock verifier.
  1039. // This can happen if we try to allocate/free pool while we execute
  1040. // code in the deadlock verifier.
  1041. //
  1042. if (ViDeadlockDetectionIsLockedAlready ()) {
  1043. return FALSE;
  1044. }
  1045. //
  1046. // Skip if we ever encountered an allocation failure
  1047. //
  1048. if (ViDeadlockGlobals->AllocationFailures > 0) {
  1049. return FALSE;
  1050. }
  1051. return TRUE;
  1052. }
  1053. /////////////////////////////////////////////////////////////////////
  1054. //////////////////////////////////////////// Deadlock detection logic
  1055. /////////////////////////////////////////////////////////////////////
  1056. BOOLEAN
  1057. ViDeadlockAnalyze(
  1058. IN PVOID ResourceAddress,
  1059. IN PVI_DEADLOCK_NODE AcquiredNode,
  1060. IN BOOLEAN FirstCall,
  1061. IN ULONG Degree
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine determines whether the acquisition of a certain resource
  1066. could result in a deadlock.
  1067. The routine assumes the deadlock database lock is held.
  1068. Arguments:
  1069. ResourceAddress - address of the resource that will be acquired
  1070. AcquiredNode - a node representing the most recent resource acquisition
  1071. made by the thread trying to acquire `ResourceAddress'.
  1072. FirstCall - true if this is not a recursive call made from within the
  1073. function. It is used for doing one time per analysis only operations.
  1074. Degree - depth of recursion.
  1075. Return Value:
  1076. True if deadlock detected, false otherwise.
  1077. --*/
  1078. {
  1079. PVI_DEADLOCK_NODE CurrentNode;
  1080. PVI_DEADLOCK_RESOURCE CurrentResource;
  1081. PVI_DEADLOCK_NODE CurrentParent;
  1082. BOOLEAN FoundDeadlock;
  1083. PLIST_ENTRY Current;
  1084. ASSERT (AcquiredNode);
  1085. //
  1086. // Setup global counters.
  1087. //
  1088. if (FirstCall) {
  1089. ViDeadlockGlobals->NodesSearched = 0;
  1090. ViDeadlockGlobals->SequenceNumber += 1;
  1091. ViDeadlockGlobals->NumberOfParticipants = 0;
  1092. ViDeadlockGlobals->Instigator = NULL;
  1093. if (ViDeadlockGlobals->SequenceNumber == ((1 << 30) - 2)) {
  1094. ViDeadlockState.SequenceNumberOverflow = 1;
  1095. }
  1096. }
  1097. //
  1098. // If our node is already stamped with the current sequence number
  1099. // then we have been here before in the current search. There is a very
  1100. // remote possibility that the node was not touched in the last
  1101. // 2^N calls to this function and the sequence number counter
  1102. // overwrapped but we can live with this.
  1103. //
  1104. if (AcquiredNode->SequenceNumber == ViDeadlockGlobals->SequenceNumber) {
  1105. return FALSE;
  1106. }
  1107. //
  1108. // Update the counter of nodes touched in this search
  1109. //
  1110. ViDeadlockGlobals->NodesSearched += 1;
  1111. //
  1112. // Stamp node with current sequence number.
  1113. //
  1114. AcquiredNode->SequenceNumber = ViDeadlockGlobals->SequenceNumber;
  1115. //
  1116. // Stop recursion if it gets too deep.
  1117. //
  1118. if (Degree > ViDeadlockGlobals->RecursionDepthLimit) {
  1119. ViDeadlockGlobals->DepthLimitHits += 1;
  1120. return FALSE;
  1121. }
  1122. //
  1123. // Stop recursion if it gets too lengthy
  1124. //
  1125. if (ViDeadlockGlobals->NodesSearched >= ViDeadlockGlobals->SearchedNodesLimit) {
  1126. ViDeadlockGlobals->SearchLimitHits += 1;
  1127. return FALSE;
  1128. }
  1129. //
  1130. // Check if AcquiredNode's resource equals ResourceAddress.
  1131. // This is the final point for a deadlock detection because
  1132. // we managed to find a path in the graph that leads us to the
  1133. // same resource as the one to be acquired. From now on we
  1134. // will start returning from recursive calls and build the
  1135. // deadlock proof along the way.
  1136. //
  1137. ASSERT (AcquiredNode->Root);
  1138. if (ResourceAddress == AcquiredNode->Root->ResourceAddress) {
  1139. ASSERT (FALSE == FirstCall);
  1140. FoundDeadlock = TRUE;
  1141. ViDeadlockAddParticipant (AcquiredNode);
  1142. goto Exit;
  1143. }
  1144. //
  1145. // Iterate all nodes in the graph using the same resource from AcquiredNode.
  1146. //
  1147. FoundDeadlock = FALSE;
  1148. CurrentResource = AcquiredNode->Root;
  1149. Current = CurrentResource->ResourceList.Flink;
  1150. while (Current != &(CurrentResource->ResourceList)) {
  1151. CurrentNode = CONTAINING_RECORD (Current,
  1152. VI_DEADLOCK_NODE,
  1153. ResourceList);
  1154. ASSERT (CurrentNode->Root);
  1155. ASSERT (CurrentNode->Root == CurrentResource);
  1156. //
  1157. // Mark node as visited
  1158. //
  1159. CurrentNode->SequenceNumber = ViDeadlockGlobals->SequenceNumber;
  1160. //
  1161. // Check recursively the parent of the CurrentNode. This will check the
  1162. // whole parent chain eventually through recursive calls.
  1163. //
  1164. CurrentParent = CurrentNode->Parent;
  1165. if (CurrentParent != NULL) {
  1166. //
  1167. // If we are traversing the Parent chain of AcquiredNode we do not
  1168. // increment the recursion Degree because we know the chain will
  1169. // end. For calls to other similar nodes we have to protect against
  1170. // too much recursion (time consuming).
  1171. //
  1172. if (CurrentNode != AcquiredNode) {
  1173. //
  1174. // Recurse across the graph
  1175. //
  1176. FoundDeadlock = ViDeadlockAnalyze (ResourceAddress,
  1177. CurrentParent,
  1178. FALSE,
  1179. Degree + 1);
  1180. }
  1181. else {
  1182. //
  1183. // Recurse down the graph
  1184. //
  1185. FoundDeadlock = ViDeadlockAnalyze (ResourceAddress,
  1186. CurrentParent,
  1187. FALSE,
  1188. Degree);
  1189. }
  1190. if (FoundDeadlock) {
  1191. ViDeadlockAddParticipant(CurrentNode);
  1192. if (CurrentNode != AcquiredNode) {
  1193. ViDeadlockAddParticipant(AcquiredNode);
  1194. }
  1195. goto Exit;
  1196. }
  1197. }
  1198. Current = Current->Flink;
  1199. }
  1200. Exit:
  1201. if (FoundDeadlock && FirstCall) {
  1202. //
  1203. // Make sure that the deadlock does not look like ABC - ACB.
  1204. // These sequences are protected by a common resource and therefore
  1205. // this is not a real deadlock.
  1206. //
  1207. if (ViDeadlockCertify ()) {
  1208. //
  1209. // Print deadlock information and save the address so the
  1210. // debugger knows who caused the deadlock.
  1211. //
  1212. ViDeadlockGlobals->Instigator = ResourceAddress;
  1213. DbgPrint("****************************************************************************\n");
  1214. DbgPrint("** **\n");
  1215. DbgPrint("** Deadlock detected! Type !deadlock in the debugger for more information **\n");
  1216. DbgPrint("** **\n");
  1217. DbgPrint("****************************************************************************\n");
  1218. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_DEADLOCK_DETECTED,
  1219. (ULONG_PTR)ResourceAddress,
  1220. (ULONG_PTR)AcquiredNode,
  1221. 0);
  1222. //
  1223. // It is impossible to continue at this point.
  1224. //
  1225. return FALSE;
  1226. } else {
  1227. //
  1228. // If we decided that this was not a deadlock after all, set the return value
  1229. // to not return a deadlock
  1230. //
  1231. FoundDeadlock = FALSE;
  1232. }
  1233. }
  1234. if (FirstCall) {
  1235. if (ViDeadlockGlobals->NodesSearched > ViDeadlockGlobals->MaxNodesSearched) {
  1236. ViDeadlockGlobals->MaxNodesSearched = ViDeadlockGlobals->NodesSearched;
  1237. }
  1238. }
  1239. return FoundDeadlock;
  1240. }
  1241. BOOLEAN
  1242. ViDeadlockCertify(
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. A potential deadlock has been detected. However our algorithm will generate
  1247. false positives in a certain case -- if two deadlocking nodes are ever taken
  1248. after the same node -- i.e. A->B->C A->C->B. While this can be considered
  1249. bad programming practice it is not really a deadlock and we should not
  1250. bugcheck.
  1251. Also we must check to make sure that there are no nodes at the top of the
  1252. deadlock chains that have only been acquired with try-acquire... this does
  1253. not cause a real deadlock.
  1254. The deadlock database lock should be held.
  1255. Arguments:
  1256. None.
  1257. Return Value:
  1258. True if this is really a deadlock, false to exonerate.
  1259. --*/
  1260. {
  1261. PVI_DEADLOCK_NODE innerNode,outerNode;
  1262. ULONG innerParticipant,outerParticipant;
  1263. ULONG numberOfParticipants;
  1264. ULONG currentParticipant;
  1265. numberOfParticipants = ViDeadlockGlobals->NumberOfParticipants;
  1266. //
  1267. // Note -- this isn't a particularly efficient way to do this. However,
  1268. // it is a particularly easy way to do it. This function should be called
  1269. // extremely rarely -- so IMO there isn't really a problem here.
  1270. //
  1271. //
  1272. // Outer loop
  1273. //
  1274. outerParticipant = numberOfParticipants;
  1275. while(outerParticipant > 1) {
  1276. outerParticipant--;
  1277. for (outerNode = ViDeadlockGlobals->Participant[outerParticipant]->Parent;
  1278. outerNode != NULL;
  1279. outerNode = outerNode->Parent ) {
  1280. //
  1281. // Inner loop
  1282. //
  1283. innerParticipant = outerParticipant-1;
  1284. while (innerParticipant) {
  1285. innerParticipant--;
  1286. for(innerNode = ViDeadlockGlobals->Participant[innerParticipant]->Parent;
  1287. innerNode != NULL;
  1288. innerNode = innerNode->Parent) {
  1289. if (innerNode->Root->ResourceAddress == outerNode->Root->ResourceAddress) {
  1290. //
  1291. // The twain shall meet -- this is not a deadlock
  1292. //
  1293. ViDeadlockGlobals->ABC_ACB_Skipped++;
  1294. return FALSE;
  1295. }
  1296. }
  1297. }
  1298. }
  1299. }
  1300. for (currentParticipant = 1; currentParticipant < numberOfParticipants; currentParticipant += 1) {
  1301. if (ViDeadlockGlobals->Participant[currentParticipant]->Root->ResourceAddress ==
  1302. ViDeadlockGlobals->Participant[currentParticipant-1]->Root->ResourceAddress) {
  1303. //
  1304. // This is the head of a chain...
  1305. //
  1306. if (ViDeadlockGlobals->Participant[currentParticipant-1]->OnlyTryAcquireUsed == TRUE) {
  1307. //
  1308. // Head of a chain used only try acquire. This can never cause a deadlock.
  1309. //
  1310. return FALSE;
  1311. }
  1312. }
  1313. }
  1314. return TRUE;
  1315. }
  1316. /////////////////////////////////////////////////////////////////////
  1317. ///////////////////////////////////////////////// Resource management
  1318. /////////////////////////////////////////////////////////////////////
  1319. PVI_DEADLOCK_RESOURCE
  1320. ViDeadlockSearchResource(
  1321. IN PVOID ResourceAddress
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. This routine finds the resource descriptor structure for a
  1326. resource if one exists.
  1327. Arguments:
  1328. ResourceAddress: Address of the resource in question (as used by
  1329. the kernel).
  1330. Return Value:
  1331. PVI_DEADLOCK_RESOURCE structure describing the resource, if available,
  1332. or else NULL
  1333. Note. The caller of the function should hold the database lock.
  1334. --*/
  1335. {
  1336. PLIST_ENTRY ListHead;
  1337. PLIST_ENTRY Current;
  1338. PVI_DEADLOCK_RESOURCE Resource;
  1339. ListHead = ViDeadlockDatabaseHash (ViDeadlockGlobals->ResourceDatabase,
  1340. ResourceAddress);
  1341. if (IsListEmpty (ListHead)) {
  1342. return NULL;
  1343. }
  1344. //
  1345. // Trim resources from this hash list. It has nothing to do with searching
  1346. // but it is a good place to do this operation.
  1347. //
  1348. ViDeadlockTrimResources (ListHead);
  1349. //
  1350. // Now search the bucket for our resource.
  1351. //
  1352. Current = ListHead->Flink;
  1353. while (Current != ListHead) {
  1354. Resource = CONTAINING_RECORD(Current,
  1355. VI_DEADLOCK_RESOURCE,
  1356. HashChainList);
  1357. if (Resource->ResourceAddress == ResourceAddress) {
  1358. return Resource;
  1359. }
  1360. Current = Current->Flink;
  1361. }
  1362. return NULL;
  1363. }
  1364. BOOLEAN
  1365. VfDeadlockInitializeResource(
  1366. IN PVOID Resource,
  1367. IN VI_DEADLOCK_RESOURCE_TYPE Type,
  1368. IN PVOID Caller,
  1369. IN BOOLEAN DoNotAcquireLock
  1370. )
  1371. /*++
  1372. Routine Description:
  1373. This routine adds an entry for a new resource to our deadlock detection
  1374. database.
  1375. Arguments:
  1376. Resource: Address of the resource in question as used by the kernel.
  1377. Type: Type of the resource.
  1378. Caller: address of the caller
  1379. DoNotAcquireLock: if true it means the call is done internally and the
  1380. deadlock verifier lock is already held.
  1381. Return Value:
  1382. True if we created and initialized a new RESOURCE structure.
  1383. --*/
  1384. {
  1385. PVOID ReservedResource;
  1386. BOOLEAN Result;
  1387. KIRQL OldIrql;
  1388. UNREFERENCED_PARAMETER (DoNotAcquireLock);
  1389. //
  1390. // If we are not initialized or package is not enabled
  1391. // we return immediately.
  1392. //
  1393. if (! ViDeadlockCanProceed(Resource, Caller, Type)) {
  1394. return FALSE;
  1395. }
  1396. ReservedResource = ViDeadlockAllocate (ViDeadlockResource);
  1397. ViDeadlockDetectionLock (&OldIrql);
  1398. Result = ViDeadlockAddResource (Resource,
  1399. Type,
  1400. Caller,
  1401. ReservedResource);
  1402. ViDeadlockDetectionUnlock (OldIrql);
  1403. return Result;
  1404. }
  1405. BOOLEAN
  1406. ViDeadlockAddResource(
  1407. IN PVOID Resource,
  1408. IN VI_DEADLOCK_RESOURCE_TYPE Type,
  1409. IN PVOID Caller,
  1410. IN PVOID ReservedResource
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This routine adds an entry for a new resource to our deadlock detection
  1415. database.
  1416. Arguments:
  1417. Resource: Address of the resource in question as used by the kernel.
  1418. Type: Type of the resource.
  1419. Caller: address of the caller
  1420. ReservedResource: block of memory to be used by the new resource.
  1421. Return Value:
  1422. True if we created and initialized a new RESOURCE structure.
  1423. --*/
  1424. {
  1425. PLIST_ENTRY HashBin;
  1426. PVI_DEADLOCK_RESOURCE ResourceRoot;
  1427. PKTHREAD Thread;
  1428. ULONG HashValue;
  1429. ULONG DeadlockFlags;
  1430. BOOLEAN ReturnValue = FALSE;
  1431. //
  1432. // Check if this resource was initialized before.
  1433. // This would be a bug in most of the cases.
  1434. //
  1435. ResourceRoot = ViDeadlockSearchResource (Resource);
  1436. if (ResourceRoot) {
  1437. DeadlockFlags = ViDeadlockResourceTypeInfo[Type];
  1438. //
  1439. // Check if we are reinitializing a good resource. This is a valid
  1440. // operation (although weird) only for spinlocks. Some drivers do that.
  1441. //
  1442. // silviuc: should we enforce here for the resource to be released first?
  1443. //
  1444. if(! (DeadlockFlags & VI_DEADLOCK_FLAG_REINITIALIZE_OK)) {
  1445. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION,
  1446. (ULONG_PTR)Resource,
  1447. (ULONG_PTR)ResourceRoot,
  1448. 0);
  1449. }
  1450. //
  1451. // Well, the resource has just been reinitialized. We will live with
  1452. // that. We will break though if we reinitialize a resource that is
  1453. // acquired. In principle this state might be bogus if we missed
  1454. // a release() operation.
  1455. //
  1456. if (ResourceRoot->ThreadOwner != NULL) {
  1457. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_MULTIPLE_INITIALIZATION,
  1458. (ULONG_PTR)Resource,
  1459. (ULONG_PTR)ResourceRoot,
  1460. 1);
  1461. }
  1462. ReturnValue = TRUE;
  1463. goto Exit;
  1464. }
  1465. //
  1466. // At this point we know for sure the resource is not represented in the
  1467. // deadlock verifier database.
  1468. //
  1469. ASSERT (ViDeadlockSearchResource (Resource) == NULL);
  1470. Thread = KeGetCurrentThread();
  1471. //
  1472. // Check to see if the resource is on the stack.
  1473. // If it is we will not verify it.
  1474. //
  1475. // SilviuC: what about the DPC stack ? We will ignore this issue for now.
  1476. //
  1477. if ((ULONG_PTR) Resource < (ULONG_PTR) Thread->InitialStack &&
  1478. (ULONG_PTR) Resource > (ULONG_PTR) Thread->StackLimit ) {
  1479. ReturnValue = FALSE;
  1480. goto Exit;
  1481. }
  1482. //
  1483. // Use reserved memory for the new resource.
  1484. // Set ReservedResource to null to signal that memory has
  1485. // been used. This will prevent freeing it at the end.
  1486. //
  1487. ResourceRoot = ReservedResource;
  1488. ReservedResource = NULL;
  1489. if (ResourceRoot == NULL) {
  1490. ReturnValue = FALSE;
  1491. goto Exit;
  1492. }
  1493. //
  1494. // Fill information about resource.
  1495. //
  1496. RtlZeroMemory (ResourceRoot, sizeof(VI_DEADLOCK_RESOURCE));
  1497. ResourceRoot->Type = Type;
  1498. ResourceRoot->ResourceAddress = Resource;
  1499. InitializeListHead (&ResourceRoot->ResourceList);
  1500. //
  1501. // Capture the stack trace of the guy that creates the resource first.
  1502. // This should happen when resource gets initialized or during the first
  1503. // acquire.
  1504. //
  1505. RtlCaptureStackBackTrace (2,
  1506. VI_MAX_STACK_DEPTH,
  1507. ResourceRoot->StackTrace,
  1508. &HashValue);
  1509. ResourceRoot->StackTrace[0] = Caller;
  1510. //
  1511. // Figure out which hash bin this resource corresponds to.
  1512. //
  1513. HashBin = ViDeadlockDatabaseHash (ViDeadlockGlobals->ResourceDatabase, Resource);
  1514. //
  1515. // Now add to the corrsponding hash bin
  1516. //
  1517. InsertHeadList(HashBin, &ResourceRoot->HashChainList);
  1518. ReturnValue = TRUE;
  1519. Exit:
  1520. if (ReservedResource) {
  1521. ViDeadlockFree (ReservedResource, ViDeadlockResource);
  1522. }
  1523. return ReturnValue;
  1524. }
  1525. BOOLEAN
  1526. ViDeadlockSimilarNode (
  1527. IN PVOID Resource,
  1528. IN BOOLEAN TryNode,
  1529. IN PVI_DEADLOCK_NODE Node
  1530. )
  1531. /*++
  1532. Routine description:
  1533. This routine determines if an acquisition with the (resource, try)
  1534. characteristics is already represented in the Node parameter.
  1535. We used to match nodes based on (resource, thread, stack trace, try)
  1536. 4-tuplet but this really causes an explosion in the number of nodes.
  1537. Such a method would yield more accurate proofs but does not affect
  1538. the correctness of the deadlock detection algorithms.
  1539. Return value:
  1540. True if similar node.
  1541. --*/
  1542. {
  1543. ASSERT (Node);
  1544. ASSERT (Node->Root);
  1545. if (Resource == Node->Root->ResourceAddress
  1546. && TryNode == Node->OnlyTryAcquireUsed) {
  1547. //
  1548. // Second condition is important to keep nodes for TryAcquire operations
  1549. // separated from normal acquires. A TryAcquire cannot cause a deadlock
  1550. // and therefore we have to be careful not to report bogus deadlocks.
  1551. //
  1552. return TRUE;
  1553. }
  1554. else {
  1555. return FALSE;
  1556. }
  1557. }
  1558. VOID
  1559. VfDeadlockAcquireResource(
  1560. IN PVOID Resource,
  1561. IN VI_DEADLOCK_RESOURCE_TYPE Type,
  1562. IN PKTHREAD Thread,
  1563. IN BOOLEAN TryAcquire,
  1564. IN PVOID Caller
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This routine makes sure that it is ok to acquire the resource without
  1569. causing a deadlock. It will also update the resource graph with the new
  1570. resource acquisition.
  1571. Arguments:
  1572. Resource: Address of the resource in question as used by kernel.
  1573. Type: Type of the resource.
  1574. Thread: thread attempting to acquire the resource
  1575. TryAcquire: true if this is a tryacquire() operation
  1576. Caller: address of the caller
  1577. Return Value:
  1578. None.
  1579. --*/
  1580. {
  1581. PKTHREAD CurrentThread;
  1582. PVI_DEADLOCK_THREAD ThreadEntry;
  1583. KIRQL OldIrql = 0;
  1584. PVI_DEADLOCK_NODE CurrentNode;
  1585. PVI_DEADLOCK_NODE NewNode;
  1586. PVI_DEADLOCK_RESOURCE ResourceRoot;
  1587. PLIST_ENTRY Current;
  1588. ULONG HashValue;
  1589. ULONG DeadlockFlags;
  1590. BOOLEAN CreatingRootNode = FALSE;
  1591. BOOLEAN ThreadCreated = FALSE;
  1592. LARGE_INTEGER StartTime;
  1593. LARGE_INTEGER EndTime;
  1594. BOOLEAN AddResult;
  1595. PVOID ReservedThread;
  1596. PVOID ReservedNode;
  1597. PVOID ReservedResource;
  1598. PVI_DEADLOCK_NODE ThreadCurrentNode;
  1599. CurrentNode = NULL;
  1600. ThreadEntry = NULL;
  1601. ThreadCurrentNode = NULL;
  1602. //
  1603. // If we are not initialized or package is not enabled
  1604. // we return immediately.
  1605. //
  1606. if (! ViDeadlockCanProceed(Resource, Caller, Type)) {
  1607. return;
  1608. }
  1609. //
  1610. // Skip if the current thread is inside paging code paths.
  1611. //
  1612. if (ViIsThreadInsidePagingCodePaths ()) {
  1613. return;
  1614. }
  1615. CurrentThread = Thread;
  1616. DeadlockFlags = ViDeadlockResourceTypeInfo[Type];
  1617. //
  1618. // Before getting into the real stuff trim the pool cache.
  1619. // This needs to happen out of any locks.
  1620. //
  1621. ViDeadlockTrimPoolCache ();
  1622. //
  1623. // Reserve resources that might be needed. If upon exit these
  1624. // variables are null it means the allocation either failed or was used.
  1625. // In both cases we do not need to free anything.
  1626. //
  1627. ReservedThread = ViDeadlockAllocate (ViDeadlockThread);
  1628. ReservedNode = ViDeadlockAllocate (ViDeadlockNode);
  1629. ReservedResource = ViDeadlockAllocate (ViDeadlockResource);
  1630. //
  1631. // Lock the deadlock database.
  1632. //
  1633. ViDeadlockDetectionLock( &OldIrql );
  1634. KeQueryTickCount (&StartTime);
  1635. //
  1636. // Allocate a node that might be needed. If we will not use it
  1637. // we will deallocate it at the end. If we fail to allocate
  1638. // we will return immediately.
  1639. //
  1640. NewNode = ReservedNode;
  1641. ReservedNode = NULL;
  1642. if (NewNode == NULL) {
  1643. goto Exit;
  1644. }
  1645. //
  1646. // Find the thread descriptor. If there is none we will create one.
  1647. //
  1648. ThreadEntry = ViDeadlockSearchThread (CurrentThread);
  1649. if (ThreadEntry == NULL) {
  1650. ThreadEntry = ViDeadlockAddThread (CurrentThread, ReservedThread);
  1651. ReservedThread = NULL;
  1652. if (ThreadEntry == NULL) {
  1653. //
  1654. // If we cannot allocate a new thread entry then
  1655. // no deadlock detection will happen.
  1656. //
  1657. goto Exit;
  1658. }
  1659. ThreadCreated = TRUE;
  1660. }
  1661. #if DBG
  1662. if (Type == VfDeadlockSpinLock) {
  1663. if (ThreadEntry->CurrentSpinNode != NULL) {
  1664. ASSERT(ThreadEntry->CurrentSpinNode->Root->ThreadOwner == ThreadEntry);
  1665. ASSERT(ThreadEntry->CurrentSpinNode->ThreadEntry == ThreadEntry);
  1666. ASSERT(ThreadEntry->NodeCount != 0);
  1667. ASSERT(ThreadEntry->CurrentSpinNode->Active != 0);
  1668. ASSERT(ThreadEntry->CurrentSpinNode->Root->NodeCount != 0);
  1669. }
  1670. }
  1671. else {
  1672. if (ThreadEntry->CurrentOtherNode != NULL) {
  1673. ASSERT(ThreadEntry->CurrentOtherNode->Root->ThreadOwner == ThreadEntry);
  1674. ASSERT(ThreadEntry->CurrentOtherNode->ThreadEntry == ThreadEntry);
  1675. ASSERT(ThreadEntry->NodeCount != 0);
  1676. ASSERT(ThreadEntry->CurrentOtherNode->Active != 0);
  1677. ASSERT(ThreadEntry->CurrentOtherNode->Root->NodeCount != 0);
  1678. }
  1679. }
  1680. #endif
  1681. //
  1682. // Find the resource descriptor. If we do not find a descriptor
  1683. // we will create one on the fly.
  1684. //
  1685. ResourceRoot = ViDeadlockSearchResource (Resource);
  1686. if (ResourceRoot == NULL) {
  1687. //
  1688. // Could not find the resource descriptor therefore we need to create one.
  1689. // Note that we will not complain about the resource not being initialized
  1690. // before because there are legitimate reasons for this to happen. For
  1691. // example the resource was initialized in an unverified driver and then
  1692. // passed to a verified driver that caled acquire().
  1693. //
  1694. if (ViDeadlockVeryStrict) {
  1695. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_UNINITIALIZED_RESOURCE,
  1696. (ULONG_PTR) Resource,
  1697. (ULONG_PTR) NULL,
  1698. (ULONG_PTR) NULL);
  1699. }
  1700. AddResult = ViDeadlockAddResource (Resource,
  1701. Type,
  1702. Caller,
  1703. ReservedResource);
  1704. ReservedResource = NULL;
  1705. if (AddResult == FALSE) {
  1706. //
  1707. // If we failed to add the resource then no deadlock detection.
  1708. //
  1709. if (ThreadCreated) {
  1710. ViDeadlockDeleteThread (ThreadEntry, FALSE);
  1711. }
  1712. goto Exit;
  1713. }
  1714. //
  1715. // Search again the resource. This time we should find it.
  1716. //
  1717. ResourceRoot = ViDeadlockSearchResource (Resource);
  1718. }
  1719. //
  1720. // At this point we have a THREAD and a RESOURCE to play with.
  1721. // In addition we are just about to acquire the resource which means
  1722. // there should not be another thread owning unless it is a recursive
  1723. // acquisition.
  1724. //
  1725. ASSERT (ResourceRoot);
  1726. ASSERT (ThreadEntry);
  1727. if (Type == VfDeadlockSpinLock) {
  1728. ThreadCurrentNode = ThreadEntry->CurrentSpinNode;
  1729. }
  1730. else {
  1731. ThreadCurrentNode = ThreadEntry->CurrentOtherNode;
  1732. }
  1733. //
  1734. // Since we just acquired the resource the valid value for ThreadOwner is
  1735. // null or ThreadEntry (for a recursive acquisition). This might not be
  1736. // true if we missed a release() from an unverified driver. So we will
  1737. // not complain about it. We will just put the resource in a consistent
  1738. // state and continue;
  1739. //
  1740. if (ResourceRoot->ThreadOwner) {
  1741. if (ResourceRoot->ThreadOwner != ThreadEntry) {
  1742. ResourceRoot->RecursionCount = 0;
  1743. }
  1744. else {
  1745. ASSERT (ResourceRoot->RecursionCount > 0);
  1746. }
  1747. }
  1748. else {
  1749. ASSERT (ResourceRoot->RecursionCount == 0);
  1750. }
  1751. ResourceRoot->ThreadOwner = ThreadEntry;
  1752. ResourceRoot->RecursionCount += 1;
  1753. //
  1754. // Check if thread holds any resources. If it does we will have to determine
  1755. // at that local point in the dependency graph if we need to create a
  1756. // new node. If this is the first resource acquired by the thread we need
  1757. // to create a new root node or reuse one created in the past.
  1758. //
  1759. if (ThreadCurrentNode != NULL) {
  1760. //
  1761. // If we get here, the current thread had already acquired resources.
  1762. // Check to see if this resource has already been acquired.
  1763. //
  1764. if (ResourceRoot->RecursionCount > 1) {
  1765. //
  1766. // Recursive acquisition is OK for some resources...
  1767. //
  1768. if ((DeadlockFlags & VI_DEADLOCK_FLAG_RECURSIVE_ACQUISITION_OK) != 0) {
  1769. //
  1770. // Recursion can't cause a deadlock. Don't set CurrentNode
  1771. // since we don't want to move any pointers.
  1772. //
  1773. goto Exit;
  1774. } else {
  1775. //
  1776. // This is a recursive acquire for a resource type that is not allowed
  1777. // to acquire recursively. Note on continuing from here: we have a recursion
  1778. // count of two which will come in handy when the resources are released.
  1779. //
  1780. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_SELF_DEADLOCK,
  1781. (ULONG_PTR)Resource,
  1782. (ULONG_PTR)ResourceRoot,
  1783. (ULONG_PTR)ThreadEntry);
  1784. goto Exit;
  1785. }
  1786. }
  1787. //
  1788. // If link already exists, update pointers and exit.
  1789. // otherwise check for deadlocks and create a new node
  1790. //
  1791. Current = ThreadCurrentNode->ChildrenList.Flink;
  1792. while (Current != &(ThreadCurrentNode->ChildrenList)) {
  1793. CurrentNode = CONTAINING_RECORD (Current,
  1794. VI_DEADLOCK_NODE,
  1795. SiblingsList);
  1796. Current = Current->Flink;
  1797. if (ViDeadlockSimilarNode (Resource, TryAcquire, CurrentNode)) {
  1798. //
  1799. // We have found a link. A link that already exists doesn't have
  1800. // to be checked for a deadlock because it would have been caught
  1801. // when the link was created in the first place. We can just update
  1802. // the pointers to reflect the new resource acquired and exit.
  1803. //
  1804. // We apply our graph compression function to minimize duplicates.
  1805. //
  1806. ViDeadlockCheckDuplicatesAmongChildren (ThreadCurrentNode,
  1807. CurrentNode);
  1808. goto Exit;
  1809. }
  1810. }
  1811. //
  1812. // Now we know that we're in it for the long haul. We must create a new
  1813. // link and make sure that it doesn't cause a deadlock. Later in the
  1814. // function CurrentNode being null will signify that we need to create
  1815. // a new node.
  1816. //
  1817. CurrentNode = NULL;
  1818. //
  1819. // We will analyze deadlock if the resource just about to be acquired
  1820. // was acquired before and there are nodes in the graph for the
  1821. // resource. Try acquire can not be the cause of a deadlock.
  1822. // Don't analyze on try acquires.
  1823. //
  1824. if (ResourceRoot->NodeCount > 0 && TryAcquire == FALSE) {
  1825. if (ViDeadlockAnalyze (Resource, ThreadCurrentNode, TRUE, 0)) {
  1826. //
  1827. // If we are here we detected deadlock. The analyze() function
  1828. // does all the reporting. Being here means we hit `g' in the
  1829. // debugger. We will just exit and do not add this resource
  1830. // to the graph.
  1831. //
  1832. goto Exit;
  1833. }
  1834. }
  1835. }
  1836. else {
  1837. //
  1838. // Thread does not have any resources acquired. We have to figure out
  1839. // if this is a scenario we have encountered in the past by looking
  1840. // at all nodes (that are roots) for the resource to be acquired.
  1841. // Note that all this is bookkeeping but we cannot encounter a deadlock
  1842. // from now on.
  1843. //
  1844. PLIST_ENTRY Current;
  1845. PVI_DEADLOCK_NODE Node = NULL;
  1846. BOOLEAN FoundNode = FALSE;
  1847. Current = ResourceRoot->ResourceList.Flink;
  1848. while (Current != &(ResourceRoot->ResourceList)) {
  1849. Node = CONTAINING_RECORD (Current,
  1850. VI_DEADLOCK_NODE,
  1851. ResourceList);
  1852. Current = Node->ResourceList.Flink;
  1853. if (Node->Parent == NULL) {
  1854. if (ViDeadlockSimilarNode (Resource, TryAcquire, Node)) {
  1855. //
  1856. // We apply our graph compression function to minimize duplicates.
  1857. //
  1858. ViDeadlockCheckDuplicatesAmongRoots (Node);
  1859. FoundNode = TRUE;
  1860. break;
  1861. }
  1862. }
  1863. }
  1864. if (FoundNode) {
  1865. CurrentNode = Node;
  1866. goto Exit;
  1867. }
  1868. else {
  1869. CreatingRootNode = TRUE;
  1870. }
  1871. }
  1872. //
  1873. // At this moment we know for sure the new link will not cause
  1874. // a deadlock. We will create the new resource node.
  1875. //
  1876. if (NewNode != NULL) {
  1877. CurrentNode = NewNode;
  1878. //
  1879. // Set newnode to NULL to signify it has been used -- otherwise it
  1880. // will get freed at the end of this function.
  1881. //
  1882. NewNode = NULL;
  1883. //
  1884. // Initialize the new resource node
  1885. //
  1886. RtlZeroMemory (CurrentNode, sizeof *CurrentNode);
  1887. CurrentNode->Active = 0;
  1888. CurrentNode->Parent = ThreadCurrentNode;
  1889. CurrentNode->Root = ResourceRoot;
  1890. InitializeListHead (&(CurrentNode->ChildrenList));
  1891. //
  1892. // Mark the TryAcquire type of the node.
  1893. //
  1894. CurrentNode->OnlyTryAcquireUsed = TryAcquire;
  1895. //
  1896. // Add to the children list of the parent.
  1897. //
  1898. if (! CreatingRootNode) {
  1899. InsertHeadList(&(ThreadCurrentNode->ChildrenList),
  1900. &(CurrentNode->SiblingsList));
  1901. }
  1902. //
  1903. // Register the new resource node in the list of nodes maintained
  1904. // for this resource.
  1905. //
  1906. InsertHeadList(&(ResourceRoot->ResourceList),
  1907. &(CurrentNode->ResourceList));
  1908. ResourceRoot->NodeCount += 1;
  1909. if (ResourceRoot->NodeCount > 0xFFF0) {
  1910. ViDeadlockState.ResourceNodeCountOverflow = 1;
  1911. }
  1912. //
  1913. // Add to the graph statistics.
  1914. //
  1915. #if DBG
  1916. {
  1917. ULONG Level;
  1918. Level = ViDeadlockNodeLevel (CurrentNode);
  1919. if (Level < 8) {
  1920. ViDeadlockGlobals->GraphNodes[Level] += 1;
  1921. }
  1922. }
  1923. #endif
  1924. }
  1925. //
  1926. // Exit point.
  1927. //
  1928. Exit:
  1929. //
  1930. // Add information we use to identify the culprit should
  1931. // a deadlock occur
  1932. //
  1933. if (CurrentNode) {
  1934. ASSERT (ThreadEntry);
  1935. ASSERT (ThreadCurrentNode == CurrentNode->Parent);
  1936. CurrentNode->Active = 1;
  1937. //
  1938. // The node should have thread entry field null either because
  1939. // it was newly created or because the node was released in the
  1940. // past and therefore the field was zeroed.
  1941. //
  1942. // silviuc: true? What about if we miss release() operations.
  1943. //
  1944. ASSERT (CurrentNode->ThreadEntry == NULL);
  1945. CurrentNode->ThreadEntry = ThreadEntry;
  1946. if (Type == VfDeadlockSpinLock) {
  1947. ThreadEntry->CurrentSpinNode = CurrentNode;
  1948. }
  1949. else {
  1950. ThreadEntry->CurrentOtherNode = CurrentNode;
  1951. }
  1952. ThreadEntry->NodeCount += 1;
  1953. #if DBG
  1954. if (ThreadEntry->NodeCount <= 8) {
  1955. ViDeadlockGlobals->NodeLevelCounter[ThreadEntry->NodeCount - 1] += 1;
  1956. }
  1957. else {
  1958. ViDeadlockGlobals->NodeLevelCounter[7] += 1;
  1959. }
  1960. #endif
  1961. //
  1962. // If we have a parent, save the parent's stack trace
  1963. //
  1964. if (CurrentNode->Parent) {
  1965. RtlCopyMemory(CurrentNode->ParentStackTrace,
  1966. CurrentNode->Parent->StackTrace,
  1967. sizeof (CurrentNode->ParentStackTrace));
  1968. }
  1969. //
  1970. // Capture stack trace for the current acquire.
  1971. //
  1972. RtlCaptureStackBackTrace (2,
  1973. VI_MAX_STACK_DEPTH,
  1974. CurrentNode->StackTrace,
  1975. &HashValue);
  1976. if (CurrentNode->Parent) {
  1977. CurrentNode->ParentStackTrace[0] = CurrentNode->Parent->StackTrace[0];
  1978. }
  1979. CurrentNode->StackTrace[0] = Caller;
  1980. //
  1981. // Copy the trace for the last acquire in the resource object.
  1982. //
  1983. RtlCopyMemory (CurrentNode->Root->LastAcquireTrace,
  1984. CurrentNode->StackTrace,
  1985. sizeof (CurrentNode->Root->LastAcquireTrace));
  1986. }
  1987. //
  1988. // We allocated space for a new node but it didn't get used -- put it back
  1989. // in the list (don't worry this doesn't do a real 'free' it just puts it
  1990. // in a free list).
  1991. //
  1992. if (NewNode != NULL) {
  1993. ViDeadlockFree (NewNode, ViDeadlockNode);
  1994. }
  1995. //
  1996. // Release deadlock database and return.
  1997. //
  1998. KeQueryTickCount (&EndTime);
  1999. if (EndTime.QuadPart - StartTime.QuadPart > ViDeadlockGlobals->TimeAcquire) {
  2000. ViDeadlockGlobals->TimeAcquire = EndTime.QuadPart - StartTime.QuadPart;
  2001. }
  2002. //
  2003. // Free up unused reserved resources
  2004. //
  2005. if (ReservedResource) {
  2006. ViDeadlockFree (ReservedResource, ViDeadlockResource);
  2007. }
  2008. if (ReservedNode) {
  2009. ViDeadlockFree (ReservedNode, ViDeadlockNode);
  2010. }
  2011. if (ReservedThread) {
  2012. ViDeadlockFree (ReservedThread, ViDeadlockThread);
  2013. }
  2014. ViDeadlockDetectionUnlock( OldIrql );
  2015. return;
  2016. }
  2017. VOID
  2018. VfDeadlockReleaseResource(
  2019. IN PVOID Resource,
  2020. IN VI_DEADLOCK_RESOURCE_TYPE Type,
  2021. IN PKTHREAD Thread,
  2022. IN PVOID Caller
  2023. )
  2024. /*++
  2025. Routine Description:
  2026. This routine does the maintenance necessary to release resources from our
  2027. deadlock detection database.
  2028. Arguments:
  2029. Resource: Address of the resource in question.
  2030. Thread: thread releasing the resource. In most of the cases this is the
  2031. current thread but it might be different for resources that can be
  2032. acquired in one thread and released in another one.
  2033. Caller: address of the caller of release()
  2034. Return Value:
  2035. None.
  2036. --*/
  2037. {
  2038. PKTHREAD CurrentThread;
  2039. PVI_DEADLOCK_THREAD ThreadEntry;
  2040. KIRQL OldIrql = 0;
  2041. PVI_DEADLOCK_RESOURCE ResourceRoot;
  2042. PVI_DEADLOCK_NODE ReleasedNode;
  2043. LARGE_INTEGER StartTime;
  2044. LARGE_INTEGER EndTime;
  2045. ULONG HashValue;
  2046. PVI_DEADLOCK_NODE ThreadCurrentNode;
  2047. UNREFERENCED_PARAMETER (Caller);
  2048. //
  2049. // If we aren't initialized or package is not enabled
  2050. // we return immediately.
  2051. //
  2052. if (! ViDeadlockCanProceed(Resource, Caller, Type)) {
  2053. return;
  2054. }
  2055. //
  2056. // Skip if the current thread is inside paging code paths.
  2057. //
  2058. if (ViIsThreadInsidePagingCodePaths ()) {
  2059. return;
  2060. }
  2061. ReleasedNode = NULL;
  2062. CurrentThread = Thread;
  2063. ThreadEntry = NULL;
  2064. ViDeadlockDetectionLock( &OldIrql );
  2065. KeQueryTickCount (&StartTime);
  2066. ResourceRoot = ViDeadlockSearchResource (Resource);
  2067. if (ResourceRoot == NULL) {
  2068. //
  2069. // Release called with a resource address that was never
  2070. // stored in our resource database. This can happen in
  2071. // the following circumstances:
  2072. //
  2073. // (a) resource is released but we never seen it before
  2074. // because it was acquired in an unverified driver.
  2075. //
  2076. // (b) we have encountered allocation failures that prevented
  2077. // us from completing an acquire() or initialize().
  2078. //
  2079. // All are legitimate cases and therefore we just ignore the
  2080. // release operation.
  2081. //
  2082. goto Exit;
  2083. }
  2084. //
  2085. // Check if we are trying to release a resource that was never
  2086. // acquired.
  2087. //
  2088. if (ResourceRoot->RecursionCount == 0) {
  2089. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_UNACQUIRED_RESOURCE,
  2090. (ULONG_PTR)Resource,
  2091. (ULONG_PTR)ResourceRoot,
  2092. (ULONG_PTR)ViDeadlockSearchThread(CurrentThread));
  2093. goto Exit;
  2094. }
  2095. //
  2096. // Look for this thread in our thread list. Note we are looking actually
  2097. // for the thread that acquired the resource -- not the current one
  2098. // It should, in fact be the current one, but if the resource is being released
  2099. // in a different thread from the one it was acquired in, we need the original.
  2100. //
  2101. ASSERT (ResourceRoot->RecursionCount > 0);
  2102. ASSERT (ResourceRoot->ThreadOwner);
  2103. ThreadEntry = ResourceRoot->ThreadOwner;
  2104. if (ThreadEntry->Thread != CurrentThread) {
  2105. //
  2106. // Someone acquired a resource that is released in another thread.
  2107. // This is bad design but we have to live with it.
  2108. //
  2109. // NB. If this occurrs, we may call a non-deadlock a deadlock.
  2110. // For example, we see a simple deadlock -- AB BA
  2111. // If another thread releases B, there won't actually
  2112. // be a deadlock. Kind of annoying and ugly.
  2113. //
  2114. #if DBG
  2115. DbgPrint("Thread %p acquired resource %p but thread %p released it\n",
  2116. ThreadEntry->Thread, Resource, CurrentThread );
  2117. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_UNEXPECTED_THREAD,
  2118. (ULONG_PTR)Resource,
  2119. (ULONG_PTR)ThreadEntry->Thread,
  2120. (ULONG_PTR)CurrentThread
  2121. );
  2122. #endif
  2123. //
  2124. // If we don't want this to be fatal, in order to
  2125. // continue we must pretend that the current
  2126. // thread is the resource's owner.
  2127. //
  2128. CurrentThread = ThreadEntry->Thread;
  2129. }
  2130. //
  2131. // In this moment we have a resource (ResourceRoot) and a
  2132. // thread (ThreadEntry) to play with.
  2133. //
  2134. ASSERT (ResourceRoot && ThreadEntry);
  2135. if (ResourceRoot->Type == VfDeadlockSpinLock) {
  2136. ThreadCurrentNode = ThreadEntry->CurrentSpinNode;
  2137. }
  2138. else {
  2139. ThreadCurrentNode = ThreadEntry->CurrentOtherNode;
  2140. }
  2141. ASSERT (ThreadCurrentNode);
  2142. ASSERT (ThreadCurrentNode->Root);
  2143. ASSERT (ThreadEntry->NodeCount > 0);
  2144. ResourceRoot->RecursionCount -= 1;
  2145. if (ResourceRoot->RecursionCount > 0) {
  2146. //
  2147. // Just decrement the recursion count and do not change any state
  2148. //
  2149. goto Exit;
  2150. }
  2151. //
  2152. // Wipe out the resource owner.
  2153. //
  2154. ResourceRoot->ThreadOwner = NULL;
  2155. #if DBG
  2156. ViDeadlockGlobals->TotalReleases += 1;
  2157. #endif
  2158. //
  2159. // Check for out of order releases
  2160. //
  2161. if (ThreadCurrentNode->Root != ResourceRoot) {
  2162. #if DBG
  2163. ViDeadlockGlobals->OutOfOrderReleases += 1;
  2164. #endif
  2165. //
  2166. // Getting here means that somebody acquires a then b then tries
  2167. // to release a before b. This is bad for certain kinds of resources,
  2168. // and for others we have to look the other way.
  2169. //
  2170. if ((ViDeadlockResourceTypeInfo[ThreadCurrentNode->Root->Type] &
  2171. VI_DEADLOCK_FLAG_REVERSE_RELEASE_OK) == 0) {
  2172. DbgPrint("Deadlock detection: Must release resources in reverse-order\n");
  2173. DbgPrint("Resource %p acquired before resource %p -- \n"
  2174. "Current thread (%p) is trying to release it first\n",
  2175. Resource,
  2176. ThreadCurrentNode->Root->ResourceAddress,
  2177. ThreadEntry);
  2178. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_UNEXPECTED_RELEASE,
  2179. (ULONG_PTR)Resource,
  2180. (ULONG_PTR)ThreadCurrentNode->Root->ResourceAddress,
  2181. (ULONG_PTR)ThreadEntry);
  2182. }
  2183. //
  2184. // We need to mark the node for the out of order released resource as
  2185. // not active so that other threads will be able to acquire it.
  2186. //
  2187. {
  2188. PVI_DEADLOCK_NODE Current;
  2189. ASSERT (ThreadCurrentNode->Active == 1);
  2190. ASSERT (ThreadCurrentNode->ThreadEntry == ThreadEntry);
  2191. Current = ThreadCurrentNode;
  2192. while (Current != NULL) {
  2193. if (Current->Root == ResourceRoot) {
  2194. ASSERT (Current->Active == 1);
  2195. ASSERT (Current->Root->RecursionCount == 0);
  2196. ASSERT (Current->ThreadEntry == ThreadEntry);
  2197. Current->Active = 0;
  2198. ReleasedNode = Current;
  2199. break;
  2200. }
  2201. Current = Current->Parent;
  2202. }
  2203. if (Current == NULL) {
  2204. //
  2205. // If we do not manage to find an active node we must be in an
  2206. // weird state. The resource must be here or else we would have
  2207. // gotten an `unxpected release' bugcheck.
  2208. //
  2209. ASSERT (0);
  2210. }
  2211. }
  2212. } else {
  2213. //
  2214. // We need to release the top node held by the thread.
  2215. //
  2216. ASSERT (ThreadCurrentNode->Active);
  2217. ReleasedNode = ThreadCurrentNode;
  2218. ReleasedNode->Active = 0;
  2219. }
  2220. //
  2221. // Put the `CurrentNode' field of the thread in a consistent state.
  2222. // It should point to the most recent active node that it owns.
  2223. //
  2224. if (ResourceRoot->Type == VfDeadlockSpinLock) {
  2225. while (ThreadEntry->CurrentSpinNode) {
  2226. if (ThreadEntry->CurrentSpinNode->Active == 1) {
  2227. if (ThreadEntry->CurrentSpinNode->ThreadEntry == ThreadEntry) {
  2228. break;
  2229. }
  2230. }
  2231. ThreadEntry->CurrentSpinNode = ThreadEntry->CurrentSpinNode->Parent;
  2232. }
  2233. }
  2234. else {
  2235. while (ThreadEntry->CurrentOtherNode) {
  2236. if (ThreadEntry->CurrentOtherNode->Active == 1) {
  2237. if (ThreadEntry->CurrentOtherNode->ThreadEntry == ThreadEntry) {
  2238. break;
  2239. }
  2240. }
  2241. ThreadEntry->CurrentOtherNode = ThreadEntry->CurrentOtherNode->Parent;
  2242. }
  2243. }
  2244. Exit:
  2245. //
  2246. // Properly release the node if there is one to be released.
  2247. //
  2248. if (ReleasedNode) {
  2249. ASSERT (ReleasedNode->Active == 0);
  2250. ASSERT (ReleasedNode->Root->ThreadOwner == 0);
  2251. ASSERT (ReleasedNode->Root->RecursionCount == 0);
  2252. ASSERT (ReleasedNode->ThreadEntry == ThreadEntry);
  2253. ASSERT (ThreadEntry->NodeCount > 0);
  2254. if (ResourceRoot->Type == VfDeadlockSpinLock) {
  2255. ASSERT (ThreadEntry->CurrentSpinNode != ReleasedNode);
  2256. }
  2257. else {
  2258. ASSERT (ThreadEntry->CurrentOtherNode != ReleasedNode);
  2259. }
  2260. ReleasedNode->ThreadEntry = NULL;
  2261. ThreadEntry->NodeCount -= 1;
  2262. #if DBG
  2263. ViDeadlockCheckNodeConsistency (ReleasedNode, FALSE);
  2264. ViDeadlockCheckResourceConsistency (ReleasedNode->Root, FALSE);
  2265. ViDeadlockCheckThreadConsistency (ThreadEntry, FALSE);
  2266. #endif
  2267. if (ThreadEntry && ThreadEntry->NodeCount == 0) {
  2268. ViDeadlockDeleteThread (ThreadEntry, FALSE);
  2269. }
  2270. //
  2271. // If this is a root node with no children, delete the node
  2272. // too. This is important to keep memory low. A single node
  2273. // can never be the cause of a deadlock.
  2274. //
  2275. if (ReleasedNode->Parent == NULL && IsListEmpty(&(ReleasedNode->ChildrenList))) {
  2276. ViDeadlockDeleteNode (ReleasedNode, FALSE);
  2277. #if DBG
  2278. ViDeadlockGlobals->RootNodesDeleted += 1;
  2279. #endif
  2280. }
  2281. }
  2282. //
  2283. // Capture the trace for the last release in the resource object.
  2284. //
  2285. if (ResourceRoot) {
  2286. RtlCaptureStackBackTrace (2,
  2287. VI_MAX_STACK_DEPTH,
  2288. ResourceRoot->LastReleaseTrace,
  2289. &HashValue);
  2290. }
  2291. KeQueryTickCount (&EndTime);
  2292. if (EndTime.QuadPart - StartTime.QuadPart > ViDeadlockGlobals->TimeRelease) {
  2293. ViDeadlockGlobals->TimeRelease = EndTime.QuadPart - StartTime.QuadPart;
  2294. }
  2295. ViDeadlockDetectionUnlock (OldIrql);
  2296. }
  2297. /////////////////////////////////////////////////////////////////////
  2298. /////////////////////////////////////////////////// Thread management
  2299. /////////////////////////////////////////////////////////////////////
  2300. PVI_DEADLOCK_THREAD
  2301. ViDeadlockSearchThread (
  2302. PKTHREAD Thread
  2303. )
  2304. /*++
  2305. Routine Description:
  2306. This routine searches for a thread in the thread database.
  2307. The function assumes the deadlock database lock is held.
  2308. Arguments:
  2309. Thread - thread address
  2310. Return Value:
  2311. Address of VI_DEADLOCK_THREAD structure if thread was found.
  2312. Null otherwise.
  2313. --*/
  2314. {
  2315. PLIST_ENTRY Current;
  2316. PLIST_ENTRY ListHead;
  2317. PVI_DEADLOCK_THREAD ThreadInfo;
  2318. ThreadInfo = NULL;
  2319. ListHead = ViDeadlockDatabaseHash (ViDeadlockGlobals->ThreadDatabase, Thread);
  2320. if (IsListEmpty(ListHead)) {
  2321. return NULL;
  2322. }
  2323. Current = ListHead->Flink;
  2324. while (Current != ListHead) {
  2325. ThreadInfo = CONTAINING_RECORD (Current,
  2326. VI_DEADLOCK_THREAD,
  2327. ListEntry);
  2328. if (ThreadInfo->Thread == Thread) {
  2329. return ThreadInfo;
  2330. }
  2331. Current = Current->Flink;
  2332. }
  2333. return NULL;
  2334. }
  2335. PVI_DEADLOCK_THREAD
  2336. ViDeadlockAddThread (
  2337. PKTHREAD Thread,
  2338. PVOID ReservedThread
  2339. )
  2340. /*++
  2341. Routine Description:
  2342. This routine adds a new thread to the thread database.
  2343. The function assumes the deadlock database lock is held.
  2344. Arguments:
  2345. Thread - thread address
  2346. Return Value:
  2347. Address of the VI_DEADLOCK_THREAD structure just added.
  2348. Null if allocation failed.
  2349. --*/
  2350. {
  2351. PVI_DEADLOCK_THREAD ThreadInfo;
  2352. PLIST_ENTRY HashBin;
  2353. ASSERT (ViDeadlockDatabaseOwner == KeGetCurrentThread());
  2354. //
  2355. // Use reserved block for the new thread. Set ReservedThread
  2356. // to null to signal that block was used.
  2357. //
  2358. ThreadInfo = ReservedThread;
  2359. ReservedThread = NULL;
  2360. if (ThreadInfo == NULL) {
  2361. return NULL;
  2362. }
  2363. RtlZeroMemory (ThreadInfo, sizeof *ThreadInfo);
  2364. ThreadInfo->Thread = Thread;
  2365. HashBin = ViDeadlockDatabaseHash (ViDeadlockGlobals->ThreadDatabase, Thread);
  2366. InsertHeadList(HashBin, &ThreadInfo->ListEntry);
  2367. return ThreadInfo;
  2368. }
  2369. VOID
  2370. ViDeadlockDeleteThread (
  2371. PVI_DEADLOCK_THREAD Thread,
  2372. BOOLEAN Cleanup
  2373. )
  2374. /*++
  2375. Routine Description:
  2376. This routine deletes a thread.
  2377. Arguments:
  2378. Thread - thread address
  2379. Cleanup - true if this is a call generated from DeadlockDetectionCleanup().
  2380. Return Value:
  2381. None.
  2382. --*/
  2383. {
  2384. if (Cleanup == FALSE) {
  2385. ASSERT (ViDeadlockDatabaseOwner == KeGetCurrentThread());
  2386. if (Thread->NodeCount != 0
  2387. || Thread->CurrentSpinNode != NULL
  2388. || Thread->CurrentOtherNode != NULL) {
  2389. //
  2390. // A thread should not be deleted while it has resources acquired.
  2391. //
  2392. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES,
  2393. (ULONG_PTR)(Thread->Thread),
  2394. (ULONG_PTR)(Thread),
  2395. (ULONG_PTR)0);
  2396. } else {
  2397. ASSERT (Thread->NodeCount == 0);
  2398. }
  2399. }
  2400. RemoveEntryList (&(Thread->ListEntry));
  2401. ViDeadlockFree (Thread, ViDeadlockThread);
  2402. }
  2403. /////////////////////////////////////////////////////////////////////
  2404. /////////////////////////////////////////////////////// Allocate/Free
  2405. /////////////////////////////////////////////////////////////////////
  2406. PVOID
  2407. ViDeadlockAllocateFromPoolCache (
  2408. PULONG Count,
  2409. ULONG MaximumCount,
  2410. PLIST_ENTRY List,
  2411. SIZE_T Offset
  2412. )
  2413. {
  2414. PVOID Address = NULL;
  2415. PLIST_ENTRY Entry;
  2416. UNREFERENCED_PARAMETER (MaximumCount);
  2417. if (*Count > 0) {
  2418. *Count -= 1;
  2419. Entry = RemoveHeadList (List);
  2420. Address = (PVOID)((SIZE_T)Entry - Offset);
  2421. }
  2422. return Address;
  2423. }
  2424. VOID
  2425. ViDeadlockFreeIntoPoolCache (
  2426. PVOID Object,
  2427. PULONG Count,
  2428. PLIST_ENTRY List,
  2429. SIZE_T Offset
  2430. )
  2431. {
  2432. PLIST_ENTRY Entry;
  2433. Entry = (PLIST_ENTRY)((SIZE_T)Object + Offset);
  2434. *Count += 1;
  2435. InsertHeadList(List, Entry);
  2436. }
  2437. PVOID
  2438. ViDeadlockAllocate (
  2439. VI_DEADLOCK_ALLOC_TYPE Type
  2440. )
  2441. /*++
  2442. Routine Description:
  2443. This routine is used to allocate deadlock verifier structures,
  2444. that is nodes, resources and threads.
  2445. Arguments:
  2446. Type - what structure do we need to allocate (node, resource or thread).
  2447. Return Value:
  2448. Address of the newly allocate structure or null if allocation failed.
  2449. Side effects:
  2450. If allocation fails the routine will bump the AllocationFailures field
  2451. from ViDeadlockGlobals.
  2452. --*/
  2453. {
  2454. PVOID Address = NULL;
  2455. KIRQL OldIrql;
  2456. SIZE_T Offset;
  2457. SIZE_T Size = 0;
  2458. //
  2459. // If it is a resource, thread, or node alocation, see
  2460. // if we have a pre-allocated one on the free list.
  2461. //
  2462. ViDeadlockDetectionLock (&OldIrql);
  2463. switch (Type) {
  2464. case ViDeadlockThread:
  2465. Offset = (SIZE_T)(&(((PVI_DEADLOCK_THREAD)0)->FreeListEntry));
  2466. Size = sizeof (VI_DEADLOCK_THREAD);
  2467. Address = ViDeadlockAllocateFromPoolCache (&(ViDeadlockGlobals->FreeThreadCount),
  2468. VI_DEADLOCK_MAX_FREE_THREAD,
  2469. &(ViDeadlockGlobals->FreeThreadList),
  2470. Offset);
  2471. break;
  2472. case ViDeadlockResource:
  2473. Offset = (SIZE_T)(&(((PVI_DEADLOCK_RESOURCE)0)->FreeListEntry));
  2474. Size = sizeof (VI_DEADLOCK_RESOURCE);
  2475. Address = ViDeadlockAllocateFromPoolCache (&(ViDeadlockGlobals->FreeResourceCount),
  2476. VI_DEADLOCK_MAX_FREE_RESOURCE,
  2477. &(ViDeadlockGlobals->FreeResourceList),
  2478. Offset);
  2479. break;
  2480. case ViDeadlockNode:
  2481. Offset = (SIZE_T)(&(((PVI_DEADLOCK_NODE)0)->FreeListEntry));
  2482. Size = sizeof (VI_DEADLOCK_NODE);
  2483. Address = ViDeadlockAllocateFromPoolCache (&(ViDeadlockGlobals->FreeNodeCount),
  2484. VI_DEADLOCK_MAX_FREE_NODE,
  2485. &(ViDeadlockGlobals->FreeNodeList),
  2486. Offset);
  2487. break;
  2488. default:
  2489. ASSERT (0);
  2490. break;
  2491. }
  2492. //
  2493. // If we did not find anything and kernel verifier is not active
  2494. // then go to the kernel pool for a direct allocation. If kernel
  2495. // verifier is enabled everything is preallocated and we never
  2496. // call into the kernel pool.
  2497. //
  2498. if (Address == NULL && ViDeadlockState.KernelVerifierEnabled == 0) {
  2499. ViDeadlockDetectionUnlock (OldIrql);
  2500. Address = ExAllocatePoolWithTag(NonPagedPool, Size, VI_DEADLOCK_TAG);
  2501. ViDeadlockDetectionLock (&OldIrql);
  2502. }
  2503. if (Address) {
  2504. switch (Type) {
  2505. case ViDeadlockThread:
  2506. ViDeadlockGlobals->Threads[0] += 1;
  2507. if (ViDeadlockGlobals->Threads[0] > ViDeadlockGlobals->Threads[1]) {
  2508. ViDeadlockGlobals->Threads[1] = ViDeadlockGlobals->Threads[0];
  2509. }
  2510. break;
  2511. case ViDeadlockResource:
  2512. ViDeadlockGlobals->Resources[0] += 1;
  2513. if (ViDeadlockGlobals->Resources[0] > ViDeadlockGlobals->Resources[1]) {
  2514. ViDeadlockGlobals->Resources[1] = ViDeadlockGlobals->Resources[0];
  2515. }
  2516. break;
  2517. case ViDeadlockNode:
  2518. ViDeadlockGlobals->Nodes[0] += 1;
  2519. if (ViDeadlockGlobals->Nodes[0] > ViDeadlockGlobals->Nodes[1]) {
  2520. ViDeadlockGlobals->Nodes[1] = ViDeadlockGlobals->Nodes[0];
  2521. }
  2522. break;
  2523. default:
  2524. ASSERT (0);
  2525. break;
  2526. }
  2527. }
  2528. else {
  2529. ViDeadlockState.AllocationFailures = 1;
  2530. ViDeadlockGlobals->AllocationFailures += 1;
  2531. //
  2532. // Note that making the AllocationFailures counter bigger than zero
  2533. // essentially disables deadlock verification because the CanProceed()
  2534. // routine will start returning false.
  2535. //
  2536. }
  2537. //
  2538. // Update statistics. No need to zero the block since every
  2539. // call site takes care of this.
  2540. //
  2541. if (Address) {
  2542. #if DBG
  2543. RtlFillMemory (Address, Size, 0xFF);
  2544. #endif
  2545. ViDeadlockGlobals->BytesAllocated += Size;
  2546. }
  2547. ViDeadlockDetectionUnlock (OldIrql);
  2548. return Address;
  2549. }
  2550. VOID
  2551. ViDeadlockFree (
  2552. PVOID Object,
  2553. VI_DEADLOCK_ALLOC_TYPE Type
  2554. )
  2555. /*++
  2556. Routine Description:
  2557. This routine deallocates a deadlock verifier structure (node, resource
  2558. or thread). The function will place the block in the corrsponding cache
  2559. based on the type of the structure. The routine never calls ExFreePool.
  2560. The reason for not calling ExFreePool is that we get notifications from
  2561. ExFreePool every time it gets called. Sometimes the notification comes
  2562. with pool locks held and therefore we cannot call again.
  2563. Arguments:
  2564. Object - block to deallocate
  2565. Type - type of object (node, resource, thread).
  2566. Return Value:
  2567. None.
  2568. --*/
  2569. //
  2570. // Note ... if a thread, node, or resource is being freed, we must not
  2571. // call ExFreePool. Since the pool lock may be already held, calling ExFreePool
  2572. // would cause a recursive spinlock acquisition (which is bad).
  2573. // Instead, we move everything to a 'free' list and try to reuse.
  2574. // Non-thread-node-resource frees get ExFreePooled
  2575. //
  2576. {
  2577. SIZE_T Offset;
  2578. SIZE_T Size = 0;
  2579. switch (Type) {
  2580. case ViDeadlockThread:
  2581. ViDeadlockGlobals->Threads[0] -= 1;
  2582. Size = sizeof (VI_DEADLOCK_THREAD);
  2583. Offset = (SIZE_T)(&(((PVI_DEADLOCK_THREAD)0)->FreeListEntry));
  2584. ViDeadlockFreeIntoPoolCache (Object,
  2585. &(ViDeadlockGlobals->FreeThreadCount),
  2586. &(ViDeadlockGlobals->FreeThreadList),
  2587. Offset);
  2588. break;
  2589. case ViDeadlockResource:
  2590. ViDeadlockGlobals->Resources[0] -= 1;
  2591. Size = sizeof (VI_DEADLOCK_RESOURCE);
  2592. Offset = (SIZE_T)(&(((PVI_DEADLOCK_RESOURCE)0)->FreeListEntry));
  2593. ViDeadlockFreeIntoPoolCache (Object,
  2594. &(ViDeadlockGlobals->FreeResourceCount),
  2595. &(ViDeadlockGlobals->FreeResourceList),
  2596. Offset);
  2597. break;
  2598. case ViDeadlockNode:
  2599. ViDeadlockGlobals->Nodes[0] -= 1;
  2600. Size = sizeof (VI_DEADLOCK_NODE);
  2601. Offset = (SIZE_T)(&(((PVI_DEADLOCK_NODE)0)->FreeListEntry));
  2602. ViDeadlockFreeIntoPoolCache (Object,
  2603. &(ViDeadlockGlobals->FreeNodeCount),
  2604. &(ViDeadlockGlobals->FreeNodeList),
  2605. Offset);
  2606. break;
  2607. default:
  2608. ASSERT (0);
  2609. break;
  2610. }
  2611. ViDeadlockGlobals->BytesAllocated -= Size;
  2612. }
  2613. VOID
  2614. ViDeadlockTrimPoolCache (
  2615. VOID
  2616. )
  2617. /*++
  2618. Routine Description:
  2619. This function trims the pool caches to decent levels. It is carefully
  2620. written to queue a work item to do the actual processing (freeing of pool)
  2621. because the caller may hold various pool mutexes above us.
  2622. Arguments:
  2623. None.
  2624. Return Value:
  2625. None.
  2626. --*/
  2627. {
  2628. KIRQL OldIrql;
  2629. if (ViDeadlockState.KernelVerifierEnabled == 1) {
  2630. return;
  2631. }
  2632. ViDeadlockDetectionLock (&OldIrql);
  2633. if (ViDeadlockGlobals->CacheReductionInProgress == TRUE) {
  2634. ViDeadlockDetectionUnlock (OldIrql);
  2635. return;
  2636. }
  2637. if ((ViDeadlockGlobals->FreeThreadCount > VI_DEADLOCK_MAX_FREE_THREAD) ||
  2638. (ViDeadlockGlobals->FreeNodeCount > VI_DEADLOCK_MAX_FREE_NODE) ||
  2639. (ViDeadlockGlobals->FreeResourceCount > VI_DEADLOCK_MAX_FREE_RESOURCE)){
  2640. ExQueueWorkItem (&ViTrimDeadlockPoolWorkItem, DelayedWorkQueue);
  2641. ViDeadlockGlobals->CacheReductionInProgress = TRUE;
  2642. }
  2643. ViDeadlockDetectionUnlock (OldIrql);
  2644. return;
  2645. }
  2646. VOID
  2647. ViDeadlockTrimPoolCacheWorker (
  2648. PVOID Parameter
  2649. )
  2650. /*++
  2651. Routine Description:
  2652. This function trims the pool caches to decent levels. It is carefully
  2653. written so that ExFreePool is called without holding any deadlock
  2654. verifier locks.
  2655. Arguments:
  2656. None.
  2657. Return Value:
  2658. None.
  2659. Environment:
  2660. Worker thread, PASSIVE_LEVEL, no locks held.
  2661. --*/
  2662. {
  2663. LIST_ENTRY ListOfThreads;
  2664. LIST_ENTRY ListOfNodes;
  2665. LIST_ENTRY ListOfResources;
  2666. KIRQL OldIrql;
  2667. PLIST_ENTRY Entry;
  2668. LOGICAL CacheReductionNeeded;
  2669. UNREFERENCED_PARAMETER (Parameter);
  2670. ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
  2671. CacheReductionNeeded = FALSE;
  2672. InitializeListHead (&ListOfThreads);
  2673. InitializeListHead (&ListOfNodes);
  2674. InitializeListHead (&ListOfResources);
  2675. ViDeadlockDetectionLock (&OldIrql);
  2676. while (ViDeadlockGlobals->FreeThreadCount > VI_DEADLOCK_MAX_FREE_THREAD) {
  2677. Entry = RemoveHeadList (&(ViDeadlockGlobals->FreeThreadList));
  2678. InsertTailList (&ListOfThreads, Entry);
  2679. ViDeadlockGlobals->FreeThreadCount -= 1;
  2680. CacheReductionNeeded = TRUE;
  2681. }
  2682. while (ViDeadlockGlobals->FreeNodeCount > VI_DEADLOCK_MAX_FREE_NODE) {
  2683. Entry = RemoveHeadList (&(ViDeadlockGlobals->FreeNodeList));
  2684. InsertTailList (&ListOfNodes, Entry);
  2685. ViDeadlockGlobals->FreeNodeCount -= 1;
  2686. CacheReductionNeeded = TRUE;
  2687. }
  2688. while (ViDeadlockGlobals->FreeResourceCount > VI_DEADLOCK_MAX_FREE_RESOURCE) {
  2689. Entry = RemoveHeadList (&(ViDeadlockGlobals->FreeResourceList));
  2690. InsertTailList (&ListOfResources, Entry);
  2691. ViDeadlockGlobals->FreeResourceCount -= 1;
  2692. CacheReductionNeeded = TRUE;
  2693. }
  2694. //
  2695. // Don't clear CacheReductionInProgress until the pool allocations are
  2696. // freed to prevent needless recursion.
  2697. //
  2698. if (CacheReductionNeeded == FALSE) {
  2699. ViDeadlockGlobals->CacheReductionInProgress = FALSE;
  2700. ViDeadlockDetectionUnlock (OldIrql);
  2701. return;
  2702. }
  2703. ViDeadlockDetectionUnlock (OldIrql);
  2704. //
  2705. // Now, out of the deadlock verifier lock we can deallocate the
  2706. // blocks trimmed.
  2707. //
  2708. Entry = ListOfThreads.Flink;
  2709. while (Entry != &ListOfThreads) {
  2710. PVI_DEADLOCK_THREAD Block;
  2711. Block = CONTAINING_RECORD (Entry,
  2712. VI_DEADLOCK_THREAD,
  2713. FreeListEntry);
  2714. Entry = Entry->Flink;
  2715. ExFreePool (Block);
  2716. }
  2717. Entry = ListOfNodes.Flink;
  2718. while (Entry != &ListOfNodes) {
  2719. PVI_DEADLOCK_NODE Block;
  2720. Block = CONTAINING_RECORD (Entry,
  2721. VI_DEADLOCK_NODE,
  2722. FreeListEntry);
  2723. Entry = Entry->Flink;
  2724. ExFreePool (Block);
  2725. }
  2726. Entry = ListOfResources.Flink;
  2727. while (Entry != &ListOfResources) {
  2728. PVI_DEADLOCK_RESOURCE Block;
  2729. Block = CONTAINING_RECORD (Entry,
  2730. VI_DEADLOCK_RESOURCE,
  2731. FreeListEntry);
  2732. Entry = Entry->Flink;
  2733. ExFreePool (Block);
  2734. }
  2735. //
  2736. // It's safe to clear CacheReductionInProgress now that the pool
  2737. // allocations are freed.
  2738. //
  2739. ViDeadlockDetectionLock (&OldIrql);
  2740. ViDeadlockGlobals->CacheReductionInProgress = FALSE;
  2741. ViDeadlockDetectionUnlock (OldIrql);
  2742. }
  2743. /////////////////////////////////////////////////////////////////////
  2744. /////////////////////////////////////// Error reporting and debugging
  2745. /////////////////////////////////////////////////////////////////////
  2746. //
  2747. // Variable accessed by the !deadlock debug extension to investigate
  2748. // failures.
  2749. //
  2750. ULONG_PTR ViDeadlockIssue[4];
  2751. VOID
  2752. ViDeadlockReportIssue (
  2753. ULONG_PTR Param1,
  2754. ULONG_PTR Param2,
  2755. ULONG_PTR Param3,
  2756. ULONG_PTR Param4
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. This routine is called to report a deadlock verifier issue.
  2761. If we are in debug mode we will just break in debugger.
  2762. Otherwise we will bugcheck,
  2763. Arguments:
  2764. Param1..Param4 - relevant information for the point of failure.
  2765. Return Value:
  2766. None.
  2767. --*/
  2768. {
  2769. ViDeadlockIssue[0] = Param1;
  2770. ViDeadlockIssue[1] = Param2;
  2771. ViDeadlockIssue[2] = Param3;
  2772. ViDeadlockIssue[3] = Param4;
  2773. if (ViDeadlockDebug) {
  2774. DbgPrint ("Verifier: deadlock: stop: %p %p %p %p %p \n",
  2775. DRIVER_VERIFIER_DETECTED_VIOLATION,
  2776. Param1,
  2777. Param2,
  2778. Param3,
  2779. Param4);
  2780. DbgBreakPoint ();
  2781. }
  2782. else {
  2783. KeBugCheckEx (DRIVER_VERIFIER_DETECTED_VIOLATION,
  2784. Param1,
  2785. Param2,
  2786. Param3,
  2787. Param4);
  2788. }
  2789. }
  2790. VOID
  2791. ViDeadlockAddParticipant(
  2792. PVI_DEADLOCK_NODE Node
  2793. )
  2794. /*++
  2795. Routine Description:
  2796. Adds a new node to the set of nodes involved in a deadlock.
  2797. The function is called only from ViDeadlockAnalyze().
  2798. Arguments:
  2799. Node - node to be added to the deadlock participants collection.
  2800. Return Value:
  2801. None.
  2802. --*/
  2803. {
  2804. ULONG Index;
  2805. Index = ViDeadlockGlobals->NumberOfParticipants;
  2806. if (Index >= NO_OF_DEADLOCK_PARTICIPANTS) {
  2807. ViDeadlockState.DeadlockParticipantsOverflow = 1;
  2808. return;
  2809. }
  2810. ViDeadlockGlobals->Participant[Index] = Node;
  2811. ViDeadlockGlobals->NumberOfParticipants += 1;
  2812. }
  2813. /////////////////////////////////////////////////////////////////////
  2814. //////////////////////////////////////////////////// Resource cleanup
  2815. /////////////////////////////////////////////////////////////////////
  2816. VOID
  2817. VfDeadlockDeleteMemoryRange(
  2818. IN PVOID Address,
  2819. IN SIZE_T Size
  2820. )
  2821. /*++
  2822. Routine Description:
  2823. This routine is called whenever some region of kernel virtual space
  2824. is no longer valid. We need this hook because most kernel resources
  2825. do not have a "delete resource" function and we need to figure out
  2826. what resources are not valid. Otherwise our dependency graph will
  2827. become populated by many zombie resources.
  2828. The important moments when the function gets called are ExFreePool
  2829. (and friends) and driver unloading. Dynamic and static memory are the
  2830. main regions where a resource gets allocated. There can be the possibility
  2831. of a resource allocated on the stack but this is a very weird scenario.
  2832. We might need to detect this and flag it as a potential issue.
  2833. If a resource or thread lives within the range specified then all graph
  2834. paths with nodes reachable from the resource or thread will be wiped out.
  2835. NOTE ON OPTIMIZATION -- rather than having to search through all of the
  2836. resources we've collected, we can make a simple optimization -- if we
  2837. put the resources into hash bins based on PFN or the page address (i.e.
  2838. page number for address 1A020 is 1A), we only have to look into a single
  2839. hash bin for each page that the range spans. Worst case scenario is when
  2840. we have an extremely long allocation, but even in this case we only look
  2841. through each hash bin once.
  2842. Arguments:
  2843. Address - start address of the range to be deleted.
  2844. Size - size in bytes of the range to be deleted.
  2845. Return Value:
  2846. None.
  2847. --*/
  2848. {
  2849. ULONG SpanningPages;
  2850. ULONG Index;
  2851. ULONG_PTR Start;
  2852. ULONG_PTR End;
  2853. PLIST_ENTRY ListHead;
  2854. PLIST_ENTRY CurrentEntry;
  2855. PVI_DEADLOCK_RESOURCE Resource;
  2856. PVI_DEADLOCK_THREAD Thread;
  2857. KIRQL OldIrql;
  2858. //
  2859. // If we are not initialized or package is not enabled
  2860. // we return immediately.
  2861. //
  2862. if (! ViDeadlockCanProceed(NULL, NULL, VfDeadlockUnknown)) {
  2863. return;
  2864. }
  2865. SpanningPages = (ULONG) ADDRESS_AND_SIZE_TO_SPAN_PAGES (Address, Size);
  2866. if (SpanningPages > VI_DEADLOCK_HASH_BINS ) {
  2867. SpanningPages = VI_DEADLOCK_HASH_BINS;
  2868. }
  2869. Start = (ULONG_PTR) Address;
  2870. End = Start + (ULONG_PTR) Size;
  2871. ViDeadlockDetectionLock(&OldIrql);
  2872. //
  2873. // Iterate all resources and delete the ones contained in the
  2874. // memory range.
  2875. //
  2876. for (Index = 0; Index < SpanningPages; Index += 1) {
  2877. //
  2878. // See optimization note above for description of why we only look
  2879. // in a single hash bin.
  2880. //
  2881. ListHead = ViDeadlockDatabaseHash (ViDeadlockGlobals->ResourceDatabase,
  2882. (PVOID) (Start + Index * PAGE_SIZE));
  2883. CurrentEntry = ListHead->Flink;
  2884. while (CurrentEntry != ListHead) {
  2885. Resource = CONTAINING_RECORD (CurrentEntry,
  2886. VI_DEADLOCK_RESOURCE,
  2887. HashChainList);
  2888. CurrentEntry = CurrentEntry->Flink;
  2889. if ((ULONG_PTR)(Resource->ResourceAddress) >= Start &&
  2890. (ULONG_PTR)(Resource->ResourceAddress) < End) {
  2891. ViDeadlockDeleteResource (Resource, FALSE);
  2892. }
  2893. }
  2894. }
  2895. //
  2896. // Iterate all threads and delete the ones contained in the
  2897. // memory range.
  2898. //
  2899. for (Index = 0; Index < SpanningPages; Index += 1) {
  2900. ListHead = ViDeadlockDatabaseHash (ViDeadlockGlobals->ThreadDatabase,
  2901. (PVOID) (Start + Index * PAGE_SIZE));
  2902. CurrentEntry = ListHead->Flink;
  2903. while (CurrentEntry != ListHead) {
  2904. Thread = CONTAINING_RECORD (CurrentEntry,
  2905. VI_DEADLOCK_THREAD,
  2906. ListEntry);
  2907. CurrentEntry = CurrentEntry->Flink;
  2908. if ((ULONG_PTR)(Thread->Thread) >= Start &&
  2909. (ULONG_PTR)(Thread->Thread) < End) {
  2910. #if DBG
  2911. if (Thread->NodeCount > 0) {
  2912. DbgPrint ("Deadlock verifier: deleting thread %p while holding resources %p \n");
  2913. DbgBreakPoint ();
  2914. }
  2915. #endif
  2916. ViDeadlockDeleteThread (Thread, FALSE);
  2917. }
  2918. }
  2919. }
  2920. ViDeadlockDetectionUnlock(OldIrql);
  2921. }
  2922. VOID
  2923. ViDeadlockDeleteResource (
  2924. PVI_DEADLOCK_RESOURCE Resource,
  2925. BOOLEAN Cleanup
  2926. )
  2927. /*++
  2928. Routine Description:
  2929. This routine deletes a routine and all nodes representing
  2930. acquisitions of that resource.
  2931. Arguments:
  2932. Resource - resource to be deleted
  2933. Cleanup - true if are called from ViDeadlockDetectionCleanup
  2934. Return Value:
  2935. None.
  2936. --*/
  2937. {
  2938. PLIST_ENTRY Current;
  2939. PVI_DEADLOCK_NODE Node;
  2940. ASSERT (Resource != NULL);
  2941. ASSERT (Cleanup || ViDeadlockDatabaseOwner == KeGetCurrentThread());
  2942. //
  2943. // Check if the resource being deleted is still acquired.
  2944. // Note that this might fire if we loose release() operations
  2945. // performed by an unverified driver.
  2946. //
  2947. if (Cleanup == FALSE && Resource->ThreadOwner != NULL) {
  2948. ViDeadlockReportIssue (VI_DEADLOCK_ISSUE_THREAD_HOLDS_RESOURCES,
  2949. (ULONG_PTR) (Resource->ResourceAddress),
  2950. (ULONG_PTR) (Resource->ThreadOwner->Thread),
  2951. (ULONG_PTR) (Resource));
  2952. }
  2953. //
  2954. // If this is a normal delete (not a cleanup) we will collapse all trees
  2955. // containing nodes for this resource. If it is a cleanup we will just
  2956. // wipe out the node.
  2957. //
  2958. Current = Resource->ResourceList.Flink;
  2959. while (Current != &(Resource->ResourceList)) {
  2960. Node = CONTAINING_RECORD (Current,
  2961. VI_DEADLOCK_NODE,
  2962. ResourceList);
  2963. Current = Current->Flink;
  2964. ASSERT (Node->Root == Resource);
  2965. ViDeadlockDeleteNode (Node, Cleanup);
  2966. }
  2967. //
  2968. // There should not be any NODEs for the resource at this moment.
  2969. //
  2970. ASSERT (&(Resource->ResourceList) == Resource->ResourceList.Flink);
  2971. ASSERT (&(Resource->ResourceList) == Resource->ResourceList.Blink);
  2972. //
  2973. // Remote the resource from the hash table and
  2974. // delete the resource structure.
  2975. //
  2976. RemoveEntryList (&(Resource->HashChainList));
  2977. ViDeadlockFree (Resource, ViDeadlockResource);
  2978. }
  2979. VOID
  2980. ViDeadlockTrimResources (
  2981. PLIST_ENTRY HashList
  2982. )
  2983. {
  2984. PLIST_ENTRY Current;
  2985. PVI_DEADLOCK_RESOURCE Resource;
  2986. Current = HashList->Flink;
  2987. while (Current != HashList) {
  2988. Resource = CONTAINING_RECORD (Current,
  2989. VI_DEADLOCK_RESOURCE,
  2990. HashChainList);
  2991. Current = Current->Flink;
  2992. ViDeadlockForgetResourceHistory (Resource,
  2993. ViDeadlockTrimThreshold,
  2994. ViDeadlockAgeWindow);
  2995. }
  2996. }
  2997. VOID
  2998. ViDeadlockForgetResourceHistory (
  2999. PVI_DEADLOCK_RESOURCE Resource,
  3000. ULONG TrimThreshold,
  3001. ULONG AgeThreshold
  3002. )
  3003. /*++
  3004. Routine Description:
  3005. This routine deletes sone of the nodes representing
  3006. acquisitions of that resource. In essence we forget
  3007. part of the history of that resource.
  3008. Arguments:
  3009. Resource - resource for which we wipe out nodes.
  3010. TrimThreshold - how many nodes should remain
  3011. AgeThreshold - nodes older than this will go away
  3012. Return Value:
  3013. None.
  3014. --*/
  3015. {
  3016. PLIST_ENTRY Current;
  3017. PVI_DEADLOCK_NODE Node;
  3018. ULONG NodesTrimmed = 0;
  3019. ULONG SequenceNumber;
  3020. ASSERT (Resource != NULL);
  3021. ASSERT (ViDeadlockDatabaseOwner == KeGetCurrentThread());
  3022. //
  3023. // If resource is owned we cannot do anything,
  3024. //
  3025. if (Resource->ThreadOwner) {
  3026. return;
  3027. }
  3028. //
  3029. // If resource has less than TrimThreshold nodes it is still fine.
  3030. //
  3031. if (Resource->NodeCount < TrimThreshold) {
  3032. return;
  3033. }
  3034. //
  3035. // Delete some nodes of the resource based on ageing.
  3036. //
  3037. SequenceNumber = ViDeadlockGlobals->SequenceNumber;
  3038. Current = Resource->ResourceList.Flink;
  3039. while (Current != &(Resource->ResourceList)) {
  3040. Node = CONTAINING_RECORD (Current,
  3041. VI_DEADLOCK_NODE,
  3042. ResourceList);
  3043. Current = Current->Flink;
  3044. ASSERT (Node->Root == Resource);
  3045. //
  3046. // Special care here because the sequence numbers are 32bits
  3047. // and they can overflow. In an ideal world the global sequence
  3048. // is always greater or equal to the node sequence but if it
  3049. // overwrapped it can be the other way around.
  3050. //
  3051. if (SequenceNumber > Node->SequenceNumber) {
  3052. if (SequenceNumber - Node->SequenceNumber > AgeThreshold) {
  3053. ViDeadlockDeleteNode (Node, FALSE);
  3054. NodesTrimmed += 1;
  3055. }
  3056. }
  3057. else {
  3058. if (SequenceNumber + Node->SequenceNumber > AgeThreshold) {
  3059. ViDeadlockDeleteNode (Node, FALSE);
  3060. NodesTrimmed += 1;
  3061. }
  3062. }
  3063. }
  3064. ViDeadlockGlobals->NodesTrimmedBasedOnAge += NodesTrimmed;
  3065. //
  3066. // If resource has less than TrimThreshold nodes it is fine.
  3067. //
  3068. if (Resource->NodeCount < TrimThreshold) {
  3069. return;
  3070. }
  3071. //
  3072. // If we did not manage to trim the nodes by the age algorithm then
  3073. // we trim everything that we encounter.
  3074. //
  3075. NodesTrimmed = 0;
  3076. Current = Resource->ResourceList.Flink;
  3077. while (Current != &(Resource->ResourceList)) {
  3078. if (Resource->NodeCount < TrimThreshold) {
  3079. break;
  3080. }
  3081. Node = CONTAINING_RECORD (Current,
  3082. VI_DEADLOCK_NODE,
  3083. ResourceList);
  3084. Current = Current->Flink;
  3085. ASSERT (Node->Root == Resource);
  3086. ViDeadlockDeleteNode (Node, FALSE);
  3087. NodesTrimmed += 1;
  3088. }
  3089. ViDeadlockGlobals->NodesTrimmedBasedOnCount += NodesTrimmed;
  3090. }
  3091. VOID
  3092. ViDeadlockDeleteNode (
  3093. PVI_DEADLOCK_NODE Node,
  3094. BOOLEAN Cleanup
  3095. )
  3096. /*++
  3097. Routine Description:
  3098. This routine deletes a node from a graph and collapses the tree,
  3099. that is connects its childrend with its parent.
  3100. If we are during a cleanup we will just delete the node without
  3101. collapsing the tree.
  3102. Arguments:
  3103. Node - node to be deleted.
  3104. Cleanup - true if we are during a total cleanup
  3105. Return Value:
  3106. None.
  3107. --*/
  3108. {
  3109. PLIST_ENTRY Current;
  3110. PVI_DEADLOCK_NODE Child;
  3111. ULONG Children;
  3112. ASSERT (Node);
  3113. //
  3114. // If are during a cleanup just delete the node and return.
  3115. //
  3116. if (Cleanup) {
  3117. RemoveEntryList (&(Node->ResourceList));
  3118. ViDeadlockFree (Node, ViDeadlockNode);
  3119. return;
  3120. }
  3121. //
  3122. // If we are here we need to collapse the tree
  3123. //
  3124. ASSERT (ViDeadlockDatabaseOwner == KeGetCurrentThread());
  3125. if (Node->Parent) {
  3126. //
  3127. // All Node's children must become Parent's children
  3128. //
  3129. Current = Node->ChildrenList.Flink;
  3130. while (Current != &(Node->ChildrenList)) {
  3131. Child = CONTAINING_RECORD (Current,
  3132. VI_DEADLOCK_NODE,
  3133. SiblingsList);
  3134. Current = Current->Flink;
  3135. RemoveEntryList (&(Child->SiblingsList));
  3136. Child->Parent = Node->Parent;
  3137. InsertTailList (&(Node->Parent->ChildrenList),
  3138. &(Child->SiblingsList));
  3139. }
  3140. RemoveEntryList (&(Node->SiblingsList));
  3141. }
  3142. else {
  3143. //
  3144. // All Node's children must become roots of the graph
  3145. //
  3146. Current = Node->ChildrenList.Flink;
  3147. Children = 0;
  3148. Child = NULL;
  3149. while (Current != &(Node->ChildrenList)) {
  3150. Children += 1;
  3151. Child = CONTAINING_RECORD (Current,
  3152. VI_DEADLOCK_NODE,
  3153. SiblingsList);
  3154. Current = Current->Flink;
  3155. RemoveEntryList (&(Child->SiblingsList));
  3156. Child->Parent = NULL;
  3157. Child->SiblingsList.Flink = NULL;
  3158. Child->SiblingsList.Blink = NULL;
  3159. }
  3160. }
  3161. ASSERT (Node->Root);
  3162. ASSERT (Node->Root->NodeCount > 0);
  3163. Node->Root->NodeCount -= 1;
  3164. RemoveEntryList (&(Node->ResourceList));
  3165. ViDeadlockFree (Node, ViDeadlockNode);
  3166. }
  3167. ULONG
  3168. ViDeadlockNodeLevel (
  3169. PVI_DEADLOCK_NODE Node
  3170. )
  3171. /*++
  3172. Routine Description:
  3173. This routine computes the level of a graph node.
  3174. Arguments:
  3175. Node - graph node
  3176. Return Value:
  3177. Level of the node. A root node has level zero.
  3178. --*/
  3179. {
  3180. PVI_DEADLOCK_NODE Current;
  3181. ULONG Level = 0;
  3182. Current = Node->Parent;
  3183. while (Current) {
  3184. Level += 1;
  3185. Current = Current->Parent;
  3186. }
  3187. return Level;
  3188. }
  3189. /////////////////////////////////////////////////////////////////////
  3190. /////////////////////////////////////// Incremental graph compression
  3191. /////////////////////////////////////////////////////////////////////
  3192. //
  3193. // SilviuC: should write a comment about graph compression
  3194. // This is a very smart and tricky algorithm :-)
  3195. //
  3196. VOID
  3197. ViDeadlockCheckDuplicatesAmongChildren (
  3198. PVI_DEADLOCK_NODE Parent,
  3199. PVI_DEADLOCK_NODE Child
  3200. )
  3201. {
  3202. PLIST_ENTRY Current;
  3203. PVI_DEADLOCK_NODE Node;
  3204. LOGICAL FoundOne;
  3205. FoundOne = FALSE;
  3206. Current = Parent->ChildrenList.Flink;
  3207. while (Current != &(Parent->ChildrenList)) {
  3208. Node = CONTAINING_RECORD (Current,
  3209. VI_DEADLOCK_NODE,
  3210. SiblingsList);
  3211. ASSERT (Current->Flink);
  3212. Current = Current->Flink;
  3213. if (ViDeadlockSimilarNodes (Node, Child)) {
  3214. if (FoundOne == FALSE) {
  3215. ASSERT (Node == Child);
  3216. FoundOne = TRUE;
  3217. }
  3218. else {
  3219. ViDeadlockMergeNodes (Child, Node);
  3220. }
  3221. }
  3222. }
  3223. }
  3224. VOID
  3225. ViDeadlockCheckDuplicatesAmongRoots (
  3226. PVI_DEADLOCK_NODE Root
  3227. )
  3228. {
  3229. PLIST_ENTRY Current;
  3230. PVI_DEADLOCK_NODE Node;
  3231. PVI_DEADLOCK_RESOURCE Resource;
  3232. LOGICAL FoundOne;
  3233. FoundOne = FALSE;
  3234. Resource = Root->Root;
  3235. Current = Resource->ResourceList.Flink;
  3236. while (Current != &(Resource->ResourceList)) {
  3237. Node = CONTAINING_RECORD (Current,
  3238. VI_DEADLOCK_NODE,
  3239. ResourceList);
  3240. ASSERT (Current->Flink);
  3241. Current = Current->Flink;
  3242. if (Node->Parent == NULL && ViDeadlockSimilarNodes (Node, Root)) {
  3243. if (FoundOne == FALSE) {
  3244. ASSERT (Node == Root);
  3245. FoundOne = TRUE;
  3246. }
  3247. else {
  3248. ViDeadlockMergeNodes (Root, Node);
  3249. }
  3250. }
  3251. }
  3252. }
  3253. LOGICAL
  3254. ViDeadlockSimilarNodes (
  3255. PVI_DEADLOCK_NODE NodeA,
  3256. PVI_DEADLOCK_NODE NodeB
  3257. )
  3258. {
  3259. if (NodeA->Root == NodeB->Root
  3260. && NodeA->OnlyTryAcquireUsed == NodeB->OnlyTryAcquireUsed) {
  3261. return TRUE;
  3262. }
  3263. else {
  3264. return FALSE;
  3265. }
  3266. }
  3267. VOID
  3268. ViDeadlockMergeNodes (
  3269. PVI_DEADLOCK_NODE NodeTo,
  3270. PVI_DEADLOCK_NODE NodeFrom
  3271. )
  3272. {
  3273. PLIST_ENTRY Current;
  3274. PVI_DEADLOCK_NODE Node;
  3275. //
  3276. // If NodeFrom is currently acquired then copy the same
  3277. // characteristics to NodeTo. Since the locks are exclusive
  3278. // it is impossible to have NodeTo also acquired.
  3279. //
  3280. if (NodeFrom->ThreadEntry) {
  3281. ASSERT (NodeTo->ThreadEntry == NULL);
  3282. NodeTo->ThreadEntry = NodeFrom->ThreadEntry;
  3283. RtlCopyMemory (NodeTo->StackTrace,
  3284. NodeFrom->StackTrace,
  3285. sizeof (NodeTo->StackTrace));
  3286. RtlCopyMemory (NodeTo->ParentStackTrace,
  3287. NodeFrom->ParentStackTrace,
  3288. sizeof (NodeTo->ParentStackTrace));
  3289. }
  3290. if (NodeFrom->Active) {
  3291. ASSERT (NodeTo->Active == 0);
  3292. NodeTo->Active = NodeFrom->Active;
  3293. }
  3294. //
  3295. // Move each child of NodeFrom as a child of NodeTo.
  3296. //
  3297. Current = NodeFrom->ChildrenList.Flink;
  3298. while (Current != &(NodeFrom->ChildrenList)) {
  3299. Node = CONTAINING_RECORD (Current,
  3300. VI_DEADLOCK_NODE,
  3301. SiblingsList);
  3302. ASSERT (Current->Flink);
  3303. Current = Current->Flink;
  3304. RemoveEntryList (&(Node->SiblingsList));
  3305. ASSERT (Node->Parent == NodeFrom);
  3306. Node->Parent = NodeTo;
  3307. InsertTailList (&(NodeTo->ChildrenList),
  3308. &(Node->SiblingsList));
  3309. }
  3310. //
  3311. // NodeFrom is empty. Delete it.
  3312. //
  3313. ASSERT (IsListEmpty(&(NodeFrom->ChildrenList)));
  3314. if (NodeFrom->Parent) {
  3315. RemoveEntryList (&(NodeFrom->SiblingsList));
  3316. }
  3317. NodeFrom->Root->NodeCount -= 1;
  3318. RemoveEntryList (&(NodeFrom->ResourceList));
  3319. ViDeadlockFree (NodeFrom, ViDeadlockNode);
  3320. }
  3321. /////////////////////////////////////////////////////////////////////
  3322. /////////////////////////////////////////////////// ExFreePool() hook
  3323. /////////////////////////////////////////////////////////////////////
  3324. VOID
  3325. VerifierDeadlockFreePool(
  3326. IN PVOID Address,
  3327. IN SIZE_T NumberOfBytes
  3328. )
  3329. /*++
  3330. Routine Description:
  3331. This routine receives notification of all pool manager memory frees.
  3332. Arguments:
  3333. Address - Supplies the virtual address being freed.
  3334. NumberOfBytes - Supplies the number of bytes spanned by the allocation.
  3335. Return Value:
  3336. None.
  3337. Environment:
  3338. This is called at various points either just before or just after the
  3339. allocation has been freed, depending on which is convenient for the pool
  3340. manager (this varies based on type of allocation).
  3341. For special pool or small pool, no pool resources are held on entry and
  3342. the memory still exists and is referencable.
  3343. For non-special pool allocations of PAGE_SIZE or greater, this routine is
  3344. called while the memory still exists and is referencable, BUT the nonpaged
  3345. pool spinlock (or paged pool mutex) is held on entry and so EXTREME care
  3346. must be taken in this routine.
  3347. --*/
  3348. {
  3349. VfDeadlockDeleteMemoryRange (Address, NumberOfBytes);
  3350. }
  3351. /////////////////////////////////////////////////////////////////////
  3352. ////////////////////////////////////////////////// Consistency checks
  3353. /////////////////////////////////////////////////////////////////////
  3354. //
  3355. // Node Resource Thread
  3356. //
  3357. // Root ThreadOwner CurrentNode
  3358. // ThreadEntry RecursionCount NodeCount
  3359. // Active ResourceAddress Thread
  3360. //
  3361. //
  3362. //
  3363. //
  3364. VOID
  3365. ViDeadlockCheckThreadConsistency (
  3366. PVI_DEADLOCK_THREAD Thread,
  3367. BOOLEAN Recursion
  3368. )
  3369. {
  3370. if (Thread->CurrentSpinNode == NULL && Thread->CurrentOtherNode == NULL) {
  3371. ASSERT (Thread->NodeCount == 0);
  3372. return;
  3373. }
  3374. if (Thread->CurrentSpinNode) {
  3375. ASSERT (Thread->NodeCount > 0);
  3376. ASSERT (Thread->CurrentSpinNode->Active);
  3377. if (Recursion == FALSE) {
  3378. ViDeadlockCheckNodeConsistency (Thread->CurrentSpinNode, TRUE);
  3379. ViDeadlockCheckResourceConsistency (Thread->CurrentSpinNode->Root, TRUE);
  3380. }
  3381. }
  3382. if (Thread->CurrentOtherNode) {
  3383. ASSERT (Thread->NodeCount > 0);
  3384. ASSERT (Thread->CurrentOtherNode->Active);
  3385. if (Recursion == FALSE) {
  3386. ViDeadlockCheckNodeConsistency (Thread->CurrentOtherNode, TRUE);
  3387. ViDeadlockCheckResourceConsistency (Thread->CurrentOtherNode->Root, TRUE);
  3388. }
  3389. }
  3390. }
  3391. VOID
  3392. ViDeadlockCheckNodeConsistency (
  3393. PVI_DEADLOCK_NODE Node,
  3394. BOOLEAN Recursion
  3395. )
  3396. {
  3397. if (Node->ThreadEntry) {
  3398. ASSERT (Node->Active == 1);
  3399. if (Recursion == FALSE) {
  3400. ViDeadlockCheckThreadConsistency (Node->ThreadEntry, TRUE);
  3401. ViDeadlockCheckResourceConsistency (Node->Root, TRUE);
  3402. }
  3403. }
  3404. else {
  3405. ASSERT (Node->Active == 0);
  3406. if (Recursion == FALSE) {
  3407. ViDeadlockCheckResourceConsistency (Node->Root, TRUE);
  3408. }
  3409. }
  3410. }
  3411. VOID
  3412. ViDeadlockCheckResourceConsistency (
  3413. PVI_DEADLOCK_RESOURCE Resource,
  3414. BOOLEAN Recursion
  3415. )
  3416. {
  3417. if (Resource->ThreadOwner) {
  3418. ASSERT (Resource->RecursionCount > 0);
  3419. if (Recursion == FALSE) {
  3420. ViDeadlockCheckThreadConsistency (Resource->ThreadOwner, TRUE);
  3421. if (Resource->Type == VfDeadlockSpinLock) {
  3422. ViDeadlockCheckNodeConsistency (Resource->ThreadOwner->CurrentSpinNode, TRUE);
  3423. }
  3424. else {
  3425. ViDeadlockCheckNodeConsistency (Resource->ThreadOwner->CurrentOtherNode, TRUE);
  3426. }
  3427. }
  3428. }
  3429. else {
  3430. ASSERT (Resource->RecursionCount == 0);
  3431. }
  3432. }
  3433. PVI_DEADLOCK_THREAD
  3434. ViDeadlockCheckThreadReferences (
  3435. PVI_DEADLOCK_NODE Node
  3436. )
  3437. /*++
  3438. Routine Description:
  3439. This routine iterates all threads in order to check if `Node' is
  3440. referred in the `CurrentNode' field in any of them.
  3441. Arguments:
  3442. Node - node to search
  3443. Return Value:
  3444. If everything goes ok we should not find the node and the return
  3445. value is null. Otherwise we return the thread referring to the node.
  3446. --*/
  3447. {
  3448. ULONG Index;
  3449. PLIST_ENTRY Current;
  3450. PVI_DEADLOCK_THREAD Thread;
  3451. for (Index = 0; Index < VI_DEADLOCK_HASH_BINS; Index += 1) {
  3452. Current = ViDeadlockGlobals->ThreadDatabase[Index].Flink;
  3453. while (Current != &(ViDeadlockGlobals->ThreadDatabase[Index])) {
  3454. Thread = CONTAINING_RECORD (Current,
  3455. VI_DEADLOCK_THREAD,
  3456. ListEntry);
  3457. if (Thread->CurrentSpinNode == Node) {
  3458. return Thread;
  3459. }
  3460. if (Thread->CurrentOtherNode == Node) {
  3461. return Thread;
  3462. }
  3463. Current = Current->Flink;
  3464. }
  3465. }
  3466. return NULL;
  3467. }
  3468. /////////////////////////////////////////////////////////////////////
  3469. //////////////////////////////////////////// Detect paging code paths
  3470. /////////////////////////////////////////////////////////////////////
  3471. BOOLEAN
  3472. VfDeadlockBeforeCallDriver (
  3473. IN PDEVICE_OBJECT DeviceObject,
  3474. IN OUT PIRP Irp
  3475. )
  3476. /*++
  3477. Routine Description:
  3478. This routine checks if the IRP is a paging I/O IRP. If it is it will
  3479. disable deadlock verification in this thread until the after() function
  3480. is called.
  3481. The function also ignores mounting IRPs. There are drivers that have
  3482. locks inversed in mounting code paths but mounting can never happen
  3483. in parallel with normal access.
  3484. Arguments:
  3485. DeviceObject - same parameter used in IoCallDriver call.
  3486. Irp - IRP passed to the driver as used in IoCallDriver call.
  3487. Return Value:
  3488. True if the Irp parameter is a paging IRP.
  3489. --*/
  3490. {
  3491. KIRQL OldIrql;
  3492. PKTHREAD SystemThread;
  3493. PVI_DEADLOCK_THREAD VerifierThread;
  3494. BOOLEAN PagingIrp = FALSE;
  3495. PVOID ReservedThread = NULL;
  3496. UNREFERENCED_PARAMETER (DeviceObject);
  3497. //
  3498. // Skip if package not initialized
  3499. //
  3500. if (ViDeadlockGlobals == NULL) {
  3501. return FALSE;
  3502. }
  3503. //
  3504. // Skip if package is disabled
  3505. //
  3506. if (! ViDeadlockDetectionEnabled) {
  3507. return FALSE;
  3508. }
  3509. //
  3510. // If it is not a paging I/O IRP or a mounting IRP we do not care.
  3511. //
  3512. if ((Irp->Flags & (IRP_PAGING_IO | IRP_MOUNT_COMPLETION)) == 0) {
  3513. return FALSE;
  3514. }
  3515. //
  3516. // Find the deadlock verifier structure maintained for the current
  3517. // thread. If we do not find one then we will create one. On top of
  3518. // this mount/page IRP there might be locks acquired and we want to
  3519. // skip them too. The only situations where we observed that lock
  3520. // hierarchies are not respected is when at least one lock was acquired
  3521. // before the IoCallDriver() with a paging IRP or no lock acquired before
  3522. // a mount IRP (udfs.sys). For this last case we need to create a thread
  3523. // in which to increase the PageCount counter.
  3524. //
  3525. SystemThread = KeGetCurrentThread ();
  3526. ReservedThread = ViDeadlockAllocate (ViDeadlockThread);
  3527. if (ReservedThread == NULL) {
  3528. return FALSE;
  3529. }
  3530. ViDeadlockDetectionLock (&OldIrql);
  3531. VerifierThread = ViDeadlockSearchThread (SystemThread);
  3532. if (VerifierThread == NULL) {
  3533. VerifierThread = ViDeadlockAddThread (SystemThread,
  3534. ReservedThread);
  3535. ReservedThread = NULL;
  3536. ASSERT (VerifierThread);
  3537. }
  3538. //
  3539. // At this point VerifierThread points to a deadlock verifier
  3540. // thread structure. We need to bump the paging recursion count
  3541. // to mark that one more level of paging I/O is active.
  3542. //
  3543. VerifierThread->PagingCount += 1;
  3544. PagingIrp = TRUE;
  3545. //
  3546. // Unlock the deadlock verifier lock and exit.
  3547. //
  3548. if (ReservedThread) {
  3549. ViDeadlockFree (ReservedThread, ViDeadlockThread);
  3550. }
  3551. ViDeadlockDetectionUnlock (OldIrql);
  3552. return PagingIrp;
  3553. }
  3554. VOID
  3555. VfDeadlockAfterCallDriver (
  3556. IN PDEVICE_OBJECT DeviceObject,
  3557. IN OUT PIRP Irp,
  3558. IN BOOLEAN PagingIrp
  3559. )
  3560. /*++
  3561. Routine Description:
  3562. This routine is called after an IoCallDriver() call returns. It is used
  3563. to undo any state created by the before() function.
  3564. Arguments:
  3565. DeviceObject - same parameter used in IoCallDriver call.
  3566. Irp - IRP passed to the driver as used in IoCallDriver call.
  3567. PagingIrp - true if a previous call to the before() routine returned
  3568. true signalling a paging IRP.
  3569. Return Value:
  3570. None.
  3571. --*/
  3572. {
  3573. KIRQL OldIrql;
  3574. PKTHREAD SystemThread;
  3575. PVI_DEADLOCK_THREAD VerifierThread;
  3576. UNREFERENCED_PARAMETER (DeviceObject);
  3577. UNREFERENCED_PARAMETER (Irp);
  3578. //
  3579. // Skip if package not initialized
  3580. //
  3581. if (ViDeadlockGlobals == NULL) {
  3582. return;
  3583. }
  3584. //
  3585. // Skip if package is disabled
  3586. //
  3587. if (! ViDeadlockDetectionEnabled) {
  3588. return;
  3589. }
  3590. //
  3591. // If it is not a paging I/O IRP we do not care.
  3592. //
  3593. if (! PagingIrp) {
  3594. return;
  3595. }
  3596. //
  3597. // Find the deadlock verifier structure maintained for the current
  3598. // thread. If we do not find one then we will let deadlock verifier
  3599. // do its job. The only situations where we observed that lock
  3600. // hierarchies are not respected is when at least one lock was acquired
  3601. // before the IoCallDriver() with a paging IRP.
  3602. //
  3603. SystemThread = KeGetCurrentThread ();
  3604. ViDeadlockDetectionLock (&OldIrql);
  3605. VerifierThread = ViDeadlockSearchThread (SystemThread);
  3606. if (VerifierThread == NULL) {
  3607. goto Exit;
  3608. }
  3609. //
  3610. // At this point VerifierThread points to a deadlock verifier
  3611. // thread structure. We need to bump the paging recursion count
  3612. // to mark that one more level of paging I/O is active.
  3613. //
  3614. ASSERT (VerifierThread->PagingCount > 0);
  3615. VerifierThread->PagingCount -= 1;
  3616. //
  3617. // Unlock the deadlock verifier lock and exit.
  3618. //
  3619. Exit:
  3620. ViDeadlockDetectionUnlock (OldIrql);
  3621. }
  3622. BOOLEAN
  3623. ViIsThreadInsidePagingCodePaths (
  3624. )
  3625. /*++
  3626. Routine Description:
  3627. This routine checks if current thread is inside paging code paths.
  3628. Arguments:
  3629. None.
  3630. Return Value:
  3631. None.
  3632. --*/
  3633. {
  3634. KIRQL OldIrql;
  3635. PKTHREAD SystemThread;
  3636. PVI_DEADLOCK_THREAD VerifierThread;
  3637. BOOLEAN Paging = FALSE;
  3638. SystemThread = KeGetCurrentThread ();
  3639. ViDeadlockDetectionLock (&OldIrql);
  3640. VerifierThread = ViDeadlockSearchThread (SystemThread);
  3641. if (VerifierThread && VerifierThread->PagingCount > 0) {
  3642. Paging = TRUE;
  3643. }
  3644. ViDeadlockDetectionUnlock (OldIrql);
  3645. return Paging;
  3646. }
  3647. VOID
  3648. ViDeadlockCheckStackLimits (
  3649. )
  3650. /*++
  3651. Routine Description:
  3652. This function checks that the current stack is a thread stack
  3653. or a DPC stack. This will catch drivers that switch their stacks.
  3654. --*/
  3655. {
  3656. #if defined(_X86_)
  3657. ULONG_PTR StartStack;
  3658. ULONG_PTR EndStack;
  3659. ULONG_PTR HintAddress;
  3660. _asm mov HintAddress, EBP;
  3661. if (KeGetCurrentIrql() > DISPATCH_LEVEL) {
  3662. return;
  3663. }
  3664. StartStack = (ULONG_PTR)(KeGetCurrentThread()->StackLimit);
  3665. EndStack = (ULONG_PTR)(KeGetCurrentThread()->StackBase);
  3666. if (StartStack <= HintAddress && HintAddress <= EndStack) {
  3667. return;
  3668. }
  3669. EndStack = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
  3670. StartStack = EndStack - KERNEL_STACK_SIZE;
  3671. if (EndStack && StartStack <= HintAddress && HintAddress <= EndStack) {
  3672. return;
  3673. }
  3674. KeBugCheckEx (DRIVER_VERIFIER_DETECTED_VIOLATION,
  3675. 0x90,
  3676. (ULONG_PTR)(KeGetPcr()->Prcb),
  3677. 0,
  3678. 0);
  3679. #else
  3680. return;
  3681. #endif
  3682. }