Skip to content

Commit

Permalink
locks: add a runtime check for missing turnstile
Browse files Browse the repository at this point in the history
There are sometimes bugs which result in the unlock fast path failing,
which in turns causes a not-helpful crash report when dereferencing a
NULL turnstile. Help debugging such cases by pointing out what happened
along with some debug.

Sponsored by:	Rubicon Communications, LLC ("Netgate")
  • Loading branch information
mjguzik committed Jul 11, 2024
1 parent af84665 commit 87ee63b
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 5 deletions.
4 changes: 3 additions & 1 deletion sys/kern/kern_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,9 @@ __mtx_unlock_sleep(volatile uintptr_t *c, uintptr_t v)
turnstile_chain_lock(&m->lock_object);
_mtx_release_lock_quick(m);
ts = turnstile_lookup(&m->lock_object);
MPASS(ts != NULL);
if (__predict_false(ts == NULL)) {
panic("got NULL turnstile on mutex %p v %zx", m, v);
}
if (LOCK_LOG_TEST(&m->lock_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m);
turnstile_broadcast(ts, TS_EXCLUSIVE_QUEUE);
Expand Down
16 changes: 12 additions & 4 deletions sys/kern/kern_rwlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,11 +770,12 @@ __rw_runlock_hard(struct rwlock *rw, struct thread *td, uintptr_t v
LOCK_FILE_LINE_ARG_DEF)
{
struct turnstile *ts;
uintptr_t setv, queue;
uintptr_t setv, passedv, queue;

if (SCHEDULER_STOPPED())
return;

passedv = v;
if (__rw_runlock_try(rw, td, &v))
goto out_lockstat;

Expand Down Expand Up @@ -827,7 +828,10 @@ __rw_runlock_hard(struct rwlock *rw, struct thread *td, uintptr_t v
* release the lock.
*/
ts = turnstile_lookup(&rw->lock_object);
MPASS(ts != NULL);
if (__predict_false(ts == NULL)) {
panic("got NULL turnstile on rwlock %p passedv %zx v %zx",
rw, passedv, v);
}
turnstile_broadcast(ts, queue);
turnstile_unpend(ts);
td->td_rw_rlocks--;
Expand Down Expand Up @@ -1206,7 +1210,7 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t v LOCK_FILE_LINE_ARG_DEF)
{
struct rwlock *rw;
struct turnstile *ts;
uintptr_t tid, setv;
uintptr_t tid, setv, passedv;
int queue;

tid = (uintptr_t)curthread;
Expand Down Expand Up @@ -1254,6 +1258,7 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t v LOCK_FILE_LINE_ARG_DEF)
* of waiters or doing some complicated lock handoff gymnastics.
*/
setv = RW_UNLOCKED;
passedv = v;
v = RW_READ_VALUE(rw);
queue = TS_SHARED_QUEUE;
if (v & RW_LOCK_WRITE_WAITERS) {
Expand All @@ -1268,7 +1273,10 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t v LOCK_FILE_LINE_ARG_DEF)
queue == TS_SHARED_QUEUE ? "read" : "write");

ts = turnstile_lookup(&rw->lock_object);
MPASS(ts != NULL);
if (__predict_false(ts == NULL)) {
panic("got NULL turnstile on rwlock %p passedv %zx v %zx", rw,
passedv, v);
}
turnstile_broadcast(ts, queue);
turnstile_unpend(ts);
turnstile_chain_unlock(&rw->lock_object);
Expand Down

0 comments on commit 87ee63b

Please sign in to comment.