Index: head/sys/kern/subr_witness.c =================================================================== --- head/sys/kern/subr_witness.c +++ head/sys/kern/subr_witness.c @@ -338,6 +338,7 @@ static void witness_ddb_level_descendants(struct witness *parent, int l); static void witness_ddb_list(struct thread *td); #endif +static void witness_enter_debugger(const char *msg); static void witness_debugger(int cond, const char *msg); static void witness_free(struct witness *m); static struct witness *witness_get(void); @@ -358,6 +359,8 @@ static void witness_list_lock(struct lock_instance *instance, int (*prnt)(const char *fmt, ...)); static int witness_output(const char *fmt, ...) __printflike(1, 2); +static int witness_output_drain(void *arg __unused, const char *data, + int len); static int witness_voutput(const char *fmt, va_list ap) __printflike(1, 0); static void witness_setflag(struct lock_object *lock, int flag, int set); @@ -1281,6 +1284,8 @@ for (j = 0, lle = lock_list; lle != NULL; lle = lle->ll_next) { for (i = lle->ll_count - 1; i >= 0; i--, j++) { + struct stack pstack; + bool pstackv, trace; MPASS(j < LOCK_CHILDCOUNT * LOCK_NCHILDREN); lock1 = &lle->ll_children[i]; @@ -1367,6 +1372,19 @@ */ if (blessed(w, w1)) goto out; + + trace = atomic_load_int(&witness_trace); + if (trace) { + struct witness_lock_order_data *data; + + pstackv = false; + data = witness_lock_order_get(w, w1); + if (data != NULL) { + stack_copy(&data->wlod_stack, + &pstack); + pstackv = true; + } + } mtx_unlock_spin(&w_mtx); #ifdef WITNESS_NO_VNODE @@ -1413,28 +1431,60 @@ i--; } while (i >= 0); if (i < 0) { - witness_output(" 1st %p %s (%s) @ %s:%d\n", + witness_output(" 1st %p %s (%s, %s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, - w1->w_name, fixup_filename(lock1->li_file), + w1->w_name, w1->w_class->lc_name, + fixup_filename(lock1->li_file), lock1->li_line); - witness_output(" 2nd %p %s (%s) @ %s:%d\n", lock, - lock->lo_name, w->w_name, - fixup_filename(file), line); + witness_output(" 2nd %p %s (%s, %s) @ %s:%d\n", + lock, lock->lo_name, w->w_name, + w->w_class->lc_name, fixup_filename(file), + line); } else { - witness_output(" 1st %p %s (%s) @ %s:%d\n", + struct witness *w2 = lock2->li_lock->lo_witness; + + witness_output(" 1st %p %s (%s, %s) @ %s:%d\n", lock2->li_lock, lock2->li_lock->lo_name, - lock2->li_lock->lo_witness->w_name, + w2->w_name, w2->w_class->lc_name, fixup_filename(lock2->li_file), lock2->li_line); - witness_output(" 2nd %p %s (%s) @ %s:%d\n", + witness_output(" 2nd %p %s (%s, %s) @ %s:%d\n", lock1->li_lock, lock1->li_lock->lo_name, - w1->w_name, fixup_filename(lock1->li_file), + w1->w_name, w1->w_class->lc_name, + fixup_filename(lock1->li_file), lock1->li_line); - witness_output(" 3rd %p %s (%s) @ %s:%d\n", lock, + witness_output(" 3rd %p %s (%s, %s) @ %s:%d\n", lock, lock->lo_name, w->w_name, - fixup_filename(file), line); + w->w_class->lc_name, fixup_filename(file), + line); } - witness_debugger(1, __func__); + if (trace) { + char buf[64]; + struct sbuf sb; + + sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); + sbuf_set_drain(&sb, witness_output_drain, + NULL); + + if (pstackv) { + sbuf_printf(&sb, + "lock order %s -> %s established at:\n", + w->w_name, w1->w_name); + stack_sbuf_print_flags(&sb, &pstack, + M_NOWAIT, STACK_SBUF_FMT_LONG); + } + + sbuf_printf(&sb, + "lock order %s -> %s attempted at:\n", + w1->w_name, w->w_name); + stack_save(&pstack); + stack_sbuf_print_flags(&sb, &pstack, M_NOWAIT, + STACK_SBUF_FMT_LONG); + + sbuf_finish(&sb); + sbuf_delete(&sb); + } + witness_enter_debugger(__func__); return; } } @@ -3085,6 +3135,12 @@ sbuf_finish(&sb); } + witness_enter_debugger(msg); +} + +static void +witness_enter_debugger(const char *msg) +{ #ifdef KDB if (witness_kdb) kdb_enter(KDB_WHY_WITNESS, msg);