Lately I've been reading the lock_manager (kern_lock.c) code, and bumped into some scenario which I think would create a race-condition.
Step 1:
@undo_shreq(...): if there is an upgrade request pending, the code will reset "LKC_UPREQ" flag and do the wakeup() call; this thing happen only if
(count & (LKC_EXREQ | LKC_UPREQ | LKC_CANCEL)) &&
(count & (LKC_SMASK | LKC_XMASK)) == 0)
Step 2:
Now, in-parallel, an another thread T2 is trying to get an exclusive lock and it reaches the trivial condition (i.e) @lockmgr_exclusive(...)
if ((count & (LKC_UPREQ | LKC_EXREQ |
LKC_XMASK)) == 0 &&
((count & LKC_SHARED) == 0 ||
(count & LKC_SMASK) == 0))
So, T2 increases the count by 1 and set itself as the owner thread-- meaning it got the exclusiveness.
Step 3:
A thread (T1) slept on a LKC_UPREQ flag woke by Step 1; and here is the code after sleep (....after, LK_SLEEPFAIL and sleep-error sanity check), @lockmgr_upgrade(...)
if ((count & LKC_UPREQ) == 0) { // reset by step 1
KKASSERT((count & LKC_XMASK) == 1); // true, by step 2
lkp->lk_lockholder = td;
break;
}
I see (please correct me if am wrong), at step 3 that, thread T1 resets the lk_lockholder to itself-- meaning, it got the exclusiveness!