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

5245 lines
138 KiB

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