xref: /freebsd/sys/kern/subr_turnstile.c (revision 8484de7555681bedf0ceebeeb5e5aeefff97d7ae)
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 $
2936412d79SJohn Baldwin  *	and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $
300384fff8SJason Evans  * $FreeBSD$
310384fff8SJason Evans  */
320384fff8SJason Evans 
330384fff8SJason Evans /*
340384fff8SJason Evans  *	Main Entry: witness
350384fff8SJason Evans  *	Pronunciation: 'wit-n&s
360384fff8SJason Evans  *	Function: noun
370384fff8SJason Evans  *	Etymology: Middle English witnesse, from Old English witnes knowledge,
380384fff8SJason Evans  *	    testimony, witness, from 2wit
390384fff8SJason Evans  *	Date: before 12th century
400384fff8SJason Evans  *	1 : attestation of a fact or event : TESTIMONY
410384fff8SJason Evans  *	2 : one that gives evidence; specifically : one who testifies in
420384fff8SJason Evans  *	    a cause or before a judicial tribunal
430384fff8SJason Evans  *	3 : one asked to be present at a transaction so as to be able to
440384fff8SJason Evans  *	    testify to its having taken place
450384fff8SJason Evans  *	4 : one who has personal knowledge of something
460384fff8SJason Evans  *	5 a : something serving as evidence or proof : SIGN
470384fff8SJason Evans  *	  b : public affirmation by word or example of usually
480384fff8SJason Evans  *	      religious faith or conviction <the heroic witness to divine
490384fff8SJason Evans  *	      life -- Pilot>
500384fff8SJason Evans  *	6 capitalized : a member of the Jehovah's Witnesses
510384fff8SJason Evans  */
520384fff8SJason Evans 
539c36c934SJohn Baldwin #include "opt_ddb.h"
54a5a96a19SJohn Baldwin #include "opt_witness.h"
55a5a96a19SJohn Baldwin 
560931dcefSAlfred Perlstein /*
570931dcefSAlfred Perlstein  * Cause non-inlined mtx_*() to be compiled.
580931dcefSAlfred Perlstein  * Must be defined early because other system headers may include mutex.h.
590931dcefSAlfred Perlstein  */
600931dcefSAlfred Perlstein #define _KERN_MUTEX_C_
610931dcefSAlfred Perlstein 
620384fff8SJason Evans #include <sys/param.h>
6336412d79SJohn Baldwin #include <sys/bus.h>
6436412d79SJohn Baldwin #include <sys/kernel.h>
6536412d79SJohn Baldwin #include <sys/malloc.h>
660384fff8SJason Evans #include <sys/proc.h>
67a5a96a19SJohn Baldwin #include <sys/sysctl.h>
680384fff8SJason Evans #include <sys/systm.h>
6936412d79SJohn Baldwin #include <sys/vmmeter.h>
700384fff8SJason Evans #include <sys/ktr.h>
710384fff8SJason Evans 
7236412d79SJohn Baldwin #include <machine/atomic.h>
7336412d79SJohn Baldwin #include <machine/bus.h>
7436412d79SJohn Baldwin #include <machine/clock.h>
750384fff8SJason Evans #include <machine/cpu.h>
7636412d79SJohn Baldwin 
779c36c934SJohn Baldwin #include <ddb/ddb.h>
789c36c934SJohn Baldwin 
7936412d79SJohn Baldwin #include <vm/vm.h>
8036412d79SJohn Baldwin #include <vm/vm_extern.h>
8136412d79SJohn Baldwin 
8236412d79SJohn Baldwin #include <sys/mutex.h>
8336412d79SJohn Baldwin 
8436412d79SJohn Baldwin /*
8536412d79SJohn Baldwin  * Machine independent bits of the mutex implementation
8636412d79SJohn Baldwin  */
870cde2e34SJason Evans 
886936206eSJohn Baldwin #ifdef WITNESS
890cde2e34SJason Evans struct mtx_debug {
900cde2e34SJason Evans 	struct witness	*mtxd_witness;
910cde2e34SJason Evans 	LIST_ENTRY(mtx)	mtxd_held;
920cde2e34SJason Evans 	const char	*mtxd_file;
930cde2e34SJason Evans 	int		mtxd_line;
940cde2e34SJason Evans };
950cde2e34SJason Evans 
968484de75SJohn Baldwin #define mtx_held	mtx_debug->mtxd_held
978484de75SJohn Baldwin #define	mtx_file	mtx_debug->mtxd_file
988484de75SJohn Baldwin #define	mtx_line	mtx_debug->mtxd_line
998484de75SJohn Baldwin #define	mtx_witness	mtx_debug->mtxd_witness
1000cde2e34SJason Evans #endif	/* WITNESS */
1010cde2e34SJason Evans 
1020cde2e34SJason Evans /*
1030cde2e34SJason Evans  * Assembly macros
1040cde2e34SJason Evans  *------------------------------------------------------------------------------
1050cde2e34SJason Evans  */
1060cde2e34SJason Evans 
1070cde2e34SJason Evans #define	_V(x)	__STRING(x)
1080cde2e34SJason Evans 
1090cde2e34SJason Evans /*
1100cde2e34SJason Evans  * Default, unoptimized mutex micro-operations
1110cde2e34SJason Evans  */
1120cde2e34SJason Evans 
1130cde2e34SJason Evans #ifndef _obtain_lock
1140cde2e34SJason Evans /* Actually obtain mtx_lock */
1150cde2e34SJason Evans #define _obtain_lock(mp, tid)						\
1160cde2e34SJason Evans 	atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid))
1170cde2e34SJason Evans #endif
1180cde2e34SJason Evans 
1190cde2e34SJason Evans #ifndef _release_lock
1200cde2e34SJason Evans /* Actually release mtx_lock */
1210cde2e34SJason Evans #define _release_lock(mp, tid)		       				\
1220cde2e34SJason Evans 	atomic_cmpset_rel_ptr(&(mp)->mtx_lock, (tid), (void *)MTX_UNOWNED)
1230cde2e34SJason Evans #endif
1240cde2e34SJason Evans 
1250cde2e34SJason Evans #ifndef _release_lock_quick
1260cde2e34SJason Evans /* Actually release mtx_lock quickly assuming that we own it */
1270cde2e34SJason Evans #define	_release_lock_quick(mp) 					\
1280cde2e34SJason Evans 	atomic_store_rel_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED)
1290cde2e34SJason Evans #endif
1300cde2e34SJason Evans 
1310cde2e34SJason Evans #ifndef _getlock_sleep
1320cde2e34SJason Evans /* Get a sleep lock, deal with recursion inline. */
1330cde2e34SJason Evans #define	_getlock_sleep(mp, tid, type) do {				\
1340cde2e34SJason Evans 	if (!_obtain_lock(mp, tid)) {					\
1350cde2e34SJason Evans 		if (((mp)->mtx_lock & MTX_FLAGMASK) != ((uintptr_t)(tid)))\
1360cde2e34SJason Evans 			mtx_enter_hard(mp, (type) & MTX_HARDOPTS, 0);	\
1370cde2e34SJason Evans 		else {							\
1380cde2e34SJason Evans 			atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSED);	\
1390cde2e34SJason Evans 			(mp)->mtx_recurse++;				\
1400cde2e34SJason Evans 		}							\
1410cde2e34SJason Evans 	}								\
1420cde2e34SJason Evans } while (0)
1430cde2e34SJason Evans #endif
1440cde2e34SJason Evans 
1450cde2e34SJason Evans #ifndef _getlock_spin_block
1460cde2e34SJason Evans /* Get a spin lock, handle recursion inline (as the less common case) */
1470cde2e34SJason Evans #define	_getlock_spin_block(mp, tid, type) do {				\
1480cde2e34SJason Evans 	u_int _mtx_intr = save_intr();					\
1490cde2e34SJason Evans 	disable_intr();							\
1500cde2e34SJason Evans 	if (!_obtain_lock(mp, tid))					\
1510cde2e34SJason Evans 		mtx_enter_hard(mp, (type) & MTX_HARDOPTS, _mtx_intr);	\
1520cde2e34SJason Evans 	else								\
1530cde2e34SJason Evans 		(mp)->mtx_saveintr = _mtx_intr;				\
1540cde2e34SJason Evans } while (0)
1550cde2e34SJason Evans #endif
1560cde2e34SJason Evans 
1570cde2e34SJason Evans #ifndef _getlock_norecurse
1580cde2e34SJason Evans /*
1590cde2e34SJason Evans  * Get a lock without any recursion handling. Calls the hard enter function if
1600cde2e34SJason Evans  * we can't get it inline.
1610cde2e34SJason Evans  */
1620cde2e34SJason Evans #define	_getlock_norecurse(mp, tid, type) do {				\
1630cde2e34SJason Evans 	if (!_obtain_lock(mp, tid))					\
1640cde2e34SJason Evans 		mtx_enter_hard((mp), (type) & MTX_HARDOPTS, 0);		\
1650cde2e34SJason Evans } while (0)
1660cde2e34SJason Evans #endif
1670cde2e34SJason Evans 
1680cde2e34SJason Evans #ifndef _exitlock_norecurse
1690cde2e34SJason Evans /*
1700cde2e34SJason Evans  * Release a sleep lock assuming we haven't recursed on it, recursion is handled
1710cde2e34SJason Evans  * in the hard function.
1720cde2e34SJason Evans  */
1730cde2e34SJason Evans #define	_exitlock_norecurse(mp, tid, type) do {				\
1740cde2e34SJason Evans 	if (!_release_lock(mp, tid))					\
1750cde2e34SJason Evans 		mtx_exit_hard((mp), (type) & MTX_HARDOPTS);		\
1760cde2e34SJason Evans } while (0)
1770cde2e34SJason Evans #endif
1780cde2e34SJason Evans 
1790cde2e34SJason Evans #ifndef _exitlock
1800cde2e34SJason Evans /*
1810cde2e34SJason Evans  * Release a sleep lock when its likely we recursed (the code to
1820cde2e34SJason Evans  * deal with simple recursion is inline).
1830cde2e34SJason Evans  */
1840cde2e34SJason Evans #define	_exitlock(mp, tid, type) do {					\
1850cde2e34SJason Evans 	if (!_release_lock(mp, tid)) {					\
1860cde2e34SJason Evans 		if ((mp)->mtx_lock & MTX_RECURSED) {			\
1870cde2e34SJason Evans 			if (--((mp)->mtx_recurse) == 0)			\
1880cde2e34SJason Evans 				atomic_clear_ptr(&(mp)->mtx_lock,	\
1890cde2e34SJason Evans 				    MTX_RECURSED);			\
1900cde2e34SJason Evans 		} else {						\
1910cde2e34SJason Evans 			mtx_exit_hard((mp), (type) & MTX_HARDOPTS);	\
1920cde2e34SJason Evans 		}							\
1930cde2e34SJason Evans 	}								\
1940cde2e34SJason Evans } while (0)
1950cde2e34SJason Evans #endif
1960cde2e34SJason Evans 
1970cde2e34SJason Evans #ifndef _exitlock_spin
1980cde2e34SJason Evans /* Release a spin lock (with possible recursion). */
1990cde2e34SJason Evans #define	_exitlock_spin(mp) do {						\
2000cde2e34SJason Evans 	if (!mtx_recursed((mp))) {					\
2010cde2e34SJason Evans 		int _mtx_intr = (mp)->mtx_saveintr;			\
2020cde2e34SJason Evans 									\
2030cde2e34SJason Evans 		_release_lock_quick(mp);				\
2040cde2e34SJason Evans 		restore_intr(_mtx_intr);				\
2050cde2e34SJason Evans 	} else {							\
2060cde2e34SJason Evans 		(mp)->mtx_recurse--;					\
2070cde2e34SJason Evans 	}								\
2080cde2e34SJason Evans } while (0)
2090cde2e34SJason Evans #endif
2100cde2e34SJason Evans 
2110cde2e34SJason Evans #ifdef WITNESS
2120cde2e34SJason Evans static void	witness_init(struct mtx *, int flag);
2130cde2e34SJason Evans static void	witness_destroy(struct mtx *);
2140cde2e34SJason Evans static void	witness_display(void(*)(const char *fmt, ...));
2150cde2e34SJason Evans 
2160cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */
2178484de75SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0 };
218d1c1b841SJason Evans /*
219d1c1b841SJason Evans  * Set to 0 once mutexes have been fully initialized so that witness code can be
220d1c1b841SJason Evans  * safely executed.
221d1c1b841SJason Evans  */
222d1c1b841SJason Evans static int witness_cold = 1;
2236936206eSJohn Baldwin #else	/* WITNESS */
2240cde2e34SJason Evans 
2250cde2e34SJason Evans /*
2260cde2e34SJason Evans  * flag++ is slezoid way of shutting up unused parameter warning
2270cde2e34SJason Evans  * in mtx_init()
2280cde2e34SJason Evans  */
2290cde2e34SJason Evans #define witness_init(m, flag) flag++
2300cde2e34SJason Evans #define witness_destroy(m)
2310cde2e34SJason Evans #define witness_try_enter(m, t, f, l)
2326936206eSJohn Baldwin #endif	/* WITNESS */
23336412d79SJohn Baldwin 
2348484de75SJohn Baldwin /* All mutexes in system (used for debug/panic) */
2358484de75SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, "All mutexes queue head",
2368484de75SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
2378484de75SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx,
2388484de75SJohn Baldwin #ifdef WITNESS
2398484de75SJohn Baldwin 	&all_mtx_debug
2408484de75SJohn Baldwin #else
2418484de75SJohn Baldwin 	NULL
2428484de75SJohn Baldwin #endif
2438484de75SJohn Baldwin 	 };
2448484de75SJohn Baldwin 
24536412d79SJohn Baldwin static int	mtx_cur_cnt;
24636412d79SJohn Baldwin static int	mtx_max_cnt;
24736412d79SJohn Baldwin 
2481bd0eefbSJohn Baldwin static void	propagate_priority(struct proc *);
2490cde2e34SJason Evans static void	mtx_enter_hard(struct mtx *, int type, int saveintr);
2500cde2e34SJason Evans static void	mtx_exit_hard(struct mtx *, int type);
25136412d79SJohn Baldwin 
25236412d79SJohn Baldwin #define	mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
25336412d79SJohn Baldwin #define	mtx_owner(m)	(mtx_unowned(m) ? NULL \
25436412d79SJohn Baldwin 			    : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
25536412d79SJohn Baldwin 
25636412d79SJohn Baldwin #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
25736412d79SJohn Baldwin #define	SET_PRIO(p, pri)	(p)->p_priority = (pri)
25836412d79SJohn Baldwin 
25936412d79SJohn Baldwin static void
26036412d79SJohn Baldwin propagate_priority(struct proc *p)
26136412d79SJohn Baldwin {
26236412d79SJohn Baldwin 	int pri = p->p_priority;
26336412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
26436412d79SJohn Baldwin 
2651bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
26636412d79SJohn Baldwin 	for (;;) {
26736412d79SJohn Baldwin 		struct proc *p1;
26836412d79SJohn Baldwin 
26936412d79SJohn Baldwin 		p = mtx_owner(m);
27036412d79SJohn Baldwin 
27136412d79SJohn Baldwin 		if (p == NULL) {
27236412d79SJohn Baldwin 			/*
27336412d79SJohn Baldwin 			 * This really isn't quite right. Really
27436412d79SJohn Baldwin 			 * ought to bump priority of process that
27536412d79SJohn Baldwin 			 * next acquires the mutex.
27636412d79SJohn Baldwin 			 */
27736412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
27836412d79SJohn Baldwin 			return;
27936412d79SJohn Baldwin 		}
28036412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
2811bd0eefbSJohn Baldwin 		KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex"));
28236412d79SJohn Baldwin 		if (p->p_priority <= pri)
28336412d79SJohn Baldwin 			return;
2841bd0eefbSJohn Baldwin 
2851bd0eefbSJohn Baldwin 		/*
2861bd0eefbSJohn Baldwin 		 * Bump this process' priority.
2871bd0eefbSJohn Baldwin 		 */
2881bd0eefbSJohn Baldwin 		SET_PRIO(p, pri);
2891bd0eefbSJohn Baldwin 
29036412d79SJohn Baldwin 		/*
29136412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
29236412d79SJohn Baldwin 		 */
2931bd0eefbSJohn Baldwin #ifdef SMP
2941bd0eefbSJohn Baldwin 		/*
2951bd0eefbSJohn Baldwin 		 * For SMP, we can check the p_oncpu field to see if we are
2961bd0eefbSJohn Baldwin 		 * running.
2971bd0eefbSJohn Baldwin 		 */
2981bd0eefbSJohn Baldwin 		if (p->p_oncpu != 0xff) {
29936412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
30036412d79SJohn Baldwin 			return;
30136412d79SJohn Baldwin 		}
3021bd0eefbSJohn Baldwin #else
3031bd0eefbSJohn Baldwin 		/*
3041bd0eefbSJohn Baldwin 		 * For UP, we check to see if p is curproc (this shouldn't
3051bd0eefbSJohn Baldwin 		 * ever happen however as it would mean we are in a deadlock.)
3061bd0eefbSJohn Baldwin 		 */
3071bd0eefbSJohn Baldwin 		if (p == curproc) {
3081bd0eefbSJohn Baldwin 			panic("Deadlock detected");
3091bd0eefbSJohn Baldwin 			return;
3101bd0eefbSJohn Baldwin 		}
3111bd0eefbSJohn Baldwin #endif
31236412d79SJohn Baldwin 		/*
31336412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
31436412d79SJohn Baldwin 		 * quit.
31536412d79SJohn Baldwin 		 */
31636412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
3171bd0eefbSJohn Baldwin 			printf("XXX: moving process %d(%s) to a new run queue\n",
3181bd0eefbSJohn Baldwin 			       p->p_pid, p->p_comm);
31936412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
32036412d79SJohn Baldwin 			remrunqueue(p);
32136412d79SJohn Baldwin 			setrunqueue(p);
32236412d79SJohn Baldwin 			return;
32336412d79SJohn Baldwin 		}
32436412d79SJohn Baldwin 
32536412d79SJohn Baldwin 		/*
3261bd0eefbSJohn Baldwin 		 * If we aren't blocked on a mutex, we should be.
32736412d79SJohn Baldwin 		 */
3281bd0eefbSJohn Baldwin 		KASSERT(p->p_stat == SMTX, (
3291bd0eefbSJohn Baldwin 		    "process %d(%s):%d holds %s but isn't blocked on a mutex\n",
3301bd0eefbSJohn Baldwin 		    p->p_pid, p->p_comm, p->p_stat,
3311bd0eefbSJohn Baldwin 		    m->mtx_description));
33236412d79SJohn Baldwin 
33336412d79SJohn Baldwin 		/*
33436412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
33536412d79SJohn Baldwin 		 */
33636412d79SJohn Baldwin 		m = p->p_blocked;
33736412d79SJohn Baldwin 		MPASS(m != NULL);
33836412d79SJohn Baldwin 
33936412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
34036412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
34136412d79SJohn Baldwin 		/*
34236412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
34336412d79SJohn Baldwin 		 * the blocked chain
34436412d79SJohn Baldwin 		 */
3451bd0eefbSJohn Baldwin 		if (p == TAILQ_FIRST(&m->mtx_blocked)) {
3461bd0eefbSJohn Baldwin 			printf("XXX: process at head of run queue\n");
3471bd0eefbSJohn Baldwin 			continue;
3481bd0eefbSJohn Baldwin 		}
3491bd0eefbSJohn Baldwin 		p1 = TAILQ_PREV(p, rq, p_procq);
3501bd0eefbSJohn Baldwin 		if (p1->p_priority <= pri) {
35136412d79SJohn Baldwin 			printf(
35236412d79SJohn Baldwin 	"XXX: previous process %d(%s) has higher priority\n",
35336412d79SJohn Baldwin 	                    p->p_pid, p->p_comm);
35436412d79SJohn Baldwin 			continue;
35536412d79SJohn Baldwin 		}
35636412d79SJohn Baldwin 
35736412d79SJohn Baldwin 		/*
3581bd0eefbSJohn Baldwin 		 * Remove proc from blocked chain and determine where
3591bd0eefbSJohn Baldwin 		 * it should be moved up to.  Since we know that p1 has
3601bd0eefbSJohn Baldwin 		 * a lower priority than p, we know that at least one
3611bd0eefbSJohn Baldwin 		 * process in the chain has a lower priority and that
3621bd0eefbSJohn Baldwin 		 * p1 will thus not be NULL after the loop.
36336412d79SJohn Baldwin 		 */
36436412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
36536412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
36636412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
36736412d79SJohn Baldwin 			if (p1->p_priority > pri)
36836412d79SJohn Baldwin 				break;
36936412d79SJohn Baldwin 		}
3701bd0eefbSJohn Baldwin 		MPASS(p1 != NULL);
37136412d79SJohn Baldwin 		TAILQ_INSERT_BEFORE(p1, p, p_procq);
37236412d79SJohn Baldwin 		CTR4(KTR_LOCK,
3738484de75SJohn Baldwin 		    "propagate_priority: p %p moved before %p on [%p] %s",
37436412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
37536412d79SJohn Baldwin 	}
37636412d79SJohn Baldwin }
37736412d79SJohn Baldwin 
3780cde2e34SJason Evans /*
3790cde2e34SJason Evans  * Get lock 'm', the macro handles the easy (and most common cases) and leaves
3800cde2e34SJason Evans  * the slow stuff to the mtx_enter_hard() function.
3810cde2e34SJason Evans  *
3820cde2e34SJason Evans  * Note: since type is usually a constant much of this code is optimized out.
3830cde2e34SJason Evans  */
3840cde2e34SJason Evans void
3850cde2e34SJason Evans _mtx_enter(struct mtx *mtxp, int type, const char *file, int line)
3860cde2e34SJason Evans {
3870cde2e34SJason Evans 	struct mtx	*mpp = mtxp;
3880cde2e34SJason Evans 
3890cde2e34SJason Evans 	/* bits only valid on mtx_exit() */
3900cde2e34SJason Evans 	MPASS4(((type) & (MTX_NORECURSE | MTX_NOSWITCH)) == 0,
3910cde2e34SJason Evans 	    STR_mtx_bad_type, file, line);
3920cde2e34SJason Evans 
3930cde2e34SJason Evans 	if ((type) & MTX_SPIN) {
3940cde2e34SJason Evans 		/*
3950cde2e34SJason Evans 		 * Easy cases of spin locks:
3960cde2e34SJason Evans 		 *
3970cde2e34SJason Evans 		 * 1) We already own the lock and will simply recurse on it (if
3980cde2e34SJason Evans 		 *    RLIKELY)
3990cde2e34SJason Evans 		 *
4000cde2e34SJason Evans 		 * 2) The lock is free, we just get it
4010cde2e34SJason Evans 		 */
4020cde2e34SJason Evans 		if ((type) & MTX_RLIKELY) {
4030cde2e34SJason Evans 			/*
4040cde2e34SJason Evans 			 * Check for recursion, if we already have this
4050cde2e34SJason Evans 			 * lock we just bump the recursion count.
4060cde2e34SJason Evans 			 */
4070cde2e34SJason Evans 			if (mpp->mtx_lock == (uintptr_t)CURTHD) {
4080cde2e34SJason Evans 				mpp->mtx_recurse++;
4090cde2e34SJason Evans 				goto done;
4100cde2e34SJason Evans 			}
4110cde2e34SJason Evans 		}
4120cde2e34SJason Evans 
4130cde2e34SJason Evans 		if (((type) & MTX_TOPHALF) == 0) {
4140cde2e34SJason Evans 			/*
4150cde2e34SJason Evans 			 * If an interrupt thread uses this we must block
4160cde2e34SJason Evans 			 * interrupts here.
4170cde2e34SJason Evans 			 */
4180cde2e34SJason Evans 			if ((type) & MTX_FIRST) {
4190cde2e34SJason Evans 				ASS_IEN;
4200cde2e34SJason Evans 				disable_intr();
4210cde2e34SJason Evans 				_getlock_norecurse(mpp, CURTHD,
4220cde2e34SJason Evans 				    (type) & MTX_HARDOPTS);
4230cde2e34SJason Evans 			} else {
4240cde2e34SJason Evans 				_getlock_spin_block(mpp, CURTHD,
4250cde2e34SJason Evans 				    (type) & MTX_HARDOPTS);
4260cde2e34SJason Evans 			}
4270cde2e34SJason Evans 		} else
4280cde2e34SJason Evans 			_getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS);
4290cde2e34SJason Evans 	} else {
4300cde2e34SJason Evans 		/* Sleep locks */
4310cde2e34SJason Evans 		if ((type) & MTX_RLIKELY)
4320cde2e34SJason Evans 			_getlock_sleep(mpp, CURTHD, (type) & MTX_HARDOPTS);
4330cde2e34SJason Evans 		else
4340cde2e34SJason Evans 			_getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS);
4350cde2e34SJason Evans 	}
4360cde2e34SJason Evans done:
4370cde2e34SJason Evans 	WITNESS_ENTER(mpp, type, file, line);
4380cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4390cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_enter_fmt,
4400cde2e34SJason Evans 		    mpp->mtx_description, mpp, mpp->mtx_recurse, file, line);
4410cde2e34SJason Evans 
4420cde2e34SJason Evans }
4430cde2e34SJason Evans 
4440cde2e34SJason Evans /*
4450cde2e34SJason Evans  * Attempt to get MTX_DEF lock, return non-zero if lock acquired.
4460cde2e34SJason Evans  *
4470cde2e34SJason Evans  * XXX DOES NOT HANDLE RECURSION
4480cde2e34SJason Evans  */
4490cde2e34SJason Evans int
4500cde2e34SJason Evans _mtx_try_enter(struct mtx *mtxp, int type, const char *file, int line)
4510cde2e34SJason Evans {
4520cde2e34SJason Evans 	struct mtx	*const mpp = mtxp;
4530cde2e34SJason Evans 	int	rval;
4540cde2e34SJason Evans 
4550cde2e34SJason Evans 	rval = _obtain_lock(mpp, CURTHD);
4560cde2e34SJason Evans #ifdef WITNESS
4570cde2e34SJason Evans 	if (rval && mpp->mtx_witness != NULL) {
4580cde2e34SJason Evans 		MPASS(mpp->mtx_recurse == 0);
4590cde2e34SJason Evans 		witness_try_enter(mpp, type, file, line);
4600cde2e34SJason Evans 	}
4610cde2e34SJason Evans #endif	/* WITNESS */
4620cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4630cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_try_enter_fmt,
4640cde2e34SJason Evans 		    mpp->mtx_description, mpp, rval, file, line);
4650cde2e34SJason Evans 
4660cde2e34SJason Evans 	return rval;
4670cde2e34SJason Evans }
4680cde2e34SJason Evans 
4690cde2e34SJason Evans /*
4700cde2e34SJason Evans  * Release lock m.
4710cde2e34SJason Evans  */
4720cde2e34SJason Evans void
4730cde2e34SJason Evans _mtx_exit(struct mtx *mtxp, int type, const char *file, int line)
4740cde2e34SJason Evans {
4750cde2e34SJason Evans 	struct mtx	*const mpp = mtxp;
4760cde2e34SJason Evans 
4770cde2e34SJason Evans 	MPASS4(mtx_owned(mpp), STR_mtx_owned, file, line);
4780cde2e34SJason Evans 	WITNESS_EXIT(mpp, type, file, line);
4790cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4800cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_exit_fmt,
4810cde2e34SJason Evans 		    mpp->mtx_description, mpp, mpp->mtx_recurse, file, line);
4820cde2e34SJason Evans 	if ((type) & MTX_SPIN) {
4830cde2e34SJason Evans 		if ((type) & MTX_NORECURSE) {
4840cde2e34SJason Evans 			int mtx_intr = mpp->mtx_saveintr;
4850cde2e34SJason Evans 
4860cde2e34SJason Evans 			MPASS4(mpp->mtx_recurse == 0, STR_mtx_recurse,
4870cde2e34SJason Evans 			    file, line);
4880cde2e34SJason Evans 			_release_lock_quick(mpp);
4890cde2e34SJason Evans 			if (((type) & MTX_TOPHALF) == 0) {
4900cde2e34SJason Evans 				if ((type) & MTX_FIRST) {
4910cde2e34SJason Evans 					ASS_IDIS;
4920cde2e34SJason Evans 					enable_intr();
4930cde2e34SJason Evans 				} else
4940cde2e34SJason Evans 					restore_intr(mtx_intr);
4950cde2e34SJason Evans 			}
4960cde2e34SJason Evans 		} else {
4970cde2e34SJason Evans 			if (((type & MTX_TOPHALF) == 0) &&
4980cde2e34SJason Evans 			    (type & MTX_FIRST)) {
4990cde2e34SJason Evans 				ASS_IDIS;
5000cde2e34SJason Evans 				ASS_SIEN(mpp);
5010cde2e34SJason Evans 			}
5020cde2e34SJason Evans 			_exitlock_spin(mpp);
5030cde2e34SJason Evans 		}
5040cde2e34SJason Evans 	} else {
5050cde2e34SJason Evans 		/* Handle sleep locks */
5060cde2e34SJason Evans 		if ((type) & MTX_RLIKELY)
5070cde2e34SJason Evans 			_exitlock(mpp, CURTHD, (type) & MTX_HARDOPTS);
5080cde2e34SJason Evans 		else {
5090cde2e34SJason Evans 			_exitlock_norecurse(mpp, CURTHD,
5100cde2e34SJason Evans 			    (type) & MTX_HARDOPTS);
5110cde2e34SJason Evans 		}
5120cde2e34SJason Evans 	}
5130cde2e34SJason Evans }
5140cde2e34SJason Evans 
51536412d79SJohn Baldwin void
51636412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr)
51736412d79SJohn Baldwin {
51836412d79SJohn Baldwin 	struct proc *p = CURPROC;
51936412d79SJohn Baldwin 
52036412d79SJohn Baldwin 	KASSERT(p != NULL, ("curproc is NULL in mutex"));
52136412d79SJohn Baldwin 
52236412d79SJohn Baldwin 	switch (type) {
52336412d79SJohn Baldwin 	case MTX_DEF:
52436412d79SJohn Baldwin 		if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
52536412d79SJohn Baldwin 			m->mtx_recurse++;
52608812b39SBosko Milekic 			atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
527562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
5288484de75SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_enter: %p recurse", m);
52936412d79SJohn Baldwin 			return;
53036412d79SJohn Baldwin 		}
531562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
532562e4ffeSJohn Baldwin 			CTR3(KTR_LOCK,
5338484de75SJohn Baldwin 			    "mtx_enter: %p contested (lock=%p) [%p]",
53431271627SJohn Baldwin 			    m, (void *)m->mtx_lock, (void *)RETIP(m));
5351bd0eefbSJohn Baldwin 
5361bd0eefbSJohn Baldwin 		/*
5371bd0eefbSJohn Baldwin 		 * Save our priority.  Even though p_nativepri is protected
5381bd0eefbSJohn Baldwin 		 * by sched_lock, we don't obtain it here as it can be
5391bd0eefbSJohn Baldwin 		 * expensive.  Since this is the only place p_nativepri is
5401bd0eefbSJohn Baldwin 		 * set, and since two CPUs will not be executing the same
5411bd0eefbSJohn Baldwin 		 * process concurrently, we know that no other CPU is going
5421bd0eefbSJohn Baldwin 		 * to be messing with this.  Also, p_nativepri is only read
5431bd0eefbSJohn Baldwin 		 * when we are blocked on a mutex, so that can't be happening
5441bd0eefbSJohn Baldwin 		 * right now either.
5451bd0eefbSJohn Baldwin 		 */
5461bd0eefbSJohn Baldwin 		p->p_nativepri = p->p_priority;
54736412d79SJohn Baldwin 		while (!_obtain_lock(m, p)) {
548f5271ebcSJohn Baldwin 			uintptr_t v;
54936412d79SJohn Baldwin 			struct proc *p1;
55036412d79SJohn Baldwin 
55136412d79SJohn Baldwin 			mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY);
55236412d79SJohn Baldwin 			/*
55336412d79SJohn Baldwin 			 * check if the lock has been released while
55436412d79SJohn Baldwin 			 * waiting for the schedlock.
55536412d79SJohn Baldwin 			 */
55636412d79SJohn Baldwin 			if ((v = m->mtx_lock) == MTX_UNOWNED) {
55736412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
55836412d79SJohn Baldwin 				continue;
55936412d79SJohn Baldwin 			}
56036412d79SJohn Baldwin 			/*
56136412d79SJohn Baldwin 			 * The mutex was marked contested on release. This
56236412d79SJohn Baldwin 			 * means that there are processes blocked on it.
56336412d79SJohn Baldwin 			 */
56436412d79SJohn Baldwin 			if (v == MTX_CONTESTED) {
56536412d79SJohn Baldwin 				p1 = TAILQ_FIRST(&m->mtx_blocked);
56636412d79SJohn Baldwin 				KASSERT(p1 != NULL, ("contested mutex has no contesters"));
56736412d79SJohn Baldwin 				KASSERT(p != NULL, ("curproc is NULL for contested mutex"));
56836412d79SJohn Baldwin 				m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
56936412d79SJohn Baldwin 				if (p1->p_priority < p->p_priority) {
57036412d79SJohn Baldwin 					SET_PRIO(p, p1->p_priority);
57136412d79SJohn Baldwin 				}
57236412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
57336412d79SJohn Baldwin 				return;
57436412d79SJohn Baldwin 			}
57536412d79SJohn Baldwin 			/*
57636412d79SJohn Baldwin 			 * If the mutex isn't already contested and
57736412d79SJohn Baldwin 			 * a failure occurs setting the contested bit the
57836412d79SJohn Baldwin 			 * mutex was either release or the
57936412d79SJohn Baldwin 			 * state of the RECURSION bit changed.
58036412d79SJohn Baldwin 			 */
58136412d79SJohn Baldwin 			if ((v & MTX_CONTESTED) == 0 &&
58236412d79SJohn Baldwin 			    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
58336412d79SJohn Baldwin 				               (void *)(v | MTX_CONTESTED))) {
58436412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
58536412d79SJohn Baldwin 				continue;
58636412d79SJohn Baldwin 			}
58736412d79SJohn Baldwin 
58836412d79SJohn Baldwin 			/* We definitely have to sleep for this lock */
58936412d79SJohn Baldwin 			mtx_assert(m, MA_NOTOWNED);
59036412d79SJohn Baldwin 
59136412d79SJohn Baldwin #ifdef notyet
59236412d79SJohn Baldwin 			/*
59336412d79SJohn Baldwin 			 * If we're borrowing an interrupted thread's VM
59436412d79SJohn Baldwin 			 * context must clean up before going to sleep.
59536412d79SJohn Baldwin 			 */
59636412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
59736412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
59836412d79SJohn Baldwin 
59936412d79SJohn Baldwin 				if (it->it_interrupted) {
600562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
60136412d79SJohn Baldwin 						CTR2(KTR_LOCK,
60236412d79SJohn Baldwin 					    "mtx_enter: 0x%x interrupted 0x%x",
60336412d79SJohn Baldwin 						    it, it->it_interrupted);
60436412d79SJohn Baldwin 					intr_thd_fixup(it);
60536412d79SJohn Baldwin 				}
60636412d79SJohn Baldwin 			}
60736412d79SJohn Baldwin #endif
60836412d79SJohn Baldwin 
60936412d79SJohn Baldwin 			/* Put us on the list of procs blocked on this mutex */
61036412d79SJohn Baldwin 			if (TAILQ_EMPTY(&m->mtx_blocked)) {
61136412d79SJohn Baldwin 				p1 = (struct proc *)(m->mtx_lock &
61236412d79SJohn Baldwin 						     MTX_FLAGMASK);
61336412d79SJohn Baldwin 				LIST_INSERT_HEAD(&p1->p_contested, m,
61436412d79SJohn Baldwin 						 mtx_contested);
61536412d79SJohn Baldwin 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
61636412d79SJohn Baldwin 			} else {
61736412d79SJohn Baldwin 				TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
61836412d79SJohn Baldwin 					if (p1->p_priority > p->p_priority)
61936412d79SJohn Baldwin 						break;
62036412d79SJohn Baldwin 				if (p1)
62136412d79SJohn Baldwin 					TAILQ_INSERT_BEFORE(p1, p, p_procq);
62236412d79SJohn Baldwin 				else
62336412d79SJohn Baldwin 					TAILQ_INSERT_TAIL(&m->mtx_blocked, p,
62436412d79SJohn Baldwin 							  p_procq);
62536412d79SJohn Baldwin 			}
62636412d79SJohn Baldwin 
62736412d79SJohn Baldwin 			p->p_blocked = m;	/* Who we're blocked on */
62886327ad8SJohn Baldwin 			p->p_mtxname = m->mtx_description;
62936412d79SJohn Baldwin 			p->p_stat = SMTX;
63036412d79SJohn Baldwin #if 0
63136412d79SJohn Baldwin 			propagate_priority(p);
63236412d79SJohn Baldwin #endif
633562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
634562e4ffeSJohn Baldwin 				CTR3(KTR_LOCK,
6358484de75SJohn Baldwin 				    "mtx_enter: p %p blocked on [%p] %s",
63636412d79SJohn Baldwin 				    p, m, m->mtx_description);
63720cdcc5bSJohn Baldwin 			mi_switch();
638562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
63936412d79SJohn Baldwin 				CTR3(KTR_LOCK,
6408484de75SJohn Baldwin 			    "mtx_enter: p %p free from blocked on [%p] %s",
64136412d79SJohn Baldwin 				    p, m, m->mtx_description);
64236412d79SJohn Baldwin 			mtx_exit(&sched_lock, MTX_SPIN);
64336412d79SJohn Baldwin 		}
64436412d79SJohn Baldwin 		return;
64536412d79SJohn Baldwin 	case MTX_SPIN:
64636412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
64736412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
64836412d79SJohn Baldwin 	    {
64936412d79SJohn Baldwin 		int i = 0;
65036412d79SJohn Baldwin 
65136412d79SJohn Baldwin 		if (m->mtx_lock == (uintptr_t)p) {
65236412d79SJohn Baldwin 			m->mtx_recurse++;
65336412d79SJohn Baldwin 			return;
65436412d79SJohn Baldwin 		}
655562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
65636412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: %p spinning", m);
65736412d79SJohn Baldwin 		for (;;) {
65836412d79SJohn Baldwin 			if (_obtain_lock(m, p))
65936412d79SJohn Baldwin 				break;
66036412d79SJohn Baldwin 			while (m->mtx_lock != MTX_UNOWNED) {
66136412d79SJohn Baldwin 				if (i++ < 1000000)
66236412d79SJohn Baldwin 					continue;
66336412d79SJohn Baldwin 				if (i++ < 6000000)
66436412d79SJohn Baldwin 					DELAY (1);
66536412d79SJohn Baldwin #ifdef DDB
66636412d79SJohn Baldwin 				else if (!db_active)
66736412d79SJohn Baldwin #else
66836412d79SJohn Baldwin 				else
66936412d79SJohn Baldwin #endif
67036412d79SJohn Baldwin 					panic(
6718484de75SJohn Baldwin 				"spin lock %s held by %p for > 5 seconds",
67236412d79SJohn Baldwin 					    m->mtx_description,
67336412d79SJohn Baldwin 					    (void *)m->mtx_lock);
67436412d79SJohn Baldwin 			}
67536412d79SJohn Baldwin 		}
67636412d79SJohn Baldwin 
67736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
67836412d79SJohn Baldwin 		if (type != MTX_SPIN)
67936412d79SJohn Baldwin 			m->mtx_saveintr = 0xbeefface;
68036412d79SJohn Baldwin 		else
68136412d79SJohn Baldwin #endif
68236412d79SJohn Baldwin 			m->mtx_saveintr = saveintr;
683562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
6848484de75SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: %p spin done", m);
68536412d79SJohn Baldwin 		return;
68636412d79SJohn Baldwin 	    }
68736412d79SJohn Baldwin 	}
68836412d79SJohn Baldwin }
68936412d79SJohn Baldwin 
69036412d79SJohn Baldwin void
69136412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type)
69236412d79SJohn Baldwin {
69336412d79SJohn Baldwin 	struct proc *p, *p1;
69436412d79SJohn Baldwin 	struct mtx *m1;
69536412d79SJohn Baldwin 	int pri;
69636412d79SJohn Baldwin 
69736412d79SJohn Baldwin 	p = CURPROC;
69836412d79SJohn Baldwin 	switch (type) {
69936412d79SJohn Baldwin 	case MTX_DEF:
70036412d79SJohn Baldwin 	case MTX_DEF | MTX_NOSWITCH:
70108812b39SBosko Milekic 		if (mtx_recursed(m)) {
70236412d79SJohn Baldwin 			if (--(m->mtx_recurse) == 0)
70308812b39SBosko Milekic 				atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
704562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
7058484de75SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: %p unrecurse", m);
70636412d79SJohn Baldwin 			return;
70736412d79SJohn Baldwin 		}
70836412d79SJohn Baldwin 		mtx_enter(&sched_lock, MTX_SPIN);
709562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
7108484de75SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: %p contested", m);
71136412d79SJohn Baldwin 		p1 = TAILQ_FIRST(&m->mtx_blocked);
71236412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
71336412d79SJohn Baldwin 		MPASS(p1->p_magic == P_MAGIC);
71436412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
71536412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
71636412d79SJohn Baldwin 			LIST_REMOVE(m, mtx_contested);
71736412d79SJohn Baldwin 			_release_lock_quick(m);
718562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
7198484de75SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: %p not held", m);
72036412d79SJohn Baldwin 		} else
721f404050eSJohn Baldwin 			atomic_store_rel_ptr(&m->mtx_lock,
722f404050eSJohn Baldwin 			    (void *)MTX_CONTESTED);
72336412d79SJohn Baldwin 		pri = MAXPRI;
72436412d79SJohn Baldwin 		LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
72536412d79SJohn Baldwin 			int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
72636412d79SJohn Baldwin 			if (cp < pri)
72736412d79SJohn Baldwin 				pri = cp;
72836412d79SJohn Baldwin 		}
72936412d79SJohn Baldwin 		if (pri > p->p_nativepri)
73036412d79SJohn Baldwin 			pri = p->p_nativepri;
73136412d79SJohn Baldwin 		SET_PRIO(p, pri);
732562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
733562e4ffeSJohn Baldwin 			CTR2(KTR_LOCK,
7348484de75SJohn Baldwin 			    "mtx_exit: %p contested setrunqueue %p", m, p1);
73536412d79SJohn Baldwin 		p1->p_blocked = NULL;
73686327ad8SJohn Baldwin 		p1->p_mtxname = NULL;
73736412d79SJohn Baldwin 		p1->p_stat = SRUN;
73836412d79SJohn Baldwin 		setrunqueue(p1);
73936412d79SJohn Baldwin 		if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
74036412d79SJohn Baldwin #ifdef notyet
74136412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
74236412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
74336412d79SJohn Baldwin 
74436412d79SJohn Baldwin 				if (it->it_interrupted) {
745562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
74636412d79SJohn Baldwin 						CTR2(KTR_LOCK,
74736412d79SJohn Baldwin 					    "mtx_exit: 0x%x interruped 0x%x",
74836412d79SJohn Baldwin 						    it, it->it_interrupted);
74936412d79SJohn Baldwin 					intr_thd_fixup(it);
75036412d79SJohn Baldwin 				}
75136412d79SJohn Baldwin 			}
75236412d79SJohn Baldwin #endif
75336412d79SJohn Baldwin 			setrunqueue(p);
754562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
755562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
7568484de75SJohn Baldwin 				    "mtx_exit: %p switching out lock=%p",
75731271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
75836412d79SJohn Baldwin 			mi_switch();
759562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
760562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
7618484de75SJohn Baldwin 				    "mtx_exit: %p resuming lock=%p",
76231271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
76336412d79SJohn Baldwin 		}
76436412d79SJohn Baldwin 		mtx_exit(&sched_lock, MTX_SPIN);
76536412d79SJohn Baldwin 		break;
76636412d79SJohn Baldwin 	case MTX_SPIN:
76736412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
76808812b39SBosko Milekic 		if (mtx_recursed(m)) {
76936412d79SJohn Baldwin 			m->mtx_recurse--;
77036412d79SJohn Baldwin 			return;
77136412d79SJohn Baldwin 		}
77236412d79SJohn Baldwin 		MPASS(mtx_owned(m));
77336412d79SJohn Baldwin 		_release_lock_quick(m);
77436412d79SJohn Baldwin 		if (type & MTX_FIRST)
77536412d79SJohn Baldwin 			enable_intr();	/* XXX is this kosher? */
77636412d79SJohn Baldwin 		else {
77736412d79SJohn Baldwin 			MPASS(m->mtx_saveintr != 0xbeefface);
77836412d79SJohn Baldwin 			restore_intr(m->mtx_saveintr);
77936412d79SJohn Baldwin 		}
78036412d79SJohn Baldwin 		break;
78136412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
78208812b39SBosko Milekic 		if (mtx_recursed(m)) {
78336412d79SJohn Baldwin 			m->mtx_recurse--;
78436412d79SJohn Baldwin 			return;
78536412d79SJohn Baldwin 		}
78636412d79SJohn Baldwin 		MPASS(mtx_owned(m));
78736412d79SJohn Baldwin 		_release_lock_quick(m);
78836412d79SJohn Baldwin 		break;
78936412d79SJohn Baldwin 	default:
79036412d79SJohn Baldwin 		panic("mtx_exit_hard: unsupported type 0x%x\n", type);
79136412d79SJohn Baldwin 	}
79236412d79SJohn Baldwin }
79336412d79SJohn Baldwin 
7940cde2e34SJason Evans #ifdef INVARIANTS
7950cde2e34SJason Evans void
79656771ca7SJason Evans _mtx_assert(struct mtx *m, int what, const char *file, int line)
7970cde2e34SJason Evans {
7980cde2e34SJason Evans 	switch ((what)) {
7990cde2e34SJason Evans 	case MA_OWNED:
8000cde2e34SJason Evans 	case MA_OWNED | MA_RECURSED:
8010cde2e34SJason Evans 	case MA_OWNED | MA_NOTRECURSED:
8020cde2e34SJason Evans 		if (!mtx_owned((m)))
8030cde2e34SJason Evans 			panic("mutex %s not owned at %s:%d",
80456771ca7SJason Evans 			    (m)->mtx_description, file, line);
8050cde2e34SJason Evans 		if (mtx_recursed((m))) {
8060cde2e34SJason Evans 			if (((what) & MA_NOTRECURSED) != 0)
8070cde2e34SJason Evans 				panic("mutex %s recursed at %s:%d",
80856771ca7SJason Evans 				    (m)->mtx_description, file, line);
8090cde2e34SJason Evans 		} else if (((what) & MA_RECURSED) != 0) {
8100cde2e34SJason Evans 			panic("mutex %s unrecursed at %s:%d",
81156771ca7SJason Evans 			    (m)->mtx_description, file, line);
8120cde2e34SJason Evans 		}
8130cde2e34SJason Evans 		break;
8140cde2e34SJason Evans 	case MA_NOTOWNED:
8150cde2e34SJason Evans 		if (mtx_owned((m)))
8160cde2e34SJason Evans 			panic("mutex %s owned at %s:%d",
81756771ca7SJason Evans 			    (m)->mtx_description, file, line);
8180cde2e34SJason Evans 		break;
8190cde2e34SJason Evans 	default:
82056771ca7SJason Evans 		panic("unknown mtx_assert at %s:%d", file, line);
8210cde2e34SJason Evans 	}
8220cde2e34SJason Evans }
8230cde2e34SJason Evans #endif
8240cde2e34SJason Evans 
82536412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
82636412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
82736412d79SJohn Baldwin 
82836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
82936412d79SJohn Baldwin 
83036412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
83136412d79SJohn Baldwin 
83236412d79SJohn Baldwin int
83336412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
83436412d79SJohn Baldwin {
83536412d79SJohn Baldwin 	struct mtx *mp;
83636412d79SJohn Baldwin 	int i;
83736412d79SJohn Baldwin 	int retval = 0;
83836412d79SJohn Baldwin 
839d1c1b841SJason Evans #ifdef WITNESS
840d1c1b841SJason Evans 	if (witness_cold)
841d1c1b841SJason Evans 		return 0;
842d1c1b841SJason Evans #endif
84336412d79SJohn Baldwin 	if (m == &all_mtx || cold)
84436412d79SJohn Baldwin 		return 0;
84536412d79SJohn Baldwin 
84636412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
84736412d79SJohn Baldwin /*
84836412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
84936412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
85036412d79SJohn Baldwin  */
85136412d79SJohn Baldwin #ifndef __alpha__
85236412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
85336412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
85436412d79SJohn Baldwin #endif
85536412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
85636412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
85736412d79SJohn Baldwin #ifndef __alpha__
85836412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
85936412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
86036412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
86136412d79SJohn Baldwin 			    mp, mp->mtx_next);
86236412d79SJohn Baldwin 		}
86336412d79SJohn Baldwin #endif
86436412d79SJohn Baldwin 		i++;
86536412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
86636412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
86736412d79SJohn Baldwin 			    mtx_cur_cnt);
86836412d79SJohn Baldwin 		}
86936412d79SJohn Baldwin 	}
87036412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
87136412d79SJohn Baldwin 	switch (when) {
87236412d79SJohn Baldwin 	case MV_DESTROY:
87336412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
87436412d79SJohn Baldwin 			if (mp == m)
87536412d79SJohn Baldwin 				break;
87636412d79SJohn Baldwin 		MPASS(mp == m);
87736412d79SJohn Baldwin 		break;
87836412d79SJohn Baldwin 	case MV_INIT:
87936412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
88036412d79SJohn Baldwin 		if (mp == m) {
88136412d79SJohn Baldwin 			/*
88236412d79SJohn Baldwin 			 * Not good. This mutex already exists.
88336412d79SJohn Baldwin 			 */
88436412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
88536412d79SJohn Baldwin 			    m->mtx_description);
88636412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
88736412d79SJohn Baldwin 			retval = 1;
88836412d79SJohn Baldwin 		}
88936412d79SJohn Baldwin 	}
89036412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
89136412d79SJohn Baldwin 	return (retval);
89236412d79SJohn Baldwin }
89336412d79SJohn Baldwin #endif
89436412d79SJohn Baldwin 
89536412d79SJohn Baldwin void
89636412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag)
89736412d79SJohn Baldwin {
898562e4ffeSJohn Baldwin 	if ((flag & MTX_QUIET) == 0)
8998484de75SJohn Baldwin 		CTR2(KTR_LOCK, "mtx_init %p (%s)", m, t);
90036412d79SJohn Baldwin #ifdef MUTEX_DEBUG
90136412d79SJohn Baldwin 	if (mtx_validate(m, MV_INIT))	/* diagnostic and error correction */
90236412d79SJohn Baldwin 		return;
9036936206eSJohn Baldwin #endif
90436412d79SJohn Baldwin 
90536412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
90636412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
9076936206eSJohn Baldwin #ifdef WITNESS
908d1c1b841SJason Evans 	if (!witness_cold) {
909d1c1b841SJason Evans 		/* XXX - should not use DEVBUF */
9108484de75SJohn Baldwin 		m->mtx_debug = malloc(sizeof(struct mtx_debug),
911d1c1b841SJason Evans 		    M_DEVBUF, M_NOWAIT | M_ZERO);
9128484de75SJohn Baldwin 		MPASS(m->mtx_debug != NULL);
913d1c1b841SJason Evans 	}
914d1c1b841SJason Evans #endif
9158484de75SJohn Baldwin 	m->mtx_description = t;
916d1c1b841SJason Evans 
917d1c1b841SJason Evans 	m->mtx_flags = flag;
91836412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
91936412d79SJohn Baldwin 	/* Put on all mutex queue */
92036412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
92136412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
92236412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
92336412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
92436412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
92536412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
92636412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
92736412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
928d1c1b841SJason Evans #ifdef WITNESS
929d1c1b841SJason Evans 	if (!witness_cold)
93036412d79SJohn Baldwin 		witness_init(m, flag);
931d1c1b841SJason Evans #endif
93236412d79SJohn Baldwin }
93336412d79SJohn Baldwin 
93436412d79SJohn Baldwin void
93536412d79SJohn Baldwin mtx_destroy(struct mtx *m)
93636412d79SJohn Baldwin {
93736412d79SJohn Baldwin 
938d1c1b841SJason Evans #ifdef WITNESS
939d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n",
940d1c1b841SJason Evans 	    __FUNCTION__));
941d1c1b841SJason Evans #endif
9428484de75SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy %p (%s)", m, m->mtx_description);
94336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
94436412d79SJohn Baldwin 	if (m->mtx_next == NULL)
94536412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
94636412d79SJohn Baldwin 		    m, m->mtx_description);
94736412d79SJohn Baldwin 
94836412d79SJohn Baldwin 	if (!mtx_owned(m)) {
94936412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
95036412d79SJohn Baldwin 	} else {
95108812b39SBosko Milekic 		MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
95236412d79SJohn Baldwin 	}
95336412d79SJohn Baldwin 	mtx_validate(m, MV_DESTROY);		/* diagnostic */
95436412d79SJohn Baldwin #endif
95536412d79SJohn Baldwin 
95636412d79SJohn Baldwin #ifdef WITNESS
95736412d79SJohn Baldwin 	if (m->mtx_witness)
95836412d79SJohn Baldwin 		witness_destroy(m);
95936412d79SJohn Baldwin #endif /* WITNESS */
96036412d79SJohn Baldwin 
96136412d79SJohn Baldwin 	/* Remove from the all mutex queue */
96236412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
96336412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
96436412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
96536412d79SJohn Baldwin #ifdef MUTEX_DEBUG
96636412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
9676936206eSJohn Baldwin #endif
9686936206eSJohn Baldwin #ifdef WITNESS
9698484de75SJohn Baldwin 	free(m->mtx_debug, M_DEVBUF);
9708484de75SJohn Baldwin 	m->mtx_debug = NULL;
97136412d79SJohn Baldwin #endif
97236412d79SJohn Baldwin 	mtx_cur_cnt--;
97336412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
97436412d79SJohn Baldwin }
9750384fff8SJason Evans 
9760384fff8SJason Evans /*
9770384fff8SJason Evans  * The non-inlined versions of the mtx_*() functions are always built (above),
9786936206eSJohn Baldwin  * but the witness code depends on the WITNESS kernel option being specified.
9790384fff8SJason Evans  */
9808484de75SJohn Baldwin 
9816936206eSJohn Baldwin #ifdef WITNESS
9828484de75SJohn Baldwin static void
9838484de75SJohn Baldwin witness_fixup(void *dummy __unused)
9848484de75SJohn Baldwin {
9858484de75SJohn Baldwin 	struct mtx *mp;
9868484de75SJohn Baldwin 
9878484de75SJohn Baldwin 	/*
9888484de75SJohn Baldwin 	 * We have to release Giant before initializing its witness
9898484de75SJohn Baldwin 	 * structure so that WITNESS doesn't get confused.
9908484de75SJohn Baldwin 	 */
9918484de75SJohn Baldwin 	mtx_exit(&Giant, MTX_DEF);
9928484de75SJohn Baldwin 	mtx_assert(&Giant, MA_NOTOWNED);
9938484de75SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
9948484de75SJohn Baldwin 
9958484de75SJohn Baldwin 	/* Iterate through all mutexes and finish up mutex initialization. */
9968484de75SJohn Baldwin 	for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
9978484de75SJohn Baldwin 
9988484de75SJohn Baldwin 		/* XXX - should not use DEVBUF */
9998484de75SJohn Baldwin 		mp->mtx_debug = malloc(sizeof(struct mtx_debug),
10008484de75SJohn Baldwin 		    M_DEVBUF, M_NOWAIT | M_ZERO);
10018484de75SJohn Baldwin 		MPASS(mp->mtx_debug != NULL);
10028484de75SJohn Baldwin 
10038484de75SJohn Baldwin 		witness_init(mp, mp->mtx_flags);
10048484de75SJohn Baldwin 	}
10058484de75SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
10068484de75SJohn Baldwin 
10078484de75SJohn Baldwin 	/* Mark the witness code as being ready for use. */
10088484de75SJohn Baldwin 	atomic_store_rel_int(&witness_cold, 0);
10098484de75SJohn Baldwin 
10108484de75SJohn Baldwin 	mtx_enter(&Giant, MTX_DEF);
10118484de75SJohn Baldwin }
10128484de75SJohn Baldwin SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL)
10130384fff8SJason Evans 
10140384fff8SJason Evans #define WITNESS_COUNT 200
10150384fff8SJason Evans #define	WITNESS_NCHILDREN 2
10160384fff8SJason Evans 
101778f0da03SJohn Baldwin int witness_watch = 1;
10180384fff8SJason Evans 
1019606f8eb2SJohn Baldwin struct witness {
10200384fff8SJason Evans 	struct witness	*w_next;
1021b67a3e6eSJohn Baldwin 	const char	*w_description;
102212473b76SJason Evans 	const char	*w_file;
10230384fff8SJason Evans 	int		 w_line;
10240384fff8SJason Evans 	struct witness	*w_morechildren;
10250384fff8SJason Evans 	u_char		 w_childcnt;
10260384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
10270384fff8SJason Evans 	u_char		 w_other_squawked:1;
10280384fff8SJason Evans 	u_char		 w_same_squawked:1;
102908812b39SBosko Milekic 	u_char		 w_spin:1;	/* MTX_SPIN type mutex. */
10300384fff8SJason Evans 	u_int		 w_level;
10310384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
1032606f8eb2SJohn Baldwin };
10330384fff8SJason Evans 
1034606f8eb2SJohn Baldwin struct witness_blessed {
10350384fff8SJason Evans 	char 	*b_lock1;
10360384fff8SJason Evans 	char	*b_lock2;
1037606f8eb2SJohn Baldwin };
10380384fff8SJason Evans 
1039a5a96a19SJohn Baldwin #ifdef DDB
10400384fff8SJason Evans /*
1041a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
10420384fff8SJason Evans  * drop into kdebug() when:
10430384fff8SJason Evans  *	- a lock heirarchy violation occurs
10440384fff8SJason Evans  *	- locks are held when going to sleep.
10450384fff8SJason Evans  */
10468484de75SJohn Baldwin int	witness_ddb;
1047a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
10488484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 1, witness_ddb);
1049a5a96a19SJohn Baldwin #else
10508484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 0, witness_ddb);
10510384fff8SJason Evans #endif
1052a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
1053a5a96a19SJohn Baldwin #endif /* DDB */
10540384fff8SJason Evans 
10558484de75SJohn Baldwin int	witness_skipspin;
1056a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
10578484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 1, witness_skipspin);
1058a5a96a19SJohn Baldwin #else
10598484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 0, witness_skipspin);
10600384fff8SJason Evans #endif
1061a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
1062a5a96a19SJohn Baldwin     "");
10630384fff8SJason Evans 
1064d1c1b841SJason Evans static struct mtx	w_mtx;
1065606f8eb2SJohn Baldwin static struct witness	*w_free;
1066606f8eb2SJohn Baldwin static struct witness	*w_all;
10670384fff8SJason Evans static int		 w_inited;
10680384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
10690384fff8SJason Evans 
1070606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
10710384fff8SJason Evans 
1072b67a3e6eSJohn Baldwin static struct witness	 *enroll __P((const char *description, int flag));
1073606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child));
1074606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child));
1075606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child));
1076606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child));
1077606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *));
1078606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *));
10790384fff8SJason Evans static void witness_displaydescendants
1080606f8eb2SJohn Baldwin     __P((void(*)(const char *fmt, ...), struct witness *));
1081606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level));
10820384fff8SJason Evans static void witness_levelall __P((void));
1083606f8eb2SJohn Baldwin static struct witness * witness_get __P((void));
1084606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m));
10850384fff8SJason Evans 
10860384fff8SJason Evans 
10870384fff8SJason Evans static char *ignore_list[] = {
10880384fff8SJason Evans 	"witness lock",
10890384fff8SJason Evans 	NULL
10900384fff8SJason Evans };
10910384fff8SJason Evans 
10920384fff8SJason Evans static char *spin_order_list[] = {
1093a5a96a19SJohn Baldwin 	"sio",
10948f838cb5SJohn Baldwin 	"sched lock",
109520cdcc5bSJohn Baldwin #ifdef __i386__
109620cdcc5bSJohn Baldwin 	"clk",
109720cdcc5bSJohn Baldwin #endif
1098fa2fbc3dSJake Burkholder 	"callout",
10990384fff8SJason Evans 	/*
11000384fff8SJason Evans 	 * leaf locks
11010384fff8SJason Evans 	 */
11020384fff8SJason Evans 	NULL
11030384fff8SJason Evans };
11040384fff8SJason Evans 
11050384fff8SJason Evans static char *order_list[] = {
11068484de75SJohn Baldwin 	"Giant", "uidinfo hash", "uidinfo struct", NULL,
11078484de75SJohn Baldwin 	"Giant", "proctree", "allproc", "process lock", NULL,
11080384fff8SJason Evans 	NULL
11090384fff8SJason Evans };
11100384fff8SJason Evans 
11110384fff8SJason Evans static char *dup_list[] = {
11120384fff8SJason Evans 	NULL
11130384fff8SJason Evans };
11140384fff8SJason Evans 
11150384fff8SJason Evans static char *sleep_list[] = {
11167da6f977SJake Burkholder 	"Giant",
11170384fff8SJason Evans 	NULL
11180384fff8SJason Evans };
11190384fff8SJason Evans 
11200384fff8SJason Evans /*
11210384fff8SJason Evans  * Pairs of locks which have been blessed
11220384fff8SJason Evans  * Don't complain about order problems with blessed locks
11230384fff8SJason Evans  */
1124606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
11250384fff8SJason Evans };
1126606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed);
11270384fff8SJason Evans 
11280cde2e34SJason Evans static void
1129606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
11300384fff8SJason Evans {
11310384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
11320384fff8SJason Evans }
11330384fff8SJason Evans 
11340cde2e34SJason Evans static void
1135606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
11360384fff8SJason Evans {
1137606f8eb2SJohn Baldwin 	struct mtx *m1;
11380384fff8SJason Evans 	struct proc *p;
11390384fff8SJason Evans 	p = CURPROC;
11400384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
11410384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
11420384fff8SJason Evans 		if (m1 == m) {
11430384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
11440384fff8SJason Evans 			break;
11450384fff8SJason Evans 		}
11460384fff8SJason Evans 	}
11470384fff8SJason Evans 	return;
11480384fff8SJason Evans 
11490384fff8SJason Evans }
11500384fff8SJason Evans 
11510cde2e34SJason Evans static void
11520cde2e34SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
11530cde2e34SJason Evans {
11540cde2e34SJason Evans 	struct witness *w, *w1;
11550cde2e34SJason Evans 
11560cde2e34SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
11570cde2e34SJason Evans 	witness_levelall();
11580cde2e34SJason Evans 
11590cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
11600cde2e34SJason Evans 		if (w->w_file == NULL)
11610cde2e34SJason Evans 			continue;
11620cde2e34SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
11630cde2e34SJason Evans 			if (isitmychild(w1, w))
11640cde2e34SJason Evans 				break;
11650cde2e34SJason Evans 		}
11660cde2e34SJason Evans 		if (w1 != NULL)
11670cde2e34SJason Evans 			continue;
11680cde2e34SJason Evans 		/*
11690cde2e34SJason Evans 		 * This lock has no anscestors, display its descendants.
11700cde2e34SJason Evans 		 */
11710cde2e34SJason Evans 		witness_displaydescendants(prnt, w);
11720cde2e34SJason Evans 	}
11730cde2e34SJason Evans 	prnt("\nMutex which were never acquired\n");
11740cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
11750cde2e34SJason Evans 		if (w->w_file != NULL)
11760cde2e34SJason Evans 			continue;
11770cde2e34SJason Evans 		prnt("%s\n", w->w_description);
11780cde2e34SJason Evans 	}
11790cde2e34SJason Evans }
11800cde2e34SJason Evans 
11810384fff8SJason Evans void
1182606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
11830384fff8SJason Evans {
1184606f8eb2SJohn Baldwin 	struct witness *w, *w1;
1185606f8eb2SJohn Baldwin 	struct mtx *m1;
11860384fff8SJason Evans 	struct proc *p;
11870384fff8SJason Evans 	int i;
1188a5a96a19SJohn Baldwin #ifdef DDB
1189a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
1190a5a96a19SJohn Baldwin #endif /* DDB */
11910384fff8SJason Evans 
11920cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
1193562e4ffeSJohn Baldwin 		return;
11940384fff8SJason Evans 	w = m->mtx_witness;
11950384fff8SJason Evans 	p = CURPROC;
11960384fff8SJason Evans 
11970384fff8SJason Evans 	if (flags & MTX_SPIN) {
11988484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
11995340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
12005340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
120108812b39SBosko Milekic 		if (mtx_recursed(m)) {
12028484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
120308812b39SBosko Milekic 				panic("mutex_enter: recursion on non-recursive"
120408812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
120508812b39SBosko Milekic 				    file, line);
12060384fff8SJason Evans 			return;
120708812b39SBosko Milekic 		}
1208562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
1209ef73ae4bSJake Burkholder 		i = PCPU_GET(witness_spin_check);
12100384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
1211562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12125340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
12135340642aSJason Evans 			    " %s:%d already holding %s:%x",
12140384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
12150384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
12160384fff8SJason Evans 		}
12170384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
1218562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
1219bbc7a98aSJohn Baldwin 		w->w_file = file;
1220bbc7a98aSJohn Baldwin 		w->w_line = line;
1221bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1222bbc7a98aSJohn Baldwin 		m->mtx_file = file;
12230384fff8SJason Evans 		return;
12240384fff8SJason Evans 	}
12258484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
12260384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12270384fff8SJason Evans 		    m->mtx_description, file, line);
12280384fff8SJason Evans 
122908812b39SBosko Milekic 	if (mtx_recursed(m)) {
12308484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
123108812b39SBosko Milekic 			panic("mutex_enter: recursion on non-recursive"
123208812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
123308812b39SBosko Milekic 			    file, line);
12340384fff8SJason Evans 		return;
123508812b39SBosko Milekic 	}
12360384fff8SJason Evans 	if (witness_dead)
12370384fff8SJason Evans 		goto out;
1238562e4ffeSJohn Baldwin 	if (cold)
12390384fff8SJason Evans 		goto out;
12400384fff8SJason Evans 
12410384fff8SJason Evans 	if (!mtx_legal2block())
12420384fff8SJason Evans 		panic("blockable mtx_enter() of %s when not legal @ %s:%d",
12430384fff8SJason Evans 			    m->mtx_description, file, line);
12440384fff8SJason Evans 	/*
12450384fff8SJason Evans 	 * Is this the first mutex acquired
12460384fff8SJason Evans 	 */
12470384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
12480384fff8SJason Evans 		goto out;
12490384fff8SJason Evans 
12500384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
12510384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
12520384fff8SJason Evans 			goto out;
12530384fff8SJason Evans 		w->w_same_squawked = 1;
12540384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
12550384fff8SJason Evans 			m->mtx_description);
12560384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
12570384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
1258a5a96a19SJohn Baldwin #ifdef DDB
1259a5a96a19SJohn Baldwin 		go_into_ddb = 1;
1260a5a96a19SJohn Baldwin #endif /* DDB */
12610384fff8SJason Evans 		goto out;
12620384fff8SJason Evans 	}
12630384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
1264562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
12650384fff8SJason Evans 	/*
12660384fff8SJason Evans 	 * If we have a known higher number just say ok
12670384fff8SJason Evans 	 */
12680384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
1269562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12700384fff8SJason Evans 		goto out;
12710384fff8SJason Evans 	}
12720384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
1273562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12740384fff8SJason Evans 		goto out;
12750384fff8SJason Evans 	}
12760384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
12770384fff8SJason Evans 
127836412d79SJohn Baldwin 		MPASS(i < 200);
12790384fff8SJason Evans 		w1 = m1->mtx_witness;
12800384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
1281562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12820384fff8SJason Evans 			if (blessed(w, w1))
12830384fff8SJason Evans 				goto out;
12840384fff8SJason Evans 			if (m1 == &Giant) {
12850384fff8SJason Evans 				if (w1->w_Giant_squawked)
12860384fff8SJason Evans 					goto out;
12870384fff8SJason Evans 				else
12880384fff8SJason Evans 					w1->w_Giant_squawked = 1;
12890384fff8SJason Evans 			} else {
12900384fff8SJason Evans 				if (w1->w_other_squawked)
12910384fff8SJason Evans 					goto out;
12920384fff8SJason Evans 				else
12930384fff8SJason Evans 					w1->w_other_squawked = 1;
12940384fff8SJason Evans 			}
12950384fff8SJason Evans 			printf("lock order reversal\n");
12960384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
12970384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
12980384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
12990384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
13000384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
13010384fff8SJason Evans 			    m, w->w_description, file, line);
1302a5a96a19SJohn Baldwin #ifdef DDB
1303a5a96a19SJohn Baldwin 			go_into_ddb = 1;
1304a5a96a19SJohn Baldwin #endif /* DDB */
13050384fff8SJason Evans 			goto out;
13060384fff8SJason Evans 		}
13070384fff8SJason Evans 	}
13080384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
13090384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
1310562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
13110384fff8SJason Evans 
13120384fff8SJason Evans out:
1313a5a96a19SJohn Baldwin #ifdef DDB
1314a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
1315a5a96a19SJohn Baldwin 		Debugger("witness_enter");
1316a5a96a19SJohn Baldwin #endif /* DDB */
13170384fff8SJason Evans 	w->w_file = file;
13180384fff8SJason Evans 	w->w_line = line;
13190384fff8SJason Evans 	m->mtx_line = line;
13200384fff8SJason Evans 	m->mtx_file = file;
13210384fff8SJason Evans 
13220384fff8SJason Evans 	/*
13230384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
13240384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
13250384fff8SJason Evans 	 * likely not the mutex this assert fails on.
13260384fff8SJason Evans 	 */
132736412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
13280384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
13290384fff8SJason Evans }
13300384fff8SJason Evans 
13310384fff8SJason Evans void
1332606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
13330384fff8SJason Evans {
13340384fff8SJason Evans 	struct proc *p;
1335606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
13360384fff8SJason Evans 
1337d1c1b841SJason Evans 	if (witness_cold)
1338d1c1b841SJason Evans 		return;
1339562e4ffeSJohn Baldwin 	if (panicstr)
1340562e4ffeSJohn Baldwin 		return;
13410384fff8SJason Evans 	if (flags & MTX_SPIN) {
13428484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
13430384fff8SJason Evans 			panic("mutex_try_enter: "
13440384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
13450384fff8SJason Evans 			    m->mtx_description, file, line);
134608812b39SBosko Milekic 		if (mtx_recursed(m)) {
13478484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
134808812b39SBosko Milekic 				panic("mutex_try_enter: recursion on"
134908812b39SBosko Milekic 				    " non-recursive mutex %s @ %s:%d",
135008812b39SBosko Milekic 				    m->mtx_description, file, line);
13510384fff8SJason Evans 			return;
135208812b39SBosko Milekic 		}
1353562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
1354ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
1355ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) | w->w_level);
1356562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
1357bbc7a98aSJohn Baldwin 		w->w_file = file;
1358bbc7a98aSJohn Baldwin 		w->w_line = line;
1359bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1360bbc7a98aSJohn Baldwin 		m->mtx_file = file;
13610384fff8SJason Evans 		return;
13620384fff8SJason Evans 	}
13630384fff8SJason Evans 
13648484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
13650384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
13660384fff8SJason Evans 		    m->mtx_description, file, line);
13670384fff8SJason Evans 
136808812b39SBosko Milekic 	if (mtx_recursed(m)) {
13698484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
137008812b39SBosko Milekic 			panic("mutex_try_enter: recursion on non-recursive"
137108812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description, file,
137208812b39SBosko Milekic 			    line);
13730384fff8SJason Evans 		return;
137408812b39SBosko Milekic 	}
13750384fff8SJason Evans 	w->w_file = file;
13760384fff8SJason Evans 	w->w_line = line;
13770384fff8SJason Evans 	m->mtx_line = line;
13780384fff8SJason Evans 	m->mtx_file = file;
13790384fff8SJason Evans 	p = CURPROC;
138036412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
13810384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
13820384fff8SJason Evans }
13830384fff8SJason Evans 
13840384fff8SJason Evans void
13850cde2e34SJason Evans witness_exit(struct mtx *m, int flags, const char *file, int line)
13860384fff8SJason Evans {
13870cde2e34SJason Evans 	struct witness *w;
13880384fff8SJason Evans 
13890cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
13900cde2e34SJason Evans 		return;
13910cde2e34SJason Evans 	w = m->mtx_witness;
13920384fff8SJason Evans 
13930cde2e34SJason Evans 	if (flags & MTX_SPIN) {
13948484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
13950cde2e34SJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
13960cde2e34SJason Evans 			    " %s:%d", m->mtx_description, file, line);
13970cde2e34SJason Evans 		if (mtx_recursed(m)) {
13988484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
13990cde2e34SJason Evans 				panic("mutex_exit: recursion on non-recursive"
14000cde2e34SJason Evans 				    " mutex %s @ %s:%d", m->mtx_description,
14010cde2e34SJason Evans 				    file, line);
14020cde2e34SJason Evans 			return;
14030384fff8SJason Evans 		}
14040cde2e34SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
14050cde2e34SJason Evans 		PCPU_SET(witness_spin_check,
14060cde2e34SJason Evans 		    PCPU_GET(witness_spin_check) & ~w->w_level);
14070cde2e34SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
14080cde2e34SJason Evans 		return;
14090384fff8SJason Evans 	}
14108484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
14110cde2e34SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
14120cde2e34SJason Evans 		    m->mtx_description, file, line);
14130cde2e34SJason Evans 
14140cde2e34SJason Evans 	if (mtx_recursed(m)) {
14158484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
14160cde2e34SJason Evans 			panic("mutex_exit: recursion on non-recursive"
14170cde2e34SJason Evans 			    " mutex %s @ %s:%d", m->mtx_description,
14180cde2e34SJason Evans 			    file, line);
14190cde2e34SJason Evans 		return;
14200384fff8SJason Evans 	}
14210cde2e34SJason Evans 
14220cde2e34SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
14230cde2e34SJason Evans 		panic("switchable mtx_exit() of %s when not legal @ %s:%d",
14240cde2e34SJason Evans 			    m->mtx_description, file, line);
14250cde2e34SJason Evans 	LIST_REMOVE(m, mtx_held);
14260cde2e34SJason Evans 	m->mtx_held.le_prev = NULL;
14270384fff8SJason Evans }
14280384fff8SJason Evans 
14290384fff8SJason Evans int
1430606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
14310384fff8SJason Evans {
1432606f8eb2SJohn Baldwin 	struct mtx *m;
14330384fff8SJason Evans 	struct proc *p;
14340384fff8SJason Evans 	char **sleep;
14350384fff8SJason Evans 	int n = 0;
14360384fff8SJason Evans 
1437d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
14380384fff8SJason Evans 	p = CURPROC;
14390384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
14400384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
14410384fff8SJason Evans 		if (m == mtx)
14420384fff8SJason Evans 			continue;
14430384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
14440384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
14450384fff8SJason Evans 				goto next;
14460384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
14470384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
14480384fff8SJason Evans 			m->mtx_description,
14490384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
14500384fff8SJason Evans 		n++;
14510384fff8SJason Evans 	next:
14520384fff8SJason Evans 	}
1453a5a96a19SJohn Baldwin #ifdef DDB
1454a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1455a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1456a5a96a19SJohn Baldwin #endif /* DDB */
14570384fff8SJason Evans 	return (n);
14580384fff8SJason Evans }
14590384fff8SJason Evans 
1460606f8eb2SJohn Baldwin static struct witness *
1461b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
14620384fff8SJason Evans {
14630384fff8SJason Evans 	int i;
1464606f8eb2SJohn Baldwin 	struct witness *w, *w1;
14650384fff8SJason Evans 	char **ignore;
14660384fff8SJason Evans 	char **order;
14670384fff8SJason Evans 
14680384fff8SJason Evans 	if (!witness_watch)
14690384fff8SJason Evans 		return (NULL);
14700384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
14710384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
14720384fff8SJason Evans 			return (NULL);
14730384fff8SJason Evans 
14740384fff8SJason Evans 	if (w_inited == 0) {
1475d1c1b841SJason Evans 		mtx_init(&w_mtx, "witness lock", MTX_SPIN);
14760384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
14770384fff8SJason Evans 			w = &w_data[i];
14780384fff8SJason Evans 			witness_free(w);
14790384fff8SJason Evans 		}
14800384fff8SJason Evans 		w_inited = 1;
14810384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
14820384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
14830384fff8SJason Evans 			w->w_file = "order list";
14840384fff8SJason Evans 			for (order++; *order != NULL; order++) {
14850384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
14860384fff8SJason Evans 				w1->w_file = "order list";
14870384fff8SJason Evans 				itismychild(w, w1);
14880384fff8SJason Evans 				w = w1;
14890384fff8SJason Evans     	    	    	}
14900384fff8SJason Evans 		}
14910384fff8SJason Evans 	}
14920384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
14930384fff8SJason Evans 		return (NULL);
1494562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
14950384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
14960384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
1497562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
14980384fff8SJason Evans 			return (w);
14990384fff8SJason Evans 		}
15000384fff8SJason Evans 	}
15010384fff8SJason Evans 	if ((w = witness_get()) == NULL)
15020384fff8SJason Evans 		return (NULL);
15030384fff8SJason Evans 	w->w_next = w_all;
15040384fff8SJason Evans 	w_all = w;
15050384fff8SJason Evans 	w->w_description = description;
1506562e4ffeSJohn Baldwin 	mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
15070384fff8SJason Evans 	if (flag & MTX_SPIN) {
15080384fff8SJason Evans 		w->w_spin = 1;
15090384fff8SJason Evans 
15100384fff8SJason Evans 		i = 1;
15110384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
15120384fff8SJason Evans 			if (strcmp(description, *order) == 0)
15130384fff8SJason Evans 				break;
15140384fff8SJason Evans 			i <<= 1;
15150384fff8SJason Evans 		}
15160384fff8SJason Evans 		if (*order == NULL)
15170384fff8SJason Evans 			panic("spin lock %s not in order list", description);
15180384fff8SJason Evans 		w->w_level = i;
15198484de75SJohn Baldwin 	}
152008812b39SBosko Milekic 
15210384fff8SJason Evans 	return (w);
15220384fff8SJason Evans }
15230384fff8SJason Evans 
15240384fff8SJason Evans static int
1525606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
15260384fff8SJason Evans {
15270384fff8SJason Evans 	static int recursed;
15280384fff8SJason Evans 
15290384fff8SJason Evans 	/*
15300384fff8SJason Evans 	 * Insert "child" after "parent"
15310384fff8SJason Evans 	 */
15320384fff8SJason Evans 	while (parent->w_morechildren)
15330384fff8SJason Evans 		parent = parent->w_morechildren;
15340384fff8SJason Evans 
15350384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
15360384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
15370384fff8SJason Evans 			return (1);
15380384fff8SJason Evans 		parent = parent->w_morechildren;
15390384fff8SJason Evans 	}
154036412d79SJohn Baldwin 	MPASS(child != NULL);
15410384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
15420384fff8SJason Evans 	/*
15430384fff8SJason Evans 	 * now prune whole tree
15440384fff8SJason Evans 	 */
15450384fff8SJason Evans 	if (recursed)
15460384fff8SJason Evans 		return (0);
15470384fff8SJason Evans 	recursed = 1;
15480384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
15490384fff8SJason Evans 		for (parent = w_all; parent != NULL;
15500384fff8SJason Evans 		    parent = parent->w_next) {
15510384fff8SJason Evans 			if (!isitmychild(parent, child))
15520384fff8SJason Evans 				continue;
15530384fff8SJason Evans 			removechild(parent, child);
15540384fff8SJason Evans 			if (isitmydescendant(parent, child))
15550384fff8SJason Evans 				continue;
15560384fff8SJason Evans 			itismychild(parent, child);
15570384fff8SJason Evans 		}
15580384fff8SJason Evans 	}
15590384fff8SJason Evans 	recursed = 0;
15600384fff8SJason Evans 	witness_levelall();
15610384fff8SJason Evans 	return (0);
15620384fff8SJason Evans }
15630384fff8SJason Evans 
15640384fff8SJason Evans static void
1565606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
15660384fff8SJason Evans {
1567606f8eb2SJohn Baldwin 	struct witness *w, *w1;
15680384fff8SJason Evans 	int i;
15690384fff8SJason Evans 
15700384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15710384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15720384fff8SJason Evans 			if (w->w_children[i] == child)
15730384fff8SJason Evans 				goto found;
15740384fff8SJason Evans 	return;
15750384fff8SJason Evans found:
15760384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
15770384fff8SJason Evans 		continue;
15780384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
157936412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
15800384fff8SJason Evans 
15810384fff8SJason Evans 	if (w1->w_childcnt != 0)
15820384fff8SJason Evans 		return;
15830384fff8SJason Evans 
15840384fff8SJason Evans 	if (w1 == parent)
15850384fff8SJason Evans 		return;
15860384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
15870384fff8SJason Evans 		continue;
15880384fff8SJason Evans 	w->w_morechildren = 0;
15890384fff8SJason Evans 	witness_free(w1);
15900384fff8SJason Evans }
15910384fff8SJason Evans 
15920384fff8SJason Evans static int
1593606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
15940384fff8SJason Evans {
1595606f8eb2SJohn Baldwin 	struct witness *w;
15960384fff8SJason Evans 	int i;
15970384fff8SJason Evans 
15980384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
15990384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16000384fff8SJason Evans 			if (w->w_children[i] == child)
16010384fff8SJason Evans 				return (1);
16020384fff8SJason Evans 		}
16030384fff8SJason Evans 	}
16040384fff8SJason Evans 	return (0);
16050384fff8SJason Evans }
16060384fff8SJason Evans 
16070384fff8SJason Evans static int
1608606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
16090384fff8SJason Evans {
1610606f8eb2SJohn Baldwin 	struct witness *w;
16110384fff8SJason Evans 	int i;
16120384fff8SJason Evans 	int j;
16130384fff8SJason Evans 
16140384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
161536412d79SJohn Baldwin 		MPASS(j < 1000);
16160384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16170384fff8SJason Evans 			if (w->w_children[i] == child)
16180384fff8SJason Evans 				return (1);
16190384fff8SJason Evans 		}
16200384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16210384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
16220384fff8SJason Evans 				return (1);
16230384fff8SJason Evans 		}
16240384fff8SJason Evans 	}
16250384fff8SJason Evans 	return (0);
16260384fff8SJason Evans }
16270384fff8SJason Evans 
16280384fff8SJason Evans void
16290384fff8SJason Evans witness_levelall (void)
16300384fff8SJason Evans {
1631606f8eb2SJohn Baldwin 	struct witness *w, *w1;
16320384fff8SJason Evans 
16330384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
163408812b39SBosko Milekic 		if (!(w->w_spin))
16350384fff8SJason Evans 			w->w_level = 0;
16360384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
16370384fff8SJason Evans 		if (w->w_spin)
16380384fff8SJason Evans 			continue;
16390384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
16400384fff8SJason Evans 			if (isitmychild(w1, w))
16410384fff8SJason Evans 				break;
16420384fff8SJason Evans 		}
16430384fff8SJason Evans 		if (w1 != NULL)
16440384fff8SJason Evans 			continue;
16450384fff8SJason Evans 		witness_leveldescendents(w, 0);
16460384fff8SJason Evans 	}
16470384fff8SJason Evans }
16480384fff8SJason Evans 
16490384fff8SJason Evans static void
1650606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
16510384fff8SJason Evans {
16520384fff8SJason Evans 	int i;
1653606f8eb2SJohn Baldwin 	struct witness *w;
16540384fff8SJason Evans 
16550384fff8SJason Evans 	if (parent->w_level < level)
16560384fff8SJason Evans 		parent->w_level = level;
16570384fff8SJason Evans 	level++;
16580384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
16590384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
16600384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
16610384fff8SJason Evans }
16620384fff8SJason Evans 
16630384fff8SJason Evans static void
1664606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1665606f8eb2SJohn Baldwin 			   struct witness *parent)
16660384fff8SJason Evans {
1667606f8eb2SJohn Baldwin 	struct witness *w;
16680384fff8SJason Evans 	int i;
16690384fff8SJason Evans 	int level = parent->w_level;
16700384fff8SJason Evans 
16710384fff8SJason Evans 	prnt("%d", level);
16720384fff8SJason Evans 	if (level < 10)
16730384fff8SJason Evans 		prnt(" ");
16740384fff8SJason Evans 	for (i = 0; i < level; i++)
16750384fff8SJason Evans 		prnt(" ");
16760384fff8SJason Evans 	prnt("%s", parent->w_description);
16770384fff8SJason Evans 	if (parent->w_file != NULL) {
16780384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
16790384fff8SJason Evans #ifndef W_USE_WHERE
16800384fff8SJason Evans 		prnt(":%d", parent->w_line);
16810384fff8SJason Evans #endif
16820384fff8SJason Evans 		prnt("\n");
16830384fff8SJason Evans 	}
16840384fff8SJason Evans 
16850384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
16860384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
16870384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
16880384fff8SJason Evans     }
16890384fff8SJason Evans 
16900384fff8SJason Evans static int
1691606f8eb2SJohn Baldwin dup_ok(struct witness *w)
16920384fff8SJason Evans {
16930384fff8SJason Evans 	char **dup;
16940384fff8SJason Evans 
16950384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
16960384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
16970384fff8SJason Evans 			return (1);
16980384fff8SJason Evans 	return (0);
16990384fff8SJason Evans }
17000384fff8SJason Evans 
17010384fff8SJason Evans static int
1702606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
17030384fff8SJason Evans {
17040384fff8SJason Evans 	int i;
1705606f8eb2SJohn Baldwin 	struct witness_blessed *b;
17060384fff8SJason Evans 
17070384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
17080384fff8SJason Evans 		b = &blessed_list[i];
17090384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
17100384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
17110384fff8SJason Evans 				return (1);
17120384fff8SJason Evans 			continue;
17130384fff8SJason Evans 		}
17140384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
17150384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
17160384fff8SJason Evans 				return (1);
17170384fff8SJason Evans 	}
17180384fff8SJason Evans 	return (0);
17190384fff8SJason Evans }
17200384fff8SJason Evans 
1721606f8eb2SJohn Baldwin static struct witness *
17220384fff8SJason Evans witness_get()
17230384fff8SJason Evans {
1724606f8eb2SJohn Baldwin 	struct witness *w;
17250384fff8SJason Evans 
17260384fff8SJason Evans 	if ((w = w_free) == NULL) {
17270384fff8SJason Evans 		witness_dead = 1;
1728562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
17290384fff8SJason Evans 		printf("witness exhausted\n");
17300384fff8SJason Evans 		return (NULL);
17310384fff8SJason Evans 	}
17320384fff8SJason Evans 	w_free = w->w_next;
17330384fff8SJason Evans 	bzero(w, sizeof(*w));
17340384fff8SJason Evans 	return (w);
17350384fff8SJason Evans }
17360384fff8SJason Evans 
17370384fff8SJason Evans static void
1738606f8eb2SJohn Baldwin witness_free(struct witness *w)
17390384fff8SJason Evans {
17400384fff8SJason Evans 	w->w_next = w_free;
17410384fff8SJason Evans 	w_free = w;
17420384fff8SJason Evans }
17430384fff8SJason Evans 
174492cf772dSJake Burkholder int
17450384fff8SJason Evans witness_list(struct proc *p)
17460384fff8SJason Evans {
1747606f8eb2SJohn Baldwin 	struct mtx *m;
174892cf772dSJake Burkholder 	int nheld;
17490384fff8SJason Evans 
1750d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
175192cf772dSJake Burkholder 	nheld = 0;
17520384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
17530384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
17540384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
17550384fff8SJason Evans 		    m->mtx_description, m,
17560384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
175792cf772dSJake Burkholder 		nheld++;
17580384fff8SJason Evans 	}
175992cf772dSJake Burkholder 
176092cf772dSJake Burkholder 	return (nheld);
17610384fff8SJason Evans }
17620384fff8SJason Evans 
17630384fff8SJason Evans void
1764606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
17650384fff8SJason Evans {
1766d1c1b841SJason Evans 
1767d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
17680cde2e34SJason Evans 	if (m->mtx_witness == NULL)
17690cde2e34SJason Evans 		return;
17700cde2e34SJason Evans 
17710384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
17720384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
17730384fff8SJason Evans }
17740384fff8SJason Evans 
17750384fff8SJason Evans void
1776606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
17770384fff8SJason Evans {
1778d1c1b841SJason Evans 
1779d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
17800cde2e34SJason Evans 	if (m->mtx_witness == NULL)
17810cde2e34SJason Evans 		return;
17820cde2e34SJason Evans 
17830384fff8SJason Evans 	m->mtx_witness->w_file = file;
17840384fff8SJason Evans 	m->mtx_witness->w_line = line;
17850384fff8SJason Evans }
17860384fff8SJason Evans 
17876936206eSJohn Baldwin #endif	/* WITNESS */
1788