Index: share/man/man4/witness.4 =================================================================== --- share/man/man4/witness.4 +++ share/man/man4/witness.4 @@ -112,6 +112,23 @@ set via the read-only sysctl .Va debug.witness.skipspin . .Pp +If +.Xr ddb 4 +and +.Xr stack 9 +support is built into the kernel, some of the invariants are printed out with +.Xr log 9 . +The +.Xr log 9 +priority can be adjusted via +.Va debug.witness.log_priority +using either the sysctl or +.Xr loader 8 +interface. +.Va debug.witness.log_priority +defaults to +.Dv LOG_DEBUG . +.Pp The sysctl .Va debug.witness.watch specifies the level of witness involvement in the system. Index: sys/kern/subr_kdb.c =================================================================== --- sys/kern/subr_kdb.c +++ sys/kern/subr_kdb.c @@ -27,6 +27,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" #include "opt_kdb.h" #include "opt_stack.h" @@ -381,6 +382,25 @@ #endif } +/* This functionality requires DDB for stack_sbuf_print_ddb */ +void +kdb_log_backtrace(int log_priority) +{ +#if defined(DDB) && defined(STACK) + struct stack st; + struct sbuf *sb; + + sb = sbuf_new_auto(); + + stack_zero(&st); + stack_save(&st); + stack_sbuf_print_ddb(sb, &st); + sbuf_finish(sb); + log(log_priority, "KDB: stack backtrace:\n%s", sbuf_data(sb)); + sbuf_delete(sb); +#endif +} + /* * Similar to kdb_backtrace() except that it prints a backtrace of an * arbitrary thread rather than the calling thread. Index: sys/kern/subr_witness.c =================================================================== --- sys/kern/subr_witness.c +++ sys/kern/subr_witness.c @@ -106,6 +106,7 @@ #include #include #include +#include #include #ifdef DDB @@ -420,6 +421,30 @@ SYSCTL_INT(_debug_witness, OID_AUTO, witness_count, CTLFLAG_RDTUN, &witness_count, 0, ""); +static int witness_log_priority_level = LOG_DEBUG; + +static int +sysctl_debug_witness_log_priority(SYSCTL_HANDLER_ARGS) +{ + int error, value; + + value = witness_log_priority_level; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if (value < LOG_EMERG || value > LOG_DEBUG) + return (EINVAL); + + witness_log_priority_level = value; + + return (0); +} + +SYSCTL_PROC(_debug_witness, OID_AUTO, log_priority, + CTLTYPE_INT | CTLFLAG_RWTUN, + NULL, 0, sysctl_debug_witness_log_priority, "I", + "log priority applied to witness messages"); + /* * Call this to print out the relations between locks. */ @@ -793,6 +818,10 @@ w = w1; } } + + witness_log_priority_level = + max(LOG_EMERG, min(witness_log_priority_level, LOG_DEBUG)); + witness_spin_warn = 1; /* Iterate through all locks and add them to witness. */ @@ -1114,19 +1143,23 @@ if (lock1 != NULL) { if ((lock1->li_flags & LI_EXCLUSIVE) != 0 && (flags & LOP_EXCLUSIVE) == 0) { - printf("shared lock of (%s) %s @ %s:%d\n", + log(witness_log_priority_level, + "shared lock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); - printf("while exclusively locked from %s:%d\n", + log(witness_log_priority_level, + "while exclusively locked from %s:%d\n", fixup_filename(lock1->li_file), lock1->li_line); kassert_panic("excl->share"); } if ((lock1->li_flags & LI_EXCLUSIVE) == 0 && (flags & LOP_EXCLUSIVE) != 0) { - printf("exclusive lock of (%s) %s @ %s:%d\n", + log(witness_log_priority_level, + "exclusive lock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); - printf("while share locked from %s:%d\n", + log(witness_log_priority_level, + "while share locked from %s:%d\n", fixup_filename(lock1->li_file), lock1->li_line); kassert_panic("share->excl"); } @@ -1190,12 +1223,14 @@ w_rmatrix[i][i] |= WITNESS_REVERSAL; w->w_reversed = 1; mtx_unlock_spin(&w_mtx); - printf( + log(witness_log_priority_level, "acquiring duplicate lock of same type: \"%s\"\n", w->w_name); - printf(" 1st %s @ %s:%d\n", plock->li_lock->lo_name, + log(witness_log_priority_level, " 1st %s @ %s:%d\n", + plock->li_lock->lo_name, fixup_filename(plock->li_file), plock->li_line); - printf(" 2nd %s @ %s:%d\n", lock->lo_name, + log(witness_log_priority_level, " 2nd %s @ %s:%d\n", + lock->lo_name, fixup_filename(file), line); witness_debugger(1); } else @@ -1319,14 +1354,14 @@ */ if (((lock->lo_flags & LO_SLEEPABLE) != 0 && (lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0)) - printf( + log(witness_log_priority_level, "lock order reversal: (sleepable after non-sleepable)\n"); else if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) == 0 && lock == &Giant.lock_object) - printf( + log(witness_log_priority_level, "lock order reversal: (Giant after non-sleepable)\n"); else - printf("lock order reversal:\n"); + log(witness_log_priority_level, "lock order reversal:\n"); /* * Try to locate an earlier lock with @@ -1345,24 +1380,29 @@ i--; } while (i >= 0); if (i < 0) { - printf(" 1st %p %s (%s) @ %s:%d\n", + log(witness_log_priority_level, + " 1st %p %s (%s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, w1->w_name, fixup_filename(lock1->li_file), lock1->li_line); - printf(" 2nd %p %s (%s) @ %s:%d\n", lock, + log(witness_log_priority_level, + " 2nd %p %s (%s) @ %s:%d\n", lock, lock->lo_name, w->w_name, fixup_filename(file), line); } else { - printf(" 1st %p %s (%s) @ %s:%d\n", + log(witness_log_priority_level, + " 1st %p %s (%s) @ %s:%d\n", lock2->li_lock, lock2->li_lock->lo_name, lock2->li_lock->lo_witness->w_name, fixup_filename(lock2->li_file), lock2->li_line); - printf(" 2nd %p %s (%s) @ %s:%d\n", + log(witness_log_priority_level, + " 2nd %p %s (%s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, w1->w_name, fixup_filename(lock1->li_file), lock1->li_line); - printf(" 3rd %p %s (%s) @ %s:%d\n", lock, + log(witness_log_priority_level, + " 3rd %p %s (%s) @ %s:%d\n", lock, lock->lo_name, w->w_name, fixup_filename(file), line); } @@ -1584,17 +1624,21 @@ /* First, check for shared/exclusive mismatches. */ if ((instance->li_flags & LI_EXCLUSIVE) != 0 && witness_watch > 0 && (flags & LOP_EXCLUSIVE) == 0) { - printf("shared unlock of (%s) %s @ %s:%d\n", class->lc_name, + log(witness_log_priority_level, + "shared unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); - printf("while exclusively locked from %s:%d\n", + log(witness_log_priority_level, + "while exclusively locked from %s:%d\n", fixup_filename(instance->li_file), instance->li_line); kassert_panic("excl->ushare"); } if ((instance->li_flags & LI_EXCLUSIVE) == 0 && witness_watch > 0 && (flags & LOP_EXCLUSIVE) != 0) { - printf("exclusive unlock of (%s) %s @ %s:%d\n", class->lc_name, + log(witness_log_priority_level, + "exclusive unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); - printf("while share locked from %s:%d\n", + log(witness_log_priority_level, + "while share locked from %s:%d\n", fixup_filename(instance->li_file), instance->li_line); kassert_panic("share->uexcl"); @@ -1609,7 +1653,8 @@ } /* The lock is now being dropped, check for NORELEASE flag */ if ((instance->li_flags & LI_NORELEASE) != 0 && witness_watch > 0) { - printf("forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name, + log(witness_log_priority_level, + "forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name, lock->lo_name, fixup_filename(file), line); kassert_panic("lock marked norelease"); } @@ -1660,7 +1705,8 @@ for (n = 0; lle != NULL; lle = lle->ll_next) for (i = lle->ll_count - 1; i >= 0; i--) { if (n == 0) - printf("Thread %p exiting with the following locks held:\n", + log(witness_log_priority_level, + "Thread %p exiting with the following locks held:\n", td); n++; witness_list_lock(&lle->ll_children[i], printf); @@ -2068,7 +2114,7 @@ if (STAILQ_EMPTY(&w_free)) { witness_watch = -1; mtx_unlock_spin(&w_mtx); - printf("WITNESS: unable to allocate a new witness object\n"); + log(LOG_WARNING, "WITNESS: unable to allocate a new witness object\n"); return (NULL); } w = STAILQ_FIRST(&w_free); @@ -2104,7 +2150,7 @@ if (lle == NULL) { witness_watch = -1; mtx_unlock_spin(&w_mtx); - printf("%s: witness exhausted\n", __func__); + log(LOG_WARNING, "%s: witness exhausted\n", __func__); return (NULL); } w_lock_list_free = lle->ll_next; @@ -2904,8 +2950,13 @@ _witness_debugger(int cond, const char *msg) { - if (witness_trace && cond) + if (witness_trace && cond) { +#ifdef DDB + kdb_log_backtrace(witness_log_priority_level); +#else kdb_backtrace(); +#endif + } if (witness_kdb && cond) kdb_enter(KDB_WHY_WITNESS, msg); } Index: sys/sys/kdb.h =================================================================== --- sys/sys/kdb.h +++ sys/sys/kdb.h @@ -75,6 +75,7 @@ void kdb_enter(const char *, const char *); void kdb_init(void); void * kdb_jmpbuf(jmp_buf); +void kdb_log_backtrace(int); void kdb_panic(const char *); void kdb_reboot(void); void kdb_reenter(void);