xref: /freebsd/sys/kern/kern_mutex.c (revision 56771ca74b5ca2534bb504c808cdc366949696be)
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 	const char	*mtxd_description;
950cde2e34SJason Evans };
960cde2e34SJason Evans 
970cde2e34SJason Evans #define mtx_description	mtx_union.mtxu_debug->mtxd_description
980cde2e34SJason Evans #define mtx_held	mtx_union.mtxu_debug->mtxd_held
990cde2e34SJason Evans #define	mtx_file	mtx_union.mtxu_debug->mtxd_file
1000cde2e34SJason Evans #define	mtx_line	mtx_union.mtxu_debug->mtxd_line
1010cde2e34SJason Evans #define	mtx_witness	mtx_union.mtxu_debug->mtxd_witness
1020cde2e34SJason Evans #else	/* WITNESS */
1030cde2e34SJason Evans #define mtx_description	mtx_union.mtxu_description
1040cde2e34SJason Evans #endif	/* WITNESS */
1050cde2e34SJason Evans 
1060cde2e34SJason Evans /*
1070cde2e34SJason Evans  * Assembly macros
1080cde2e34SJason Evans  *------------------------------------------------------------------------------
1090cde2e34SJason Evans  */
1100cde2e34SJason Evans 
1110cde2e34SJason Evans #define	_V(x)	__STRING(x)
1120cde2e34SJason Evans 
1130cde2e34SJason Evans /*
1140cde2e34SJason Evans  * Default, unoptimized mutex micro-operations
1150cde2e34SJason Evans  */
1160cde2e34SJason Evans 
1170cde2e34SJason Evans #ifndef _obtain_lock
1180cde2e34SJason Evans /* Actually obtain mtx_lock */
1190cde2e34SJason Evans #define _obtain_lock(mp, tid)						\
1200cde2e34SJason Evans 	atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid))
1210cde2e34SJason Evans #endif
1220cde2e34SJason Evans 
1230cde2e34SJason Evans #ifndef _release_lock
1240cde2e34SJason Evans /* Actually release mtx_lock */
1250cde2e34SJason Evans #define _release_lock(mp, tid)		       				\
1260cde2e34SJason Evans 	atomic_cmpset_rel_ptr(&(mp)->mtx_lock, (tid), (void *)MTX_UNOWNED)
1270cde2e34SJason Evans #endif
1280cde2e34SJason Evans 
1290cde2e34SJason Evans #ifndef _release_lock_quick
1300cde2e34SJason Evans /* Actually release mtx_lock quickly assuming that we own it */
1310cde2e34SJason Evans #define	_release_lock_quick(mp) 					\
1320cde2e34SJason Evans 	atomic_store_rel_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED)
1330cde2e34SJason Evans #endif
1340cde2e34SJason Evans 
1350cde2e34SJason Evans #ifndef _getlock_sleep
1360cde2e34SJason Evans /* Get a sleep lock, deal with recursion inline. */
1370cde2e34SJason Evans #define	_getlock_sleep(mp, tid, type) do {				\
1380cde2e34SJason Evans 	if (!_obtain_lock(mp, tid)) {					\
1390cde2e34SJason Evans 		if (((mp)->mtx_lock & MTX_FLAGMASK) != ((uintptr_t)(tid)))\
1400cde2e34SJason Evans 			mtx_enter_hard(mp, (type) & MTX_HARDOPTS, 0);	\
1410cde2e34SJason Evans 		else {							\
1420cde2e34SJason Evans 			atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSED);	\
1430cde2e34SJason Evans 			(mp)->mtx_recurse++;				\
1440cde2e34SJason Evans 		}							\
1450cde2e34SJason Evans 	}								\
1460cde2e34SJason Evans } while (0)
1470cde2e34SJason Evans #endif
1480cde2e34SJason Evans 
1490cde2e34SJason Evans #ifndef _getlock_spin_block
1500cde2e34SJason Evans /* Get a spin lock, handle recursion inline (as the less common case) */
1510cde2e34SJason Evans #define	_getlock_spin_block(mp, tid, type) do {				\
1520cde2e34SJason Evans 	u_int _mtx_intr = save_intr();					\
1530cde2e34SJason Evans 	disable_intr();							\
1540cde2e34SJason Evans 	if (!_obtain_lock(mp, tid))					\
1550cde2e34SJason Evans 		mtx_enter_hard(mp, (type) & MTX_HARDOPTS, _mtx_intr);	\
1560cde2e34SJason Evans 	else								\
1570cde2e34SJason Evans 		(mp)->mtx_saveintr = _mtx_intr;				\
1580cde2e34SJason Evans } while (0)
1590cde2e34SJason Evans #endif
1600cde2e34SJason Evans 
1610cde2e34SJason Evans #ifndef _getlock_norecurse
1620cde2e34SJason Evans /*
1630cde2e34SJason Evans  * Get a lock without any recursion handling. Calls the hard enter function if
1640cde2e34SJason Evans  * we can't get it inline.
1650cde2e34SJason Evans  */
1660cde2e34SJason Evans #define	_getlock_norecurse(mp, tid, type) do {				\
1670cde2e34SJason Evans 	if (!_obtain_lock(mp, tid))					\
1680cde2e34SJason Evans 		mtx_enter_hard((mp), (type) & MTX_HARDOPTS, 0);		\
1690cde2e34SJason Evans } while (0)
1700cde2e34SJason Evans #endif
1710cde2e34SJason Evans 
1720cde2e34SJason Evans #ifndef _exitlock_norecurse
1730cde2e34SJason Evans /*
1740cde2e34SJason Evans  * Release a sleep lock assuming we haven't recursed on it, recursion is handled
1750cde2e34SJason Evans  * in the hard function.
1760cde2e34SJason Evans  */
1770cde2e34SJason Evans #define	_exitlock_norecurse(mp, tid, type) do {				\
1780cde2e34SJason Evans 	if (!_release_lock(mp, tid))					\
1790cde2e34SJason Evans 		mtx_exit_hard((mp), (type) & MTX_HARDOPTS);		\
1800cde2e34SJason Evans } while (0)
1810cde2e34SJason Evans #endif
1820cde2e34SJason Evans 
1830cde2e34SJason Evans #ifndef _exitlock
1840cde2e34SJason Evans /*
1850cde2e34SJason Evans  * Release a sleep lock when its likely we recursed (the code to
1860cde2e34SJason Evans  * deal with simple recursion is inline).
1870cde2e34SJason Evans  */
1880cde2e34SJason Evans #define	_exitlock(mp, tid, type) do {					\
1890cde2e34SJason Evans 	if (!_release_lock(mp, tid)) {					\
1900cde2e34SJason Evans 		if ((mp)->mtx_lock & MTX_RECURSED) {			\
1910cde2e34SJason Evans 			if (--((mp)->mtx_recurse) == 0)			\
1920cde2e34SJason Evans 				atomic_clear_ptr(&(mp)->mtx_lock,	\
1930cde2e34SJason Evans 				    MTX_RECURSED);			\
1940cde2e34SJason Evans 		} else {						\
1950cde2e34SJason Evans 			mtx_exit_hard((mp), (type) & MTX_HARDOPTS);	\
1960cde2e34SJason Evans 		}							\
1970cde2e34SJason Evans 	}								\
1980cde2e34SJason Evans } while (0)
1990cde2e34SJason Evans #endif
2000cde2e34SJason Evans 
2010cde2e34SJason Evans #ifndef _exitlock_spin
2020cde2e34SJason Evans /* Release a spin lock (with possible recursion). */
2030cde2e34SJason Evans #define	_exitlock_spin(mp) do {						\
2040cde2e34SJason Evans 	if (!mtx_recursed((mp))) {					\
2050cde2e34SJason Evans 		int _mtx_intr = (mp)->mtx_saveintr;			\
2060cde2e34SJason Evans 									\
2070cde2e34SJason Evans 		_release_lock_quick(mp);				\
2080cde2e34SJason Evans 		restore_intr(_mtx_intr);				\
2090cde2e34SJason Evans 	} else {							\
2100cde2e34SJason Evans 		(mp)->mtx_recurse--;					\
2110cde2e34SJason Evans 	}								\
2120cde2e34SJason Evans } while (0)
2130cde2e34SJason Evans #endif
2140cde2e34SJason Evans 
2150cde2e34SJason Evans #ifdef WITNESS
2160cde2e34SJason Evans static void	witness_init(struct mtx *, int flag);
2170cde2e34SJason Evans static void	witness_destroy(struct mtx *);
2180cde2e34SJason Evans static void	witness_display(void(*)(const char *fmt, ...));
2190cde2e34SJason Evans 
2200cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */
22136412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0,
22236412d79SJohn Baldwin 	"All mutexes queue head" };
223527c2fd2SJason Evans static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, {&all_mtx_debug},
22436412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
22536412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
226d1c1b841SJason Evans /*
227d1c1b841SJason Evans  * Set to 0 once mutexes have been fully initialized so that witness code can be
228d1c1b841SJason Evans  * safely executed.
229d1c1b841SJason Evans  */
230d1c1b841SJason Evans static int witness_cold = 1;
2316936206eSJohn Baldwin #else	/* WITNESS */
2320cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */
233527c2fd2SJason Evans static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, {"All mutexes queue head"},
23436412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
23536412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
2360cde2e34SJason Evans 
2370cde2e34SJason Evans /*
2380cde2e34SJason Evans  * flag++ is slezoid way of shutting up unused parameter warning
2390cde2e34SJason Evans  * in mtx_init()
2400cde2e34SJason Evans  */
2410cde2e34SJason Evans #define witness_init(m, flag) flag++
2420cde2e34SJason Evans #define witness_destroy(m)
2430cde2e34SJason Evans #define witness_try_enter(m, t, f, l)
2446936206eSJohn Baldwin #endif	/* WITNESS */
24536412d79SJohn Baldwin 
24636412d79SJohn Baldwin static int	mtx_cur_cnt;
24736412d79SJohn Baldwin static int	mtx_max_cnt;
24836412d79SJohn Baldwin 
2491bd0eefbSJohn Baldwin static void	propagate_priority(struct proc *);
2500cde2e34SJason Evans static void	mtx_enter_hard(struct mtx *, int type, int saveintr);
2510cde2e34SJason Evans static void	mtx_exit_hard(struct mtx *, int type);
25236412d79SJohn Baldwin 
25336412d79SJohn Baldwin #define	mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
25436412d79SJohn Baldwin #define	mtx_owner(m)	(mtx_unowned(m) ? NULL \
25536412d79SJohn Baldwin 			    : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
25636412d79SJohn Baldwin 
25736412d79SJohn Baldwin #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
25836412d79SJohn Baldwin #define	SET_PRIO(p, pri)	(p)->p_priority = (pri)
25936412d79SJohn Baldwin 
26036412d79SJohn Baldwin static void
26136412d79SJohn Baldwin propagate_priority(struct proc *p)
26236412d79SJohn Baldwin {
26336412d79SJohn Baldwin 	int pri = p->p_priority;
26436412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
26536412d79SJohn Baldwin 
2661bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
26736412d79SJohn Baldwin 	for (;;) {
26836412d79SJohn Baldwin 		struct proc *p1;
26936412d79SJohn Baldwin 
27036412d79SJohn Baldwin 		p = mtx_owner(m);
27136412d79SJohn Baldwin 
27236412d79SJohn Baldwin 		if (p == NULL) {
27336412d79SJohn Baldwin 			/*
27436412d79SJohn Baldwin 			 * This really isn't quite right. Really
27536412d79SJohn Baldwin 			 * ought to bump priority of process that
27636412d79SJohn Baldwin 			 * next acquires the mutex.
27736412d79SJohn Baldwin 			 */
27836412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
27936412d79SJohn Baldwin 			return;
28036412d79SJohn Baldwin 		}
28136412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
2821bd0eefbSJohn Baldwin 		KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex"));
28336412d79SJohn Baldwin 		if (p->p_priority <= pri)
28436412d79SJohn Baldwin 			return;
2851bd0eefbSJohn Baldwin 
2861bd0eefbSJohn Baldwin 		/*
2871bd0eefbSJohn Baldwin 		 * Bump this process' priority.
2881bd0eefbSJohn Baldwin 		 */
2891bd0eefbSJohn Baldwin 		SET_PRIO(p, pri);
2901bd0eefbSJohn Baldwin 
29136412d79SJohn Baldwin 		/*
29236412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
29336412d79SJohn Baldwin 		 */
2941bd0eefbSJohn Baldwin #ifdef SMP
2951bd0eefbSJohn Baldwin 		/*
2961bd0eefbSJohn Baldwin 		 * For SMP, we can check the p_oncpu field to see if we are
2971bd0eefbSJohn Baldwin 		 * running.
2981bd0eefbSJohn Baldwin 		 */
2991bd0eefbSJohn Baldwin 		if (p->p_oncpu != 0xff) {
30036412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
30136412d79SJohn Baldwin 			return;
30236412d79SJohn Baldwin 		}
3031bd0eefbSJohn Baldwin #else
3041bd0eefbSJohn Baldwin 		/*
3051bd0eefbSJohn Baldwin 		 * For UP, we check to see if p is curproc (this shouldn't
3061bd0eefbSJohn Baldwin 		 * ever happen however as it would mean we are in a deadlock.)
3071bd0eefbSJohn Baldwin 		 */
3081bd0eefbSJohn Baldwin 		if (p == curproc) {
3091bd0eefbSJohn Baldwin 			panic("Deadlock detected");
3101bd0eefbSJohn Baldwin 			return;
3111bd0eefbSJohn Baldwin 		}
3121bd0eefbSJohn Baldwin #endif
31336412d79SJohn Baldwin 		/*
31436412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
31536412d79SJohn Baldwin 		 * quit.
31636412d79SJohn Baldwin 		 */
31736412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
3181bd0eefbSJohn Baldwin 			printf("XXX: moving process %d(%s) to a new run queue\n",
3191bd0eefbSJohn Baldwin 			       p->p_pid, p->p_comm);
32036412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
32136412d79SJohn Baldwin 			remrunqueue(p);
32236412d79SJohn Baldwin 			setrunqueue(p);
32336412d79SJohn Baldwin 			return;
32436412d79SJohn Baldwin 		}
32536412d79SJohn Baldwin 
32636412d79SJohn Baldwin 		/*
3271bd0eefbSJohn Baldwin 		 * If we aren't blocked on a mutex, we should be.
32836412d79SJohn Baldwin 		 */
3291bd0eefbSJohn Baldwin 		KASSERT(p->p_stat == SMTX, (
3301bd0eefbSJohn Baldwin 		    "process %d(%s):%d holds %s but isn't blocked on a mutex\n",
3311bd0eefbSJohn Baldwin 		    p->p_pid, p->p_comm, p->p_stat,
3321bd0eefbSJohn Baldwin 		    m->mtx_description));
33336412d79SJohn Baldwin 
33436412d79SJohn Baldwin 		/*
33536412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
33636412d79SJohn Baldwin 		 */
33736412d79SJohn Baldwin 		m = p->p_blocked;
33836412d79SJohn Baldwin 		MPASS(m != NULL);
33936412d79SJohn Baldwin 
34036412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
34136412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
34236412d79SJohn Baldwin 		/*
34336412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
34436412d79SJohn Baldwin 		 * the blocked chain
34536412d79SJohn Baldwin 		 */
3461bd0eefbSJohn Baldwin 		if (p == TAILQ_FIRST(&m->mtx_blocked)) {
3471bd0eefbSJohn Baldwin 			printf("XXX: process at head of run queue\n");
3481bd0eefbSJohn Baldwin 			continue;
3491bd0eefbSJohn Baldwin 		}
3501bd0eefbSJohn Baldwin 		p1 = TAILQ_PREV(p, rq, p_procq);
3511bd0eefbSJohn Baldwin 		if (p1->p_priority <= pri) {
35236412d79SJohn Baldwin 			printf(
35336412d79SJohn Baldwin 	"XXX: previous process %d(%s) has higher priority\n",
35436412d79SJohn Baldwin 	                    p->p_pid, p->p_comm);
35536412d79SJohn Baldwin 			continue;
35636412d79SJohn Baldwin 		}
35736412d79SJohn Baldwin 
35836412d79SJohn Baldwin 		/*
3591bd0eefbSJohn Baldwin 		 * Remove proc from blocked chain and determine where
3601bd0eefbSJohn Baldwin 		 * it should be moved up to.  Since we know that p1 has
3611bd0eefbSJohn Baldwin 		 * a lower priority than p, we know that at least one
3621bd0eefbSJohn Baldwin 		 * process in the chain has a lower priority and that
3631bd0eefbSJohn Baldwin 		 * p1 will thus not be NULL after the loop.
36436412d79SJohn Baldwin 		 */
36536412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
36636412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
36736412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
36836412d79SJohn Baldwin 			if (p1->p_priority > pri)
36936412d79SJohn Baldwin 				break;
37036412d79SJohn Baldwin 		}
3711bd0eefbSJohn Baldwin 		MPASS(p1 != NULL);
37236412d79SJohn Baldwin 		TAILQ_INSERT_BEFORE(p1, p, p_procq);
37336412d79SJohn Baldwin 		CTR4(KTR_LOCK,
3741bd0eefbSJohn Baldwin 		    "propagate_priority: p 0x%p moved before 0x%p on [0x%p] %s",
37536412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
37636412d79SJohn Baldwin 	}
37736412d79SJohn Baldwin }
37836412d79SJohn Baldwin 
3790cde2e34SJason Evans /*
3800cde2e34SJason Evans  * Get lock 'm', the macro handles the easy (and most common cases) and leaves
3810cde2e34SJason Evans  * the slow stuff to the mtx_enter_hard() function.
3820cde2e34SJason Evans  *
3830cde2e34SJason Evans  * Note: since type is usually a constant much of this code is optimized out.
3840cde2e34SJason Evans  */
3850cde2e34SJason Evans void
3860cde2e34SJason Evans _mtx_enter(struct mtx *mtxp, int type, const char *file, int line)
3870cde2e34SJason Evans {
3880cde2e34SJason Evans 	struct mtx	*mpp = mtxp;
3890cde2e34SJason Evans 
3900cde2e34SJason Evans 	/* bits only valid on mtx_exit() */
3910cde2e34SJason Evans 	MPASS4(((type) & (MTX_NORECURSE | MTX_NOSWITCH)) == 0,
3920cde2e34SJason Evans 	    STR_mtx_bad_type, file, line);
3930cde2e34SJason Evans 
3940cde2e34SJason Evans 	if ((type) & MTX_SPIN) {
3950cde2e34SJason Evans 		/*
3960cde2e34SJason Evans 		 * Easy cases of spin locks:
3970cde2e34SJason Evans 		 *
3980cde2e34SJason Evans 		 * 1) We already own the lock and will simply recurse on it (if
3990cde2e34SJason Evans 		 *    RLIKELY)
4000cde2e34SJason Evans 		 *
4010cde2e34SJason Evans 		 * 2) The lock is free, we just get it
4020cde2e34SJason Evans 		 */
4030cde2e34SJason Evans 		if ((type) & MTX_RLIKELY) {
4040cde2e34SJason Evans 			/*
4050cde2e34SJason Evans 			 * Check for recursion, if we already have this
4060cde2e34SJason Evans 			 * lock we just bump the recursion count.
4070cde2e34SJason Evans 			 */
4080cde2e34SJason Evans 			if (mpp->mtx_lock == (uintptr_t)CURTHD) {
4090cde2e34SJason Evans 				mpp->mtx_recurse++;
4100cde2e34SJason Evans 				goto done;
4110cde2e34SJason Evans 			}
4120cde2e34SJason Evans 		}
4130cde2e34SJason Evans 
4140cde2e34SJason Evans 		if (((type) & MTX_TOPHALF) == 0) {
4150cde2e34SJason Evans 			/*
4160cde2e34SJason Evans 			 * If an interrupt thread uses this we must block
4170cde2e34SJason Evans 			 * interrupts here.
4180cde2e34SJason Evans 			 */
4190cde2e34SJason Evans 			if ((type) & MTX_FIRST) {
4200cde2e34SJason Evans 				ASS_IEN;
4210cde2e34SJason Evans 				disable_intr();
4220cde2e34SJason Evans 				_getlock_norecurse(mpp, CURTHD,
4230cde2e34SJason Evans 				    (type) & MTX_HARDOPTS);
4240cde2e34SJason Evans 			} else {
4250cde2e34SJason Evans 				_getlock_spin_block(mpp, CURTHD,
4260cde2e34SJason Evans 				    (type) & MTX_HARDOPTS);
4270cde2e34SJason Evans 			}
4280cde2e34SJason Evans 		} else
4290cde2e34SJason Evans 			_getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS);
4300cde2e34SJason Evans 	} else {
4310cde2e34SJason Evans 		/* Sleep locks */
4320cde2e34SJason Evans 		if ((type) & MTX_RLIKELY)
4330cde2e34SJason Evans 			_getlock_sleep(mpp, CURTHD, (type) & MTX_HARDOPTS);
4340cde2e34SJason Evans 		else
4350cde2e34SJason Evans 			_getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS);
4360cde2e34SJason Evans 	}
4370cde2e34SJason Evans done:
4380cde2e34SJason Evans 	WITNESS_ENTER(mpp, type, file, line);
4390cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4400cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_enter_fmt,
4410cde2e34SJason Evans 		    mpp->mtx_description, mpp, mpp->mtx_recurse, file, line);
4420cde2e34SJason Evans 
4430cde2e34SJason Evans }
4440cde2e34SJason Evans 
4450cde2e34SJason Evans /*
4460cde2e34SJason Evans  * Attempt to get MTX_DEF lock, return non-zero if lock acquired.
4470cde2e34SJason Evans  *
4480cde2e34SJason Evans  * XXX DOES NOT HANDLE RECURSION
4490cde2e34SJason Evans  */
4500cde2e34SJason Evans int
4510cde2e34SJason Evans _mtx_try_enter(struct mtx *mtxp, int type, const char *file, int line)
4520cde2e34SJason Evans {
4530cde2e34SJason Evans 	struct mtx	*const mpp = mtxp;
4540cde2e34SJason Evans 	int	rval;
4550cde2e34SJason Evans 
4560cde2e34SJason Evans 	rval = _obtain_lock(mpp, CURTHD);
4570cde2e34SJason Evans #ifdef WITNESS
4580cde2e34SJason Evans 	if (rval && mpp->mtx_witness != NULL) {
4590cde2e34SJason Evans 		MPASS(mpp->mtx_recurse == 0);
4600cde2e34SJason Evans 		witness_try_enter(mpp, type, file, line);
4610cde2e34SJason Evans 	}
4620cde2e34SJason Evans #endif	/* WITNESS */
4630cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4640cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_try_enter_fmt,
4650cde2e34SJason Evans 		    mpp->mtx_description, mpp, rval, file, line);
4660cde2e34SJason Evans 
4670cde2e34SJason Evans 	return rval;
4680cde2e34SJason Evans }
4690cde2e34SJason Evans 
4700cde2e34SJason Evans /*
4710cde2e34SJason Evans  * Release lock m.
4720cde2e34SJason Evans  */
4730cde2e34SJason Evans void
4740cde2e34SJason Evans _mtx_exit(struct mtx *mtxp, int type, const char *file, int line)
4750cde2e34SJason Evans {
4760cde2e34SJason Evans 	struct mtx	*const mpp = mtxp;
4770cde2e34SJason Evans 
4780cde2e34SJason Evans 	MPASS4(mtx_owned(mpp), STR_mtx_owned, file, line);
4790cde2e34SJason Evans 	WITNESS_EXIT(mpp, type, file, line);
4800cde2e34SJason Evans 	if (((type) & MTX_QUIET) == 0)
4810cde2e34SJason Evans 		CTR5(KTR_LOCK, STR_mtx_exit_fmt,
4820cde2e34SJason Evans 		    mpp->mtx_description, mpp, mpp->mtx_recurse, file, line);
4830cde2e34SJason Evans 	if ((type) & MTX_SPIN) {
4840cde2e34SJason Evans 		if ((type) & MTX_NORECURSE) {
4850cde2e34SJason Evans 			int mtx_intr = mpp->mtx_saveintr;
4860cde2e34SJason Evans 
4870cde2e34SJason Evans 			MPASS4(mpp->mtx_recurse == 0, STR_mtx_recurse,
4880cde2e34SJason Evans 			    file, line);
4890cde2e34SJason Evans 			_release_lock_quick(mpp);
4900cde2e34SJason Evans 			if (((type) & MTX_TOPHALF) == 0) {
4910cde2e34SJason Evans 				if ((type) & MTX_FIRST) {
4920cde2e34SJason Evans 					ASS_IDIS;
4930cde2e34SJason Evans 					enable_intr();
4940cde2e34SJason Evans 				} else
4950cde2e34SJason Evans 					restore_intr(mtx_intr);
4960cde2e34SJason Evans 			}
4970cde2e34SJason Evans 		} else {
4980cde2e34SJason Evans 			if (((type & MTX_TOPHALF) == 0) &&
4990cde2e34SJason Evans 			    (type & MTX_FIRST)) {
5000cde2e34SJason Evans 				ASS_IDIS;
5010cde2e34SJason Evans 				ASS_SIEN(mpp);
5020cde2e34SJason Evans 			}
5030cde2e34SJason Evans 			_exitlock_spin(mpp);
5040cde2e34SJason Evans 		}
5050cde2e34SJason Evans 	} else {
5060cde2e34SJason Evans 		/* Handle sleep locks */
5070cde2e34SJason Evans 		if ((type) & MTX_RLIKELY)
5080cde2e34SJason Evans 			_exitlock(mpp, CURTHD, (type) & MTX_HARDOPTS);
5090cde2e34SJason Evans 		else {
5100cde2e34SJason Evans 			_exitlock_norecurse(mpp, CURTHD,
5110cde2e34SJason Evans 			    (type) & MTX_HARDOPTS);
5120cde2e34SJason Evans 		}
5130cde2e34SJason Evans 	}
5140cde2e34SJason Evans }
5150cde2e34SJason Evans 
51636412d79SJohn Baldwin void
51736412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr)
51836412d79SJohn Baldwin {
51936412d79SJohn Baldwin 	struct proc *p = CURPROC;
52036412d79SJohn Baldwin 
52136412d79SJohn Baldwin 	KASSERT(p != NULL, ("curproc is NULL in mutex"));
52236412d79SJohn Baldwin 
52336412d79SJohn Baldwin 	switch (type) {
52436412d79SJohn Baldwin 	case MTX_DEF:
52536412d79SJohn Baldwin 		if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
52636412d79SJohn Baldwin 			m->mtx_recurse++;
52708812b39SBosko Milekic 			atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
528562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
52936412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m);
53036412d79SJohn Baldwin 			return;
53136412d79SJohn Baldwin 		}
532562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
533562e4ffeSJohn Baldwin 			CTR3(KTR_LOCK,
534562e4ffeSJohn Baldwin 			    "mtx_enter: 0x%p contested (lock=%p) [0x%p]",
53531271627SJohn Baldwin 			    m, (void *)m->mtx_lock, (void *)RETIP(m));
5361bd0eefbSJohn Baldwin 
5371bd0eefbSJohn Baldwin 		/*
5381bd0eefbSJohn Baldwin 		 * Save our priority.  Even though p_nativepri is protected
5391bd0eefbSJohn Baldwin 		 * by sched_lock, we don't obtain it here as it can be
5401bd0eefbSJohn Baldwin 		 * expensive.  Since this is the only place p_nativepri is
5411bd0eefbSJohn Baldwin 		 * set, and since two CPUs will not be executing the same
5421bd0eefbSJohn Baldwin 		 * process concurrently, we know that no other CPU is going
5431bd0eefbSJohn Baldwin 		 * to be messing with this.  Also, p_nativepri is only read
5441bd0eefbSJohn Baldwin 		 * when we are blocked on a mutex, so that can't be happening
5451bd0eefbSJohn Baldwin 		 * right now either.
5461bd0eefbSJohn Baldwin 		 */
5471bd0eefbSJohn Baldwin 		p->p_nativepri = p->p_priority;
54836412d79SJohn Baldwin 		while (!_obtain_lock(m, p)) {
549f5271ebcSJohn Baldwin 			uintptr_t v;
55036412d79SJohn Baldwin 			struct proc *p1;
55136412d79SJohn Baldwin 
55236412d79SJohn Baldwin 			mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY);
55336412d79SJohn Baldwin 			/*
55436412d79SJohn Baldwin 			 * check if the lock has been released while
55536412d79SJohn Baldwin 			 * waiting for the schedlock.
55636412d79SJohn Baldwin 			 */
55736412d79SJohn Baldwin 			if ((v = m->mtx_lock) == MTX_UNOWNED) {
55836412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
55936412d79SJohn Baldwin 				continue;
56036412d79SJohn Baldwin 			}
56136412d79SJohn Baldwin 			/*
56236412d79SJohn Baldwin 			 * The mutex was marked contested on release. This
56336412d79SJohn Baldwin 			 * means that there are processes blocked on it.
56436412d79SJohn Baldwin 			 */
56536412d79SJohn Baldwin 			if (v == MTX_CONTESTED) {
56636412d79SJohn Baldwin 				p1 = TAILQ_FIRST(&m->mtx_blocked);
56736412d79SJohn Baldwin 				KASSERT(p1 != NULL, ("contested mutex has no contesters"));
56836412d79SJohn Baldwin 				KASSERT(p != NULL, ("curproc is NULL for contested mutex"));
56936412d79SJohn Baldwin 				m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
57036412d79SJohn Baldwin 				if (p1->p_priority < p->p_priority) {
57136412d79SJohn Baldwin 					SET_PRIO(p, p1->p_priority);
57236412d79SJohn Baldwin 				}
57336412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
57436412d79SJohn Baldwin 				return;
57536412d79SJohn Baldwin 			}
57636412d79SJohn Baldwin 			/*
57736412d79SJohn Baldwin 			 * If the mutex isn't already contested and
57836412d79SJohn Baldwin 			 * a failure occurs setting the contested bit the
57936412d79SJohn Baldwin 			 * mutex was either release or the
58036412d79SJohn Baldwin 			 * state of the RECURSION bit changed.
58136412d79SJohn Baldwin 			 */
58236412d79SJohn Baldwin 			if ((v & MTX_CONTESTED) == 0 &&
58336412d79SJohn Baldwin 			    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
58436412d79SJohn Baldwin 				               (void *)(v | MTX_CONTESTED))) {
58536412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
58636412d79SJohn Baldwin 				continue;
58736412d79SJohn Baldwin 			}
58836412d79SJohn Baldwin 
58936412d79SJohn Baldwin 			/* We definitely have to sleep for this lock */
59036412d79SJohn Baldwin 			mtx_assert(m, MA_NOTOWNED);
59136412d79SJohn Baldwin 
59236412d79SJohn Baldwin #ifdef notyet
59336412d79SJohn Baldwin 			/*
59436412d79SJohn Baldwin 			 * If we're borrowing an interrupted thread's VM
59536412d79SJohn Baldwin 			 * context must clean up before going to sleep.
59636412d79SJohn Baldwin 			 */
59736412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
59836412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
59936412d79SJohn Baldwin 
60036412d79SJohn Baldwin 				if (it->it_interrupted) {
601562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
60236412d79SJohn Baldwin 						CTR2(KTR_LOCK,
60336412d79SJohn Baldwin 					    "mtx_enter: 0x%x interrupted 0x%x",
60436412d79SJohn Baldwin 						    it, it->it_interrupted);
60536412d79SJohn Baldwin 					intr_thd_fixup(it);
60636412d79SJohn Baldwin 				}
60736412d79SJohn Baldwin 			}
60836412d79SJohn Baldwin #endif
60936412d79SJohn Baldwin 
61036412d79SJohn Baldwin 			/* Put us on the list of procs blocked on this mutex */
61136412d79SJohn Baldwin 			if (TAILQ_EMPTY(&m->mtx_blocked)) {
61236412d79SJohn Baldwin 				p1 = (struct proc *)(m->mtx_lock &
61336412d79SJohn Baldwin 						     MTX_FLAGMASK);
61436412d79SJohn Baldwin 				LIST_INSERT_HEAD(&p1->p_contested, m,
61536412d79SJohn Baldwin 						 mtx_contested);
61636412d79SJohn Baldwin 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
61736412d79SJohn Baldwin 			} else {
61836412d79SJohn Baldwin 				TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
61936412d79SJohn Baldwin 					if (p1->p_priority > p->p_priority)
62036412d79SJohn Baldwin 						break;
62136412d79SJohn Baldwin 				if (p1)
62236412d79SJohn Baldwin 					TAILQ_INSERT_BEFORE(p1, p, p_procq);
62336412d79SJohn Baldwin 				else
62436412d79SJohn Baldwin 					TAILQ_INSERT_TAIL(&m->mtx_blocked, p,
62536412d79SJohn Baldwin 							  p_procq);
62636412d79SJohn Baldwin 			}
62736412d79SJohn Baldwin 
62836412d79SJohn Baldwin 			p->p_blocked = m;	/* Who we're blocked on */
62986327ad8SJohn Baldwin 			p->p_mtxname = m->mtx_description;
63036412d79SJohn Baldwin 			p->p_stat = SMTX;
63136412d79SJohn Baldwin #if 0
63236412d79SJohn Baldwin 			propagate_priority(p);
63336412d79SJohn Baldwin #endif
634562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
635562e4ffeSJohn Baldwin 				CTR3(KTR_LOCK,
636562e4ffeSJohn Baldwin 				    "mtx_enter: p 0x%p blocked on [0x%p] %s",
63736412d79SJohn Baldwin 				    p, m, m->mtx_description);
63820cdcc5bSJohn Baldwin 			mi_switch();
639562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
64036412d79SJohn Baldwin 				CTR3(KTR_LOCK,
64136412d79SJohn Baldwin 			    "mtx_enter: p 0x%p free from blocked on [0x%p] %s",
64236412d79SJohn Baldwin 				    p, m, m->mtx_description);
64336412d79SJohn Baldwin 			mtx_exit(&sched_lock, MTX_SPIN);
64436412d79SJohn Baldwin 		}
64536412d79SJohn Baldwin 		return;
64636412d79SJohn Baldwin 	case MTX_SPIN:
64736412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
64836412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
64936412d79SJohn Baldwin 	    {
65036412d79SJohn Baldwin 		int i = 0;
65136412d79SJohn Baldwin 
65236412d79SJohn Baldwin 		if (m->mtx_lock == (uintptr_t)p) {
65336412d79SJohn Baldwin 			m->mtx_recurse++;
65436412d79SJohn Baldwin 			return;
65536412d79SJohn Baldwin 		}
656562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
65736412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: %p spinning", m);
65836412d79SJohn Baldwin 		for (;;) {
65936412d79SJohn Baldwin 			if (_obtain_lock(m, p))
66036412d79SJohn Baldwin 				break;
66136412d79SJohn Baldwin 			while (m->mtx_lock != MTX_UNOWNED) {
66236412d79SJohn Baldwin 				if (i++ < 1000000)
66336412d79SJohn Baldwin 					continue;
66436412d79SJohn Baldwin 				if (i++ < 6000000)
66536412d79SJohn Baldwin 					DELAY (1);
66636412d79SJohn Baldwin #ifdef DDB
66736412d79SJohn Baldwin 				else if (!db_active)
66836412d79SJohn Baldwin #else
66936412d79SJohn Baldwin 				else
67036412d79SJohn Baldwin #endif
67136412d79SJohn Baldwin 					panic(
67236412d79SJohn Baldwin 				"spin lock %s held by 0x%p for > 5 seconds",
67336412d79SJohn Baldwin 					    m->mtx_description,
67436412d79SJohn Baldwin 					    (void *)m->mtx_lock);
67536412d79SJohn Baldwin 			}
67636412d79SJohn Baldwin 		}
67736412d79SJohn Baldwin 
67836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
67936412d79SJohn Baldwin 		if (type != MTX_SPIN)
68036412d79SJohn Baldwin 			m->mtx_saveintr = 0xbeefface;
68136412d79SJohn Baldwin 		else
68236412d79SJohn Baldwin #endif
68336412d79SJohn Baldwin 			m->mtx_saveintr = saveintr;
684562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
68536412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m);
68636412d79SJohn Baldwin 		return;
68736412d79SJohn Baldwin 	    }
68836412d79SJohn Baldwin 	}
68936412d79SJohn Baldwin }
69036412d79SJohn Baldwin 
69136412d79SJohn Baldwin void
69236412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type)
69336412d79SJohn Baldwin {
69436412d79SJohn Baldwin 	struct proc *p, *p1;
69536412d79SJohn Baldwin 	struct mtx *m1;
69636412d79SJohn Baldwin 	int pri;
69736412d79SJohn Baldwin 
69836412d79SJohn Baldwin 	p = CURPROC;
69936412d79SJohn Baldwin 	switch (type) {
70036412d79SJohn Baldwin 	case MTX_DEF:
70136412d79SJohn Baldwin 	case MTX_DEF | MTX_NOSWITCH:
70208812b39SBosko Milekic 		if (mtx_recursed(m)) {
70336412d79SJohn Baldwin 			if (--(m->mtx_recurse) == 0)
70408812b39SBosko Milekic 				atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
705562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
70636412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m);
70736412d79SJohn Baldwin 			return;
70836412d79SJohn Baldwin 		}
70936412d79SJohn Baldwin 		mtx_enter(&sched_lock, MTX_SPIN);
710562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
71136412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m);
71236412d79SJohn Baldwin 		p1 = TAILQ_FIRST(&m->mtx_blocked);
71336412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
71436412d79SJohn Baldwin 		MPASS(p1->p_magic == P_MAGIC);
71536412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
71636412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
71736412d79SJohn Baldwin 			LIST_REMOVE(m, mtx_contested);
71836412d79SJohn Baldwin 			_release_lock_quick(m);
719562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
72036412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m);
72136412d79SJohn Baldwin 		} else
722f404050eSJohn Baldwin 			atomic_store_rel_ptr(&m->mtx_lock,
723f404050eSJohn Baldwin 			    (void *)MTX_CONTESTED);
72436412d79SJohn Baldwin 		pri = MAXPRI;
72536412d79SJohn Baldwin 		LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
72636412d79SJohn Baldwin 			int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
72736412d79SJohn Baldwin 			if (cp < pri)
72836412d79SJohn Baldwin 				pri = cp;
72936412d79SJohn Baldwin 		}
73036412d79SJohn Baldwin 		if (pri > p->p_nativepri)
73136412d79SJohn Baldwin 			pri = p->p_nativepri;
73236412d79SJohn Baldwin 		SET_PRIO(p, pri);
733562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
734562e4ffeSJohn Baldwin 			CTR2(KTR_LOCK,
735562e4ffeSJohn Baldwin 			    "mtx_exit: 0x%p contested setrunqueue 0x%p", m, p1);
73636412d79SJohn Baldwin 		p1->p_blocked = NULL;
73786327ad8SJohn Baldwin 		p1->p_mtxname = NULL;
73836412d79SJohn Baldwin 		p1->p_stat = SRUN;
73936412d79SJohn Baldwin 		setrunqueue(p1);
74036412d79SJohn Baldwin 		if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
74136412d79SJohn Baldwin #ifdef notyet
74236412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
74336412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
74436412d79SJohn Baldwin 
74536412d79SJohn Baldwin 				if (it->it_interrupted) {
746562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
74736412d79SJohn Baldwin 						CTR2(KTR_LOCK,
74836412d79SJohn Baldwin 					    "mtx_exit: 0x%x interruped 0x%x",
74936412d79SJohn Baldwin 						    it, it->it_interrupted);
75036412d79SJohn Baldwin 					intr_thd_fixup(it);
75136412d79SJohn Baldwin 				}
75236412d79SJohn Baldwin 			}
75336412d79SJohn Baldwin #endif
75436412d79SJohn Baldwin 			setrunqueue(p);
755562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
756562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
757562e4ffeSJohn Baldwin 				    "mtx_exit: 0x%p switching out lock=0x%p",
75831271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
75936412d79SJohn Baldwin 			mi_switch();
760562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
761562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
762562e4ffeSJohn Baldwin 				    "mtx_exit: 0x%p resuming lock=0x%p",
76331271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
76436412d79SJohn Baldwin 		}
76536412d79SJohn Baldwin 		mtx_exit(&sched_lock, MTX_SPIN);
76636412d79SJohn Baldwin 		break;
76736412d79SJohn Baldwin 	case MTX_SPIN:
76836412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
76908812b39SBosko Milekic 		if (mtx_recursed(m)) {
77036412d79SJohn Baldwin 			m->mtx_recurse--;
77136412d79SJohn Baldwin 			return;
77236412d79SJohn Baldwin 		}
77336412d79SJohn Baldwin 		MPASS(mtx_owned(m));
77436412d79SJohn Baldwin 		_release_lock_quick(m);
77536412d79SJohn Baldwin 		if (type & MTX_FIRST)
77636412d79SJohn Baldwin 			enable_intr();	/* XXX is this kosher? */
77736412d79SJohn Baldwin 		else {
77836412d79SJohn Baldwin 			MPASS(m->mtx_saveintr != 0xbeefface);
77936412d79SJohn Baldwin 			restore_intr(m->mtx_saveintr);
78036412d79SJohn Baldwin 		}
78136412d79SJohn Baldwin 		break;
78236412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
78308812b39SBosko Milekic 		if (mtx_recursed(m)) {
78436412d79SJohn Baldwin 			m->mtx_recurse--;
78536412d79SJohn Baldwin 			return;
78636412d79SJohn Baldwin 		}
78736412d79SJohn Baldwin 		MPASS(mtx_owned(m));
78836412d79SJohn Baldwin 		_release_lock_quick(m);
78936412d79SJohn Baldwin 		break;
79036412d79SJohn Baldwin 	default:
79136412d79SJohn Baldwin 		panic("mtx_exit_hard: unsupported type 0x%x\n", type);
79236412d79SJohn Baldwin 	}
79336412d79SJohn Baldwin }
79436412d79SJohn Baldwin 
7950cde2e34SJason Evans #ifdef INVARIANTS
7960cde2e34SJason Evans void
79756771ca7SJason Evans _mtx_assert(struct mtx *m, int what, const char *file, int line)
7980cde2e34SJason Evans {
7990cde2e34SJason Evans 	switch ((what)) {
8000cde2e34SJason Evans 	case MA_OWNED:
8010cde2e34SJason Evans 	case MA_OWNED | MA_RECURSED:
8020cde2e34SJason Evans 	case MA_OWNED | MA_NOTRECURSED:
8030cde2e34SJason Evans 		if (!mtx_owned((m)))
8040cde2e34SJason Evans 			panic("mutex %s not owned at %s:%d",
80556771ca7SJason Evans 			    (m)->mtx_description, file, line);
8060cde2e34SJason Evans 		if (mtx_recursed((m))) {
8070cde2e34SJason Evans 			if (((what) & MA_NOTRECURSED) != 0)
8080cde2e34SJason Evans 				panic("mutex %s recursed at %s:%d",
80956771ca7SJason Evans 				    (m)->mtx_description, file, line);
8100cde2e34SJason Evans 		} else if (((what) & MA_RECURSED) != 0) {
8110cde2e34SJason Evans 			panic("mutex %s unrecursed at %s:%d",
81256771ca7SJason Evans 			    (m)->mtx_description, file, line);
8130cde2e34SJason Evans 		}
8140cde2e34SJason Evans 		break;
8150cde2e34SJason Evans 	case MA_NOTOWNED:
8160cde2e34SJason Evans 		if (mtx_owned((m)))
8170cde2e34SJason Evans 			panic("mutex %s owned at %s:%d",
81856771ca7SJason Evans 			    (m)->mtx_description, file, line);
8190cde2e34SJason Evans 		break;
8200cde2e34SJason Evans 	default:
82156771ca7SJason Evans 		panic("unknown mtx_assert at %s:%d", file, line);
8220cde2e34SJason Evans 	}
8230cde2e34SJason Evans }
8240cde2e34SJason Evans #endif
8250cde2e34SJason Evans 
82636412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
82736412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
82836412d79SJohn Baldwin 
82936412d79SJohn Baldwin #ifdef MUTEX_DEBUG
83036412d79SJohn Baldwin 
83136412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
83236412d79SJohn Baldwin 
83336412d79SJohn Baldwin int
83436412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
83536412d79SJohn Baldwin {
83636412d79SJohn Baldwin 	struct mtx *mp;
83736412d79SJohn Baldwin 	int i;
83836412d79SJohn Baldwin 	int retval = 0;
83936412d79SJohn Baldwin 
840d1c1b841SJason Evans #ifdef WITNESS
841d1c1b841SJason Evans 	if (witness_cold)
842d1c1b841SJason Evans 		return 0;
843d1c1b841SJason Evans #endif
84436412d79SJohn Baldwin 	if (m == &all_mtx || cold)
84536412d79SJohn Baldwin 		return 0;
84636412d79SJohn Baldwin 
84736412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
84836412d79SJohn Baldwin /*
84936412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
85036412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
85136412d79SJohn Baldwin  */
85236412d79SJohn Baldwin #ifndef __alpha__
85336412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
85436412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
85536412d79SJohn Baldwin #endif
85636412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
85736412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
85836412d79SJohn Baldwin #ifndef __alpha__
85936412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
86036412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
86136412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
86236412d79SJohn Baldwin 			    mp, mp->mtx_next);
86336412d79SJohn Baldwin 		}
86436412d79SJohn Baldwin #endif
86536412d79SJohn Baldwin 		i++;
86636412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
86736412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
86836412d79SJohn Baldwin 			    mtx_cur_cnt);
86936412d79SJohn Baldwin 		}
87036412d79SJohn Baldwin 	}
87136412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
87236412d79SJohn Baldwin 	switch (when) {
87336412d79SJohn Baldwin 	case MV_DESTROY:
87436412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
87536412d79SJohn Baldwin 			if (mp == m)
87636412d79SJohn Baldwin 				break;
87736412d79SJohn Baldwin 		MPASS(mp == m);
87836412d79SJohn Baldwin 		break;
87936412d79SJohn Baldwin 	case MV_INIT:
88036412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
88136412d79SJohn Baldwin 		if (mp == m) {
88236412d79SJohn Baldwin 			/*
88336412d79SJohn Baldwin 			 * Not good. This mutex already exists.
88436412d79SJohn Baldwin 			 */
88536412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
88636412d79SJohn Baldwin 			    m->mtx_description);
88736412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
88836412d79SJohn Baldwin 			retval = 1;
88936412d79SJohn Baldwin 		}
89036412d79SJohn Baldwin 	}
89136412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
89236412d79SJohn Baldwin 	return (retval);
89336412d79SJohn Baldwin }
89436412d79SJohn Baldwin #endif
89536412d79SJohn Baldwin 
89636412d79SJohn Baldwin void
89736412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag)
89836412d79SJohn Baldwin {
899562e4ffeSJohn Baldwin 	if ((flag & MTX_QUIET) == 0)
90036412d79SJohn Baldwin 		CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t);
90136412d79SJohn Baldwin #ifdef MUTEX_DEBUG
90236412d79SJohn Baldwin 	if (mtx_validate(m, MV_INIT))	/* diagnostic and error correction */
90336412d79SJohn Baldwin 		return;
9046936206eSJohn Baldwin #endif
90536412d79SJohn Baldwin 
90636412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
90736412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
9086936206eSJohn Baldwin #ifdef WITNESS
909d1c1b841SJason Evans 	if (!witness_cold) {
910d1c1b841SJason Evans 		/* XXX - should not use DEVBUF */
911d1c1b841SJason Evans 		m->mtx_union.mtxu_debug = malloc(sizeof(struct mtx_debug),
912d1c1b841SJason Evans 		    M_DEVBUF, M_NOWAIT | M_ZERO);
913d1c1b841SJason Evans 		MPASS(m->mtx_union.mtxu_debug != NULL);
914d1c1b841SJason Evans 
91536412d79SJohn Baldwin 		m->mtx_description = t;
916d1c1b841SJason Evans 	} else {
917d1c1b841SJason Evans 		/*
918d1c1b841SJason Evans 		 * Save a pointer to the description so that witness_fixup()
919d1c1b841SJason Evans 		 * can properly initialize this mutex later on.
920d1c1b841SJason Evans 		 */
921d1c1b841SJason Evans 		m->mtx_union.mtxu_description = t;
922d1c1b841SJason Evans 	}
923d1c1b841SJason Evans #else
924d1c1b841SJason Evans 	m->mtx_description = t;
925d1c1b841SJason Evans #endif
926d1c1b841SJason Evans 
927d1c1b841SJason Evans 	m->mtx_flags = flag;
92836412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
92936412d79SJohn Baldwin 	/* Put on all mutex queue */
93036412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
93136412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
93236412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
93336412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
93436412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
93536412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
93636412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
93736412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
938d1c1b841SJason Evans #ifdef WITNESS
939d1c1b841SJason Evans 	if (!witness_cold)
94036412d79SJohn Baldwin 		witness_init(m, flag);
941d1c1b841SJason Evans #endif
94236412d79SJohn Baldwin }
94336412d79SJohn Baldwin 
94436412d79SJohn Baldwin void
94536412d79SJohn Baldwin mtx_destroy(struct mtx *m)
94636412d79SJohn Baldwin {
94736412d79SJohn Baldwin 
948d1c1b841SJason Evans #ifdef WITNESS
949d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n",
950d1c1b841SJason Evans 	    __FUNCTION__));
951d1c1b841SJason Evans #endif
95236412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description);
95336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
95436412d79SJohn Baldwin 	if (m->mtx_next == NULL)
95536412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
95636412d79SJohn Baldwin 		    m, m->mtx_description);
95736412d79SJohn Baldwin 
95836412d79SJohn Baldwin 	if (!mtx_owned(m)) {
95936412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
96036412d79SJohn Baldwin 	} else {
96108812b39SBosko Milekic 		MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
96236412d79SJohn Baldwin 	}
96336412d79SJohn Baldwin 	mtx_validate(m, MV_DESTROY);		/* diagnostic */
96436412d79SJohn Baldwin #endif
96536412d79SJohn Baldwin 
96636412d79SJohn Baldwin #ifdef WITNESS
96736412d79SJohn Baldwin 	if (m->mtx_witness)
96836412d79SJohn Baldwin 		witness_destroy(m);
96936412d79SJohn Baldwin #endif /* WITNESS */
97036412d79SJohn Baldwin 
97136412d79SJohn Baldwin 	/* Remove from the all mutex queue */
97236412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
97336412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
97436412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
97536412d79SJohn Baldwin #ifdef MUTEX_DEBUG
97636412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
9776936206eSJohn Baldwin #endif
9786936206eSJohn Baldwin #ifdef WITNESS
979d1c1b841SJason Evans 	free(m->mtx_union.mtxu_debug, M_DEVBUF);
980d1c1b841SJason Evans 	m->mtx_union.mtxu_debug = NULL;
98136412d79SJohn Baldwin #endif
98236412d79SJohn Baldwin 	mtx_cur_cnt--;
98336412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
98436412d79SJohn Baldwin }
9850384fff8SJason Evans 
986d1c1b841SJason Evans static void
987d1c1b841SJason Evans witness_fixup(void *dummy __unused)
988d1c1b841SJason Evans {
989d1c1b841SJason Evans #ifdef WITNESS
990d1c1b841SJason Evans 	struct mtx *mp;
991d1c1b841SJason Evans 	const char *description;
992d1c1b841SJason Evans 
993d1c1b841SJason Evans 	/* Iterate through all mutexes and finish up mutex initialization. */
994d1c1b841SJason Evans 	for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
995d1c1b841SJason Evans 		description = mp->mtx_union.mtxu_description;
996d1c1b841SJason Evans 
997d1c1b841SJason Evans 		/* XXX - should not use DEVBUF */
998d1c1b841SJason Evans 		mp->mtx_union.mtxu_debug = malloc(sizeof(struct mtx_debug),
999d1c1b841SJason Evans 		    M_DEVBUF, M_NOWAIT | M_ZERO);
1000d1c1b841SJason Evans 		MPASS(mp->mtx_union.mtxu_debug != NULL);
1001d1c1b841SJason Evans 
1002d1c1b841SJason Evans 		mp->mtx_description = description;
1003d1c1b841SJason Evans 
1004d1c1b841SJason Evans 		witness_init(mp, mp->mtx_flags);
1005d1c1b841SJason Evans 	}
1006d1c1b841SJason Evans 
1007d1c1b841SJason Evans 	/* Mark the witness code as being ready for use. */
1008d1c1b841SJason Evans 	atomic_store_rel_int(&witness_cold, 0);
1009d1c1b841SJason Evans #endif
1010d1c1b841SJason Evans }
1011d1c1b841SJason Evans SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL)
1012d1c1b841SJason Evans 
10130384fff8SJason Evans /*
10140384fff8SJason Evans  * The non-inlined versions of the mtx_*() functions are always built (above),
10156936206eSJohn Baldwin  * but the witness code depends on the WITNESS kernel option being specified.
10160384fff8SJason Evans  */
10176936206eSJohn Baldwin #ifdef WITNESS
10180384fff8SJason Evans 
10190384fff8SJason Evans #define WITNESS_COUNT 200
10200384fff8SJason Evans #define	WITNESS_NCHILDREN 2
10210384fff8SJason Evans 
102278f0da03SJohn Baldwin int witness_watch = 1;
10230384fff8SJason Evans 
1024606f8eb2SJohn Baldwin struct witness {
10250384fff8SJason Evans 	struct witness	*w_next;
1026b67a3e6eSJohn Baldwin 	const char	*w_description;
102712473b76SJason Evans 	const char	*w_file;
10280384fff8SJason Evans 	int		 w_line;
10290384fff8SJason Evans 	struct witness	*w_morechildren;
10300384fff8SJason Evans 	u_char		 w_childcnt;
10310384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
10320384fff8SJason Evans 	u_char		 w_other_squawked:1;
10330384fff8SJason Evans 	u_char		 w_same_squawked:1;
103408812b39SBosko Milekic 	u_char		 w_sleep:1;	/* MTX_DEF type mutex. */
103508812b39SBosko Milekic 	u_char		 w_spin:1;	/* MTX_SPIN type mutex. */
103608812b39SBosko Milekic 	u_char		 w_recurse:1;	/* MTX_RECURSE mutex option. */
10370384fff8SJason Evans 	u_int		 w_level;
10380384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
1039606f8eb2SJohn Baldwin };
10400384fff8SJason Evans 
1041606f8eb2SJohn Baldwin struct witness_blessed {
10420384fff8SJason Evans 	char 	*b_lock1;
10430384fff8SJason Evans 	char	*b_lock2;
1044606f8eb2SJohn Baldwin };
10450384fff8SJason Evans 
1046a5a96a19SJohn Baldwin #ifdef DDB
10470384fff8SJason Evans /*
1048a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
10490384fff8SJason Evans  * drop into kdebug() when:
10500384fff8SJason Evans  *	- a lock heirarchy violation occurs
10510384fff8SJason Evans  *	- locks are held when going to sleep.
10520384fff8SJason Evans  */
1053a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
1054a5a96a19SJohn Baldwin int	witness_ddb = 1;
1055a5a96a19SJohn Baldwin #else
1056a5a96a19SJohn Baldwin int	witness_ddb = 0;
10570384fff8SJason Evans #endif
1058a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
1059a5a96a19SJohn Baldwin #endif /* DDB */
10600384fff8SJason Evans 
1061a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
1062a5a96a19SJohn Baldwin int	witness_skipspin = 1;
1063a5a96a19SJohn Baldwin #else
1064a5a96a19SJohn Baldwin int	witness_skipspin = 0;
10650384fff8SJason Evans #endif
1066a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
1067a5a96a19SJohn Baldwin     "");
10680384fff8SJason Evans 
1069d1c1b841SJason Evans static struct mtx	w_mtx;
1070606f8eb2SJohn Baldwin static struct witness	*w_free;
1071606f8eb2SJohn Baldwin static struct witness	*w_all;
10720384fff8SJason Evans static int		 w_inited;
10730384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
10740384fff8SJason Evans 
1075606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
10760384fff8SJason Evans 
1077b67a3e6eSJohn Baldwin static struct witness	 *enroll __P((const char *description, int flag));
1078606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child));
1079606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child));
1080606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child));
1081606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child));
1082606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *));
1083606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *));
10840384fff8SJason Evans static void witness_displaydescendants
1085606f8eb2SJohn Baldwin     __P((void(*)(const char *fmt, ...), struct witness *));
1086606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level));
10870384fff8SJason Evans static void witness_levelall __P((void));
1088606f8eb2SJohn Baldwin static struct witness * witness_get __P((void));
1089606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m));
10900384fff8SJason Evans 
10910384fff8SJason Evans 
10920384fff8SJason Evans static char *ignore_list[] = {
10930384fff8SJason Evans 	"witness lock",
10940384fff8SJason Evans 	NULL
10950384fff8SJason Evans };
10960384fff8SJason Evans 
10970384fff8SJason Evans static char *spin_order_list[] = {
1098a5a96a19SJohn Baldwin 	"sio",
10998f838cb5SJohn Baldwin 	"sched lock",
110020cdcc5bSJohn Baldwin #ifdef __i386__
110120cdcc5bSJohn Baldwin 	"clk",
110220cdcc5bSJohn Baldwin #endif
1103fa2fbc3dSJake Burkholder 	"callout",
11040384fff8SJason Evans 	/*
11050384fff8SJason Evans 	 * leaf locks
11060384fff8SJason Evans 	 */
11070384fff8SJason Evans 	NULL
11080384fff8SJason Evans };
11090384fff8SJason Evans 
11100384fff8SJason Evans static char *order_list[] = {
1111a5d5c61cSJake Burkholder 	"uidinfo hash", "uidinfo struct", NULL,
11120384fff8SJason Evans 	NULL
11130384fff8SJason Evans };
11140384fff8SJason Evans 
11150384fff8SJason Evans static char *dup_list[] = {
11160384fff8SJason Evans 	NULL
11170384fff8SJason Evans };
11180384fff8SJason Evans 
11190384fff8SJason Evans static char *sleep_list[] = {
11207da6f977SJake Burkholder 	"Giant",
11210384fff8SJason Evans 	NULL
11220384fff8SJason Evans };
11230384fff8SJason Evans 
11240384fff8SJason Evans /*
11250384fff8SJason Evans  * Pairs of locks which have been blessed
11260384fff8SJason Evans  * Don't complain about order problems with blessed locks
11270384fff8SJason Evans  */
1128606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
11290384fff8SJason Evans };
1130606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed);
11310384fff8SJason Evans 
11320cde2e34SJason Evans static void
1133606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
11340384fff8SJason Evans {
11350384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
11360384fff8SJason Evans }
11370384fff8SJason Evans 
11380cde2e34SJason Evans static void
1139606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
11400384fff8SJason Evans {
1141606f8eb2SJohn Baldwin 	struct mtx *m1;
11420384fff8SJason Evans 	struct proc *p;
11430384fff8SJason Evans 	p = CURPROC;
11440384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
11450384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
11460384fff8SJason Evans 		if (m1 == m) {
11470384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
11480384fff8SJason Evans 			break;
11490384fff8SJason Evans 		}
11500384fff8SJason Evans 	}
11510384fff8SJason Evans 	return;
11520384fff8SJason Evans 
11530384fff8SJason Evans }
11540384fff8SJason Evans 
11550cde2e34SJason Evans static void
11560cde2e34SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
11570cde2e34SJason Evans {
11580cde2e34SJason Evans 	struct witness *w, *w1;
11590cde2e34SJason Evans 
11600cde2e34SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
11610cde2e34SJason Evans 	witness_levelall();
11620cde2e34SJason Evans 
11630cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
11640cde2e34SJason Evans 		if (w->w_file == NULL)
11650cde2e34SJason Evans 			continue;
11660cde2e34SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
11670cde2e34SJason Evans 			if (isitmychild(w1, w))
11680cde2e34SJason Evans 				break;
11690cde2e34SJason Evans 		}
11700cde2e34SJason Evans 		if (w1 != NULL)
11710cde2e34SJason Evans 			continue;
11720cde2e34SJason Evans 		/*
11730cde2e34SJason Evans 		 * This lock has no anscestors, display its descendants.
11740cde2e34SJason Evans 		 */
11750cde2e34SJason Evans 		witness_displaydescendants(prnt, w);
11760cde2e34SJason Evans 	}
11770cde2e34SJason Evans 	prnt("\nMutex which were never acquired\n");
11780cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
11790cde2e34SJason Evans 		if (w->w_file != NULL)
11800cde2e34SJason Evans 			continue;
11810cde2e34SJason Evans 		prnt("%s\n", w->w_description);
11820cde2e34SJason Evans 	}
11830cde2e34SJason Evans }
11840cde2e34SJason Evans 
11850384fff8SJason Evans void
1186606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
11870384fff8SJason Evans {
1188606f8eb2SJohn Baldwin 	struct witness *w, *w1;
1189606f8eb2SJohn Baldwin 	struct mtx *m1;
11900384fff8SJason Evans 	struct proc *p;
11910384fff8SJason Evans 	int i;
1192a5a96a19SJohn Baldwin #ifdef DDB
1193a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
1194a5a96a19SJohn Baldwin #endif /* DDB */
11950384fff8SJason Evans 
11960cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
1197562e4ffeSJohn Baldwin 		return;
11980384fff8SJason Evans 	w = m->mtx_witness;
11990384fff8SJason Evans 	p = CURPROC;
12000384fff8SJason Evans 
12010384fff8SJason Evans 	if (flags & MTX_SPIN) {
120208812b39SBosko Milekic 		if (!(w->w_spin))
12035340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
12045340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
120508812b39SBosko Milekic 		if (mtx_recursed(m)) {
120608812b39SBosko Milekic 			if (!(w->w_recurse))
120708812b39SBosko Milekic 				panic("mutex_enter: recursion on non-recursive"
120808812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
120908812b39SBosko Milekic 				    file, line);
12100384fff8SJason Evans 			return;
121108812b39SBosko Milekic 		}
1212562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
1213ef73ae4bSJake Burkholder 		i = PCPU_GET(witness_spin_check);
12140384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
1215562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12165340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
12175340642aSJason Evans 			    " %s:%d already holding %s:%x",
12180384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
12190384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
12200384fff8SJason Evans 		}
12210384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
1222562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
1223bbc7a98aSJohn Baldwin 		w->w_file = file;
1224bbc7a98aSJohn Baldwin 		w->w_line = line;
1225bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1226bbc7a98aSJohn Baldwin 		m->mtx_file = file;
12270384fff8SJason Evans 		return;
12280384fff8SJason Evans 	}
12290384fff8SJason Evans 	if (w->w_spin)
12300384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12310384fff8SJason Evans 		    m->mtx_description, file, line);
12320384fff8SJason Evans 
123308812b39SBosko Milekic 	if (mtx_recursed(m)) {
123408812b39SBosko Milekic 		if (!(w->w_recurse))
123508812b39SBosko Milekic 			panic("mutex_enter: recursion on non-recursive"
123608812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
123708812b39SBosko Milekic 			    file, line);
12380384fff8SJason Evans 		return;
123908812b39SBosko Milekic 	}
12400384fff8SJason Evans 	if (witness_dead)
12410384fff8SJason Evans 		goto out;
1242562e4ffeSJohn Baldwin 	if (cold)
12430384fff8SJason Evans 		goto out;
12440384fff8SJason Evans 
12450384fff8SJason Evans 	if (!mtx_legal2block())
12460384fff8SJason Evans 		panic("blockable mtx_enter() of %s when not legal @ %s:%d",
12470384fff8SJason Evans 			    m->mtx_description, file, line);
12480384fff8SJason Evans 	/*
12490384fff8SJason Evans 	 * Is this the first mutex acquired
12500384fff8SJason Evans 	 */
12510384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
12520384fff8SJason Evans 		goto out;
12530384fff8SJason Evans 
12540384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
12550384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
12560384fff8SJason Evans 			goto out;
12570384fff8SJason Evans 		w->w_same_squawked = 1;
12580384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
12590384fff8SJason Evans 			m->mtx_description);
12600384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
12610384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
1262a5a96a19SJohn Baldwin #ifdef DDB
1263a5a96a19SJohn Baldwin 		go_into_ddb = 1;
1264a5a96a19SJohn Baldwin #endif /* DDB */
12650384fff8SJason Evans 		goto out;
12660384fff8SJason Evans 	}
12670384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
1268562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
12690384fff8SJason Evans 	/*
12700384fff8SJason Evans 	 * If we have a known higher number just say ok
12710384fff8SJason Evans 	 */
12720384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
1273562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12740384fff8SJason Evans 		goto out;
12750384fff8SJason Evans 	}
12760384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
1277562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12780384fff8SJason Evans 		goto out;
12790384fff8SJason Evans 	}
12800384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
12810384fff8SJason Evans 
128236412d79SJohn Baldwin 		MPASS(i < 200);
12830384fff8SJason Evans 		w1 = m1->mtx_witness;
12840384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
1285562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
12860384fff8SJason Evans 			if (blessed(w, w1))
12870384fff8SJason Evans 				goto out;
12880384fff8SJason Evans 			if (m1 == &Giant) {
12890384fff8SJason Evans 				if (w1->w_Giant_squawked)
12900384fff8SJason Evans 					goto out;
12910384fff8SJason Evans 				else
12920384fff8SJason Evans 					w1->w_Giant_squawked = 1;
12930384fff8SJason Evans 			} else {
12940384fff8SJason Evans 				if (w1->w_other_squawked)
12950384fff8SJason Evans 					goto out;
12960384fff8SJason Evans 				else
12970384fff8SJason Evans 					w1->w_other_squawked = 1;
12980384fff8SJason Evans 			}
12990384fff8SJason Evans 			printf("lock order reversal\n");
13000384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
13010384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
13020384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
13030384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
13040384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
13050384fff8SJason Evans 			    m, w->w_description, file, line);
1306a5a96a19SJohn Baldwin #ifdef DDB
1307a5a96a19SJohn Baldwin 			go_into_ddb = 1;
1308a5a96a19SJohn Baldwin #endif /* DDB */
13090384fff8SJason Evans 			goto out;
13100384fff8SJason Evans 		}
13110384fff8SJason Evans 	}
13120384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
13130384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
1314562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
13150384fff8SJason Evans 
13160384fff8SJason Evans out:
1317a5a96a19SJohn Baldwin #ifdef DDB
1318a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
1319a5a96a19SJohn Baldwin 		Debugger("witness_enter");
1320a5a96a19SJohn Baldwin #endif /* DDB */
13210384fff8SJason Evans 	w->w_file = file;
13220384fff8SJason Evans 	w->w_line = line;
13230384fff8SJason Evans 	m->mtx_line = line;
13240384fff8SJason Evans 	m->mtx_file = file;
13250384fff8SJason Evans 
13260384fff8SJason Evans 	/*
13270384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
13280384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
13290384fff8SJason Evans 	 * likely not the mutex this assert fails on.
13300384fff8SJason Evans 	 */
133136412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
13320384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
13330384fff8SJason Evans }
13340384fff8SJason Evans 
13350384fff8SJason Evans void
1336606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
13370384fff8SJason Evans {
13380384fff8SJason Evans 	struct proc *p;
1339606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
13400384fff8SJason Evans 
1341d1c1b841SJason Evans 	if (witness_cold)
1342d1c1b841SJason Evans 		return;
1343562e4ffeSJohn Baldwin 	if (panicstr)
1344562e4ffeSJohn Baldwin 		return;
13450384fff8SJason Evans 	if (flags & MTX_SPIN) {
134608812b39SBosko Milekic 		if (!(w->w_spin))
13470384fff8SJason Evans 			panic("mutex_try_enter: "
13480384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
13490384fff8SJason Evans 			    m->mtx_description, file, line);
135008812b39SBosko Milekic 		if (mtx_recursed(m)) {
135108812b39SBosko Milekic 			if (!(w->w_recurse))
135208812b39SBosko Milekic 				panic("mutex_try_enter: recursion on"
135308812b39SBosko Milekic 				    " non-recursive mutex %s @ %s:%d",
135408812b39SBosko Milekic 				    m->mtx_description, file, line);
13550384fff8SJason Evans 			return;
135608812b39SBosko Milekic 		}
1357562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
1358ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
1359ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) | w->w_level);
1360562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
1361bbc7a98aSJohn Baldwin 		w->w_file = file;
1362bbc7a98aSJohn Baldwin 		w->w_line = line;
1363bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1364bbc7a98aSJohn Baldwin 		m->mtx_file = file;
13650384fff8SJason Evans 		return;
13660384fff8SJason Evans 	}
13670384fff8SJason Evans 
13680384fff8SJason Evans 	if (w->w_spin)
13690384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
13700384fff8SJason Evans 		    m->mtx_description, file, line);
13710384fff8SJason Evans 
137208812b39SBosko Milekic 	if (mtx_recursed(m)) {
137308812b39SBosko Milekic 		if (!(w->w_recurse))
137408812b39SBosko Milekic 			panic("mutex_try_enter: recursion on non-recursive"
137508812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description, file,
137608812b39SBosko Milekic 			    line);
13770384fff8SJason Evans 		return;
137808812b39SBosko Milekic 	}
13790384fff8SJason Evans 	w->w_file = file;
13800384fff8SJason Evans 	w->w_line = line;
13810384fff8SJason Evans 	m->mtx_line = line;
13820384fff8SJason Evans 	m->mtx_file = file;
13830384fff8SJason Evans 	p = CURPROC;
138436412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
13850384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
13860384fff8SJason Evans }
13870384fff8SJason Evans 
13880384fff8SJason Evans void
13890cde2e34SJason Evans witness_exit(struct mtx *m, int flags, const char *file, int line)
13900384fff8SJason Evans {
13910cde2e34SJason Evans 	struct witness *w;
13920384fff8SJason Evans 
13930cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
13940cde2e34SJason Evans 		return;
13950cde2e34SJason Evans 	w = m->mtx_witness;
13960384fff8SJason Evans 
13970cde2e34SJason Evans 	if (flags & MTX_SPIN) {
13980cde2e34SJason Evans 		if (!(w->w_spin))
13990cde2e34SJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
14000cde2e34SJason Evans 			    " %s:%d", m->mtx_description, file, line);
14010cde2e34SJason Evans 		if (mtx_recursed(m)) {
14020cde2e34SJason Evans 			if (!(w->w_recurse))
14030cde2e34SJason Evans 				panic("mutex_exit: recursion on non-recursive"
14040cde2e34SJason Evans 				    " mutex %s @ %s:%d", m->mtx_description,
14050cde2e34SJason Evans 				    file, line);
14060cde2e34SJason Evans 			return;
14070384fff8SJason Evans 		}
14080cde2e34SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
14090cde2e34SJason Evans 		PCPU_SET(witness_spin_check,
14100cde2e34SJason Evans 		    PCPU_GET(witness_spin_check) & ~w->w_level);
14110cde2e34SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
14120cde2e34SJason Evans 		return;
14130384fff8SJason Evans 	}
14140cde2e34SJason Evans 	if (w->w_spin)
14150cde2e34SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
14160cde2e34SJason Evans 		    m->mtx_description, file, line);
14170cde2e34SJason Evans 
14180cde2e34SJason Evans 	if (mtx_recursed(m)) {
14190cde2e34SJason Evans 		if (!(w->w_recurse))
14200cde2e34SJason Evans 			panic("mutex_exit: recursion on non-recursive"
14210cde2e34SJason Evans 			    " mutex %s @ %s:%d", m->mtx_description,
14220cde2e34SJason Evans 			    file, line);
14230cde2e34SJason Evans 		return;
14240384fff8SJason Evans 	}
14250cde2e34SJason Evans 
14260cde2e34SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
14270cde2e34SJason Evans 		panic("switchable mtx_exit() of %s when not legal @ %s:%d",
14280cde2e34SJason Evans 			    m->mtx_description, file, line);
14290cde2e34SJason Evans 	LIST_REMOVE(m, mtx_held);
14300cde2e34SJason Evans 	m->mtx_held.le_prev = NULL;
14310384fff8SJason Evans }
14320384fff8SJason Evans 
14330384fff8SJason Evans int
1434606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
14350384fff8SJason Evans {
1436606f8eb2SJohn Baldwin 	struct mtx *m;
14370384fff8SJason Evans 	struct proc *p;
14380384fff8SJason Evans 	char **sleep;
14390384fff8SJason Evans 	int n = 0;
14400384fff8SJason Evans 
1441d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
14420384fff8SJason Evans 	p = CURPROC;
14430384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
14440384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
14450384fff8SJason Evans 		if (m == mtx)
14460384fff8SJason Evans 			continue;
14470384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
14480384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
14490384fff8SJason Evans 				goto next;
14500384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
14510384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
14520384fff8SJason Evans 			m->mtx_description,
14530384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
14540384fff8SJason Evans 		n++;
14550384fff8SJason Evans 	next:
14560384fff8SJason Evans 	}
1457a5a96a19SJohn Baldwin #ifdef DDB
1458a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1459a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1460a5a96a19SJohn Baldwin #endif /* DDB */
14610384fff8SJason Evans 	return (n);
14620384fff8SJason Evans }
14630384fff8SJason Evans 
1464606f8eb2SJohn Baldwin static struct witness *
1465b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
14660384fff8SJason Evans {
14670384fff8SJason Evans 	int i;
1468606f8eb2SJohn Baldwin 	struct witness *w, *w1;
14690384fff8SJason Evans 	char **ignore;
14700384fff8SJason Evans 	char **order;
14710384fff8SJason Evans 
14720384fff8SJason Evans 	if (!witness_watch)
14730384fff8SJason Evans 		return (NULL);
14740384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
14750384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
14760384fff8SJason Evans 			return (NULL);
14770384fff8SJason Evans 
14780384fff8SJason Evans 	if (w_inited == 0) {
1479d1c1b841SJason Evans 		mtx_init(&w_mtx, "witness lock", MTX_SPIN);
14800384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
14810384fff8SJason Evans 			w = &w_data[i];
14820384fff8SJason Evans 			witness_free(w);
14830384fff8SJason Evans 		}
14840384fff8SJason Evans 		w_inited = 1;
14850384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
14860384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
14870384fff8SJason Evans 			w->w_file = "order list";
14880384fff8SJason Evans 			for (order++; *order != NULL; order++) {
14890384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
14900384fff8SJason Evans 				w1->w_file = "order list";
14910384fff8SJason Evans 				itismychild(w, w1);
14920384fff8SJason Evans 				w = w1;
14930384fff8SJason Evans     	    	    	}
14940384fff8SJason Evans 		}
14950384fff8SJason Evans 	}
14960384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
14970384fff8SJason Evans 		return (NULL);
1498562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
14990384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
15000384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
1501562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
15020384fff8SJason Evans 			return (w);
15030384fff8SJason Evans 		}
15040384fff8SJason Evans 	}
15050384fff8SJason Evans 	if ((w = witness_get()) == NULL)
15060384fff8SJason Evans 		return (NULL);
15070384fff8SJason Evans 	w->w_next = w_all;
15080384fff8SJason Evans 	w_all = w;
15090384fff8SJason Evans 	w->w_description = description;
1510562e4ffeSJohn Baldwin 	mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
15110384fff8SJason Evans 	if (flag & MTX_SPIN) {
15120384fff8SJason Evans 		w->w_spin = 1;
15130384fff8SJason Evans 
15140384fff8SJason Evans 		i = 1;
15150384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
15160384fff8SJason Evans 			if (strcmp(description, *order) == 0)
15170384fff8SJason Evans 				break;
15180384fff8SJason Evans 			i <<= 1;
15190384fff8SJason Evans 		}
15200384fff8SJason Evans 		if (*order == NULL)
15210384fff8SJason Evans 			panic("spin lock %s not in order list", description);
15220384fff8SJason Evans 		w->w_level = i;
152308812b39SBosko Milekic 	} else
152408812b39SBosko Milekic 		w->w_sleep = 1;
152508812b39SBosko Milekic 
152608812b39SBosko Milekic 	if (flag & MTX_RECURSE)
152708812b39SBosko Milekic 		w->w_recurse = 1;
152808812b39SBosko Milekic 
15290384fff8SJason Evans 	return (w);
15300384fff8SJason Evans }
15310384fff8SJason Evans 
15320384fff8SJason Evans static int
1533606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
15340384fff8SJason Evans {
15350384fff8SJason Evans 	static int recursed;
15360384fff8SJason Evans 
15370384fff8SJason Evans 	/*
15380384fff8SJason Evans 	 * Insert "child" after "parent"
15390384fff8SJason Evans 	 */
15400384fff8SJason Evans 	while (parent->w_morechildren)
15410384fff8SJason Evans 		parent = parent->w_morechildren;
15420384fff8SJason Evans 
15430384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
15440384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
15450384fff8SJason Evans 			return (1);
15460384fff8SJason Evans 		parent = parent->w_morechildren;
15470384fff8SJason Evans 	}
154836412d79SJohn Baldwin 	MPASS(child != NULL);
15490384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
15500384fff8SJason Evans 	/*
15510384fff8SJason Evans 	 * now prune whole tree
15520384fff8SJason Evans 	 */
15530384fff8SJason Evans 	if (recursed)
15540384fff8SJason Evans 		return (0);
15550384fff8SJason Evans 	recursed = 1;
15560384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
15570384fff8SJason Evans 		for (parent = w_all; parent != NULL;
15580384fff8SJason Evans 		    parent = parent->w_next) {
15590384fff8SJason Evans 			if (!isitmychild(parent, child))
15600384fff8SJason Evans 				continue;
15610384fff8SJason Evans 			removechild(parent, child);
15620384fff8SJason Evans 			if (isitmydescendant(parent, child))
15630384fff8SJason Evans 				continue;
15640384fff8SJason Evans 			itismychild(parent, child);
15650384fff8SJason Evans 		}
15660384fff8SJason Evans 	}
15670384fff8SJason Evans 	recursed = 0;
15680384fff8SJason Evans 	witness_levelall();
15690384fff8SJason Evans 	return (0);
15700384fff8SJason Evans }
15710384fff8SJason Evans 
15720384fff8SJason Evans static void
1573606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
15740384fff8SJason Evans {
1575606f8eb2SJohn Baldwin 	struct witness *w, *w1;
15760384fff8SJason Evans 	int i;
15770384fff8SJason Evans 
15780384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15790384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15800384fff8SJason Evans 			if (w->w_children[i] == child)
15810384fff8SJason Evans 				goto found;
15820384fff8SJason Evans 	return;
15830384fff8SJason Evans found:
15840384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
15850384fff8SJason Evans 		continue;
15860384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
158736412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
15880384fff8SJason Evans 
15890384fff8SJason Evans 	if (w1->w_childcnt != 0)
15900384fff8SJason Evans 		return;
15910384fff8SJason Evans 
15920384fff8SJason Evans 	if (w1 == parent)
15930384fff8SJason Evans 		return;
15940384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
15950384fff8SJason Evans 		continue;
15960384fff8SJason Evans 	w->w_morechildren = 0;
15970384fff8SJason Evans 	witness_free(w1);
15980384fff8SJason Evans }
15990384fff8SJason Evans 
16000384fff8SJason Evans static int
1601606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
16020384fff8SJason Evans {
1603606f8eb2SJohn Baldwin 	struct witness *w;
16040384fff8SJason Evans 	int i;
16050384fff8SJason Evans 
16060384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
16070384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16080384fff8SJason Evans 			if (w->w_children[i] == child)
16090384fff8SJason Evans 				return (1);
16100384fff8SJason Evans 		}
16110384fff8SJason Evans 	}
16120384fff8SJason Evans 	return (0);
16130384fff8SJason Evans }
16140384fff8SJason Evans 
16150384fff8SJason Evans static int
1616606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
16170384fff8SJason Evans {
1618606f8eb2SJohn Baldwin 	struct witness *w;
16190384fff8SJason Evans 	int i;
16200384fff8SJason Evans 	int j;
16210384fff8SJason Evans 
16220384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
162336412d79SJohn Baldwin 		MPASS(j < 1000);
16240384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16250384fff8SJason Evans 			if (w->w_children[i] == child)
16260384fff8SJason Evans 				return (1);
16270384fff8SJason Evans 		}
16280384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
16290384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
16300384fff8SJason Evans 				return (1);
16310384fff8SJason Evans 		}
16320384fff8SJason Evans 	}
16330384fff8SJason Evans 	return (0);
16340384fff8SJason Evans }
16350384fff8SJason Evans 
16360384fff8SJason Evans void
16370384fff8SJason Evans witness_levelall (void)
16380384fff8SJason Evans {
1639606f8eb2SJohn Baldwin 	struct witness *w, *w1;
16400384fff8SJason Evans 
16410384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
164208812b39SBosko Milekic 		if (!(w->w_spin))
16430384fff8SJason Evans 			w->w_level = 0;
16440384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
16450384fff8SJason Evans 		if (w->w_spin)
16460384fff8SJason Evans 			continue;
16470384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
16480384fff8SJason Evans 			if (isitmychild(w1, w))
16490384fff8SJason Evans 				break;
16500384fff8SJason Evans 		}
16510384fff8SJason Evans 		if (w1 != NULL)
16520384fff8SJason Evans 			continue;
16530384fff8SJason Evans 		witness_leveldescendents(w, 0);
16540384fff8SJason Evans 	}
16550384fff8SJason Evans }
16560384fff8SJason Evans 
16570384fff8SJason Evans static void
1658606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
16590384fff8SJason Evans {
16600384fff8SJason Evans 	int i;
1661606f8eb2SJohn Baldwin 	struct witness *w;
16620384fff8SJason Evans 
16630384fff8SJason Evans 	if (parent->w_level < level)
16640384fff8SJason Evans 		parent->w_level = level;
16650384fff8SJason Evans 	level++;
16660384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
16670384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
16680384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
16690384fff8SJason Evans }
16700384fff8SJason Evans 
16710384fff8SJason Evans static void
1672606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1673606f8eb2SJohn Baldwin 			   struct witness *parent)
16740384fff8SJason Evans {
1675606f8eb2SJohn Baldwin 	struct witness *w;
16760384fff8SJason Evans 	int i;
16770384fff8SJason Evans 	int level = parent->w_level;
16780384fff8SJason Evans 
16790384fff8SJason Evans 	prnt("%d", level);
16800384fff8SJason Evans 	if (level < 10)
16810384fff8SJason Evans 		prnt(" ");
16820384fff8SJason Evans 	for (i = 0; i < level; i++)
16830384fff8SJason Evans 		prnt(" ");
16840384fff8SJason Evans 	prnt("%s", parent->w_description);
16850384fff8SJason Evans 	if (parent->w_file != NULL) {
16860384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
16870384fff8SJason Evans #ifndef W_USE_WHERE
16880384fff8SJason Evans 		prnt(":%d", parent->w_line);
16890384fff8SJason Evans #endif
16900384fff8SJason Evans 		prnt("\n");
16910384fff8SJason Evans 	}
16920384fff8SJason Evans 
16930384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
16940384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
16950384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
16960384fff8SJason Evans     }
16970384fff8SJason Evans 
16980384fff8SJason Evans static int
1699606f8eb2SJohn Baldwin dup_ok(struct witness *w)
17000384fff8SJason Evans {
17010384fff8SJason Evans 	char **dup;
17020384fff8SJason Evans 
17030384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
17040384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
17050384fff8SJason Evans 			return (1);
17060384fff8SJason Evans 	return (0);
17070384fff8SJason Evans }
17080384fff8SJason Evans 
17090384fff8SJason Evans static int
1710606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
17110384fff8SJason Evans {
17120384fff8SJason Evans 	int i;
1713606f8eb2SJohn Baldwin 	struct witness_blessed *b;
17140384fff8SJason Evans 
17150384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
17160384fff8SJason Evans 		b = &blessed_list[i];
17170384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
17180384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
17190384fff8SJason Evans 				return (1);
17200384fff8SJason Evans 			continue;
17210384fff8SJason Evans 		}
17220384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
17230384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
17240384fff8SJason Evans 				return (1);
17250384fff8SJason Evans 	}
17260384fff8SJason Evans 	return (0);
17270384fff8SJason Evans }
17280384fff8SJason Evans 
1729606f8eb2SJohn Baldwin static struct witness *
17300384fff8SJason Evans witness_get()
17310384fff8SJason Evans {
1732606f8eb2SJohn Baldwin 	struct witness *w;
17330384fff8SJason Evans 
17340384fff8SJason Evans 	if ((w = w_free) == NULL) {
17350384fff8SJason Evans 		witness_dead = 1;
1736562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
17370384fff8SJason Evans 		printf("witness exhausted\n");
17380384fff8SJason Evans 		return (NULL);
17390384fff8SJason Evans 	}
17400384fff8SJason Evans 	w_free = w->w_next;
17410384fff8SJason Evans 	bzero(w, sizeof(*w));
17420384fff8SJason Evans 	return (w);
17430384fff8SJason Evans }
17440384fff8SJason Evans 
17450384fff8SJason Evans static void
1746606f8eb2SJohn Baldwin witness_free(struct witness *w)
17470384fff8SJason Evans {
17480384fff8SJason Evans 	w->w_next = w_free;
17490384fff8SJason Evans 	w_free = w;
17500384fff8SJason Evans }
17510384fff8SJason Evans 
175292cf772dSJake Burkholder int
17530384fff8SJason Evans witness_list(struct proc *p)
17540384fff8SJason Evans {
1755606f8eb2SJohn Baldwin 	struct mtx *m;
175692cf772dSJake Burkholder 	int nheld;
17570384fff8SJason Evans 
1758d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
175992cf772dSJake Burkholder 	nheld = 0;
17600384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
17610384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
17620384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
17630384fff8SJason Evans 		    m->mtx_description, m,
17640384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
176592cf772dSJake Burkholder 		nheld++;
17660384fff8SJason Evans 	}
176792cf772dSJake Burkholder 
176892cf772dSJake Burkholder 	return (nheld);
17690384fff8SJason Evans }
17700384fff8SJason Evans 
17710384fff8SJason Evans void
1772606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
17730384fff8SJason Evans {
1774d1c1b841SJason Evans 
1775d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
17760cde2e34SJason Evans 	if (m->mtx_witness == NULL)
17770cde2e34SJason Evans 		return;
17780cde2e34SJason Evans 
17790384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
17800384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
17810384fff8SJason Evans }
17820384fff8SJason Evans 
17830384fff8SJason Evans void
1784606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
17850384fff8SJason Evans {
1786d1c1b841SJason Evans 
1787d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
17880cde2e34SJason Evans 	if (m->mtx_witness == NULL)
17890cde2e34SJason Evans 		return;
17900cde2e34SJason Evans 
17910384fff8SJason Evans 	m->mtx_witness->w_file = file;
17920384fff8SJason Evans 	m->mtx_witness->w_line = line;
17930384fff8SJason Evans }
17940384fff8SJason Evans 
17956936206eSJohn Baldwin #endif	/* WITNESS */
1796