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