xref: /freebsd/sys/kern/kern_mutex.c (revision 0384fff8c5b098545c3db311b0e0aa1ec4c9ae7e)
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