diff options
author | Visa Hankala <visa@cvs.openbsd.org> | 2018-05-16 14:53:44 +0000 |
---|---|---|
committer | Visa Hankala <visa@cvs.openbsd.org> | 2018-05-16 14:53:44 +0000 |
commit | 4f333c3b2e0f1d3454aee26e003bf33ec0fdcdb5 (patch) | |
tree | e9351725d004a27632843811a7a62952119adcba /sys/kern | |
parent | d3cb355fa2aa377efebbeeeb7f9d2cd732761849 (diff) |
Add kern.witnesswatch sysctl for controlling witness(4). By default,
lock order checking is disabled but it can be enabled at runtime.
Suggested by deraadt@ / mpi@
OK mpi@
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_sysctl.c | 7 | ||||
-rw-r--r-- | sys/kern/subr_witness.c | 65 |
2 files changed, 58 insertions, 14 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 56134f4d597..439fa57fe7d 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.336 2018/05/08 14:15:30 mpi Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.337 2018/05/16 14:53:43 visa Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -79,6 +79,7 @@ #include <sys/sched.h> #include <sys/mount.h> #include <sys/syscallargs.h> +#include <sys/witness.h> #include <uvm/uvm_extern.h> @@ -650,6 +651,10 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, dnsjackport = port; return 0; } +#ifdef WITNESS + case KERN_WITNESSWATCH: + return witness_sysctl_watch(oldp, oldlenp, newp, newlen); +#endif default: return (EOPNOTSUPP); } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 38999b97971..e47ea4a5b13 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_witness.c,v 1.13 2018/05/09 03:43:45 visa Exp $ */ +/* $OpenBSD: subr_witness.c,v 1.14 2018/05/16 14:53:43 visa Exp $ */ /*- * Copyright (c) 2008 Isilon Systems, Inc. @@ -333,7 +333,7 @@ static void witness_ddb_display_list(int(*prnt)(const char *fmt, ...), static void witness_ddb_level_descendants(struct witness *parent, int l); static void witness_ddb_list(struct proc *td); #endif -static void witness_debugger(int cond, const char *msg); +static void witness_debugger(int dump); static void witness_free(struct witness *m); static struct witness *witness_get(void); static uint32_t witness_hash_djb2(const uint8_t *key, uint32_t size); @@ -363,7 +363,11 @@ static void witness_setflag(struct lock_object *lock, int flag, int set); * may be toggled. However, witness cannot be reenabled once it is * completely disabled. */ -static int witness_watch = 1; +#ifdef WITNESS_WATCH +static int witness_watch = 3; +#else +static int witness_watch = 0; +#endif #ifdef WITNESS_SKIPSPIN int witness_skipspin = 1; @@ -875,7 +879,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file, fixup_filename(plock->li_file), plock->li_line); db_printf(" 2nd %s @ %s:%d\n", lock->lo_name, fixup_filename(file), line); - witness_debugger(1, __func__); + witness_debugger(1); } else mtx_leave(&w_mtx); goto out_splx; @@ -1035,7 +1039,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file, lock->lo_name, w->w_type->lt_name, fixup_filename(file), line); } - witness_debugger(1, __func__); + witness_debugger(0); goto out_splx; } } @@ -1404,10 +1408,12 @@ witness_warn(int flags, struct lock_object *lock, const char *fmt, ...) (flags & WARN_SLEEPOK) != 0 ? "non-sleepable " : ""); n += witness_list_locks(&lock_list, printf); } - if (flags & WARN_PANIC && n) - panic("%s", __func__); - else - witness_debugger(n, __func__); + if (n > 0) { + if (flags & WARN_PANIC) + panic("%s", __func__); + else + witness_debugger(1); + } return (n); } @@ -2460,10 +2466,43 @@ witness_increment_graph_generation(void) } static void -witness_debugger(int cond, const char *msg) +witness_debugger(int dump) { - if (!cond) - return; + switch (witness_watch) { + case 1: + break; + case 2: + if (dump) + db_stack_dump(); + break; + case 3: + if (dump) + db_stack_dump(); + db_enter(); + break; + default: + panic("witness: locking error"); + } +} + +int +witness_sysctl_watch(void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + int error; + int value; - db_enter(); + value = witness_watch; + error = sysctl_int(oldp, oldlenp, newp, newlen, &value); + if (error == 0 && newp != NULL) { + if (value >= -1 && value <= 3) { + mtx_enter(&w_mtx); + if (value < 0 || witness_watch >= 0) + witness_watch = value; + else + error = EINVAL; + mtx_leave(&w_mtx); + } else + error = EINVAL; + } + return (error); } |