Module Name:    src
Committed By:   ozaki-r
Date:           Fri Mar 16 04:44:51 UTC 2018

Modified Files:
        src/share/man/man4: ddb.4
        src/sys/ddb: db_command.c
        src/sys/kern: subr_lockdebug.c
        src/sys/sys: lockdebug.h

Log Message:
Add a new command, show all locks, which shows information of active locks

The command shows information of all active (i.e., being held) locks that are
tracked through either of LWPs or CPUs by the LOCKDEBUG facility.  The /t
modifier additionally shows a backtrace for each LWP additionally.  This
feature is useful for debugging especially to analyze deadlocks.

The command is useful only if LOCKDEBUG is enabled.


To generate a diff of this commit:
cvs rdiff -u -r1.175 -r1.176 src/share/man/man4/ddb.4
cvs rdiff -u -r1.150 -r1.151 src/sys/ddb/db_command.c
cvs rdiff -u -r1.61 -r1.62 src/sys/kern/subr_lockdebug.c
cvs rdiff -u -r1.17 -r1.18 src/sys/sys/lockdebug.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/ddb.4
diff -u src/share/man/man4/ddb.4:1.175 src/share/man/man4/ddb.4:1.176
--- src/share/man/man4/ddb.4:1.175	Fri Mar 16 04:37:55 2018
+++ src/share/man/man4/ddb.4	Fri Mar 16 04:44:51 2018
@@ -1,4 +1,4 @@
-.\"	$NetBSD: ddb.4,v 1.175 2018/03/16 04:37:55 ozaki-r Exp $
+.\"	$NetBSD: ddb.4,v 1.176 2018/03/16 04:44:51 ozaki-r Exp $
 .\"
 .\" Copyright (c) 1997 - 2009 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -556,6 +556,13 @@ Display information about callouts in th
 See
 .Xr callout 9
 for more information on callouts.
+.It Ic show all locks Ns Op Cm /t
+Display details information about all active locks.
+If
+.Cm /t
+is specified, stack traces of LWPs holding locks are printed additionally.
+This command is useful only if a kernel is compiled with
+.Cd options LOCKDEBUG .
 .It Ic show all pages
 Display basic information about all physical pages managed by the VM system.
 For more detailed information about a single page, use

Index: src/sys/ddb/db_command.c
diff -u src/sys/ddb/db_command.c:1.150 src/sys/ddb/db_command.c:1.151
--- src/sys/ddb/db_command.c:1.150	Fri Mar 16 04:37:55 2018
+++ src/sys/ddb/db_command.c	Fri Mar 16 04:44:51 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: db_command.c,v 1.150 2018/03/16 04:37:55 ozaki-r Exp $	*/
+/*	$NetBSD: db_command.c,v 1.151 2018/03/16 04:44:51 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2009 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.150 2018/03/16 04:37:55 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_command.c,v 1.151 2018/03/16 04:44:51 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_aio.h"
@@ -190,6 +190,7 @@ static void	db_event_print_cmd(db_expr_t
 static void	db_fncall(db_expr_t, bool, db_expr_t, const char *);
 static void     db_help_print_cmd(db_expr_t, bool, db_expr_t, const char *);
 static void	db_lock_print_cmd(db_expr_t, bool, db_expr_t, const char *);
+static void	db_show_all_locks(db_expr_t, bool, db_expr_t, const char *);
 static void	db_show_lockstat(db_expr_t, bool, db_expr_t, const char *);
 static void	db_mount_print_cmd(db_expr_t, bool, db_expr_t, const char *);
 static void	db_mbuf_print_cmd(db_expr_t, bool, db_expr_t, const char *);
@@ -226,6 +227,8 @@ static const struct db_command db_show_c
 	    0 ,"List all processes.",NULL,NULL) },
 	{ DDB_ADD_CMD("pools",	db_show_all_pools,
 	    0 ,"Show all pools",NULL,NULL) },
+	{ DDB_ADD_CMD("locks",	db_show_all_locks,
+	    0 ,"Show all held locks", "[/t]", NULL) },
 #ifdef AIO
 	/*added from all sub cmds*/
 	{ DDB_ADD_CMD("aio_jobs",	db_show_aio_jobs,	0,
@@ -1231,6 +1234,16 @@ db_lock_print_cmd(db_expr_t addr, bool h
 }
 
 static void
+db_show_all_locks(db_expr_t addr, bool have_addr,
+    db_expr_t count, const char *modif)
+{
+
+#ifdef _KERNEL	/* XXX CRASH(8) */
+	lockdebug_show_all_locks(db_printf, modif);
+#endif
+}
+
+static void
 db_show_lockstat(db_expr_t addr, bool have_addr,
     db_expr_t count, const char *modif)
 {

Index: src/sys/kern/subr_lockdebug.c
diff -u src/sys/kern/subr_lockdebug.c:1.61 src/sys/kern/subr_lockdebug.c:1.62
--- src/sys/kern/subr_lockdebug.c:1.61	Fri Mar 16 04:43:37 2018
+++ src/sys/kern/subr_lockdebug.c	Fri Mar 16 04:44:51 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_lockdebug.c,v 1.61 2018/03/16 04:43:37 ozaki-r Exp $	*/
+/*	$NetBSD: subr_lockdebug.c,v 1.62 2018/03/16 04:44:51 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_lockdebug.c,v 1.61 2018/03/16 04:43:37 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_lockdebug.c,v 1.62 2018/03/16 04:44:51 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -51,6 +51,7 @@ __KERNEL_RCSID(0, "$NetBSD: subr_lockdeb
 #include <sys/atomic.h>
 #include <sys/lock.h>
 #include <sys/rbtree.h>
+#include <sys/ksyms.h>
 
 #include <machine/lock.h>
 
@@ -815,6 +816,9 @@ lockdebug_abort1(const char *func, size_
  *	Handle the DDB 'show lock' command.
  */
 #ifdef DDB
+#include <machine/db_machdep.h>
+#include <ddb/db_interface.h>
+
 void
 lockdebug_lock_print(void *addr, void (*pr)(const char *, ...))
 {
@@ -839,6 +843,93 @@ lockdebug_lock_print(void *addr, void (*
 #endif	/* LOCKDEBUG */
 }
 
+#ifdef LOCKDEBUG
+static void
+lockdebug_show_all_locks_lwp(void (*pr)(const char *, ...), bool show_trace)
+{
+	struct proc *p;
+
+	LIST_FOREACH(p, &allproc, p_list) {
+		struct lwp *l;
+		LIST_FOREACH(l, &p->p_lwps, l_sibling) {
+			lockdebug_t *ld;
+			const char *sym;
+			int i = 0;
+			if (TAILQ_EMPTY(&l->l_ld_locks))
+				continue;
+			(*pr)("Locks held by an LWP (%s):\n",
+			    l->l_name ? l->l_name : p->p_comm);
+			TAILQ_FOREACH(ld, &l->l_ld_locks, ld_chain) {
+				ksyms_getname(NULL, &sym,
+				    (vaddr_t)ld->ld_initaddr,
+				    KSYMS_CLOSEST|KSYMS_PROC|KSYMS_ANY);
+				(*pr)("Initialized at %s\n", sym);
+				(*pr)("Lock %d (initialized at %s)\n", i++, sym);
+				lockdebug_dump(ld, pr);
+			}
+			if (show_trace) {
+				db_stack_trace_print((db_expr_t)(intptr_t)l,
+				    true,
+				    32 /* Limit just in case */,
+				    "a", pr);
+			}
+			(*pr)("\n");
+		}
+	}
+}
+
+static void
+lockdebug_show_all_locks_cpu(void (*pr)(const char *, ...), bool show_trace)
+{
+	lockdebug_t *ld;
+	CPU_INFO_ITERATOR cii;
+	struct cpu_info *ci;
+	const char *sym;
+
+	for (CPU_INFO_FOREACH(cii, ci)) {
+		int i = 0;
+		if (TAILQ_EMPTY(&ci->ci_data.cpu_ld_locks))
+			continue;
+		(*pr)("Locks held on CPU %u:\n", ci->ci_index);
+		TAILQ_FOREACH(ld, &ci->ci_data.cpu_ld_locks, ld_chain) {
+			ksyms_getname(NULL, &sym,
+			    (vaddr_t)ld->ld_initaddr,
+			    KSYMS_CLOSEST|KSYMS_PROC|KSYMS_ANY);
+			(*pr)("Lock %d (initialized at %s)\n", i++, sym);
+			lockdebug_dump(ld, pr);
+			if (show_trace) {
+				db_stack_trace_print(
+				    (db_expr_t)(intptr_t)ci->ci_curlwp,
+				    true,
+				    32 /* Limit just in case */,
+				    "a", pr);
+			}
+			(*pr)("\n");
+		}
+	}
+}
+#endif	/* LOCKDEBUG */
+
+void
+lockdebug_show_all_locks(void (*pr)(const char *, ...), const char *modif)
+{
+#ifdef LOCKDEBUG
+	bool show_trace = false;
+	if (modif[0] == 't')
+		show_trace = true;
+
+	(*pr)("[Locks tracked through LWPs]\n");
+	lockdebug_show_all_locks_lwp(pr, show_trace);
+	(*pr)("\n");
+
+	(*pr)("[Locks tracked through CPUs]\n");
+	lockdebug_show_all_locks_cpu(pr, show_trace);
+	(*pr)("\n");
+#else
+	(*pr)("Sorry, kernel not built with the LOCKDEBUG option.\n");
+#endif	/* LOCKDEBUG */
+}
+
 void
 lockdebug_show_lockstat(void (*pr)(const char *, ...))
 {

Index: src/sys/sys/lockdebug.h
diff -u src/sys/sys/lockdebug.h:1.17 src/sys/sys/lockdebug.h:1.18
--- src/sys/sys/lockdebug.h:1.17	Fri Mar 16 04:37:55 2018
+++ src/sys/sys/lockdebug.h	Fri Mar 16 04:44:51 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: lockdebug.h,v 1.17 2018/03/16 04:37:55 ozaki-r Exp $	*/
+/*	$NetBSD: lockdebug.h,v 1.18 2018/03/16 04:44:51 ozaki-r Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -58,6 +58,8 @@ void	lockdebug_abort(const char *, size_
 
 void	lockdebug_lock_print(void *, void (*)(const char *, ...)
     __printflike(1, 2));
+void	lockdebug_show_all_locks(void (*)(const char *, ...) __printflike(1, 2),
+	    const char *);
 void	lockdebug_show_lockstat(void (*)(const char *, ...) __printflike(1, 2));
 
 #ifdef LOCKDEBUG

Reply via email to