Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

813 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vfirpdb.c
  5. Abstract:
  6. This module contains functions used to manage the database of IRP tracking
  7. data.
  8. Author:
  9. Adrian J. Oney (adriao) 20-Apr-1998
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. AdriaO 05/02/2000 - Seperated out from ntos\io\hashirp.c
  14. --*/
  15. #include "vfdef.h"
  16. #include "viirpdb.h"
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(INIT, VfIrpDatabaseInit)
  19. #pragma alloc_text(PAGEVRFY, ViIrpDatabaseFindPointer)
  20. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryInsertAndLock)
  21. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryFindAndLock)
  22. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryAcquireLock)
  23. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryReleaseLock)
  24. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryReference)
  25. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryDereference)
  26. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryAppendToChain)
  27. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryRemoveFromChain)
  28. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryGetChainPrevious)
  29. #pragma alloc_text(PAGEVRFY, VfIrpDatabaseEntryGetChainNext)
  30. #pragma alloc_text(PAGEVRFY, ViIrpDatabaseEntryDestroy)
  31. #endif
  32. #define POOL_TAG_IRP_DATABASE 'tToI'
  33. //
  34. // This is our IRP tracking table, a hash table that points to a block of
  35. // data associated with each IRP.
  36. //
  37. PLIST_ENTRY ViIrpDatabase;
  38. KSPIN_LOCK ViIrpDatabaseLock;
  39. /*
  40. * The routines listed below -
  41. * VfIrpDatabaseInit
  42. * VfIrpDatabaseEntryInsertAndLock
  43. * VfIrpDatabaseEntryFindAndLock
  44. * VfIrpDatabaseAcquireLock
  45. * VfIrpDatabaseReleaseLock
  46. * VfIrpDatabaseReference
  47. * VfIrpDatabaseDereference
  48. * VfIrpDatabaseEntryAppendToChain
  49. * VfIrpDatabaseEntryRemoveFromChain
  50. * VfIrpDatabaseEntryGetChainPrevious
  51. * VfIrpDatabaseEntryGetChainNext
  52. * ViIrpDatabaseFindPointer - (internal)
  53. * ViIrpDatabaseEntryDestroy - (internal)
  54. *
  55. * - store and retrieve IRP tracking information from the IRP database. Users
  56. * of the database pass around IOV_DATABASE_HEADER's which are usually part of
  57. * a larger structure. We use a hash table setup to quickly find the IRPs in
  58. * our table.
  59. *
  60. * Each entry in the table has a pointer count and a reference count. The
  61. * pointer count expresses the number of reasons the IRP should be located by
  62. * address. For instance, when an IRP is freed or recycled the pointer count
  63. * would go to zero. The reference count is greater or equal to the pointer
  64. * count, and expresses the number of reasons to keep the data structure around.
  65. * It is fairly common for a database entry to lose it's "pointer" but have a
  66. * non-zero reference count during which time thread stacks may be unwinding.
  67. *
  68. * Another aspect of the IRP database is it supports the "chaining" of
  69. * entries together. Locking an entry automatically locks all entries back to
  70. * the head of the chain. Entries can only be added or removed from the end of
  71. * the chain. This feature is used to support "surrogate" IRPs, where a new
  72. * IRP is sent in place of the IRP originally delivered to a new stack.
  73. *
  74. * Locking semantics:
  75. * There are two locks involved when dealing with IRP database entries, the
  76. * global database lock and the per-entry header lock. No IRP may be removed
  77. * from or inserted into the table without the DatabaseLock being taken. The
  78. * database lock must also be held when the IRP pointer is zeroed due to a newly
  79. * zeroed pointer count. The reference count must be manipulated using
  80. * interlocked operators, as it is may be modified when either lock is held.
  81. * The pointer count on the other hand is only modified with the header lock
  82. * held, and as such does not require interlocked ops.
  83. *
  84. * Perf - The database lock should be replaced with an array of
  85. * VI_DATABASE_HASH_SIZE database locks with little cost.
  86. */
  87. VOID
  88. FASTCALL
  89. VfIrpDatabaseInit(
  90. VOID
  91. )
  92. /*++
  93. Description:
  94. This routine initializes all the important structures we use to track
  95. IRPs through the hash tables.
  96. Arguments:
  97. None
  98. Return Value:
  99. None
  100. --*/
  101. {
  102. ULONG i;
  103. PAGED_CODE();
  104. KeInitializeSpinLock(&ViIrpDatabaseLock);
  105. //
  106. // As this is system startup code, it is one of the very few places where
  107. // it's ok to use MustSucceed.
  108. //
  109. ViIrpDatabase = (PLIST_ENTRY) ExAllocatePoolWithTag(
  110. NonPagedPoolMustSucceed,
  111. VI_DATABASE_HASH_SIZE * sizeof(LIST_ENTRY),
  112. POOL_TAG_IRP_DATABASE
  113. );
  114. for(i=0; i < VI_DATABASE_HASH_SIZE; i++) {
  115. InitializeListHead(ViIrpDatabase+i);
  116. }
  117. }
  118. PIOV_DATABASE_HEADER
  119. FASTCALL
  120. ViIrpDatabaseFindPointer(
  121. IN PIRP Irp,
  122. OUT PLIST_ENTRY *HashHead
  123. )
  124. /*++
  125. Description:
  126. This routine returns a pointer to a pointer to the Irp tracking data.
  127. This function is meant to be called by other routines in this file.
  128. N.B. The tracking lock is assumed to be held by the caller.
  129. Arguments:
  130. Irp - Irp to locate in the tracking table.
  131. HashHead - If return is non-null, points to the
  132. list head that should be used to insert
  133. the IRP.
  134. Return Value:
  135. IovHeader iff found, NULL otherwise.
  136. --*/
  137. {
  138. PIOV_DATABASE_HEADER iovHeader;
  139. PLIST_ENTRY listEntry, listHead;
  140. UINT_PTR hashIndex;
  141. hashIndex = VI_DATABASE_CALCULATE_HASH(Irp);
  142. ASSERT_SPINLOCK_HELD(&ViIrpDatabaseLock);
  143. *HashHead = listHead = ViIrpDatabase + hashIndex;
  144. for(listEntry = listHead;
  145. listEntry->Flink != listHead;
  146. listEntry = listEntry->Flink) {
  147. iovHeader = CONTAINING_RECORD(listEntry->Flink, IOV_DATABASE_HEADER, HashLink);
  148. if (iovHeader->TrackedIrp == Irp) {
  149. return iovHeader;
  150. }
  151. }
  152. return NULL;
  153. }
  154. BOOLEAN
  155. FASTCALL
  156. VfIrpDatabaseEntryInsertAndLock(
  157. IN PIRP Irp,
  158. IN PFN_IRPDBEVENT_CALLBACK NotificationCallback,
  159. IN OUT PIOV_DATABASE_HEADER IovHeader
  160. )
  161. /*++
  162. Description:
  163. This routine inserts an IovHeader that is associated with the Irp into the
  164. IRP database table. The IRP does not get an initial reference count however.
  165. VfIrpDatabaseEntryReleaseLock must be called to drop the lock taken out.
  166. Arguments:
  167. Irp - Irp to begin tracking.
  168. NotificationCallback - Callback function to invoke for various database
  169. events.
  170. IovHeader - Points to an IovHeader to insert. The IovHeader
  171. fields will be properly initialized by this function.
  172. Return Value:
  173. TRUE if successful, FALSE if driver error detected. On error the passed in
  174. header will have been freed.
  175. --*/
  176. {
  177. KIRQL oldIrql;
  178. PIOV_DATABASE_HEADER iovHeaderPointer;
  179. PLIST_ENTRY hashHead;
  180. ExAcquireSpinLock(&ViIrpDatabaseLock, &oldIrql);
  181. iovHeaderPointer = ViIrpDatabaseFindPointer(Irp, &hashHead);
  182. ASSERT(iovHeaderPointer == NULL);
  183. if (iovHeaderPointer) {
  184. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  185. return FALSE;
  186. }
  187. //
  188. // From top to bottom, initialize the fields. Note that there is not a
  189. // "surrogateHead". If any code needs to find out the first entry in the
  190. // circularly linked list of IRPs (the first is the only non-surrogate IRP),
  191. // then HeadPacket should be used. Note that the link to the session is
  192. // stored by the headPacket, more on this later.
  193. //
  194. IovHeader->TrackedIrp = Irp;
  195. KeInitializeSpinLock(&IovHeader->HeaderLock);
  196. IovHeader->ReferenceCount = 1;
  197. IovHeader->PointerCount = 1;
  198. IovHeader->HeaderFlags = 0;
  199. InitializeListHead(&IovHeader->HashLink);
  200. InitializeListHead(&IovHeader->ChainLink);
  201. IovHeader->ChainHead = IovHeader;
  202. IovHeader->NotificationCallback = NotificationCallback;
  203. //
  204. // Place into hash table under lock (with the initial reference count)
  205. //
  206. InsertHeadList(hashHead, &IovHeader->HashLink);
  207. VERIFIER_DBGPRINT((
  208. " VRP CREATE(%x)->%x\n",
  209. Irp,
  210. IovHeader
  211. ), 3);
  212. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  213. iovHeaderPointer = VfIrpDatabaseEntryFindAndLock(Irp);
  214. ASSERT(iovHeaderPointer == IovHeader);
  215. if (iovHeaderPointer == NULL) {
  216. return FALSE;
  217. } else if (iovHeaderPointer != IovHeader) {
  218. VfIrpDatabaseEntryReleaseLock(iovHeaderPointer);
  219. return FALSE;
  220. }
  221. InterlockedDecrement(&IovHeader->ReferenceCount);
  222. IovHeader->PointerCount--;
  223. ASSERT(IovHeader->PointerCount == 0);
  224. return TRUE;
  225. }
  226. PIOV_DATABASE_HEADER
  227. FASTCALL
  228. VfIrpDatabaseEntryFindAndLock(
  229. IN PIRP Irp
  230. )
  231. /*++
  232. Description:
  233. This routine will return the tracking data for an IRP that is
  234. being tracked without a surrogate or the tracking data for with
  235. a surrogate if the surrogate IRP is what was passed in.
  236. Arguments:
  237. Irp - Irp to find.
  238. Return Value:
  239. IovHeader block, iff above conditions are satified.
  240. --*/
  241. {
  242. KIRQL oldIrql;
  243. PIOV_DATABASE_HEADER iovHeader;
  244. PLIST_ENTRY listHead;
  245. ASSERT(Irp);
  246. ExAcquireSpinLock(&ViIrpDatabaseLock, &oldIrql);
  247. iovHeader = ViIrpDatabaseFindPointer(Irp, &listHead);
  248. if (!iovHeader) {
  249. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  250. return NULL;
  251. }
  252. InterlockedIncrement(&iovHeader->ReferenceCount);
  253. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  254. VfIrpDatabaseEntryAcquireLock(iovHeader);
  255. iovHeader->LockIrql = oldIrql;
  256. InterlockedDecrement(&iovHeader->ReferenceCount);
  257. //
  258. // Here we check the PointerCount field under the header lock. This might
  259. // be zero if the another thread just unlocked the entry after decrementing
  260. // the pointer count all the way to zero.
  261. //
  262. if (iovHeader->PointerCount == 0) {
  263. //
  264. // This might happen in the following manner:
  265. // 1) IoInitializeIrp is called on an allocated block of pool
  266. // 2) The IRP is first seen by the verifier in IoCallDriver
  267. // 3) The IRP completes, disappearing from the verifier's view
  268. // 4) At that exact moment, the driver calls IoCancelIrp
  269. // The above sequence can occur in a safetly coded driver if the memory
  270. // backing the IRP isn't freed until some event fired. Ie...
  271. // ExAllocatePool
  272. // IoInitializeIrp
  273. // IoCallDriver
  274. // IoCompleteRequest
  275. // IoCancelIrp*
  276. // KeWaitForSingleObject
  277. // ExFreePool
  278. //
  279. //ASSERT(0);
  280. VfIrpDatabaseEntryReleaseLock(iovHeader);
  281. return NULL;
  282. }
  283. VERIFIER_DBGPRINT((
  284. " VRP FIND(%x)->%x\n",
  285. Irp,
  286. iovHeader
  287. ), 3);
  288. return iovHeader;
  289. }
  290. VOID
  291. FASTCALL
  292. VfIrpDatabaseEntryAcquireLock(
  293. IN PIOV_DATABASE_HEADER IovHeader OPTIONAL
  294. )
  295. /*++
  296. Description:
  297. This routine is called by to acquire the IRPs tracking data lock.
  298. This function returns at DISPATCH_LEVEL. Callers *must* follow up with
  299. VfIrpDatabaseEntryReleaseLock.
  300. Arguments:
  301. IovHeader - Pointer to the IRP tracking data (or NULL, in which
  302. case this routine does nothing).
  303. Return Value:
  304. None.
  305. --*/
  306. {
  307. KIRQL oldIrql;
  308. PIOV_DATABASE_HEADER iovCurHeader;
  309. if (!IovHeader) {
  310. return;
  311. }
  312. iovCurHeader = IovHeader;
  313. ASSERT(iovCurHeader->ReferenceCount != 0);
  314. while(1) {
  315. ExAcquireSpinLock(&iovCurHeader->HeaderLock, &oldIrql);
  316. iovCurHeader->LockIrql = oldIrql;
  317. if (iovCurHeader == iovCurHeader->ChainHead) {
  318. break;
  319. }
  320. iovCurHeader = CONTAINING_RECORD(
  321. iovCurHeader->ChainLink.Blink,
  322. IOV_DATABASE_HEADER,
  323. ChainLink
  324. );
  325. }
  326. }
  327. VOID
  328. FASTCALL
  329. VfIrpDatabaseEntryReleaseLock(
  330. IN PIOV_DATABASE_HEADER IovHeader
  331. )
  332. /*++
  333. Description:
  334. This routine releases the IRPs tracking data lock and adjusts the ref count
  335. as appropriate. If the reference count drops to zero, the tracking data is
  336. freed.
  337. Arguments:
  338. IovHeader - Pointer to the IRP tracking data.
  339. Return Value:
  340. Nothing.
  341. --*/
  342. {
  343. BOOLEAN freeTrackingData;
  344. PIOV_DATABASE_HEADER iovCurHeader, iovChainHead, iovNextHeader;
  345. KIRQL oldIrql;
  346. //
  347. // Pass one, delink anyone from the tree who's leaving, and assert that
  348. // no surrogates are left after a freed one.
  349. //
  350. iovCurHeader = iovChainHead = IovHeader->ChainHead;
  351. while(1) {
  352. ASSERT_SPINLOCK_HELD(&iovCurHeader->HeaderLock);
  353. iovNextHeader = CONTAINING_RECORD(
  354. iovCurHeader->ChainLink.Flink,
  355. IOV_DATABASE_HEADER,
  356. ChainLink
  357. );
  358. //
  359. // PointerCount is always referenced under the header lock.
  360. //
  361. if (iovCurHeader->PointerCount == 0) {
  362. ExAcquireSpinLock(&ViIrpDatabaseLock, &oldIrql);
  363. //
  364. // This field may be examined only under the database lock.
  365. //
  366. if (iovCurHeader->TrackedIrp) {
  367. iovCurHeader->NotificationCallback(
  368. iovCurHeader,
  369. iovCurHeader->TrackedIrp,
  370. IRPDBEVENT_POINTER_COUNT_ZERO
  371. );
  372. iovCurHeader->TrackedIrp = NULL;
  373. }
  374. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  375. }
  376. //
  377. // We now remove any entries that will be leaving from the hash table.
  378. // Note that the ReferenceCount may be incremented outside the header
  379. // lock (but under the database lock) but ReferenceCount can never be
  380. // dropped outside of the IRP lock. Therefore for performance we check
  381. // once and then take the lock to prevent anyone finding it and
  382. // incrementing it.
  383. //
  384. if (iovCurHeader->ReferenceCount == 0) {
  385. ExAcquireSpinLock(&ViIrpDatabaseLock, &oldIrql);
  386. if (iovCurHeader->ReferenceCount == 0) {
  387. ASSERT(iovCurHeader->PointerCount == 0);
  388. /*
  389. ASSERT((iovCurHeader->pIovSessionData == NULL) ||
  390. (iovCurHeader != iovChainHead));
  391. */
  392. ASSERT((iovNextHeader->ReferenceCount == 0) ||
  393. (iovNextHeader == iovChainHead));
  394. RemoveEntryList(&iovCurHeader->HashLink);
  395. InitializeListHead(&iovCurHeader->HashLink);
  396. }
  397. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  398. }
  399. if (iovCurHeader == IovHeader) {
  400. break;
  401. }
  402. iovCurHeader = iovNextHeader;
  403. }
  404. //
  405. // Pass two, drop locks and free neccessary data.
  406. //
  407. iovCurHeader = iovChainHead;
  408. while(1) {
  409. freeTrackingData = (BOOLEAN)IsListEmpty(&iovCurHeader->HashLink);
  410. iovNextHeader = CONTAINING_RECORD(
  411. iovCurHeader->ChainLink.Flink,
  412. IOV_DATABASE_HEADER,
  413. ChainLink
  414. );
  415. ExReleaseSpinLock(&iovCurHeader->HeaderLock, iovCurHeader->LockIrql);
  416. if (freeTrackingData) {
  417. ASSERT(IsListEmpty(&iovCurHeader->ChainLink));
  418. ViIrpDatabaseEntryDestroy(iovCurHeader);
  419. iovCurHeader->NotificationCallback(
  420. iovCurHeader,
  421. iovCurHeader->TrackedIrp,
  422. IRPDBEVENT_REFERENCE_COUNT_ZERO
  423. );
  424. }
  425. if (iovCurHeader == IovHeader) {
  426. break;
  427. }
  428. iovCurHeader = iovNextHeader;
  429. }
  430. }
  431. VOID
  432. FASTCALL
  433. VfIrpDatabaseEntryReference(
  434. IN PIOV_DATABASE_HEADER IovHeader,
  435. IN IOV_REFERENCE_TYPE IovRefType
  436. )
  437. {
  438. ASSERT_SPINLOCK_HELD(&IovHeader->HeaderLock);
  439. VERIFIER_DBGPRINT((
  440. " VRP REF(%x) %x++\n",
  441. IovHeader,
  442. IovHeader->ReferenceCount
  443. ), 3);
  444. InterlockedIncrement(&IovHeader->ReferenceCount);
  445. if (IovRefType == IOVREFTYPE_POINTER) {
  446. VERIFIER_DBGPRINT((
  447. " VRP REF2(%x) %x++\n",
  448. IovHeader,
  449. IovHeader->PointerCount
  450. ), 3);
  451. IovHeader->PointerCount++;
  452. }
  453. }
  454. VOID
  455. FASTCALL
  456. VfIrpDatabaseEntryDereference(
  457. IN PIOV_DATABASE_HEADER IovHeader,
  458. IN IOV_REFERENCE_TYPE IovRefType
  459. )
  460. {
  461. KIRQL oldIrql;
  462. ASSERT_SPINLOCK_HELD(&IovHeader->HeaderLock);
  463. ASSERT(IovHeader->ReferenceCount > 0);
  464. VERIFIER_DBGPRINT((
  465. " VRP DEREF(%x) %x--\n",
  466. IovHeader,
  467. IovHeader->ReferenceCount
  468. ), 3);
  469. if (IovRefType == IOVREFTYPE_POINTER) {
  470. ASSERT(IovHeader->PointerCount > 0);
  471. VERIFIER_DBGPRINT((
  472. " VRP DEREF2(%x) %x--\n",
  473. IovHeader,
  474. IovHeader->PointerCount
  475. ), 3);
  476. IovHeader->PointerCount--;
  477. if (IovHeader->PointerCount == 0) {
  478. ExAcquireSpinLock(&ViIrpDatabaseLock, &oldIrql);
  479. IovHeader->NotificationCallback(
  480. IovHeader,
  481. IovHeader->TrackedIrp,
  482. IRPDBEVENT_POINTER_COUNT_ZERO
  483. );
  484. IovHeader->TrackedIrp = NULL;
  485. ExReleaseSpinLock(&ViIrpDatabaseLock, oldIrql);
  486. }
  487. }
  488. InterlockedDecrement(&IovHeader->ReferenceCount);
  489. ASSERT(IovHeader->ReferenceCount >= IovHeader->PointerCount);
  490. }
  491. VOID
  492. FASTCALL
  493. VfIrpDatabaseEntryAppendToChain(
  494. IN OUT PIOV_DATABASE_HEADER IovExistingHeader,
  495. IN OUT PIOV_DATABASE_HEADER IovNewHeader
  496. )
  497. {
  498. ASSERT_SPINLOCK_HELD(&IovExistingHeader->HeaderLock);
  499. ASSERT_SPINLOCK_HELD(&IovNewHeader->HeaderLock);
  500. IovNewHeader->ChainHead = IovExistingHeader->ChainHead;
  501. //
  502. // Fix up IRQL's so spinlocks are released in the right order. Link'm.
  503. //
  504. IovNewHeader->LockIrql = IovExistingHeader->LockIrql;
  505. IovExistingHeader->LockIrql = DISPATCH_LEVEL;
  506. //
  507. // Insert this entry into the chain list
  508. //
  509. InsertTailList(
  510. &IovExistingHeader->ChainHead->ChainLink,
  511. &IovNewHeader->ChainLink
  512. );
  513. }
  514. VOID
  515. FASTCALL
  516. VfIrpDatabaseEntryRemoveFromChain(
  517. IN OUT PIOV_DATABASE_HEADER IovHeader
  518. )
  519. {
  520. PIOV_DATABASE_HEADER iovNextHeader;
  521. ASSERT_SPINLOCK_HELD(&IovHeader->HeaderLock);
  522. //
  523. // It is not legal to remove an entry unless it is at the end of the chain.
  524. // This is illegal because the following entries might not be locked down,
  525. // and the ChainLink must be protected.
  526. //
  527. iovNextHeader = CONTAINING_RECORD(
  528. IovHeader->ChainLink.Flink,
  529. IOV_DATABASE_HEADER,
  530. ChainLink
  531. );
  532. ASSERT(iovNextHeader == IovHeader->ChainHead);
  533. RemoveEntryList(&IovHeader->ChainLink);
  534. InitializeListHead(&IovHeader->ChainLink);
  535. IovHeader->ChainHead = IovHeader;
  536. }
  537. PIOV_DATABASE_HEADER
  538. FASTCALL
  539. VfIrpDatabaseEntryGetChainPrevious(
  540. IN PIOV_DATABASE_HEADER IovHeader
  541. )
  542. {
  543. PIOV_DATABASE_HEADER iovPrevHeader;
  544. ASSERT_SPINLOCK_HELD(&IovHeader->HeaderLock);
  545. if (IovHeader == IovHeader->ChainHead) {
  546. return NULL;
  547. }
  548. iovPrevHeader = CONTAINING_RECORD(
  549. IovHeader->ChainLink.Blink,
  550. IOV_DATABASE_HEADER,
  551. ChainLink
  552. );
  553. return iovPrevHeader;
  554. }
  555. PIOV_DATABASE_HEADER
  556. FASTCALL
  557. VfIrpDatabaseEntryGetChainNext(
  558. IN PIOV_DATABASE_HEADER IovHeader
  559. )
  560. {
  561. PIOV_DATABASE_HEADER iovNextHeader;
  562. ASSERT_SPINLOCK_HELD(&IovHeader->HeaderLock);
  563. iovNextHeader = CONTAINING_RECORD(
  564. IovHeader->ChainLink.Flink,
  565. IOV_DATABASE_HEADER,
  566. ChainLink
  567. );
  568. return (iovNextHeader == IovHeader->ChainHead) ? NULL : iovNextHeader;
  569. }
  570. VOID
  571. FASTCALL
  572. ViIrpDatabaseEntryDestroy(
  573. IN OUT PIOV_DATABASE_HEADER IovHeader
  574. )
  575. /*++
  576. Description:
  577. This routine marks an IovHeader as dead. The header should already have been
  578. removed from the table by a call to VfIrpDatabaseEntryReleaseLock with the
  579. ReferenceCount at 0. This routine is solely here for debugging purposes.
  580. Arguments:
  581. IovHeader - Header to mark dead.
  582. Return Value:
  583. Nope.
  584. --*/
  585. {
  586. //
  587. // The list entry is inited to point back to itself when removed. The
  588. // pointer count should of course still be zero.
  589. //
  590. IovHeader->HeaderFlags |= IOVHEADERFLAG_REMOVED_FROM_TABLE;
  591. ASSERT(IsListEmpty(&IovHeader->HashLink));
  592. //
  593. // with no reference counts...
  594. //
  595. ASSERT(!IovHeader->ReferenceCount);
  596. ASSERT(!IovHeader->PointerCount);
  597. VERIFIER_DBGPRINT((
  598. " VRP FREE(%x)x\n",
  599. IovHeader
  600. ), 3);
  601. }