git: e7e958d83d85 - main - ddb show allchains: avoid traps and show pointers for lockmgr and sx

From: Ryan Libby <rlibby_at_FreeBSD.org>
Date: Fri, 03 Oct 2025 05:55:16 UTC
The branch main has been updated by rlibby:

URL: https://cgit.FreeBSD.org/src/commit/?id=e7e958d83d8503c3b8714f68418d4509b8288ed9

commit e7e958d83d8503c3b8714f68418d4509b8288ed9
Author:     Ryan Libby <rlibby@FreeBSD.org>
AuthorDate: 2025-10-03 05:47:47 +0000
Commit:     Ryan Libby <rlibby@FreeBSD.org>
CommitDate: 2025-10-03 05:47:47 +0000

    ddb show allchains: avoid traps and show pointers for lockmgr and sx
    
    When trying to walk lock chains, we have to deduce what a thread is
    blocked on.  Checking LOCK_CLASS(td->td_wchan) is not a very reliable
    method by itself, as it just tests whether a particular 4 bits near
    where td_wchan points have a particular value.  Misinterpreting wait
    channel pointers of other sleeps as lockmgr locks would frequently cause
    ddb show allchains (or show lockchain) to trap, or to produce incorrect
    output.
    
    Now, check the sleepq_type.  When calling sleepq_add, we use SLEEPQ_LK
    for lockmgr locks and SLEEPQ_SX for sx locks.  This is a more reliable
    indication that the td_wchan is actually a lock.
    
    While here, also make the output of lockmgr and sx locks consistent with
    the output for other locks (see print_lockchain).  Outputting a pointer
    to the lock allows it to be inspected further with ddb show lock or
    other methods.
    
    Reviewed by:    markj
    Sponsored by:   Dell Inc.
    Differential Revision:  https://reviews.freebsd.org/D52794
---
 sys/kern/kern_lock.c |  6 ++++--
 sys/kern/kern_sx.c   | 11 +++++++----
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index 31bff6d2c1aa..76f68677e292 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -1780,9 +1780,11 @@ lockmgr_chain(struct thread *td, struct thread **ownerp)
 
 	lk = td->td_wchan;
 
-	if (LOCK_CLASS(&lk->lock_object) != &lock_class_lockmgr)
+	if (!TD_ON_SLEEPQ(td) || sleepq_type(td->td_wchan) != SLEEPQ_LK ||
+	    LOCK_CLASS(&lk->lock_object) != &lock_class_lockmgr)
 		return (0);
-	db_printf("blocked on lockmgr %s", lk->lock_object.lo_name);
+	db_printf("blocked on lock %p (%s) \"%s\" ", &lk->lock_object,
+	    lock_class_lockmgr.lc_name, lk->lock_object.lo_name);
 	if (lk->lk_lock & LK_SHARE)
 		db_printf("SHARED (count %ju)\n",
 		    (uintmax_t)LK_SHARERS(lk->lk_lock));
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c
index c005e112d3b9..249faf5b1ec4 100644
--- a/sys/kern/kern_sx.c
+++ b/sys/kern/kern_sx.c
@@ -1539,16 +1539,19 @@ sx_chain(struct thread *td, struct thread **ownerp)
 
 	/*
 	 * Check to see if this thread is blocked on an sx lock.
-	 * First, we check the lock class.  If that is ok, then we
-	 * compare the lock name against the wait message.
+	 * The thread should be on a sleep queue with type SLEEPQ_SX, the
+	 * purported lock should have the lock class index of sx, and the lock
+	 * name should match the wait message.
 	 */
 	sx = td->td_wchan;
-	if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
+	if (!TD_ON_SLEEPQ(td) || sleepq_type(td->td_wchan) != SLEEPQ_SX ||
+	    LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
 	    sx->lock_object.lo_name != td->td_wmesg)
 		return (0);
 
 	/* We think we have an sx lock, so output some details. */
-	db_printf("blocked on sx \"%s\" ", td->td_wmesg);
+	db_printf("blocked on lock %p (%s) \"%s\" ", &sx->lock_object,
+	    lock_class_sx.lc_name, td->td_wmesg);
 	*ownerp = sx_xholder(sx);
 	if (sx->sx_lock & SX_LOCK_SHARED)
 		db_printf("SLOCK (count %ju)\n",