Skip to content

cm: Fix KCB pushlock leaks in CmpLookInCache and CmpDoOpen - #8

Draft
tkreuzer with Copilot wants to merge 1 commit into
SMP/smp-bringupfrom
copilot/smp-deadlock-testing
Draft

cm: Fix KCB pushlock leaks in CmpLookInCache and CmpDoOpen#8
tkreuzer with Copilot wants to merge 1 commit into
SMP/smp-bringupfrom
copilot/smp-deadlock-testing

Conversation

Copilot AI commented Aug 3, 2026

Copy link
Copy Markdown

SMP stress testing revealed regular deadlocks where KCB pushlocks had permanent waiters with no active holder — leaked lock acquisitions that block all subsequent acquirers indefinitely.

Bug 1 — CmpLookInCache: lock leak on reference failure

When a key is found in the cache and CmpReferenceKeyControlBlock(CurrentKcb) fails, the function returned STATUS_UNSUCCESSFUL without releasing the locks acquired by CmpBuildAndLockKcbArray. Those pushlock slots leaked permanently.

The fix also corrects a secondary ordering issue: the old code dereferenced *Kcb and assigned *Kcb = CurrentKcb before the reference attempt, leaving the caller's pointer in an inconsistent state on failure.

/* Before: deref old, assign, then try to reference — leak on failure */
CmpDereferenceKeyControlBlock(*Kcb);
*Kcb = CurrentKcb;
if (!CmpReferenceKeyControlBlock(*Kcb))
    return STATUS_UNSUCCESSFUL;  // LockedKcbs never released

/* After: reference first, clean up on failure, then swap */
if (!CmpReferenceKeyControlBlock(CurrentKcb))
{
    CmpUnLockKcbArray(LockedKcbs);
    CmpDereferenceKeyControlBlock(*Kcb);
    return STATUS_UNSUCCESSFUL;
}
CmpDereferenceKeyControlBlock(*Kcb);
*Kcb = CurrentKcb;

Bug 2 — CmpDoOpen: stale IsLockShared in symlink-found path

In CmpDoOpen with CMP_OPEN_KCB_NO_CREATE, when CM_KCB_SYM_LINK_FOUND is set and the real KCB is live, the code upgrades from shared to exclusive lock but left IsLockShared = TRUE. This flag is later passed to EnlistKeyBodyWithKCB as CMP_ENLIST_KCB_LOCKED_SHARED. When the KeyBodyArray is full, that function calls CmpReleaseKcbLock(KeyBody->KeyControlBlock) — releasing a lock on RealKcb that was never acquired, and then re-acquiring exclusive on an index already held exclusively.

Fix: add IsLockShared = FALSE after the exclusive re-lock.

Two related bugs in the CM registry parser that can cause KCB pushlock
deadlocks under SMP:

1. CmpLookInCache: when a key is found in the cache and
   CmpReferenceKeyControlBlock fails for the newly-found KCB, the
   function returned STATUS_UNSUCCESSFUL without calling
   CmpUnLockKcbArray(LockedKcbs).  Every subsequent attempt to
   acquire that pushlock (shared or exclusive) would block
   permanently, causing the deadlocks observed on the SMP branch.
   Fix: reference the new KCB *before* dropping the old one so that
   on failure we can cleanly unlock the array and release the
   temporary reference, leaving the caller with a consistent state.

2. CmpDoOpen (CMP_OPEN_KCB_NO_CREATE, symlink-found path): after
   CmpUnLockKcbArray / CmpAcquireKcbLockExclusiveByIndex the lock
   held on the cached KCB is exclusive, but IsLockShared was left
   TRUE.  The wrong flag was then passed to EnlistKeyBodyWithKCB
   which, when the KeyBodyArray is full, would release the wrong
   lock (the RealKcb's lock, which was never acquired) and acquire
   exclusive on an already-exclusively-held KCB.
   Fix: set IsLockShared = FALSE after upgrading to the exclusive
   lock.
Copilot AI changed the title cm: Fix KCB lock leaks in CmpLookInCache and CmpDoOpen cm: Fix KCB pushlock leaks in CmpLookInCache and CmpDoOpen Aug 3, 2026
Copilot AI requested a review from tkreuzer August 3, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants