10384fff8SJason Evans /*- 20384fff8SJason Evans * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved. 30384fff8SJason Evans * 40384fff8SJason Evans * Redistribution and use in source and binary forms, with or without 50384fff8SJason Evans * modification, are permitted provided that the following conditions 60384fff8SJason Evans * are met: 70384fff8SJason Evans * 1. Redistributions of source code must retain the above copyright 80384fff8SJason Evans * notice, this list of conditions and the following disclaimer. 90384fff8SJason Evans * 2. Redistributions in binary form must reproduce the above copyright 100384fff8SJason Evans * notice, this list of conditions and the following disclaimer in the 110384fff8SJason Evans * documentation and/or other materials provided with the distribution. 120384fff8SJason Evans * 3. Berkeley Software Design Inc's name may not be used to endorse or 130384fff8SJason Evans * promote products derived from this software without specific prior 140384fff8SJason Evans * written permission. 150384fff8SJason Evans * 160384fff8SJason Evans * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 170384fff8SJason Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180384fff8SJason Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190384fff8SJason Evans * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 200384fff8SJason Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210384fff8SJason Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220384fff8SJason Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230384fff8SJason Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240384fff8SJason Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250384fff8SJason Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260384fff8SJason Evans * SUCH DAMAGE. 270384fff8SJason Evans * 280384fff8SJason Evans * from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $ 290384fff8SJason Evans * $FreeBSD$ 300384fff8SJason Evans */ 310384fff8SJason Evans 320384fff8SJason Evans /* 330384fff8SJason Evans * Main Entry: witness 340384fff8SJason Evans * Pronunciation: 'wit-n&s 350384fff8SJason Evans * Function: noun 360384fff8SJason Evans * Etymology: Middle English witnesse, from Old English witnes knowledge, 370384fff8SJason Evans * testimony, witness, from 2wit 380384fff8SJason Evans * Date: before 12th century 390384fff8SJason Evans * 1 : attestation of a fact or event : TESTIMONY 400384fff8SJason Evans * 2 : one that gives evidence; specifically : one who testifies in 410384fff8SJason Evans * a cause or before a judicial tribunal 420384fff8SJason Evans * 3 : one asked to be present at a transaction so as to be able to 430384fff8SJason Evans * testify to its having taken place 440384fff8SJason Evans * 4 : one who has personal knowledge of something 450384fff8SJason Evans * 5 a : something serving as evidence or proof : SIGN 460384fff8SJason Evans * b : public affirmation by word or example of usually 470384fff8SJason Evans * religious faith or conviction <the heroic witness to divine 480384fff8SJason Evans * life -- Pilot> 490384fff8SJason Evans * 6 capitalized : a member of the Jehovah's Witnesses 500384fff8SJason Evans */ 510384fff8SJason Evans 520384fff8SJason Evans #include <sys/param.h> 530384fff8SJason Evans #include <sys/proc.h> 540384fff8SJason Evans #include <sys/systm.h> 550384fff8SJason Evans #include <sys/ktr.h> 560384fff8SJason Evans 570384fff8SJason Evans #include <machine/cpu.h> 580384fff8SJason Evans #define _KERN_MUTEX_C_ /* Cause non-inlined mtx_*() to be compiled. */ 590384fff8SJason Evans #include <machine/mutex.h> 600384fff8SJason Evans 610384fff8SJason Evans /* 620384fff8SJason Evans * The non-inlined versions of the mtx_*() functions are always built (above), 630384fff8SJason Evans * but the witness code depends on the SMP_DEBUG and WITNESS kernel options 640384fff8SJason Evans * being specified. 650384fff8SJason Evans */ 660384fff8SJason Evans #if (defined(SMP_DEBUG) && defined(WITNESS)) 670384fff8SJason Evans 680384fff8SJason Evans #define WITNESS_COUNT 200 690384fff8SJason Evans #define WITNESS_NCHILDREN 2 700384fff8SJason Evans 710384fff8SJason Evans #ifndef WITNESS 720384fff8SJason Evans #define WITNESS 0 /* default off */ 730384fff8SJason Evans #endif 740384fff8SJason Evans 750384fff8SJason Evans #ifndef SMP 760384fff8SJason Evans extern int witness_spin_check; 770384fff8SJason Evans #endif 780384fff8SJason Evans 790384fff8SJason Evans int witness_watch; 800384fff8SJason Evans 810384fff8SJason Evans typedef struct witness { 820384fff8SJason Evans struct witness *w_next; 830384fff8SJason Evans char *w_description; 840384fff8SJason Evans char *w_file; 850384fff8SJason Evans int w_line; 860384fff8SJason Evans struct witness *w_morechildren; 870384fff8SJason Evans u_char w_childcnt; 880384fff8SJason Evans u_char w_Giant_squawked:1; 890384fff8SJason Evans u_char w_other_squawked:1; 900384fff8SJason Evans u_char w_same_squawked:1; 910384fff8SJason Evans u_char w_sleep:1; 920384fff8SJason Evans u_char w_spin:1; /* this is a spin mutex */ 930384fff8SJason Evans u_int w_level; 940384fff8SJason Evans struct witness *w_children[WITNESS_NCHILDREN]; 950384fff8SJason Evans } witness_t; 960384fff8SJason Evans 970384fff8SJason Evans typedef struct witness_blessed { 980384fff8SJason Evans char *b_lock1; 990384fff8SJason Evans char *b_lock2; 1000384fff8SJason Evans } witness_blessed_t; 1010384fff8SJason Evans 1020384fff8SJason Evans #ifdef KDEBUG 1030384fff8SJason Evans /* 1040384fff8SJason Evans * When WITNESS_KDEBUG is set to 1, it will cause the system to 1050384fff8SJason Evans * drop into kdebug() when: 1060384fff8SJason Evans * - a lock heirarchy violation occurs 1070384fff8SJason Evans * - locks are held when going to sleep. 1080384fff8SJason Evans */ 1090384fff8SJason Evans #ifndef WITNESS_KDEBUG 1100384fff8SJason Evans #define WITNESS_KDEBUG 0 1110384fff8SJason Evans #endif 1120384fff8SJason Evans int witness_kdebug = WITNESS_KDEBUG; 1130384fff8SJason Evans #endif /* KDEBUG */ 1140384fff8SJason Evans 1150384fff8SJason Evans #ifndef WITNESS_SKIPSPIN 1160384fff8SJason Evans #define WITNESS_SKIPSPIN 0 1170384fff8SJason Evans #endif 1180384fff8SJason Evans int witness_skipspin = WITNESS_SKIPSPIN; 1190384fff8SJason Evans 1200384fff8SJason Evans 1210384fff8SJason Evans static mtx_t w_mtx; 1220384fff8SJason Evans static witness_t *w_free; 1230384fff8SJason Evans static witness_t *w_all; 1240384fff8SJason Evans static int w_inited; 1250384fff8SJason Evans static int witness_dead; /* fatal error, probably no memory */ 1260384fff8SJason Evans 1270384fff8SJason Evans static witness_t w_data[WITNESS_COUNT]; 1280384fff8SJason Evans 1290384fff8SJason Evans static witness_t *enroll __P((char *description, int flag)); 1300384fff8SJason Evans static int itismychild __P((witness_t *parent, witness_t *child)); 1310384fff8SJason Evans static void removechild __P((witness_t *parent, witness_t *child)); 1320384fff8SJason Evans static int isitmychild __P((witness_t *parent, witness_t *child)); 1330384fff8SJason Evans static int isitmydescendant __P((witness_t *parent, witness_t *child)); 1340384fff8SJason Evans static int dup_ok __P((witness_t *)); 1350384fff8SJason Evans static int blessed __P((witness_t *, witness_t *)); 1360384fff8SJason Evans static void witness_displaydescendants 1370384fff8SJason Evans __P((void(*)(const char *fmt, ...), witness_t *)); 1380384fff8SJason Evans static void witness_leveldescendents __P((witness_t *parent, int level)); 1390384fff8SJason Evans static void witness_levelall __P((void)); 1400384fff8SJason Evans static witness_t * witness_get __P((void)); 1410384fff8SJason Evans static void witness_free __P((witness_t *m)); 1420384fff8SJason Evans 1430384fff8SJason Evans 1440384fff8SJason Evans static char *ignore_list[] = { 1450384fff8SJason Evans "witness lock", 1460384fff8SJason Evans "Kdebug", /* breaks rules and may or may not work */ 1470384fff8SJason Evans "Page Alias", /* sparc only, witness lock won't block intr */ 1480384fff8SJason Evans NULL 1490384fff8SJason Evans }; 1500384fff8SJason Evans 1510384fff8SJason Evans static char *spin_order_list[] = { 1520384fff8SJason Evans "sched lock", 1530384fff8SJason Evans "log mtx", 1540384fff8SJason Evans "zslock", /* sparc only above log, this one is a real hack */ 1550384fff8SJason Evans "time lock", /* above callout */ 1560384fff8SJason Evans "callout mtx", /* above wayout */ 1570384fff8SJason Evans /* 1580384fff8SJason Evans * leaf locks 1590384fff8SJason Evans */ 1600384fff8SJason Evans "wayout mtx", 1610384fff8SJason Evans "kernel_pmap", /* sparc only, logically equal "pmap" below */ 1620384fff8SJason Evans "pmap", /* sparc only */ 1630384fff8SJason Evans NULL 1640384fff8SJason Evans }; 1650384fff8SJason Evans 1660384fff8SJason Evans static char *order_list[] = { 1670384fff8SJason Evans "tcb", "inp", "so_snd", "so_rcv", "Giant lock", NULL, 1680384fff8SJason Evans "udb", "inp", NULL, 1690384fff8SJason Evans "unp head", "unp", "so_snd", NULL, 1700384fff8SJason Evans "de0", "Giant lock", NULL, 1710384fff8SJason Evans "ifnet", "Giant lock", NULL, 1720384fff8SJason Evans "fifo", "so_snd", NULL, 1730384fff8SJason Evans "hme0", "Giant lock", NULL, 1740384fff8SJason Evans "esp0", "Giant lock", NULL, 1750384fff8SJason Evans "hfa0", "Giant lock", NULL, 1760384fff8SJason Evans "so_rcv", "atm_global", NULL, 1770384fff8SJason Evans "so_snd", "atm_global", NULL, 1780384fff8SJason Evans "NFS", "Giant lock", NULL, 1790384fff8SJason Evans NULL 1800384fff8SJason Evans }; 1810384fff8SJason Evans 1820384fff8SJason Evans static char *dup_list[] = { 1830384fff8SJason Evans "inp", 1840384fff8SJason Evans "process group", 1850384fff8SJason Evans "session", 1860384fff8SJason Evans "unp", 1870384fff8SJason Evans "rtentry", 1880384fff8SJason Evans "rawcb", 1890384fff8SJason Evans NULL 1900384fff8SJason Evans }; 1910384fff8SJason Evans 1920384fff8SJason Evans static char *sleep_list[] = { 1930384fff8SJason Evans "Giant lock", 1940384fff8SJason Evans NULL 1950384fff8SJason Evans }; 1960384fff8SJason Evans 1970384fff8SJason Evans /* 1980384fff8SJason Evans * Pairs of locks which have been blessed 1990384fff8SJason Evans * Don't complain about order problems with blessed locks 2000384fff8SJason Evans */ 2010384fff8SJason Evans static witness_blessed_t blessed_list[] = { 2020384fff8SJason Evans }; 2030384fff8SJason Evans static int blessed_count = sizeof (blessed_list) / sizeof (witness_blessed_t); 2040384fff8SJason Evans 2050384fff8SJason Evans void 2060384fff8SJason Evans witness_init(mtx_t *m, int flag) 2070384fff8SJason Evans { 2080384fff8SJason Evans m->mtx_witness = enroll(m->mtx_description, flag); 2090384fff8SJason Evans } 2100384fff8SJason Evans 2110384fff8SJason Evans void 2120384fff8SJason Evans witness_destroy(mtx_t *m) 2130384fff8SJason Evans { 2140384fff8SJason Evans mtx_t *m1; 2150384fff8SJason Evans struct proc *p; 2160384fff8SJason Evans p = CURPROC; 2170384fff8SJason Evans for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL; 2180384fff8SJason Evans m1 = LIST_NEXT(m1, mtx_held)) { 2190384fff8SJason Evans if (m1 == m) { 2200384fff8SJason Evans LIST_REMOVE(m, mtx_held); 2210384fff8SJason Evans break; 2220384fff8SJason Evans } 2230384fff8SJason Evans } 2240384fff8SJason Evans return; 2250384fff8SJason Evans 2260384fff8SJason Evans } 2270384fff8SJason Evans 2280384fff8SJason Evans void 2290384fff8SJason Evans witness_enter(mtx_t *m, int flags, char *file, int line) 2300384fff8SJason Evans { 2310384fff8SJason Evans witness_t *w, *w1; 2320384fff8SJason Evans mtx_t *m1; 2330384fff8SJason Evans struct proc *p; 2340384fff8SJason Evans int i; 2350384fff8SJason Evans #ifdef KDEBUG 2360384fff8SJason Evans int go_into_kdebug = 0; 2370384fff8SJason Evans #endif /* KDEBUG */ 2380384fff8SJason Evans 2390384fff8SJason Evans w = m->mtx_witness; 2400384fff8SJason Evans p = CURPROC; 2410384fff8SJason Evans 2420384fff8SJason Evans if (flags & MTX_SPIN) { 2430384fff8SJason Evans if (!w->w_spin) 2440384fff8SJason Evans panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @ %s:%d", 2450384fff8SJason Evans m->mtx_description, file, line); 2460384fff8SJason Evans if (m->mtx_recurse != 0) 2470384fff8SJason Evans return; 2480384fff8SJason Evans mtx_enter(&w_mtx, MTX_SPIN); 2490384fff8SJason Evans i = witness_spin_check; 2500384fff8SJason Evans if (i != 0 && w->w_level < i) { 2510384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 2520384fff8SJason Evans panic("mutex_enter(%s:%x, MTX_SPIN) out of order @ %s:%d" 2530384fff8SJason Evans " already holding %s:%x", 2540384fff8SJason Evans m->mtx_description, w->w_level, file, line, 2550384fff8SJason Evans spin_order_list[ffs(i)-1], i); 2560384fff8SJason Evans } 2570384fff8SJason Evans PCPU_SET(witness_spin_check, i | w->w_level); 2580384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 2590384fff8SJason Evans return; 2600384fff8SJason Evans } 2610384fff8SJason Evans if (w->w_spin) 2620384fff8SJason Evans panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 2630384fff8SJason Evans m->mtx_description, file, line); 2640384fff8SJason Evans 2650384fff8SJason Evans if (m->mtx_recurse != 0) 2660384fff8SJason Evans return; 2670384fff8SJason Evans if (witness_dead) 2680384fff8SJason Evans goto out; 2690384fff8SJason Evans if (cold) 2700384fff8SJason Evans goto out; 2710384fff8SJason Evans 2720384fff8SJason Evans if (!mtx_legal2block()) 2730384fff8SJason Evans panic("blockable mtx_enter() of %s when not legal @ %s:%d", 2740384fff8SJason Evans m->mtx_description, file, line); 2750384fff8SJason Evans /* 2760384fff8SJason Evans * Is this the first mutex acquired 2770384fff8SJason Evans */ 2780384fff8SJason Evans if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL) 2790384fff8SJason Evans goto out; 2800384fff8SJason Evans 2810384fff8SJason Evans 2820384fff8SJason Evans if ((w1 = m1->mtx_witness) == w) { 2830384fff8SJason Evans if (w->w_same_squawked || dup_ok(w)) 2840384fff8SJason Evans goto out; 2850384fff8SJason Evans w->w_same_squawked = 1; 2860384fff8SJason Evans printf("acquring duplicate lock of same type: \"%s\"\n", 2870384fff8SJason Evans m->mtx_description); 2880384fff8SJason Evans printf(" 1st @ %s:%d\n", w->w_file, w->w_line); 2890384fff8SJason Evans printf(" 2nd @ %s:%d\n", file, line); 2900384fff8SJason Evans #ifdef KDEBUG 2910384fff8SJason Evans go_into_kdebug = 1; 2920384fff8SJason Evans #endif /* KDEBUG */ 2930384fff8SJason Evans goto out; 2940384fff8SJason Evans } 2950384fff8SJason Evans MPASS(!mtx_owned(&w_mtx)); 2960384fff8SJason Evans mtx_enter(&w_mtx, MTX_SPIN); 2970384fff8SJason Evans /* 2980384fff8SJason Evans * If we have a known higher number just say ok 2990384fff8SJason Evans */ 3000384fff8SJason Evans if (witness_watch > 1 && w->w_level > w1->w_level) { 3010384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 3020384fff8SJason Evans goto out; 3030384fff8SJason Evans } 3040384fff8SJason Evans if (isitmydescendant(m1->mtx_witness, w)) { 3050384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 3060384fff8SJason Evans goto out; 3070384fff8SJason Evans } 3080384fff8SJason Evans for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) { 3090384fff8SJason Evans 3100384fff8SJason Evans ASS(i < 200); 3110384fff8SJason Evans w1 = m1->mtx_witness; 3120384fff8SJason Evans if (isitmydescendant(w, w1)) { 3130384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 3140384fff8SJason Evans if (blessed(w, w1)) 3150384fff8SJason Evans goto out; 3160384fff8SJason Evans if (m1 == &Giant) { 3170384fff8SJason Evans if (w1->w_Giant_squawked) 3180384fff8SJason Evans goto out; 3190384fff8SJason Evans else 3200384fff8SJason Evans w1->w_Giant_squawked = 1; 3210384fff8SJason Evans } else { 3220384fff8SJason Evans if (w1->w_other_squawked) 3230384fff8SJason Evans goto out; 3240384fff8SJason Evans else 3250384fff8SJason Evans w1->w_other_squawked = 1; 3260384fff8SJason Evans } 3270384fff8SJason Evans printf("lock order reversal\n"); 3280384fff8SJason Evans printf(" 1st %s last acquired @ %s:%d\n", 3290384fff8SJason Evans w->w_description, w->w_file, w->w_line); 3300384fff8SJason Evans printf(" 2nd %p %s @ %s:%d\n", 3310384fff8SJason Evans m1, w1->w_description, w1->w_file, w1->w_line); 3320384fff8SJason Evans printf(" 3rd %p %s @ %s:%d\n", 3330384fff8SJason Evans m, w->w_description, file, line); 3340384fff8SJason Evans #ifdef KDEBUG 3350384fff8SJason Evans go_into_kdebug = 1; 3360384fff8SJason Evans #endif /* KDEBUG */ 3370384fff8SJason Evans goto out; 3380384fff8SJason Evans } 3390384fff8SJason Evans } 3400384fff8SJason Evans m1 = LIST_FIRST(&p->p_heldmtx); 3410384fff8SJason Evans if (!itismychild(m1->mtx_witness, w)) 3420384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 3430384fff8SJason Evans 3440384fff8SJason Evans out: 3450384fff8SJason Evans #ifdef KDEBUG 3460384fff8SJason Evans if (witness_kdebug && go_into_kdebug) 3470384fff8SJason Evans kdebug(); 3480384fff8SJason Evans #endif /* KDEBUG */ 3490384fff8SJason Evans w->w_file = file; 3500384fff8SJason Evans w->w_line = line; 3510384fff8SJason Evans m->mtx_line = line; 3520384fff8SJason Evans m->mtx_file = file; 3530384fff8SJason Evans 3540384fff8SJason Evans /* 3550384fff8SJason Evans * If this pays off it likely means that a mutex being witnessed 3560384fff8SJason Evans * is acquired in hardclock. Put it in the ignore list. It is 3570384fff8SJason Evans * likely not the mutex this assert fails on. 3580384fff8SJason Evans */ 3590384fff8SJason Evans ASS(m->mtx_held.le_prev == NULL); 3600384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 3610384fff8SJason Evans } 3620384fff8SJason Evans 3630384fff8SJason Evans void 3640384fff8SJason Evans witness_exit(mtx_t *m, int flags, char *file, int line) 3650384fff8SJason Evans { 3660384fff8SJason Evans witness_t *w; 3670384fff8SJason Evans 3680384fff8SJason Evans w = m->mtx_witness; 3690384fff8SJason Evans 3700384fff8SJason Evans if (flags & MTX_SPIN) { 3710384fff8SJason Evans if (!w->w_spin) 3720384fff8SJason Evans panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @ %s:%d", 3730384fff8SJason Evans m->mtx_description, file, line); 3740384fff8SJason Evans if (m->mtx_recurse != 0) 3750384fff8SJason Evans return; 3760384fff8SJason Evans mtx_enter(&w_mtx, MTX_SPIN); 3770384fff8SJason Evans PCPU_SET(witness_spin_check, witness_spin_check & ~w->w_level); 3780384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 3790384fff8SJason Evans return; 3800384fff8SJason Evans } 3810384fff8SJason Evans if (w->w_spin) 3820384fff8SJason Evans panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 3830384fff8SJason Evans m->mtx_description, file, line); 3840384fff8SJason Evans 3850384fff8SJason Evans if (m->mtx_recurse != 0) 3860384fff8SJason Evans return; 3870384fff8SJason Evans 3880384fff8SJason Evans if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold) 3890384fff8SJason Evans panic("switchable mtx_exit() of %s when not legal @ %s:%d", 3900384fff8SJason Evans m->mtx_description, file, line); 3910384fff8SJason Evans LIST_REMOVE(m, mtx_held); 3920384fff8SJason Evans m->mtx_held.le_prev = NULL; 3930384fff8SJason Evans } 3940384fff8SJason Evans 3950384fff8SJason Evans void 3960384fff8SJason Evans witness_try_enter(mtx_t *m, int flags, char *file, int line) 3970384fff8SJason Evans { 3980384fff8SJason Evans struct proc *p; 3990384fff8SJason Evans witness_t *w = m->mtx_witness; 4000384fff8SJason Evans 4010384fff8SJason Evans 4020384fff8SJason Evans if (flags & MTX_SPIN) { 4030384fff8SJason Evans if (!w->w_spin) 4040384fff8SJason Evans panic("mutex_try_enter: " 4050384fff8SJason Evans "MTX_SPIN on MTX_DEF mutex %s @ %s:%d", 4060384fff8SJason Evans m->mtx_description, file, line); 4070384fff8SJason Evans if (m->mtx_recurse != 0) 4080384fff8SJason Evans return; 4090384fff8SJason Evans mtx_enter(&w_mtx, MTX_SPIN); 4100384fff8SJason Evans PCPU_SET(witness_spin_check, witness_spin_check | w->w_level); 4110384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 4120384fff8SJason Evans return; 4130384fff8SJason Evans } 4140384fff8SJason Evans 4150384fff8SJason Evans if (w->w_spin) 4160384fff8SJason Evans panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 4170384fff8SJason Evans m->mtx_description, file, line); 4180384fff8SJason Evans 4190384fff8SJason Evans if (m->mtx_recurse != 0) 4200384fff8SJason Evans return; 4210384fff8SJason Evans 4220384fff8SJason Evans w->w_file = file; 4230384fff8SJason Evans w->w_line = line; 4240384fff8SJason Evans m->mtx_line = line; 4250384fff8SJason Evans m->mtx_file = file; 4260384fff8SJason Evans p = CURPROC; 4270384fff8SJason Evans ASS(m->mtx_held.le_prev == NULL); 4280384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 4290384fff8SJason Evans } 4300384fff8SJason Evans 4310384fff8SJason Evans void 4320384fff8SJason Evans witness_display(void(*prnt)(const char *fmt, ...)) 4330384fff8SJason Evans { 4340384fff8SJason Evans witness_t *w, *w1; 4350384fff8SJason Evans 4360384fff8SJason Evans witness_levelall(); 4370384fff8SJason Evans 4380384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 4390384fff8SJason Evans if (w->w_file == NULL) 4400384fff8SJason Evans continue; 4410384fff8SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 4420384fff8SJason Evans if (isitmychild(w1, w)) 4430384fff8SJason Evans break; 4440384fff8SJason Evans } 4450384fff8SJason Evans if (w1 != NULL) 4460384fff8SJason Evans continue; 4470384fff8SJason Evans /* 4480384fff8SJason Evans * This lock has no anscestors, display its descendants. 4490384fff8SJason Evans */ 4500384fff8SJason Evans witness_displaydescendants(prnt, w); 4510384fff8SJason Evans } 4520384fff8SJason Evans prnt("\nMutex which were never acquired\n"); 4530384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 4540384fff8SJason Evans if (w->w_file != NULL) 4550384fff8SJason Evans continue; 4560384fff8SJason Evans prnt("%s\n", w->w_description); 4570384fff8SJason Evans } 4580384fff8SJason Evans } 4590384fff8SJason Evans 4600384fff8SJason Evans int 4610384fff8SJason Evans witness_sleep(int check_only, mtx_t *mtx, char *file, int line) 4620384fff8SJason Evans { 4630384fff8SJason Evans mtx_t *m; 4640384fff8SJason Evans struct proc *p; 4650384fff8SJason Evans char **sleep; 4660384fff8SJason Evans int n = 0; 4670384fff8SJason Evans 4680384fff8SJason Evans p = CURPROC; 4690384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 4700384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 4710384fff8SJason Evans if (m == mtx) 4720384fff8SJason Evans continue; 4730384fff8SJason Evans for (sleep = sleep_list; *sleep!= NULL; sleep++) 4740384fff8SJason Evans if (strcmp(m->mtx_description, *sleep) == 0) 4750384fff8SJason Evans goto next; 4760384fff8SJason Evans printf("%s:%d: %s with \"%s\" locked from %s:%d\n", 4770384fff8SJason Evans file, line, check_only ? "could sleep" : "sleeping", 4780384fff8SJason Evans m->mtx_description, 4790384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 4800384fff8SJason Evans n++; 4810384fff8SJason Evans next: 4820384fff8SJason Evans } 4830384fff8SJason Evans #ifdef KDEBUG 4840384fff8SJason Evans if (witness_kdebug && n) 4850384fff8SJason Evans kdebug(); 4860384fff8SJason Evans #endif /* KDEBUG */ 4870384fff8SJason Evans return (n); 4880384fff8SJason Evans } 4890384fff8SJason Evans 4900384fff8SJason Evans static witness_t * 4910384fff8SJason Evans enroll(char *description, int flag) 4920384fff8SJason Evans { 4930384fff8SJason Evans int i; 4940384fff8SJason Evans witness_t *w, *w1; 4950384fff8SJason Evans char **ignore; 4960384fff8SJason Evans char **order; 4970384fff8SJason Evans 4980384fff8SJason Evans if (!witness_watch) 4990384fff8SJason Evans return (NULL); 5000384fff8SJason Evans for (ignore = ignore_list; *ignore != NULL; ignore++) 5010384fff8SJason Evans if (strcmp(description, *ignore) == 0) 5020384fff8SJason Evans return (NULL); 5030384fff8SJason Evans 5040384fff8SJason Evans if (w_inited == 0) { 5050384fff8SJason Evans mtx_init(&w_mtx, "witness lock", MTX_DEF); 5060384fff8SJason Evans for (i = 0; i < WITNESS_COUNT; i++) { 5070384fff8SJason Evans w = &w_data[i]; 5080384fff8SJason Evans witness_free(w); 5090384fff8SJason Evans } 5100384fff8SJason Evans w_inited = 1; 5110384fff8SJason Evans for (order = order_list; *order != NULL; order++) { 5120384fff8SJason Evans w = enroll(*order, MTX_DEF); 5130384fff8SJason Evans w->w_file = "order list"; 5140384fff8SJason Evans for (order++; *order != NULL; order++) { 5150384fff8SJason Evans w1 = enroll(*order, MTX_DEF); 5160384fff8SJason Evans w1->w_file = "order list"; 5170384fff8SJason Evans itismychild(w, w1); 5180384fff8SJason Evans w = w1; 5190384fff8SJason Evans } 5200384fff8SJason Evans } 5210384fff8SJason Evans } 5220384fff8SJason Evans if ((flag & MTX_SPIN) && witness_skipspin) 5230384fff8SJason Evans return (NULL); 5240384fff8SJason Evans mtx_enter(&w_mtx, MTX_SPIN); 5250384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 5260384fff8SJason Evans if (strcmp(description, w->w_description) == 0) { 5270384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 5280384fff8SJason Evans return (w); 5290384fff8SJason Evans } 5300384fff8SJason Evans } 5310384fff8SJason Evans if ((w = witness_get()) == NULL) 5320384fff8SJason Evans return (NULL); 5330384fff8SJason Evans w->w_next = w_all; 5340384fff8SJason Evans w_all = w; 5350384fff8SJason Evans w->w_description = description; 5360384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 5370384fff8SJason Evans if (flag & MTX_SPIN) { 5380384fff8SJason Evans w->w_spin = 1; 5390384fff8SJason Evans 5400384fff8SJason Evans i = 1; 5410384fff8SJason Evans for (order = spin_order_list; *order != NULL; order++) { 5420384fff8SJason Evans if (strcmp(description, *order) == 0) 5430384fff8SJason Evans break; 5440384fff8SJason Evans i <<= 1; 5450384fff8SJason Evans } 5460384fff8SJason Evans if (*order == NULL) 5470384fff8SJason Evans panic("spin lock %s not in order list", description); 5480384fff8SJason Evans w->w_level = i; 5490384fff8SJason Evans } 5500384fff8SJason Evans return (w); 5510384fff8SJason Evans } 5520384fff8SJason Evans 5530384fff8SJason Evans static int 5540384fff8SJason Evans itismychild(witness_t *parent, witness_t *child) 5550384fff8SJason Evans { 5560384fff8SJason Evans static int recursed; 5570384fff8SJason Evans 5580384fff8SJason Evans /* 5590384fff8SJason Evans * Insert "child" after "parent" 5600384fff8SJason Evans */ 5610384fff8SJason Evans while (parent->w_morechildren) 5620384fff8SJason Evans parent = parent->w_morechildren; 5630384fff8SJason Evans 5640384fff8SJason Evans if (parent->w_childcnt == WITNESS_NCHILDREN) { 5650384fff8SJason Evans if ((parent->w_morechildren = witness_get()) == NULL) 5660384fff8SJason Evans return (1); 5670384fff8SJason Evans parent = parent->w_morechildren; 5680384fff8SJason Evans } 5690384fff8SJason Evans ASS(child != NULL); 5700384fff8SJason Evans parent->w_children[parent->w_childcnt++] = child; 5710384fff8SJason Evans /* 5720384fff8SJason Evans * now prune whole tree 5730384fff8SJason Evans */ 5740384fff8SJason Evans if (recursed) 5750384fff8SJason Evans return (0); 5760384fff8SJason Evans recursed = 1; 5770384fff8SJason Evans for (child = w_all; child != NULL; child = child->w_next) { 5780384fff8SJason Evans for (parent = w_all; parent != NULL; 5790384fff8SJason Evans parent = parent->w_next) { 5800384fff8SJason Evans if (!isitmychild(parent, child)) 5810384fff8SJason Evans continue; 5820384fff8SJason Evans removechild(parent, child); 5830384fff8SJason Evans if (isitmydescendant(parent, child)) 5840384fff8SJason Evans continue; 5850384fff8SJason Evans itismychild(parent, child); 5860384fff8SJason Evans } 5870384fff8SJason Evans } 5880384fff8SJason Evans recursed = 0; 5890384fff8SJason Evans witness_levelall(); 5900384fff8SJason Evans return (0); 5910384fff8SJason Evans } 5920384fff8SJason Evans 5930384fff8SJason Evans static void 5940384fff8SJason Evans removechild(witness_t *parent, witness_t *child) 5950384fff8SJason Evans { 5960384fff8SJason Evans witness_t *w, *w1; 5970384fff8SJason Evans int i; 5980384fff8SJason Evans 5990384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 6000384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 6010384fff8SJason Evans if (w->w_children[i] == child) 6020384fff8SJason Evans goto found; 6030384fff8SJason Evans return; 6040384fff8SJason Evans found: 6050384fff8SJason Evans for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren) 6060384fff8SJason Evans continue; 6070384fff8SJason Evans w->w_children[i] = w1->w_children[--w1->w_childcnt]; 6080384fff8SJason Evans ASS(w->w_children[i] != NULL); 6090384fff8SJason Evans 6100384fff8SJason Evans if (w1->w_childcnt != 0) 6110384fff8SJason Evans return; 6120384fff8SJason Evans 6130384fff8SJason Evans if (w1 == parent) 6140384fff8SJason Evans return; 6150384fff8SJason Evans for (w = parent; w->w_morechildren != w1; w = w->w_morechildren) 6160384fff8SJason Evans continue; 6170384fff8SJason Evans w->w_morechildren = 0; 6180384fff8SJason Evans witness_free(w1); 6190384fff8SJason Evans } 6200384fff8SJason Evans 6210384fff8SJason Evans static int 6220384fff8SJason Evans isitmychild(witness_t *parent, witness_t *child) 6230384fff8SJason Evans { 6240384fff8SJason Evans witness_t *w; 6250384fff8SJason Evans int i; 6260384fff8SJason Evans 6270384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) { 6280384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 6290384fff8SJason Evans if (w->w_children[i] == child) 6300384fff8SJason Evans return (1); 6310384fff8SJason Evans } 6320384fff8SJason Evans } 6330384fff8SJason Evans return (0); 6340384fff8SJason Evans } 6350384fff8SJason Evans 6360384fff8SJason Evans static int 6370384fff8SJason Evans isitmydescendant(witness_t *parent, witness_t *child) 6380384fff8SJason Evans { 6390384fff8SJason Evans witness_t *w; 6400384fff8SJason Evans int i; 6410384fff8SJason Evans int j; 6420384fff8SJason Evans 6430384fff8SJason Evans for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) { 6440384fff8SJason Evans ASS(j < 1000); 6450384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 6460384fff8SJason Evans if (w->w_children[i] == child) 6470384fff8SJason Evans return (1); 6480384fff8SJason Evans } 6490384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 6500384fff8SJason Evans if (isitmydescendant(w->w_children[i], child)) 6510384fff8SJason Evans return (1); 6520384fff8SJason Evans } 6530384fff8SJason Evans } 6540384fff8SJason Evans return (0); 6550384fff8SJason Evans } 6560384fff8SJason Evans 6570384fff8SJason Evans void 6580384fff8SJason Evans witness_levelall (void) 6590384fff8SJason Evans { 6600384fff8SJason Evans witness_t *w, *w1; 6610384fff8SJason Evans 6620384fff8SJason Evans for (w = w_all; w; w = w->w_next) 6630384fff8SJason Evans if (!w->w_spin) 6640384fff8SJason Evans w->w_level = 0; 6650384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 6660384fff8SJason Evans if (w->w_spin) 6670384fff8SJason Evans continue; 6680384fff8SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 6690384fff8SJason Evans if (isitmychild(w1, w)) 6700384fff8SJason Evans break; 6710384fff8SJason Evans } 6720384fff8SJason Evans if (w1 != NULL) 6730384fff8SJason Evans continue; 6740384fff8SJason Evans witness_leveldescendents(w, 0); 6750384fff8SJason Evans } 6760384fff8SJason Evans } 6770384fff8SJason Evans 6780384fff8SJason Evans static void 6790384fff8SJason Evans witness_leveldescendents(witness_t *parent, int level) 6800384fff8SJason Evans { 6810384fff8SJason Evans int i; 6820384fff8SJason Evans witness_t *w; 6830384fff8SJason Evans 6840384fff8SJason Evans if (parent->w_level < level) 6850384fff8SJason Evans parent->w_level = level; 6860384fff8SJason Evans level++; 6870384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 6880384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 6890384fff8SJason Evans witness_leveldescendents(w->w_children[i], level); 6900384fff8SJason Evans } 6910384fff8SJason Evans 6920384fff8SJason Evans static void 6930384fff8SJason Evans witness_displaydescendants(void(*prnt)(const char *fmt, ...), witness_t *parent) 6940384fff8SJason Evans { 6950384fff8SJason Evans witness_t *w; 6960384fff8SJason Evans int i; 6970384fff8SJason Evans int level = parent->w_level; 6980384fff8SJason Evans 6990384fff8SJason Evans prnt("%d", level); 7000384fff8SJason Evans if (level < 10) 7010384fff8SJason Evans prnt(" "); 7020384fff8SJason Evans for (i = 0; i < level; i++) 7030384fff8SJason Evans prnt(" "); 7040384fff8SJason Evans prnt("%s", parent->w_description); 7050384fff8SJason Evans if (parent->w_file != NULL) { 7060384fff8SJason Evans prnt(" -- last acquired @ %s", parent->w_file); 7070384fff8SJason Evans #ifndef W_USE_WHERE 7080384fff8SJason Evans prnt(":%d", parent->w_line); 7090384fff8SJason Evans #endif 7100384fff8SJason Evans prnt("\n"); 7110384fff8SJason Evans } 7120384fff8SJason Evans 7130384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 7140384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 7150384fff8SJason Evans witness_displaydescendants(prnt, w->w_children[i]); 7160384fff8SJason Evans } 7170384fff8SJason Evans 7180384fff8SJason Evans static int 7190384fff8SJason Evans dup_ok(witness_t *w) 7200384fff8SJason Evans { 7210384fff8SJason Evans char **dup; 7220384fff8SJason Evans 7230384fff8SJason Evans for (dup = dup_list; *dup!= NULL; dup++) 7240384fff8SJason Evans if (strcmp(w->w_description, *dup) == 0) 7250384fff8SJason Evans return (1); 7260384fff8SJason Evans return (0); 7270384fff8SJason Evans } 7280384fff8SJason Evans 7290384fff8SJason Evans static int 7300384fff8SJason Evans blessed(witness_t *w1, witness_t *w2) 7310384fff8SJason Evans { 7320384fff8SJason Evans int i; 7330384fff8SJason Evans witness_blessed_t *b; 7340384fff8SJason Evans 7350384fff8SJason Evans for (i = 0; i < blessed_count; i++) { 7360384fff8SJason Evans b = &blessed_list[i]; 7370384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock1) == 0) { 7380384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock2) == 0) 7390384fff8SJason Evans return (1); 7400384fff8SJason Evans continue; 7410384fff8SJason Evans } 7420384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock2) == 0) 7430384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock1) == 0) 7440384fff8SJason Evans return (1); 7450384fff8SJason Evans } 7460384fff8SJason Evans return (0); 7470384fff8SJason Evans } 7480384fff8SJason Evans 7490384fff8SJason Evans static witness_t * 7500384fff8SJason Evans witness_get() 7510384fff8SJason Evans { 7520384fff8SJason Evans witness_t *w; 7530384fff8SJason Evans 7540384fff8SJason Evans if ((w = w_free) == NULL) { 7550384fff8SJason Evans witness_dead = 1; 7560384fff8SJason Evans mtx_exit(&w_mtx, MTX_SPIN); 7570384fff8SJason Evans printf("witness exhausted\n"); 7580384fff8SJason Evans return (NULL); 7590384fff8SJason Evans } 7600384fff8SJason Evans w_free = w->w_next; 7610384fff8SJason Evans bzero(w, sizeof (*w)); 7620384fff8SJason Evans return (w); 7630384fff8SJason Evans } 7640384fff8SJason Evans 7650384fff8SJason Evans static void 7660384fff8SJason Evans witness_free(witness_t *w) 7670384fff8SJason Evans { 7680384fff8SJason Evans w->w_next = w_free; 7690384fff8SJason Evans w_free = w; 7700384fff8SJason Evans } 7710384fff8SJason Evans 7720384fff8SJason Evans void 7730384fff8SJason Evans witness_list(struct proc *p) 7740384fff8SJason Evans { 7750384fff8SJason Evans mtx_t *m; 7760384fff8SJason Evans 7770384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 7780384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 7790384fff8SJason Evans printf("\t\"%s\" (%p) locked at %s:%d\n", 7800384fff8SJason Evans m->mtx_description, m, 7810384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 7820384fff8SJason Evans } 7830384fff8SJason Evans } 7840384fff8SJason Evans 7850384fff8SJason Evans void 7860384fff8SJason Evans witness_save(mtx_t *m, char **filep, int *linep) 7870384fff8SJason Evans { 7880384fff8SJason Evans *filep = m->mtx_witness->w_file; 7890384fff8SJason Evans *linep = m->mtx_witness->w_line; 7900384fff8SJason Evans } 7910384fff8SJason Evans 7920384fff8SJason Evans void 7930384fff8SJason Evans witness_restore(mtx_t *m, char *file, int line) 7940384fff8SJason Evans { 7950384fff8SJason Evans m->mtx_witness->w_file = file; 7960384fff8SJason Evans m->mtx_witness->w_line = line; 7970384fff8SJason Evans } 7980384fff8SJason Evans 7990384fff8SJason Evans #endif /* (defined(SMP_DEBUG) && defined(WITNESS)) */ 800