Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Add a new command, show all locks, which shows information o...



details:   https://anonhg.NetBSD.org/src/rev/45ab65f03b40
branches:  trunk
changeset: 831194:45ab65f03b40
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Fri Mar 16 04:44:51 2018 +0000

description:
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.

diffstat:

 share/man/man4/ddb.4      |   9 +++-
 sys/ddb/db_command.c      |  17 +++++++-
 sys/kern/subr_lockdebug.c |  95 ++++++++++++++++++++++++++++++++++++++++++++++-
 sys/sys/lockdebug.h       |   4 +-
 4 files changed, 119 insertions(+), 6 deletions(-)

diffs (223 lines):

diff -r 9741d41eb7b3 -r 45ab65f03b40 share/man/man4/ddb.4
--- a/share/man/man4/ddb.4      Fri Mar 16 04:37:55 2018 +0000
+++ b/share/man/man4/ddb.4      Fri Mar 16 04:44:51 2018 +0000
@@ -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 @@
 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
diff -r 9741d41eb7b3 -r 45ab65f03b40 sys/ddb/db_command.c
--- a/sys/ddb/db_command.c      Fri Mar 16 04:37:55 2018 +0000
+++ b/sys/ddb/db_command.c      Fri Mar 16 04:44:51 2018 +0000
@@ -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_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 @@
            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 @@
 }
 
 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)
 {
diff -r 9741d41eb7b3 -r 45ab65f03b40 sys/kern/subr_lockdebug.c
--- a/sys/kern/subr_lockdebug.c Fri Mar 16 04:37:55 2018 +0000
+++ b/sys/kern/subr_lockdebug.c Fri Mar 16 04:44:51 2018 +0000
@@ -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 @@
 #include <sys/atomic.h>
 #include <sys/lock.h>
 #include <sys/rbtree.h>
+#include <sys/ksyms.h>
 
 #include <machine/lock.h>
 
@@ -815,6 +816,9 @@
  *     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 @@
 #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 *, ...))
 {
diff -r 9741d41eb7b3 -r 45ab65f03b40 sys/sys/lockdebug.h
--- a/sys/sys/lockdebug.h       Fri Mar 16 04:37:55 2018 +0000
+++ b/sys/sys/lockdebug.h       Fri Mar 16 04:44:51 2018 +0000
@@ -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_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



Home | Main Index | Thread Index | Old Index