# HG changeset patch # User Taylor R Campbell # Date 1771802723 0 # Sun Feb 22 23:25:23 2026 +0000 # Branch trunk # Node ID 79b21aa48c357cf325ff712321cee97bd5578fa3 # Parent 2489653fbd32de8d45a986717c42bff916899e16 # EXP-Topic riastradh-pr60030-showalllocks WIP: Track what lock each lwp is waiting for without LOCKDEBUG. This is reasonably cheap -- one extra pointer on the stack, couple extra stores when _waiting_ (spinning or sleeping) for a _contended_ lock -- and doesn't change the kernel ABI. Will enable us to get diagnostics from crash dumps when, e.g., there's a softint deadlock tripping a heartbeat panic. diff -r 2489653fbd32 -r 79b21aa48c35 sys/external/bsd/drm2/linux/linux_rwsem.c --- a/sys/external/bsd/drm2/linux/linux_rwsem.c Fri May 22 06:15:01 2026 +0000 +++ b/sys/external/bsd/drm2/linux/linux_rwsem.c Sun Feb 22 23:25:23 2026 +0000 @@ -42,15 +42,15 @@ #include -#define RWSEM_WANTLOCK(RWSEM) \ +#define RWSEM_WANTLOCK(RWSEM, OWANTEDP) \ LOCKDEBUG_WANTLOCK((RWSEM)->rws_debug, (RWSEM), \ - (uintptr_t)__builtin_return_address(0), 0) -#define RWSEM_LOCKED_EX(RWSEM) \ + (uintptr_t)__builtin_return_address(0), 0, OWANTEDP) +#define RWSEM_LOCKED_EX(RWSEM, OWANTEDP) \ LOCKDEBUG_LOCKED((RWSEM)->rws_debug, (RWSEM), NULL, \ - (uintptr_t)__builtin_return_address(0), 0) -#define RWSEM_LOCKED_SH(RWSEM) \ + (uintptr_t)__builtin_return_address(0), 0, OWANTEDP) +#define RWSEM_LOCKED_SH(RWSEM, OWANTEDP) \ LOCKDEBUG_LOCKED((RWSEM)->rws_debug, (RWSEM), NULL, \ - (uintptr_t)__builtin_return_address(0), 1) + (uintptr_t)__builtin_return_address(0), 1, OWANTEDP) #define RWSEM_UNLOCKED_EX(RWSEM) \ LOCKDEBUG_UNLOCKED((RWSEM)->rws_debug, (RWSEM), \ (uintptr_t)__builtin_return_address(0), 0) @@ -109,8 +109,9 @@ destroy_rwsem(struct rw_semaphore *rwsem void down_read(struct rw_semaphore *rwsem) { + volatile void *owanted; - RWSEM_WANTLOCK(rwsem); + RWSEM_WANTLOCK(rwsem, &owanted); mutex_enter(&rwsem->rws_lock); while (rwsem->rws_writer || rwsem->rws_writewanted) @@ -119,7 +120,7 @@ down_read(struct rw_semaphore *rwsem) rwsem->rws_readers++; mutex_exit(&rwsem->rws_lock); - RWSEM_LOCKED_SH(rwsem); + RWSEM_LOCKED_SH(rwsem, &owanted); } bool @@ -144,7 +145,8 @@ down_read_trylock(struct rw_semaphore *r mutex_exit(&rwsem->rws_lock); if (ret) { - RWSEM_LOCKED_SH(rwsem); + RWSEM_WANTLOCK(rwsem, NULL); + RWSEM_LOCKED_SH(rwsem, NULL); } return ret; @@ -167,8 +169,9 @@ up_read(struct rw_semaphore *rwsem) void down_write(struct rw_semaphore *rwsem) { + volatile void *owanted; - RWSEM_WANTLOCK(rwsem); + RWSEM_WANTLOCK(rwsem, &owanted); mutex_enter(&rwsem->rws_lock); @@ -196,7 +199,7 @@ down_write(struct rw_semaphore *rwsem) mutex_exit(&rwsem->rws_lock); - RWSEM_LOCKED_EX(rwsem); + RWSEM_LOCKED_EX(rwsem, &owanted); } void @@ -227,5 +230,6 @@ downgrade_write(struct rw_semaphore *rws cv_broadcast(&rwsem->rws_cv); mutex_exit(&rwsem->rws_lock); - RWSEM_LOCKED_SH(rwsem); + RWSEM_WANTLOCK(rwsem, NULL); + RWSEM_LOCKED_SH(rwsem, NULL); } diff -r 2489653fbd32 -r 79b21aa48c35 sys/external/bsd/drm2/linux/linux_ww_mutex.c --- a/sys/external/bsd/drm2/linux/linux_ww_mutex.c Fri May 22 06:15:01 2026 +0000 +++ b/sys/external/bsd/drm2/linux/linux_ww_mutex.c Sun Feb 22 23:25:23 2026 +0000 @@ -43,12 +43,12 @@ #include #include -#define WW_WANTLOCK(WW) \ +#define WW_WANTLOCK(WW, OWANTEDP) \ LOCKDEBUG_WANTLOCK((WW)->wwm_debug, (WW), \ - (uintptr_t)__builtin_return_address(0), 0) -#define WW_LOCKED(WW) \ + (uintptr_t)__builtin_return_address(0), 0, OWANTEDP) +#define WW_LOCKED(WW, OWANTEDP) \ LOCKDEBUG_LOCKED((WW)->wwm_debug, (WW), NULL, \ - (uintptr_t)__builtin_return_address(0), 0) + (uintptr_t)__builtin_return_address(0), 0, OWANTEDP) #define WW_UNLOCKED(WW) \ LOCKDEBUG_UNLOCKED((WW)->wwm_debug, (WW), \ (uintptr_t)__builtin_return_address(0), 0) @@ -458,7 +458,7 @@ ww_mutex_lock_wait_sig(struct ww_mutex * } /* - * ww_mutex_lock_noctx(mutex) + * ww_mutex_lock_noctx(mutex, &owanted) * * Acquire mutex without an acquire context. Caller must not * already hold the mutex. Uninterruptible; never fails. @@ -468,7 +468,7 @@ ww_mutex_lock_wait_sig(struct ww_mutex * * Internal subroutine, implementing ww_mutex_lock(..., NULL). */ static void -ww_mutex_lock_noctx(struct ww_mutex *mutex) +ww_mutex_lock_noctx(struct ww_mutex *mutex, volatile void **owantedp) { mutex_enter(&mutex->wwm_lock); @@ -497,12 +497,12 @@ retry: switch (mutex->wwm_state) { } KASSERT(mutex->wwm_state == WW_OWNED); KASSERT(mutex->wwm_u.owner == curlwp); - WW_LOCKED(mutex); + WW_LOCKED(mutex, owantedp); mutex_exit(&mutex->wwm_lock); } /* - * ww_mutex_lock_noctx_sig(mutex) + * ww_mutex_lock_noctx_sig(mutex, &owanted) * * Acquire mutex without an acquire context and return 0, or fail * and return -EINTR if interrupted by a signal. Caller must not @@ -514,7 +514,7 @@ retry: switch (mutex->wwm_state) { * ww_mutex_lock_interruptible(..., NULL). */ static int -ww_mutex_lock_noctx_sig(struct ww_mutex *mutex) +ww_mutex_lock_noctx_sig(struct ww_mutex *mutex, volatile void **owantedp) { int ret; @@ -552,7 +552,7 @@ retry: switch (mutex->wwm_state) { } KASSERT(mutex->wwm_state == WW_OWNED); KASSERT(mutex->wwm_u.owner == curlwp); - WW_LOCKED(mutex); + WW_LOCKED(mutex, owantedp); ret = 0; out: mutex_exit(&mutex->wwm_lock); KASSERTMSG((ret == 0 || ret == -EINTR), "ret=%d", ret); @@ -577,6 +577,7 @@ out: mutex_exit(&mutex->wwm_lock); int ww_mutex_lock(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) { + volatile void *owanted; int ret; /* @@ -587,8 +588,8 @@ ww_mutex_lock(struct ww_mutex *mutex, st ASSERT_SLEEPABLE(); if (ctx == NULL) { - WW_WANTLOCK(mutex); - ww_mutex_lock_noctx(mutex); + WW_WANTLOCK(mutex, &owanted); + ww_mutex_lock_noctx(mutex, &owanted); ret = 0; goto out; } @@ -605,12 +606,12 @@ ww_mutex_lock(struct ww_mutex *mutex, st ww_acquire_done_check(mutex, ctx); retry: switch (mutex->wwm_state) { case WW_UNLOCKED: - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); mutex->wwm_state = WW_CTX; mutex->wwm_u.ctx = ctx; goto locked; case WW_OWNED: - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); KASSERTMSG((mutex->wwm_u.owner != curlwp), "locking %p against myself: %p", mutex, curlwp); ww_mutex_state_wait(mutex, WW_OWNED); @@ -644,7 +645,7 @@ retry: switch (mutex->wwm_state) { * We do not own it. We can safely assert to LOCKDEBUG that we * want it. */ - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) { /* @@ -667,7 +668,7 @@ retry: switch (mutex->wwm_state) { locked: KASSERT((mutex->wwm_state == WW_CTX) || (mutex->wwm_state == WW_WANTOWN)); KASSERT(mutex->wwm_u.ctx == ctx); - WW_LOCKED(mutex); + WW_LOCKED(mutex, &owanted); ctx->wwx_acquired++; ret = 0; out_unlock: @@ -697,6 +698,7 @@ out: KASSERTMSG((ret == 0 || ret == -EAL int ww_mutex_lock_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) { + volatile void *owanted; int ret; /* @@ -707,8 +709,8 @@ ww_mutex_lock_interruptible(struct ww_mu ASSERT_SLEEPABLE(); if (ctx == NULL) { - WW_WANTLOCK(mutex); - ret = ww_mutex_lock_noctx_sig(mutex); + WW_WANTLOCK(mutex, &owanted); + ret = ww_mutex_lock_noctx_sig(mutex, &owanted); KASSERTMSG((ret == 0 || ret == -EINTR), "ret=%d", ret); goto out; } @@ -725,12 +727,12 @@ ww_mutex_lock_interruptible(struct ww_mu ww_acquire_done_check(mutex, ctx); retry: switch (mutex->wwm_state) { case WW_UNLOCKED: - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); mutex->wwm_state = WW_CTX; mutex->wwm_u.ctx = ctx; goto locked; case WW_OWNED: - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); KASSERTMSG((mutex->wwm_u.owner != curlwp), "locking %p against myself: %p", mutex, curlwp); ret = ww_mutex_state_wait_sig(mutex, WW_OWNED); @@ -772,7 +774,7 @@ retry: switch (mutex->wwm_state) { * We do not own it. We can safely assert to LOCKDEBUG that we * want it. */ - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); if (mutex->wwm_u.ctx->wwx_ticket < ctx->wwx_ticket) { /* @@ -799,7 +801,7 @@ retry: switch (mutex->wwm_state) { locked: KASSERT((mutex->wwm_state == WW_CTX) || (mutex->wwm_state == WW_WANTOWN)); KASSERT(mutex->wwm_u.ctx == ctx); - WW_LOCKED(mutex); + WW_LOCKED(mutex, &owanted); ctx->wwx_acquired++; ret = 0; out_unlock: @@ -824,13 +826,14 @@ out: KASSERTMSG((ret == 0 || ret == -EAL void ww_mutex_lock_slow(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) { + volatile void *owanted; /* Caller must not try to lock against self here. */ - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); ASSERT_SLEEPABLE(); if (ctx == NULL) { - ww_mutex_lock_noctx(mutex); + ww_mutex_lock_noctx(mutex, &owanted); return; } @@ -881,7 +884,7 @@ retry: switch (mutex->wwm_state) { locked: KASSERT((mutex->wwm_state == WW_CTX) || (mutex->wwm_state == WW_WANTOWN)); KASSERT(mutex->wwm_u.ctx == ctx); - WW_LOCKED(mutex); + WW_LOCKED(mutex, &owanted); ctx->wwx_acquired++; mutex_exit(&mutex->wwm_lock); } @@ -901,13 +904,14 @@ int ww_mutex_lock_slow_interruptible(struct ww_mutex *mutex, struct ww_acquire_ctx *ctx) { + volatile void *owanted; int ret; - WW_WANTLOCK(mutex); + WW_WANTLOCK(mutex, &owanted); ASSERT_SLEEPABLE(); if (ctx == NULL) { - ret = ww_mutex_lock_noctx_sig(mutex); + ret = ww_mutex_lock_noctx_sig(mutex, &owanted); KASSERTMSG((ret == 0 || ret == -EINTR), "ret=%d", ret); goto out; } @@ -971,7 +975,7 @@ retry: switch (mutex->wwm_state) { locked: KASSERT((mutex->wwm_state == WW_CTX) || (mutex->wwm_state == WW_WANTOWN)); KASSERT(mutex->wwm_u.ctx == ctx); - WW_LOCKED(mutex); + WW_LOCKED(mutex, &owanted); ctx->wwx_acquired++; ret = 0; out_unlock: @@ -995,8 +999,8 @@ ww_mutex_trylock(struct ww_mutex *mutex) if (mutex->wwm_state == WW_UNLOCKED) { mutex->wwm_state = WW_OWNED; mutex->wwm_u.owner = curlwp; - WW_WANTLOCK(mutex); - WW_LOCKED(mutex); + WW_WANTLOCK(mutex, NULL); + WW_LOCKED(mutex, NULL); ret = 1; } else { /* diff -r 2489653fbd32 -r 79b21aa48c35 sys/kern/kern_lock.c --- a/sys/kern/kern_lock.c Fri May 22 06:15:01 2026 +0000 +++ b/sys/kern/kern_lock.c Sun Feb 22 23:25:23 2026 +0000 @@ -298,6 +298,7 @@ void u_int starttime; int s; struct lwp *l = curlwp; + volatile void *owanted; _KERNEL_LOCK_ASSERT(nlocks > 0); @@ -314,7 +315,7 @@ void _KERNEL_LOCK_ASSERT(l->l_blcnt == 0); LOCKDEBUG_WANTLOCK(kernel_lock_dodebug, kernel_lock, RETURN_ADDRESS, - 0); + 0, &owanted); if (__predict_true(__cpu_simple_lock_try(kernel_lock))) { atomic_store_relaxed(&kernel_lock_holder, curcpu()); @@ -322,7 +323,7 @@ void ci->ci_biglock_count = nlocks; l->l_blcnt = nlocks; LOCKDEBUG_LOCKED(kernel_lock_dodebug, kernel_lock, NULL, - RETURN_ADDRESS, 0); + RETURN_ADDRESS, 0, &owanted); splx(s); return; } @@ -346,9 +347,6 @@ void membar_producer(); owant = ci->ci_biglock_wanted; atomic_store_relaxed(&ci->ci_biglock_wanted, l); -#if defined(DIAGNOSTIC) && !defined(LOCKDEBUG) - l->l_ld_wanted = __builtin_return_address(0); -#endif /* * Spin until we acquire the lock. Once we have it, record the @@ -378,7 +376,7 @@ void l->l_blcnt = nlocks; LOCKSTAT_STOP_TIMER(lsflag, spintime); LOCKDEBUG_LOCKED(kernel_lock_dodebug, kernel_lock, NULL, - RETURN_ADDRESS, 0); + RETURN_ADDRESS, 0, &owanted); if (owant == NULL) { LOCKSTAT_EVENT_RA(lsflag, kernel_lock, LB_KERNEL_LOCK | LB_SPIN, 1, spintime, RETURN_ADDRESS); diff -r 2489653fbd32 -r 79b21aa48c35 sys/kern/kern_mutex.c --- a/sys/kern/kern_mutex.c Fri May 22 06:15:01 2026 +0000 +++ b/sys/kern/kern_mutex.c Sun Feb 22 23:25:23 2026 +0000 @@ -77,15 +77,15 @@ * Debugging support. */ -#define MUTEX_WANTLOCK(mtx) \ +#define MUTEX_WANTLOCK(mtx, owantedp) \ LOCKDEBUG_WANTLOCK(MUTEX_DEBUG_P(mtx), (mtx), \ - (uintptr_t)__builtin_return_address(0), 0) + (uintptr_t)__builtin_return_address(0), 0, owantedp) #define MUTEX_TESTLOCK(mtx) \ LOCKDEBUG_WANTLOCK(MUTEX_DEBUG_P(mtx), (mtx), \ - (uintptr_t)__builtin_return_address(0), -1) -#define MUTEX_LOCKED(mtx) \ + (uintptr_t)__builtin_return_address(0), -1, NULL) +#define MUTEX_LOCKED(mtx, owantedp) \ LOCKDEBUG_LOCKED(MUTEX_DEBUG_P(mtx), (mtx), NULL, \ - (uintptr_t)__builtin_return_address(0), 0) + (uintptr_t)__builtin_return_address(0), 0, owantedp) #define MUTEX_UNLOCKED(mtx) \ LOCKDEBUG_UNLOCKED(MUTEX_DEBUG_P(mtx), (mtx), \ (uintptr_t)__builtin_return_address(0), 0) @@ -454,6 +454,7 @@ mutex_vector_enter(kmutex_t *mtx) #ifdef MULTIPROCESSOR u_int count; #endif + volatile void *owanted; LOCKSTAT_COUNTER(spincnt); LOCKSTAT_COUNTER(slpcnt); LOCKSTAT_TIMER(spintime); @@ -471,10 +472,10 @@ mutex_vector_enter(kmutex_t *mtx) #endif KPREEMPT_ENABLE(curlwp); MUTEX_SPIN_SPLRAISE(mtx); - MUTEX_WANTLOCK(mtx); + MUTEX_WANTLOCK(mtx, &owanted); #ifdef FULL if (MUTEX_SPINBIT_LOCK_TRY(mtx)) { - MUTEX_LOCKED(mtx); + MUTEX_LOCKED(mtx, &owanted); return; } #if !defined(MULTIPROCESSOR) @@ -508,7 +509,7 @@ mutex_vector_enter(kmutex_t *mtx) LOCKSTAT_EXIT(lsflag); #endif /* !MULTIPROCESSOR */ #endif /* FULL */ - MUTEX_LOCKED(mtx); + MUTEX_LOCKED(mtx, &owanted); return; } @@ -517,7 +518,7 @@ mutex_vector_enter(kmutex_t *mtx) MUTEX_DASSERT(mtx, MUTEX_ADAPTIVE_P(owner)); MUTEX_ASSERT(mtx, curthread != 0); MUTEX_ASSERT(mtx, !cpu_intr_p()); - MUTEX_WANTLOCK(mtx); + MUTEX_WANTLOCK(mtx, &owanted); if (__predict_true(panicstr == NULL)) { KDASSERT(pserialize_not_in_read_section()); @@ -704,7 +705,7 @@ mutex_vector_enter(kmutex_t *mtx) LOCKSTAT_EXIT(lsflag); MUTEX_DASSERT(mtx, MUTEX_OWNER(mtx->mtx_owner) == curthread); - MUTEX_LOCKED(mtx); + MUTEX_LOCKED(mtx, &owanted); } /* @@ -881,22 +882,22 @@ mutex_tryenter(kmutex_t *mtx) MUTEX_SPIN_SPLRAISE(mtx); #ifdef FULL if (MUTEX_SPINBIT_LOCK_TRY(mtx)) { - MUTEX_WANTLOCK(mtx); - MUTEX_LOCKED(mtx); + MUTEX_WANTLOCK(mtx, NULL); + MUTEX_LOCKED(mtx, NULL); return 1; } MUTEX_SPIN_SPLRESTORE(mtx); #else - MUTEX_WANTLOCK(mtx); - MUTEX_LOCKED(mtx); + MUTEX_WANTLOCK(mtx, NULL); + MUTEX_LOCKED(mtx, NULL); return 1; #endif } else { curthread = (uintptr_t)curlwp; MUTEX_ASSERT(mtx, curthread != 0); if (MUTEX_ACQUIRE(mtx, curthread)) { - MUTEX_WANTLOCK(mtx); - MUTEX_LOCKED(mtx); + MUTEX_WANTLOCK(mtx, NULL); + MUTEX_LOCKED(mtx, NULL); MUTEX_DASSERT(mtx, MUTEX_OWNER(mtx->mtx_owner) == curthread); return 1; @@ -923,8 +924,9 @@ mutex_spin_retry(kmutex_t *mtx) #ifdef LOCKDEBUG u_int spins = 0; #endif /* LOCKDEBUG */ + volatile void *owanted; - MUTEX_WANTLOCK(mtx); + MUTEX_WANTLOCK(mtx, &owanted); LOCKSTAT_ENTER(lsflag); LOCKSTAT_START_TIMER(lsflag, spintime); @@ -948,7 +950,7 @@ mutex_spin_retry(kmutex_t *mtx) LOCKSTAT_EVENT(lsflag, mtx, LB_SPIN_MUTEX | LB_SPIN, 1, spintime); LOCKSTAT_EXIT(lsflag); - MUTEX_LOCKED(mtx); + MUTEX_LOCKED(mtx, &owanted); #else /* MULTIPROCESSOR */ MUTEX_ABORT(mtx, "locking against myself"); #endif /* MULTIPROCESSOR */ diff -r 2489653fbd32 -r 79b21aa48c35 sys/kern/kern_rwlock.c --- a/sys/kern/kern_rwlock.c Fri May 22 06:15:01 2026 +0000 +++ b/sys/kern/kern_rwlock.c Sun Feb 22 23:25:23 2026 +0000 @@ -75,12 +75,12 @@ #define RW_DEBUG_P(rw) (((rw)->rw_owner & RW_NODEBUG) == 0) -#define RW_WANTLOCK(rw, op) \ +#define RW_WANTLOCK(rw, op, owantedp) \ LOCKDEBUG_WANTLOCK(RW_DEBUG_P(rw), (rw), \ - (uintptr_t)__builtin_return_address(0), op == RW_READER); -#define RW_LOCKED(rw, op) \ + (uintptr_t)__builtin_return_address(0), op == RW_READER, owantedp); +#define RW_LOCKED(rw, op, owantedp) \ LOCKDEBUG_LOCKED(RW_DEBUG_P(rw), (rw), NULL, \ - (uintptr_t)__builtin_return_address(0), op == RW_READER); + (uintptr_t)__builtin_return_address(0), op == RW_READER, owantedp); #define RW_UNLOCKED(rw, op) \ LOCKDEBUG_UNLOCKED(RW_DEBUG_P(rw), (rw), \ (uintptr_t)__builtin_return_address(0), op == RW_READER); @@ -286,6 +286,7 @@ rw_vector_enter(krwlock_t *rw, const krw turnstile_t *ts; int queue; lwp_t *l; + volatile void *owanted; LOCKSTAT_TIMER(slptime); LOCKSTAT_TIMER(slpcnt); LOCKSTAT_TIMER(spintime); @@ -297,7 +298,7 @@ rw_vector_enter(krwlock_t *rw, const krw RW_ASSERT(rw, !cpu_intr_p()); RW_ASSERT(rw, curthread != 0); - RW_WANTLOCK(rw, op); + RW_WANTLOCK(rw, op, &owanted); if (__predict_true(panicstr == NULL)) { KDASSERT(pserialize_not_in_read_section()); @@ -425,7 +426,7 @@ rw_vector_enter(krwlock_t *rw, const krw RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || (op == RW_READER && RW_COUNT(rw) != 0)); - RW_LOCKED(rw, op); + RW_LOCKED(rw, op, &owanted); } /* @@ -576,8 +577,8 @@ rw_vector_tryenter(krwlock_t *rw, const } } - RW_WANTLOCK(rw, op); - RW_LOCKED(rw, op); + RW_WANTLOCK(rw, op, NULL); + RW_LOCKED(rw, op, NULL); RW_ASSERT(rw, (op != RW_READER && RW_OWNER(rw) == curthread) || (op == RW_READER && RW_COUNT(rw) != 0)); @@ -617,7 +618,8 @@ rw_downgrade(krwlock_t *rw) newown = (owner & RW_NODEBUG); next = rw_cas(rw, owner, newown + RW_READ_INCR); if (__predict_true(next == owner)) { - RW_LOCKED(rw, RW_READER); + RW_WANTLOCK(rw, RW_READER, NULL); + RW_LOCKED(rw, RW_READER, NULL); RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); RW_ASSERT(rw, RW_COUNT(rw) != 0); @@ -676,8 +678,8 @@ rw_downgrade(krwlock_t *rw) } } - RW_WANTLOCK(rw, RW_READER); - RW_LOCKED(rw, RW_READER); + RW_WANTLOCK(rw, RW_READER, NULL); + RW_LOCKED(rw, RW_READER, NULL); RW_ASSERT(rw, (rw->rw_owner & RW_WRITE_LOCKED) == 0); RW_ASSERT(rw, RW_COUNT(rw) != 0); } @@ -714,8 +716,8 @@ rw_tryupgrade(krwlock_t *rw) } RW_UNLOCKED(rw, RW_READER); - RW_WANTLOCK(rw, RW_WRITER); - RW_LOCKED(rw, RW_WRITER); + RW_WANTLOCK(rw, RW_WRITER, NULL); + RW_LOCKED(rw, RW_WRITER, NULL); RW_ASSERT(rw, rw->rw_owner & RW_WRITE_LOCKED); RW_ASSERT(rw, RW_OWNER(rw) == curthread); diff -r 2489653fbd32 -r 79b21aa48c35 sys/sys/lockdebug.h --- a/sys/sys/lockdebug.h Fri May 22 06:15:01 2026 +0000 +++ b/sys/sys/lockdebug.h Sun Feb 22 23:25:23 2026 +0000 @@ -82,10 +82,10 @@ void lockdebug_mem_check(const char *, s lockdebug_alloc(__func__, __LINE__, lock, ops, addr) #define LOCKDEBUG_FREE(dodebug, lock) \ if (dodebug) lockdebug_free(__func__, __LINE__, lock) -#define LOCKDEBUG_WANTLOCK(dodebug, lock, where, s) \ - if (dodebug) lockdebug_wantlock(__func__, __LINE__, lock, where, s) -#define LOCKDEBUG_LOCKED(dodebug, lock, al, where, s) \ - if (dodebug) lockdebug_locked(__func__, __LINE__, lock, al, where, s) +#define LOCKDEBUG_WANTLOCK(dodebug, lock, where, s, owantedp) \ + if (dodebug) { lockdebug_wantlock(__func__, __LINE__, lock, where, s); __USE(owantedp); } +#define LOCKDEBUG_LOCKED(dodebug, lock, al, where, s, owantedp) \ + if (dodebug) { lockdebug_locked(__func__, __LINE__, lock, al, where, s); __USE(owantedp); } #define LOCKDEBUG_UNLOCKED(dodebug, lock, where, s) \ if (dodebug) lockdebug_unlocked(__func__, __LINE__, lock, where, s) #define LOCKDEBUG_BARRIER(lock, slp) \ @@ -96,12 +96,31 @@ void lockdebug_mem_check(const char *, s #else /* LOCKDEBUG */ #define LOCKDEBUG_ALLOC(lock, ops, addr) false -#define LOCKDEBUG_FREE(dodebug, lock) /* nothing */ -#define LOCKDEBUG_WANTLOCK(dodebug, lock, where, s) /* nothing */ -#define LOCKDEBUG_LOCKED(dodebug, lock, al, where, s) /* nothing */ -#define LOCKDEBUG_UNLOCKED(dodebug, lock, where, s) /* nothing */ -#define LOCKDEBUG_BARRIER(lock, slp) /* nothing */ -#define LOCKDEBUG_MEM_CHECK(base, sz) /* nothing */ +#define LOCKDEBUG_FREE(dodebug, lock) __nothing +#if 0 +#define LOCKDEBUG_WANTLOCK(dodebug, lock, where, s, owantedp) __nothing +#define LOCKDEBUG_LOCKED(dodebug, lock, al, where, s, owantedp) __nothing +#else +#define LOCKDEBUG_WANTLOCK(dodebug, lock, where, s, owantedp) do \ +{ \ + if ((owantedp) == NULL) \ + break; \ + *((owantedp) == NULL ? (volatile void **)NULL : (owantedp)) = \ + curlwp->l_ld_wanted; \ + curlwp->l_ld_wanted = (lock); \ +} while (0) +#define LOCKDEBUG_LOCKED(dodebug, lock, al, where, s, owantedp) do \ +{ \ + if ((owantedp) == NULL) \ + break; \ + curlwp->l_ld_wanted = \ + *((owantedp) == NULL ? (volatile void **)NULL : (owantedp)); \ + *((owantedp) == NULL ? (volatile void **)NULL : (owantedp)) = NULL; \ +} while (0) +#endif +#define LOCKDEBUG_UNLOCKED(dodebug, lock, where, s) __nothing +#define LOCKDEBUG_BARRIER(lock, slp) __nothing +#define LOCKDEBUG_MEM_CHECK(base, sz) __nothing #endif /* LOCKDEBUG */ # HG changeset patch # User Taylor R Campbell # Date 1771813534 0 # Mon Feb 23 02:25:34 2026 +0000 # Branch trunk # Node ID 0a63f57fa6552f872a1229685f76eae14186df5e # Parent 79b21aa48c357cf325ff712321cee97bd5578fa3 # EXP-Topic riastradh-pr60030-showalllocks WIP: Make `show all locks' work without LOCKDEBUG. diff -r 79b21aa48c35 -r 0a63f57fa655 sys/kern/subr_lockdebug.c --- a/sys/kern/subr_lockdebug.c Sun Feb 22 23:25:23 2026 +0000 +++ b/sys/kern/subr_lockdebug.c Mon Feb 23 02:25:34 2026 +0000 @@ -60,6 +60,7 @@ #include #include #include +#include #include #endif @@ -863,7 +864,17 @@ lockdebug_lock_print(void *addr, } #ifdef _KERNEL + +static void +lockdebug_show_trace(const void *ptr, + void (*pr)(const char *, ...) __printflike(1, 2)) +{ + + db_stack_trace_print((db_expr_t)(intptr_t)ptr, true, 32, "a", pr); +} + #ifdef LOCKDEBUG + static void lockdebug_show_one(lwp_t *l, lockdebug_t *ld, int i, void (*pr)(const char *, ...) __printflike(1, 2)) @@ -880,14 +891,6 @@ lockdebug_show_one(lwp_t *l, lockdebug_t } static void -lockdebug_show_trace(const void *ptr, - void (*pr)(const char *, ...) __printflike(1, 2)) -{ - - db_stack_trace_print((db_expr_t)(intptr_t)ptr, true, 32, "a", pr); -} - -static void lockdebug_show_all_locks_lwp(void (*pr)(const char *, ...) __printflike(1, 2), bool show_trace) { @@ -957,15 +960,18 @@ lockdebug_show_all_locks_cpu(void (*pr)( } } } -#endif /* _KERNEL */ + #endif /* LOCKDEBUG */ +#endif /* _KERNEL */ + #ifdef _KERNEL +/* XXX dedup with usr.sbin/crash.c lockdebug_show_all_locks */ void lockdebug_show_all_locks(void (*pr)(const char *, ...) __printflike(1, 2), const char *modif) { -#ifdef LOCKDEBUG +#if defined LOCKDEBUG bool show_trace = false; if (modif[0] == 't') show_trace = true; @@ -977,6 +983,78 @@ lockdebug_show_all_locks(void (*pr)(cons (*pr)("[Locks tracked through CPUs]\n"); lockdebug_show_all_locks_cpu(pr, show_trace); (*pr)("\n"); +#elif defined DDB + struct proc *p; + bool show_trace = false; + + if (modif[0] == 't') + show_trace = true; + + (*pr)("%-5s %5s %3s %18s %18s %18s %4s\n", + "PID", "LID", "CPU", "STRUCT LWP *", "LOCK", "OWNER", "BITS"); + for (p = db_proc_first(); p != NULL; p = db_proc_next(p)) { + pid_t pid; + struct lwp *l; + + db_read_bytes((db_addr_t)(uintptr_t)&p->p_pid, sizeof(pid), + (char *)&pid); + + for (db_read_bytes( + (db_addr_t)(uintptr_t) &LIST_FIRST(&p->p_lwps), + sizeof(l), (char *)&l); + l != NULL; + db_read_bytes( + (db_addr_t)(uintptr_t)&LIST_NEXT(l, l_sibling), + sizeof(l), (char *)&l)) { + lwpid_t lid; + int stat, pflag; + struct cpu_info *ci; + int cpuno = -1; + volatile void *ld_wanted; + uintptr_t ownerword; + + db_read_bytes((db_addr_t)(uintptr_t)&l->l_ld_wanted, + sizeof(ld_wanted), (char *)&ld_wanted); + if (ld_wanted == NULL) + continue; + + db_read_bytes((db_addr_t)(uintptr_t)&l->l_lid, + sizeof(lid), (char *)&lid); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_stat, + sizeof(stat), (char *)&stat); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_pflag, + sizeof(pflag), (char *)&pflag); + const bool run = (stat == LSONPROC || + (pflag & LP_RUNNING) != 0); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_cpu, + sizeof(ci), (char *)&ci); + if (ci != NULL) { + db_read_bytes( + (db_addr_t)(uintptr_t)&ci->ci_index, + sizeof(cpuno), (char *)&cpuno); + } + db_read_bytes((db_addr_t)(uintptr_t)ld_wanted, + sizeof(ownerword), (char *)&ownerword); + (*pr)("%-5d%c%5d %3d %18lx %18lx %18lx %4x\n", + pid, run ? '>' : ' ', lid, cpuno, + (long)l, (long)ld_wanted, + (long)(ownerword & ~(uintptr_t)ALIGNBYTES), + (int)(ownerword & ALIGNBYTES)); + if (show_trace) { + const struct lwp *owner = + (const void *)(ownerword & + ~(uintptr_t)ALIGNBYTES); + + /* + * XXX Skip this if the owner isn't a + * pointer at all -- reader-held + * rwlock, or spin mutex. + */ + if (owner != NULL) + lockdebug_show_trace(owner, pr); + } + } + } #else (*pr)("Sorry, kernel not built with the LOCKDEBUG option.\n"); #endif /* LOCKDEBUG */ diff -r 79b21aa48c35 -r 0a63f57fa655 usr.sbin/crash/crash.c --- a/usr.sbin/crash/crash.c Sun Feb 22 23:25:23 2026 +0000 +++ b/usr.sbin/crash/crash.c Mon Feb 23 02:25:34 2026 +0000 @@ -85,13 +85,115 @@ static struct nlist nl[] = { }; #ifdef LOCKDEBUG + struct lockdebug; TAILQ_HEAD(, lockdebug) ld_all; +static bool lockdebug_enabled; + +/* XXX dedup with sys/kern/subr_lockdebug.c lockdebug_show_trace */ +#include +static void +lockdebug_show_trace(const void *ptr, + void (*pr)(const char *, ...) __printflike(1, 2)) +{ + + db_stack_trace_print((db_expr_t)(intptr_t)ptr, true, 32, "a", pr); +} + +/* XXX dedup with sys/kern/subr_lockdebug.c.c lockdebug_show_all_locks */ +#include +#include +#include +void +lockdebug_show_all_locks(void (*pr)(const char *, ...) __printflike(1,2), + const char *modif) +{ + struct proc *p; + bool show_trace = false; + + if (modif[0] == 't') + show_trace = true; + + if (lockdebug_enabled) { + /* XXX implement me */ + printf("This command only works in-kernel.\n"); + return; + } + + (*pr)("%-5s %5s %3s %18s %18s %18s %4s\n", + "PID", "LID", "CPU", "STRUCT LWP *", "LOCK", "OWNER", "BITS"); + for (p = db_proc_first(); p != NULL; p = db_proc_next(p)) { + pid_t pid; + struct lwp *l; + + db_read_bytes((db_addr_t)(uintptr_t)&p->p_pid, sizeof(pid), + (char *)&pid); + + for (db_read_bytes( + (db_addr_t)(uintptr_t) &LIST_FIRST(&p->p_lwps), + sizeof(l), (char *)&l); + l != NULL; + db_read_bytes( + (db_addr_t)(uintptr_t)&LIST_NEXT(l, l_sibling), + sizeof(l), (char *)&l)) { + lwpid_t lid; + int stat, pflag; + struct cpu_info *ci; + int cpuno = -1; + volatile void *ld_wanted; + uintptr_t ownerword; + + db_read_bytes((db_addr_t)(uintptr_t)&l->l_ld_wanted, + sizeof(ld_wanted), (char *)&ld_wanted); + if (ld_wanted == NULL) + continue; + + db_read_bytes((db_addr_t)(uintptr_t)&l->l_lid, + sizeof(lid), (char *)&lid); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_stat, + sizeof(stat), (char *)&stat); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_pflag, + sizeof(pflag), (char *)&pflag); + const bool run = (stat == LSONPROC || + (pflag & LP_RUNNING) != 0); + db_read_bytes((db_addr_t)(uintptr_t)&l->l_cpu, + sizeof(ci), (char *)&ci); + if (ci != NULL) { + db_read_bytes( + (db_addr_t)(uintptr_t)&ci->ci_index, + sizeof(cpuno), (char *)&cpuno); + } + db_read_bytes((db_addr_t)(uintptr_t)ld_wanted, + sizeof(ownerword), (char *)&ownerword); + (*pr)("%-5d%c%5d %3d %18lx %18lx %18lx %4x\n", + pid, run ? '>' : ' ', lid, cpuno, + (long)l, (long)ld_wanted, + (long)(ownerword & ~(uintptr_t)ALIGNBYTES), + (int)(ownerword & ALIGNBYTES)); + if (show_trace) { + const struct lwp *owner = + (const void *)(ownerword & + ~(uintptr_t)ALIGNBYTES); + + /* + * XXX Skip this if the owner isn't a + * pointer at all -- reader-held + * rwlock, or spin mutex. + */ + if (owner != NULL) + lockdebug_show_trace(owner, pr); + } + } + } +} + #else + void lockdebug_lock_print(void); void lockdebug_lock_print(void) { warnx("No lockdebug support compiled in"); } + #endif static void @@ -439,8 +541,12 @@ main(int argc, char **argv) } #ifdef LOCKDEBUG if ((size_t)kvm_read(kd, nl[X_LOCKDEBUG].n_value, &ld_all, - sizeof(ld_all)) != sizeof(ld_all)) + sizeof(ld_all)) == sizeof(ld_all)) { + lockdebug_enabled = true; + } else { printf("Kernel compiled without options LOCKDEBUG.\n"); + lockdebug_enabled = false; + } #endif /*