xref: /freebsd/sys/kern/kern_mutex.c (revision a10f496636e899b148029e65437eef7882b69531)
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 /*
349ed346baSBosko Milekic  * Machine independent bits of mutex implementation and implementation of
359ed346baSBosko Milekic  * `witness' structure & related debugging routines.
369ed346baSBosko Milekic  */
379ed346baSBosko Milekic 
389ed346baSBosko Milekic /*
390384fff8SJason Evans  *	Main Entry: witness
400384fff8SJason Evans  *	Pronunciation: 'wit-n&s
410384fff8SJason Evans  *	Function: noun
420384fff8SJason Evans  *	Etymology: Middle English witnesse, from Old English witnes knowledge,
430384fff8SJason Evans  *	    testimony, witness, from 2wit
440384fff8SJason Evans  *	Date: before 12th century
450384fff8SJason Evans  *	1 : attestation of a fact or event : TESTIMONY
460384fff8SJason Evans  *	2 : one that gives evidence; specifically : one who testifies in
470384fff8SJason Evans  *	    a cause or before a judicial tribunal
480384fff8SJason Evans  *	3 : one asked to be present at a transaction so as to be able to
490384fff8SJason Evans  *	    testify to its having taken place
500384fff8SJason Evans  *	4 : one who has personal knowledge of something
510384fff8SJason Evans  *	5 a : something serving as evidence or proof : SIGN
520384fff8SJason Evans  *	  b : public affirmation by word or example of usually
530384fff8SJason Evans  *	      religious faith or conviction <the heroic witness to divine
540384fff8SJason Evans  *	      life -- Pilot>
550384fff8SJason Evans  *	6 capitalized : a member of the Jehovah's Witnesses
560384fff8SJason Evans  */
570384fff8SJason Evans 
589c36c934SJohn Baldwin #include "opt_ddb.h"
59a5a96a19SJohn Baldwin #include "opt_witness.h"
60a5a96a19SJohn Baldwin 
610384fff8SJason Evans #include <sys/param.h>
6236412d79SJohn Baldwin #include <sys/bus.h>
6336412d79SJohn Baldwin #include <sys/kernel.h>
6436412d79SJohn Baldwin #include <sys/malloc.h>
650384fff8SJason Evans #include <sys/proc.h>
66a5a96a19SJohn Baldwin #include <sys/sysctl.h>
670384fff8SJason Evans #include <sys/systm.h>
6836412d79SJohn Baldwin #include <sys/vmmeter.h>
690384fff8SJason Evans #include <sys/ktr.h>
700384fff8SJason Evans 
7136412d79SJohn Baldwin #include <machine/atomic.h>
7236412d79SJohn Baldwin #include <machine/bus.h>
7336412d79SJohn Baldwin #include <machine/clock.h>
740384fff8SJason Evans #include <machine/cpu.h>
7536412d79SJohn Baldwin 
769c36c934SJohn Baldwin #include <ddb/ddb.h>
779c36c934SJohn Baldwin 
7836412d79SJohn Baldwin #include <vm/vm.h>
7936412d79SJohn Baldwin #include <vm/vm_extern.h>
8036412d79SJohn Baldwin 
8136412d79SJohn Baldwin #include <sys/mutex.h>
8236412d79SJohn Baldwin 
8336412d79SJohn Baldwin /*
849ed346baSBosko Milekic  * The WITNESS-enabled mutex debug structure.
8536412d79SJohn Baldwin  */
866936206eSJohn Baldwin #ifdef WITNESS
870cde2e34SJason Evans struct mtx_debug {
880cde2e34SJason Evans 	struct witness	*mtxd_witness;
890cde2e34SJason Evans 	LIST_ENTRY(mtx)	mtxd_held;
900cde2e34SJason Evans 	const char	*mtxd_file;
910cde2e34SJason Evans 	int		mtxd_line;
920cde2e34SJason Evans };
930cde2e34SJason Evans 
948484de75SJohn Baldwin #define mtx_held	mtx_debug->mtxd_held
958484de75SJohn Baldwin #define	mtx_file	mtx_debug->mtxd_file
968484de75SJohn Baldwin #define	mtx_line	mtx_debug->mtxd_line
978484de75SJohn Baldwin #define	mtx_witness	mtx_debug->mtxd_witness
980cde2e34SJason Evans #endif	/* WITNESS */
990cde2e34SJason Evans 
1000cde2e34SJason Evans /*
1019ed346baSBosko Milekic  * Internal utility macros.
1020cde2e34SJason Evans  */
1039ed346baSBosko Milekic #define mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
1040cde2e34SJason Evans 
1059ed346baSBosko Milekic #define mtx_owner(m)	(mtx_unowned((m)) ? NULL \
1069ed346baSBosko Milekic 	: (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
1079ed346baSBosko Milekic 
108d5a08a60SJake Burkholder #define SET_PRIO(p, pri)	(p)->p_pri.pri_level = (pri)
1090cde2e34SJason Evans 
1100cde2e34SJason Evans /*
1119ed346baSBosko Milekic  * Early WITNESS-enabled declarations.
1120cde2e34SJason Evans  */
1130cde2e34SJason Evans #ifdef WITNESS
1149ed346baSBosko Milekic 
1159ed346baSBosko Milekic /*
1169ed346baSBosko Milekic  * Internal WITNESS routines which must be prototyped early.
1179ed346baSBosko Milekic  *
1189ed346baSBosko Milekic  * XXX: When/if witness code is cleaned up, it would be wise to place all
1199ed346baSBosko Milekic  *	witness prototyping early in this file.
1209ed346baSBosko Milekic  */
1210cde2e34SJason Evans static void witness_init(struct mtx *, int flag);
1220cde2e34SJason Evans static void witness_destroy(struct mtx *);
1230cde2e34SJason Evans static void witness_display(void(*)(const char *fmt, ...));
1240cde2e34SJason Evans 
1259ed346baSBosko Milekic MALLOC_DEFINE(M_WITNESS, "witness", "witness mtx_debug structure");
1269ed346baSBosko Milekic 
1270cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */
1288484de75SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0 };
1290cde2e34SJason Evans 
1300cde2e34SJason Evans /*
1319ed346baSBosko Milekic  * This global is set to 0 once it becomes safe to use the witness code.
1329ed346baSBosko Milekic  */
1339ed346baSBosko Milekic static int witness_cold = 1;
1349ed346baSBosko Milekic 
1359ed346baSBosko Milekic #else	/* WITNESS */
1369ed346baSBosko Milekic 
1379ed346baSBosko Milekic /* XXX XXX XXX
1389ed346baSBosko Milekic  * flag++ is sleazoid way of shuting up warning
1390cde2e34SJason Evans  */
1400cde2e34SJason Evans #define witness_init(m, flag) flag++
1410cde2e34SJason Evans #define witness_destroy(m)
1420cde2e34SJason Evans #define witness_try_enter(m, t, f, l)
1436936206eSJohn Baldwin #endif	/* WITNESS */
14436412d79SJohn Baldwin 
1459ed346baSBosko Milekic /*
1469ed346baSBosko Milekic  * All mutex locks in system are kept on the all_mtx list.
1479ed346baSBosko Milekic  */
1488484de75SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, "All mutexes queue head",
1498484de75SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
1508484de75SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx,
1518484de75SJohn Baldwin #ifdef WITNESS
1528484de75SJohn Baldwin 	&all_mtx_debug
1538484de75SJohn Baldwin #else
1548484de75SJohn Baldwin 	NULL
1558484de75SJohn Baldwin #endif
1568484de75SJohn Baldwin 	 };
1578484de75SJohn Baldwin 
1589ed346baSBosko Milekic /*
1599ed346baSBosko Milekic  * Global variables for book keeping.
1609ed346baSBosko Milekic  */
16136412d79SJohn Baldwin static int	mtx_cur_cnt;
16236412d79SJohn Baldwin static int	mtx_max_cnt;
16336412d79SJohn Baldwin 
1649ed346baSBosko Milekic /*
1655746a1d8SBosko Milekic  * Couple of strings for KTR_LOCK tracing in order to avoid duplicates.
1665746a1d8SBosko Milekic  */
1675746a1d8SBosko Milekic char	STR_mtx_lock_slp[] = "GOT (sleep) %s [%p] r=%d at %s:%d";
1685746a1d8SBosko Milekic char	STR_mtx_unlock_slp[] = "REL (sleep) %s [%p] r=%d at %s:%d";
1695746a1d8SBosko Milekic char	STR_mtx_lock_spn[] = "GOT (spin) %s [%p] r=%d at %s:%d";
1705746a1d8SBosko Milekic char	STR_mtx_unlock_spn[] = "REL (spin) %s [%p] r=%d at %s:%d";
1715746a1d8SBosko Milekic 
1725746a1d8SBosko Milekic /*
1739ed346baSBosko Milekic  * Prototypes for non-exported routines.
1749ed346baSBosko Milekic  *
1759ed346baSBosko Milekic  * NOTE: Prototypes for witness routines are placed at the bottom of the file.
1769ed346baSBosko Milekic  */
1771bd0eefbSJohn Baldwin static void	propagate_priority(struct proc *);
17836412d79SJohn Baldwin 
17936412d79SJohn Baldwin static void
18036412d79SJohn Baldwin propagate_priority(struct proc *p)
18136412d79SJohn Baldwin {
182d5a08a60SJake Burkholder 	int pri = p->p_pri.pri_level;
18336412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
18436412d79SJohn Baldwin 
1851bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
18636412d79SJohn Baldwin 	for (;;) {
18736412d79SJohn Baldwin 		struct proc *p1;
18836412d79SJohn Baldwin 
18936412d79SJohn Baldwin 		p = mtx_owner(m);
19036412d79SJohn Baldwin 
19136412d79SJohn Baldwin 		if (p == NULL) {
19236412d79SJohn Baldwin 			/*
19336412d79SJohn Baldwin 			 * This really isn't quite right. Really
19436412d79SJohn Baldwin 			 * ought to bump priority of process that
19536412d79SJohn Baldwin 			 * next acquires the mutex.
19636412d79SJohn Baldwin 			 */
19736412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
19836412d79SJohn Baldwin 			return;
19936412d79SJohn Baldwin 		}
2009ed346baSBosko Milekic 
20136412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
2021bd0eefbSJohn Baldwin 		KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex"));
203d5a08a60SJake Burkholder 		if (p->p_pri.pri_level <= pri)
20436412d79SJohn Baldwin 			return;
2051bd0eefbSJohn Baldwin 
2061bd0eefbSJohn Baldwin 		/*
2071bd0eefbSJohn Baldwin 		 * Bump this process' priority.
2081bd0eefbSJohn Baldwin 		 */
2091bd0eefbSJohn Baldwin 		SET_PRIO(p, pri);
2101bd0eefbSJohn Baldwin 
21136412d79SJohn Baldwin 		/*
21236412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
21336412d79SJohn Baldwin 		 */
21425d209f2SJohn Baldwin 		if (p->p_oncpu != NOCPU) {
21536412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
21636412d79SJohn Baldwin 			return;
21736412d79SJohn Baldwin 		}
218d5a08a60SJake Burkholder 
21936412d79SJohn Baldwin 		/*
22036412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
22136412d79SJohn Baldwin 		 * quit.
22236412d79SJohn Baldwin 		 */
22336412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
22436412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
22536412d79SJohn Baldwin 			remrunqueue(p);
22636412d79SJohn Baldwin 			setrunqueue(p);
22736412d79SJohn Baldwin 			return;
22836412d79SJohn Baldwin 		}
22936412d79SJohn Baldwin 
23036412d79SJohn Baldwin 		/*
2311bd0eefbSJohn Baldwin 		 * If we aren't blocked on a mutex, we should be.
23236412d79SJohn Baldwin 		 */
2331bd0eefbSJohn Baldwin 		KASSERT(p->p_stat == SMTX, (
2341bd0eefbSJohn Baldwin 		    "process %d(%s):%d holds %s but isn't blocked on a mutex\n",
2351bd0eefbSJohn Baldwin 		    p->p_pid, p->p_comm, p->p_stat,
2361bd0eefbSJohn Baldwin 		    m->mtx_description));
23736412d79SJohn Baldwin 
23836412d79SJohn Baldwin 		/*
23936412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
24036412d79SJohn Baldwin 		 */
24136412d79SJohn Baldwin 		m = p->p_blocked;
24236412d79SJohn Baldwin 		MPASS(m != NULL);
24336412d79SJohn Baldwin 
24436412d79SJohn Baldwin 		/*
24536412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
24636412d79SJohn Baldwin 		 * the blocked chain
24736412d79SJohn Baldwin 		 */
2481bd0eefbSJohn Baldwin 		if (p == TAILQ_FIRST(&m->mtx_blocked)) {
2491bd0eefbSJohn Baldwin 			continue;
2501bd0eefbSJohn Baldwin 		}
2519ed346baSBosko Milekic 
252d5a08a60SJake Burkholder 		p1 = TAILQ_PREV(p, procqueue, p_procq);
253d5a08a60SJake Burkholder 		if (p1->p_pri.pri_level <= pri) {
25436412d79SJohn Baldwin 			continue;
25536412d79SJohn Baldwin 		}
25636412d79SJohn Baldwin 
25736412d79SJohn Baldwin 		/*
2581bd0eefbSJohn Baldwin 		 * Remove proc from blocked chain and determine where
2591bd0eefbSJohn Baldwin 		 * it should be moved up to.  Since we know that p1 has
2601bd0eefbSJohn Baldwin 		 * a lower priority than p, we know that at least one
2611bd0eefbSJohn Baldwin 		 * process in the chain has a lower priority and that
2621bd0eefbSJohn Baldwin 		 * p1 will thus not be NULL after the loop.
26336412d79SJohn Baldwin 		 */
26436412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
26536412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
26636412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
267d5a08a60SJake Burkholder 			if (p1->p_pri.pri_level > pri)
26836412d79SJohn Baldwin 				break;
26936412d79SJohn Baldwin 		}
2709ed346baSBosko Milekic 
2711bd0eefbSJohn Baldwin 		MPASS(p1 != NULL);
27236412d79SJohn Baldwin 		TAILQ_INSERT_BEFORE(p1, p, p_procq);
27336412d79SJohn Baldwin 		CTR4(KTR_LOCK,
2748484de75SJohn Baldwin 		    "propagate_priority: p %p moved before %p on [%p] %s",
27536412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
27636412d79SJohn Baldwin 	}
27736412d79SJohn Baldwin }
27836412d79SJohn Baldwin 
2790cde2e34SJason Evans /*
2809ed346baSBosko Milekic  * The important part of mtx_trylock{,_flags}()
2819ed346baSBosko Milekic  * Tries to acquire lock `m.' We do NOT handle recursion here; we assume that
2829ed346baSBosko Milekic  * if we're called, it's because we know we don't already own this lock.
2830cde2e34SJason Evans  */
2840cde2e34SJason Evans int
2859ed346baSBosko Milekic _mtx_trylock(struct mtx *m, int opts, const char *file, int line)
2860cde2e34SJason Evans {
2870cde2e34SJason Evans 	int rval;
2880cde2e34SJason Evans 
28927863426SBosko Milekic 	MPASS(curproc != NULL);
2909ed346baSBosko Milekic 
2919ed346baSBosko Milekic 	/*
2929ed346baSBosko Milekic 	 * _mtx_trylock does not accept MTX_NOSWITCH option.
2939ed346baSBosko Milekic 	 */
2945746a1d8SBosko Milekic 	KASSERT((opts & MTX_NOSWITCH) == 0,
2955746a1d8SBosko Milekic 	    ("mtx_trylock() called with invalid option flag(s) %d", opts));
2969ed346baSBosko Milekic 
29727863426SBosko Milekic 	rval = _obtain_lock(m, curproc);
2989ed346baSBosko Milekic 
2990cde2e34SJason Evans #ifdef WITNESS
3009ed346baSBosko Milekic 	if (rval && m->mtx_witness != NULL) {
3019ed346baSBosko Milekic 		/*
3029ed346baSBosko Milekic 		 * We do not handle recursion in _mtx_trylock; see the
3039ed346baSBosko Milekic 		 * note at the top of the routine.
3049ed346baSBosko Milekic 		 */
3055746a1d8SBosko Milekic 		KASSERT(!mtx_recursed(m),
3065746a1d8SBosko Milekic 		    ("mtx_trylock() called on a recursed mutex"));
3079ed346baSBosko Milekic 		witness_try_enter(m, (opts | m->mtx_flags), file, line);
3080cde2e34SJason Evans 	}
3090cde2e34SJason Evans #endif	/* WITNESS */
3109ed346baSBosko Milekic 
3119ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
31215ec816aSJohn Baldwin 		CTR5(KTR_LOCK, "TRY_LOCK %s [%p] result=%d at %s:%d",
3139ed346baSBosko Milekic 		    m->mtx_description, m, rval, file, line);
3140cde2e34SJason Evans 
3150cde2e34SJason Evans 	return rval;
3160cde2e34SJason Evans }
3170cde2e34SJason Evans 
3180cde2e34SJason Evans /*
3199ed346baSBosko Milekic  * _mtx_lock_sleep: the tougher part of acquiring an MTX_DEF lock.
3209ed346baSBosko Milekic  *
3219ed346baSBosko Milekic  * We call this if the lock is either contested (i.e. we need to go to
3229ed346baSBosko Milekic  * sleep waiting for it), or if we need to recurse on it.
3230cde2e34SJason Evans  */
3240cde2e34SJason Evans void
3259ed346baSBosko Milekic _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
32636412d79SJohn Baldwin {
32727863426SBosko Milekic 	struct proc *p = curproc;
32836412d79SJohn Baldwin 
32936412d79SJohn Baldwin 	if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
33036412d79SJohn Baldwin 		m->mtx_recurse++;
33108812b39SBosko Milekic 		atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
3329ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
3335746a1d8SBosko Milekic 			CTR1(KTR_LOCK, "_mtx_lock_sleep: %p recursing", m);
33436412d79SJohn Baldwin 		return;
33536412d79SJohn Baldwin 	}
3369ed346baSBosko Milekic 
3379ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
33815ec816aSJohn Baldwin 		CTR4(KTR_LOCK,
33915ec816aSJohn Baldwin 		    "_mtx_lock_sleep: %s contested (lock=%p) at %s:%d",
34015ec816aSJohn Baldwin 		    m->mtx_description, (void *)m->mtx_lock, file, line);
3411bd0eefbSJohn Baldwin 
3421bd0eefbSJohn Baldwin 	/*
3439ed346baSBosko Milekic 	 * Save our priority. Even though p_nativepri is protected by
3449ed346baSBosko Milekic 	 * sched_lock, we don't obtain it here as it can be expensive.
3459ed346baSBosko Milekic 	 * Since this is the only place p_nativepri is set, and since two
3469ed346baSBosko Milekic 	 * CPUs will not be executing the same process concurrently, we know
3479ed346baSBosko Milekic 	 * that no other CPU is going to be messing with this. Also,
3489ed346baSBosko Milekic 	 * p_nativepri is only read when we are blocked on a mutex, so that
3499ed346baSBosko Milekic 	 * can't be happening right now either.
3501bd0eefbSJohn Baldwin 	 */
351d5a08a60SJake Burkholder 	p->p_pri.pri_native = p->p_pri.pri_level;
3529ed346baSBosko Milekic 
35336412d79SJohn Baldwin 	while (!_obtain_lock(m, p)) {
354f5271ebcSJohn Baldwin 		uintptr_t v;
35536412d79SJohn Baldwin 		struct proc *p1;
35636412d79SJohn Baldwin 
3579ed346baSBosko Milekic 		mtx_lock_spin(&sched_lock);
35836412d79SJohn Baldwin 		/*
3599ed346baSBosko Milekic 		 * Check if the lock has been released while spinning for
3609ed346baSBosko Milekic 		 * the sched_lock.
36136412d79SJohn Baldwin 		 */
36236412d79SJohn Baldwin 		if ((v = m->mtx_lock) == MTX_UNOWNED) {
3639ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
36436412d79SJohn Baldwin 			continue;
36536412d79SJohn Baldwin 		}
3669ed346baSBosko Milekic 
36736412d79SJohn Baldwin 		/*
3689ed346baSBosko Milekic 		 * The mutex was marked contested on release. This means that
3699ed346baSBosko Milekic 		 * there are processes blocked on it.
37036412d79SJohn Baldwin 		 */
37136412d79SJohn Baldwin 		if (v == MTX_CONTESTED) {
37236412d79SJohn Baldwin 			p1 = TAILQ_FIRST(&m->mtx_blocked);
3735746a1d8SBosko Milekic 			MPASS(p1 != NULL);
37436412d79SJohn Baldwin 			m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
3759ed346baSBosko Milekic 
376d5a08a60SJake Burkholder 			if (p1->p_pri.pri_level < p->p_pri.pri_level)
377d5a08a60SJake Burkholder 				SET_PRIO(p, p1->p_pri.pri_level);
3789ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
37936412d79SJohn Baldwin 			return;
38036412d79SJohn Baldwin 		}
3819ed346baSBosko Milekic 
38236412d79SJohn Baldwin 		/*
3839ed346baSBosko Milekic 		 * If the mutex isn't already contested and a failure occurs
3849ed346baSBosko Milekic 		 * setting the contested bit, the mutex was either released
3859ed346baSBosko Milekic 		 * or the state of the MTX_RECURSED bit changed.
38636412d79SJohn Baldwin 		 */
38736412d79SJohn Baldwin 		if ((v & MTX_CONTESTED) == 0 &&
38836412d79SJohn Baldwin 		    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
38936412d79SJohn Baldwin 			(void *)(v | MTX_CONTESTED))) {
3909ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
39136412d79SJohn Baldwin 			continue;
39236412d79SJohn Baldwin 		}
39336412d79SJohn Baldwin 
3949ed346baSBosko Milekic 		/*
3959ed346baSBosko Milekic 		 * We deffinately must sleep for this lock.
3969ed346baSBosko Milekic 		 */
39736412d79SJohn Baldwin 		mtx_assert(m, MA_NOTOWNED);
39836412d79SJohn Baldwin 
39936412d79SJohn Baldwin #ifdef notyet
40036412d79SJohn Baldwin 		/*
4019ed346baSBosko Milekic 		 * If we're borrowing an interrupted thread's VM context, we
4029ed346baSBosko Milekic 		 * must clean up before going to sleep.
40336412d79SJohn Baldwin 		 */
40415ec816aSJohn Baldwin 		if (p->p_ithd != NULL) {
40515ec816aSJohn Baldwin 			struct ithd *it = p->p_ithd;
40636412d79SJohn Baldwin 
40736412d79SJohn Baldwin 			if (it->it_interrupted) {
4089ed346baSBosko Milekic 				if ((opts & MTX_QUIET) == 0)
40936412d79SJohn Baldwin 					CTR2(KTR_LOCK,
41015ec816aSJohn Baldwin 				    "_mtx_lock_sleep: %p interrupted %p",
41136412d79SJohn Baldwin 					    it, it->it_interrupted);
41236412d79SJohn Baldwin 				intr_thd_fixup(it);
41336412d79SJohn Baldwin 			}
41436412d79SJohn Baldwin 		}
41536412d79SJohn Baldwin #endif
41636412d79SJohn Baldwin 
4179ed346baSBosko Milekic 		/*
4189ed346baSBosko Milekic 		 * Put us on the list of threads blocked on this mutex.
4199ed346baSBosko Milekic 		 */
42036412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
4219ed346baSBosko Milekic 			p1 = (struct proc *)(m->mtx_lock & MTX_FLAGMASK);
4229ed346baSBosko Milekic 			LIST_INSERT_HEAD(&p1->p_contested, m, mtx_contested);
42336412d79SJohn Baldwin 			TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
42436412d79SJohn Baldwin 		} else {
42536412d79SJohn Baldwin 			TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
426d5a08a60SJake Burkholder 				if (p1->p_pri.pri_level > p->p_pri.pri_level)
42736412d79SJohn Baldwin 					break;
42836412d79SJohn Baldwin 			if (p1)
42936412d79SJohn Baldwin 				TAILQ_INSERT_BEFORE(p1, p, p_procq);
43036412d79SJohn Baldwin 			else
4319ed346baSBosko Milekic 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
43236412d79SJohn Baldwin 		}
43336412d79SJohn Baldwin 
4349ed346baSBosko Milekic 		/*
4359ed346baSBosko Milekic 		 * Save who we're blocked on.
4369ed346baSBosko Milekic 		 */
4379ed346baSBosko Milekic 		p->p_blocked = m;
43886327ad8SJohn Baldwin 		p->p_mtxname = m->mtx_description;
43936412d79SJohn Baldwin 		p->p_stat = SMTX;
44036412d79SJohn Baldwin 		propagate_priority(p);
4419ed346baSBosko Milekic 
4429ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
443562e4ffeSJohn Baldwin 			CTR3(KTR_LOCK,
4449ed346baSBosko Milekic 			    "_mtx_lock_sleep: p %p blocked on [%p] %s", p, m,
4459ed346baSBosko Milekic 			    m->mtx_description);
4469ed346baSBosko Milekic 
44720cdcc5bSJohn Baldwin 		mi_switch();
4489ed346baSBosko Milekic 
4499ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
45036412d79SJohn Baldwin 			CTR3(KTR_LOCK,
4519ed346baSBosko Milekic 			  "_mtx_lock_sleep: p %p free from blocked on [%p] %s",
45236412d79SJohn Baldwin 			  p, m, m->mtx_description);
4539ed346baSBosko Milekic 
4549ed346baSBosko Milekic 		mtx_unlock_spin(&sched_lock);
45536412d79SJohn Baldwin 	}
4569ed346baSBosko Milekic 
45736412d79SJohn Baldwin 	return;
4589ed346baSBosko Milekic }
4599ed346baSBosko Milekic 
4609ed346baSBosko Milekic /*
4619ed346baSBosko Milekic  * _mtx_lock_spin: the tougher part of acquiring an MTX_SPIN lock.
4629ed346baSBosko Milekic  *
4639ed346baSBosko Milekic  * This is only called if we need to actually spin for the lock. Recursion
4649ed346baSBosko Milekic  * is handled inline.
4659ed346baSBosko Milekic  */
4669ed346baSBosko Milekic void
4679ed346baSBosko Milekic _mtx_lock_spin(struct mtx *m, int opts, u_int mtx_intr, const char *file,
4689ed346baSBosko Milekic 	       int line)
46936412d79SJohn Baldwin {
47036412d79SJohn Baldwin 	int i = 0;
47136412d79SJohn Baldwin 
4729ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
4735746a1d8SBosko Milekic 		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);
4749ed346baSBosko Milekic 
47536412d79SJohn Baldwin 	for (;;) {
47627863426SBosko Milekic 		if (_obtain_lock(m, curproc))
47736412d79SJohn Baldwin 			break;
4789ed346baSBosko Milekic 
47936412d79SJohn Baldwin 		while (m->mtx_lock != MTX_UNOWNED) {
48036412d79SJohn Baldwin 			if (i++ < 1000000)
48136412d79SJohn Baldwin 				continue;
48236412d79SJohn Baldwin 			if (i++ < 6000000)
48336412d79SJohn Baldwin 				DELAY(1);
48436412d79SJohn Baldwin #ifdef DDB
48536412d79SJohn Baldwin 			else if (!db_active)
48636412d79SJohn Baldwin #else
48736412d79SJohn Baldwin 			else
48836412d79SJohn Baldwin #endif
4899ed346baSBosko Milekic 			panic("spin lock %s held by %p for > 5 seconds",
4909ed346baSBosko Milekic 			    m->mtx_description, (void *)m->mtx_lock);
49136412d79SJohn Baldwin 		}
49236412d79SJohn Baldwin 	}
49336412d79SJohn Baldwin 
4949ed346baSBosko Milekic 	m->mtx_saveintr = mtx_intr;
4959ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
4969ed346baSBosko Milekic 		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
4979ed346baSBosko Milekic 
49836412d79SJohn Baldwin 	return;
49936412d79SJohn Baldwin }
50036412d79SJohn Baldwin 
5019ed346baSBosko Milekic /*
5029ed346baSBosko Milekic  * _mtx_unlock_sleep: the tougher part of releasing an MTX_DEF lock.
5039ed346baSBosko Milekic  *
5049ed346baSBosko Milekic  * We are only called here if the lock is recursed or contested (i.e. we
5059ed346baSBosko Milekic  * need to wake up a blocked thread).
5069ed346baSBosko Milekic  */
50736412d79SJohn Baldwin void
5089ed346baSBosko Milekic _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
50936412d79SJohn Baldwin {
51036412d79SJohn Baldwin 	struct proc *p, *p1;
51136412d79SJohn Baldwin 	struct mtx *m1;
51236412d79SJohn Baldwin 	int pri;
51336412d79SJohn Baldwin 
51427863426SBosko Milekic 	p = curproc;
5159ed346baSBosko Milekic 	MPASS4(mtx_owned(m), "mtx_owned(mpp)", file, line);
5169ed346baSBosko Milekic 
51708812b39SBosko Milekic 	if (mtx_recursed(m)) {
51836412d79SJohn Baldwin 		if (--(m->mtx_recurse) == 0)
51908812b39SBosko Milekic 			atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
5209ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
5219ed346baSBosko Milekic 			CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p unrecurse", m);
52236412d79SJohn Baldwin 		return;
52336412d79SJohn Baldwin 	}
5249ed346baSBosko Milekic 
5259ed346baSBosko Milekic 	mtx_lock_spin(&sched_lock);
5269ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5279ed346baSBosko Milekic 		CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m);
5289ed346baSBosko Milekic 
52936412d79SJohn Baldwin 	p1 = TAILQ_FIRST(&m->mtx_blocked);
53036412d79SJohn Baldwin 	MPASS(p->p_magic == P_MAGIC);
53136412d79SJohn Baldwin 	MPASS(p1->p_magic == P_MAGIC);
5329ed346baSBosko Milekic 
53336412d79SJohn Baldwin 	TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
5349ed346baSBosko Milekic 
53536412d79SJohn Baldwin 	if (TAILQ_EMPTY(&m->mtx_blocked)) {
53636412d79SJohn Baldwin 		LIST_REMOVE(m, mtx_contested);
53736412d79SJohn Baldwin 		_release_lock_quick(m);
5389ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
5399ed346baSBosko Milekic 			CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
54036412d79SJohn Baldwin 	} else
5419ed346baSBosko Milekic 		atomic_store_rel_ptr(&m->mtx_lock, (void *)MTX_CONTESTED);
5429ed346baSBosko Milekic 
543d5a08a60SJake Burkholder 	pri = PRI_MAX;
54436412d79SJohn Baldwin 	LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
545d5a08a60SJake Burkholder 		int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_pri.pri_level;
54636412d79SJohn Baldwin 		if (cp < pri)
54736412d79SJohn Baldwin 			pri = cp;
54836412d79SJohn Baldwin 	}
5499ed346baSBosko Milekic 
550d5a08a60SJake Burkholder 	if (pri > p->p_pri.pri_native)
551d5a08a60SJake Burkholder 		pri = p->p_pri.pri_native;
55236412d79SJohn Baldwin 	SET_PRIO(p, pri);
5539ed346baSBosko Milekic 
5549ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5559ed346baSBosko Milekic 		CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p contested setrunqueue %p",
5569ed346baSBosko Milekic 		    m, p1);
5579ed346baSBosko Milekic 
55836412d79SJohn Baldwin 	p1->p_blocked = NULL;
55936412d79SJohn Baldwin 	p1->p_stat = SRUN;
56036412d79SJohn Baldwin 	setrunqueue(p1);
5619ed346baSBosko Milekic 
562d5a08a60SJake Burkholder 	if ((opts & MTX_NOSWITCH) == 0 && p1->p_pri.pri_level < pri) {
56336412d79SJohn Baldwin #ifdef notyet
56415ec816aSJohn Baldwin 		if (p->p_ithd != NULL) {
56515ec816aSJohn Baldwin 			struct ithd *it = p->p_ithd;
56636412d79SJohn Baldwin 
56736412d79SJohn Baldwin 			if (it->it_interrupted) {
5689ed346baSBosko Milekic 				if ((opts & MTX_QUIET) == 0)
56936412d79SJohn Baldwin 					CTR2(KTR_LOCK,
57015ec816aSJohn Baldwin 				    "_mtx_unlock_sleep: %p interrupted %p",
57136412d79SJohn Baldwin 					    it, it->it_interrupted);
57236412d79SJohn Baldwin 				intr_thd_fixup(it);
57336412d79SJohn Baldwin 			}
57436412d79SJohn Baldwin 		}
57536412d79SJohn Baldwin #endif
57636412d79SJohn Baldwin 		setrunqueue(p);
5779ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
578562e4ffeSJohn Baldwin 			CTR2(KTR_LOCK,
5799ed346baSBosko Milekic 			    "_mtx_unlock_sleep: %p switching out lock=%p", m,
5809ed346baSBosko Milekic 			    (void *)m->mtx_lock);
5819ed346baSBosko Milekic 
58236412d79SJohn Baldwin 		mi_switch();
5839ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
5849ed346baSBosko Milekic 			CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p resuming lock=%p",
58531271627SJohn Baldwin 			    m, (void *)m->mtx_lock);
58636412d79SJohn Baldwin 	}
58736412d79SJohn Baldwin 
5889ed346baSBosko Milekic 	mtx_unlock_spin(&sched_lock);
5899ed346baSBosko Milekic 
5909ed346baSBosko Milekic 	return;
5919ed346baSBosko Milekic }
5929ed346baSBosko Milekic 
5939ed346baSBosko Milekic /*
5949ed346baSBosko Milekic  * All the unlocking of MTX_SPIN locks is done inline.
5959ed346baSBosko Milekic  * See the _rel_spin_lock() macro for the details.
5969ed346baSBosko Milekic  */
5979ed346baSBosko Milekic 
5989ed346baSBosko Milekic /*
59915ec816aSJohn Baldwin  * The backing function for the INVARIANTS-enabled mtx_assert()
6009ed346baSBosko Milekic  */
6011103f3b0SJohn Baldwin #ifdef INVARIANT_SUPPORT
6020cde2e34SJason Evans void
60356771ca7SJason Evans _mtx_assert(struct mtx *m, int what, const char *file, int line)
6040cde2e34SJason Evans {
605a10f4966SJake Burkholder 	switch (what) {
6060cde2e34SJason Evans 	case MA_OWNED:
6070cde2e34SJason Evans 	case MA_OWNED | MA_RECURSED:
6080cde2e34SJason Evans 	case MA_OWNED | MA_NOTRECURSED:
609a10f4966SJake Burkholder 		if (!mtx_owned(m))
6100cde2e34SJason Evans 			panic("mutex %s not owned at %s:%d",
611a10f4966SJake Burkholder 			    m->mtx_description, file, line);
612a10f4966SJake Burkholder 		if (mtx_recursed(m)) {
613a10f4966SJake Burkholder 			if ((what & MA_NOTRECURSED) != 0)
6140cde2e34SJason Evans 				panic("mutex %s recursed at %s:%d",
615a10f4966SJake Burkholder 				    m->mtx_description, file, line);
616a10f4966SJake Burkholder 		} else if ((what & MA_RECURSED) != 0) {
6170cde2e34SJason Evans 			panic("mutex %s unrecursed at %s:%d",
618a10f4966SJake Burkholder 			    m->mtx_description, file, line);
6190cde2e34SJason Evans 		}
6200cde2e34SJason Evans 		break;
6210cde2e34SJason Evans 	case MA_NOTOWNED:
622a10f4966SJake Burkholder 		if (mtx_owned(m))
6230cde2e34SJason Evans 			panic("mutex %s owned at %s:%d",
624a10f4966SJake Burkholder 			    m->mtx_description, file, line);
6250cde2e34SJason Evans 		break;
6260cde2e34SJason Evans 	default:
62756771ca7SJason Evans 		panic("unknown mtx_assert at %s:%d", file, line);
6280cde2e34SJason Evans 	}
6290cde2e34SJason Evans }
6300cde2e34SJason Evans #endif
6310cde2e34SJason Evans 
6329ed346baSBosko Milekic /*
6339ed346baSBosko Milekic  * The MUTEX_DEBUG-enabled mtx_validate()
6349ed346baSBosko Milekic  */
63536412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
63636412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
63736412d79SJohn Baldwin 
63836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
63936412d79SJohn Baldwin 
64036412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
64136412d79SJohn Baldwin 
64236412d79SJohn Baldwin int
64336412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
64436412d79SJohn Baldwin {
64536412d79SJohn Baldwin 	struct mtx *mp;
64636412d79SJohn Baldwin 	int i;
64736412d79SJohn Baldwin 	int retval = 0;
64836412d79SJohn Baldwin 
649d1c1b841SJason Evans #ifdef WITNESS
650d1c1b841SJason Evans 	if (witness_cold)
651d1c1b841SJason Evans 		return 0;
652d1c1b841SJason Evans #endif
65336412d79SJohn Baldwin 	if (m == &all_mtx || cold)
65436412d79SJohn Baldwin 		return 0;
65536412d79SJohn Baldwin 
6569ed346baSBosko Milekic 	mtx_lock(&all_mtx);
65736412d79SJohn Baldwin /*
65836412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
65936412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
66036412d79SJohn Baldwin  */
66136412d79SJohn Baldwin #ifndef __alpha__
66236412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
66336412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
66436412d79SJohn Baldwin #endif
66536412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
66636412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
66736412d79SJohn Baldwin #ifndef __alpha__
66836412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
66936412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
67036412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
67136412d79SJohn Baldwin 			    mp, mp->mtx_next);
67236412d79SJohn Baldwin 		}
67336412d79SJohn Baldwin #endif
67436412d79SJohn Baldwin 		i++;
67536412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
67636412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
67736412d79SJohn Baldwin 			    mtx_cur_cnt);
67836412d79SJohn Baldwin 		}
67936412d79SJohn Baldwin 	}
68036412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
68136412d79SJohn Baldwin 	switch (when) {
68236412d79SJohn Baldwin 	case MV_DESTROY:
68336412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
68436412d79SJohn Baldwin 			if (mp == m)
68536412d79SJohn Baldwin 				break;
68636412d79SJohn Baldwin 		MPASS(mp == m);
68736412d79SJohn Baldwin 		break;
68836412d79SJohn Baldwin 	case MV_INIT:
68936412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
69036412d79SJohn Baldwin 		if (mp == m) {
69136412d79SJohn Baldwin 			/*
69236412d79SJohn Baldwin 			 * Not good. This mutex already exists.
69336412d79SJohn Baldwin 			 */
69436412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
69536412d79SJohn Baldwin 			    m->mtx_description);
69636412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
69736412d79SJohn Baldwin 			retval = 1;
69836412d79SJohn Baldwin 		}
69936412d79SJohn Baldwin 	}
7009ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
70136412d79SJohn Baldwin 	return (retval);
70236412d79SJohn Baldwin }
70336412d79SJohn Baldwin #endif
70436412d79SJohn Baldwin 
7059ed346baSBosko Milekic /*
7069ed346baSBosko Milekic  * Mutex initialization routine; initialize lock `m' of type contained in
7079ed346baSBosko Milekic  * `opts' with options contained in `opts' and description `description.'
7089ed346baSBosko Milekic  * Place on "all_mtx" queue.
7099ed346baSBosko Milekic  */
71036412d79SJohn Baldwin void
7119ed346baSBosko Milekic mtx_init(struct mtx *m, const char *description, int opts)
71236412d79SJohn Baldwin {
7139ed346baSBosko Milekic 
7149ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
7159ed346baSBosko Milekic 		CTR2(KTR_LOCK, "mtx_init %p (%s)", m, description);
7169ed346baSBosko Milekic 
71736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
7189ed346baSBosko Milekic 	/* Diagnostic and error correction */
7199ed346baSBosko Milekic 	if (mtx_validate(m, MV_INIT))
72036412d79SJohn Baldwin 		return;
7216936206eSJohn Baldwin #endif
72236412d79SJohn Baldwin 
72336412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
72436412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
7259ed346baSBosko Milekic 
7266936206eSJohn Baldwin #ifdef WITNESS
727d1c1b841SJason Evans 	if (!witness_cold) {
7288484de75SJohn Baldwin 		m->mtx_debug = malloc(sizeof(struct mtx_debug),
7299ed346baSBosko Milekic 		    M_WITNESS, M_NOWAIT | M_ZERO);
7308484de75SJohn Baldwin 		MPASS(m->mtx_debug != NULL);
731d1c1b841SJason Evans 	}
732d1c1b841SJason Evans #endif
733d1c1b841SJason Evans 
7349ed346baSBosko Milekic 	m->mtx_description = description;
7359ed346baSBosko Milekic 	m->mtx_flags = opts;
73636412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
7379ed346baSBosko Milekic 
73836412d79SJohn Baldwin 	/* Put on all mutex queue */
7399ed346baSBosko Milekic 	mtx_lock(&all_mtx);
74036412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
74136412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
74236412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
74336412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
74436412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
74536412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
7469ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
7479ed346baSBosko Milekic 
748d1c1b841SJason Evans #ifdef WITNESS
749d1c1b841SJason Evans 	if (!witness_cold)
7509ed346baSBosko Milekic 		witness_init(m, opts);
751d1c1b841SJason Evans #endif
75236412d79SJohn Baldwin }
75336412d79SJohn Baldwin 
7549ed346baSBosko Milekic /*
7559ed346baSBosko Milekic  * Remove lock `m' from all_mtx queue.
7569ed346baSBosko Milekic  */
75736412d79SJohn Baldwin void
75836412d79SJohn Baldwin mtx_destroy(struct mtx *m)
75936412d79SJohn Baldwin {
76036412d79SJohn Baldwin 
761d1c1b841SJason Evans #ifdef WITNESS
762d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n",
763d1c1b841SJason Evans 	    __FUNCTION__));
764d1c1b841SJason Evans #endif
7659ed346baSBosko Milekic 
7668484de75SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy %p (%s)", m, m->mtx_description);
7679ed346baSBosko Milekic 
76836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
76936412d79SJohn Baldwin 	if (m->mtx_next == NULL)
77036412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
77136412d79SJohn Baldwin 		    m, m->mtx_description);
77236412d79SJohn Baldwin 
77336412d79SJohn Baldwin 	if (!mtx_owned(m)) {
77436412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
77536412d79SJohn Baldwin 	} else {
77608812b39SBosko Milekic 		MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
77736412d79SJohn Baldwin 	}
7789ed346baSBosko Milekic 
7799ed346baSBosko Milekic 	/* diagnostic */
7809ed346baSBosko Milekic 	mtx_validate(m, MV_DESTROY);
78136412d79SJohn Baldwin #endif
78236412d79SJohn Baldwin 
78336412d79SJohn Baldwin #ifdef WITNESS
78436412d79SJohn Baldwin 	if (m->mtx_witness)
78536412d79SJohn Baldwin 		witness_destroy(m);
78636412d79SJohn Baldwin #endif /* WITNESS */
78736412d79SJohn Baldwin 
78836412d79SJohn Baldwin 	/* Remove from the all mutex queue */
7899ed346baSBosko Milekic 	mtx_lock(&all_mtx);
79036412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
79136412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
7929ed346baSBosko Milekic 
79336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
79436412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
7956936206eSJohn Baldwin #endif
7969ed346baSBosko Milekic 
7976936206eSJohn Baldwin #ifdef WITNESS
7989ed346baSBosko Milekic 	free(m->mtx_debug, M_WITNESS);
7998484de75SJohn Baldwin 	m->mtx_debug = NULL;
80036412d79SJohn Baldwin #endif
8019ed346baSBosko Milekic 
80236412d79SJohn Baldwin 	mtx_cur_cnt--;
8039ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
80436412d79SJohn Baldwin }
8050384fff8SJason Evans 
8068484de75SJohn Baldwin 
8079ed346baSBosko Milekic /*
8089ed346baSBosko Milekic  * The WITNESS-enabled diagnostic code.
8099ed346baSBosko Milekic  */
8106936206eSJohn Baldwin #ifdef WITNESS
8118484de75SJohn Baldwin static void
8128484de75SJohn Baldwin witness_fixup(void *dummy __unused)
8138484de75SJohn Baldwin {
8148484de75SJohn Baldwin 	struct mtx *mp;
8158484de75SJohn Baldwin 
8168484de75SJohn Baldwin 	/*
8178484de75SJohn Baldwin 	 * We have to release Giant before initializing its witness
8188484de75SJohn Baldwin 	 * structure so that WITNESS doesn't get confused.
8198484de75SJohn Baldwin 	 */
8209ed346baSBosko Milekic 	mtx_unlock(&Giant);
8218484de75SJohn Baldwin 	mtx_assert(&Giant, MA_NOTOWNED);
8229ed346baSBosko Milekic 
8239ed346baSBosko Milekic 	mtx_lock(&all_mtx);
8248484de75SJohn Baldwin 
8258484de75SJohn Baldwin 	/* Iterate through all mutexes and finish up mutex initialization. */
8268484de75SJohn Baldwin 	for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
8278484de75SJohn Baldwin 
8288484de75SJohn Baldwin 		mp->mtx_debug = malloc(sizeof(struct mtx_debug),
8299ed346baSBosko Milekic 		    M_WITNESS, M_NOWAIT | M_ZERO);
8308484de75SJohn Baldwin 		MPASS(mp->mtx_debug != NULL);
8318484de75SJohn Baldwin 
8328484de75SJohn Baldwin 		witness_init(mp, mp->mtx_flags);
8338484de75SJohn Baldwin 	}
8349ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
8358484de75SJohn Baldwin 
8368484de75SJohn Baldwin 	/* Mark the witness code as being ready for use. */
8378484de75SJohn Baldwin 	atomic_store_rel_int(&witness_cold, 0);
8388484de75SJohn Baldwin 
8399ed346baSBosko Milekic 	mtx_lock(&Giant);
8408484de75SJohn Baldwin }
8418484de75SJohn Baldwin SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL)
8420384fff8SJason Evans 
8430384fff8SJason Evans #define WITNESS_COUNT 200
8440384fff8SJason Evans #define	WITNESS_NCHILDREN 2
8450384fff8SJason Evans 
84678f0da03SJohn Baldwin int witness_watch = 1;
8470384fff8SJason Evans 
848606f8eb2SJohn Baldwin struct witness {
8490384fff8SJason Evans 	struct witness	*w_next;
850b67a3e6eSJohn Baldwin 	const char	*w_description;
85112473b76SJason Evans 	const char	*w_file;
8520384fff8SJason Evans 	int		 w_line;
8530384fff8SJason Evans 	struct witness	*w_morechildren;
8540384fff8SJason Evans 	u_char		 w_childcnt;
8550384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
8560384fff8SJason Evans 	u_char		 w_other_squawked:1;
8570384fff8SJason Evans 	u_char		 w_same_squawked:1;
85808812b39SBosko Milekic 	u_char		 w_spin:1;	/* MTX_SPIN type mutex. */
8590384fff8SJason Evans 	u_int		 w_level;
8600384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
861606f8eb2SJohn Baldwin };
8620384fff8SJason Evans 
863606f8eb2SJohn Baldwin struct witness_blessed {
8640384fff8SJason Evans 	char 	*b_lock1;
8650384fff8SJason Evans 	char	*b_lock2;
866606f8eb2SJohn Baldwin };
8670384fff8SJason Evans 
868a5a96a19SJohn Baldwin #ifdef DDB
8690384fff8SJason Evans /*
870a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
8710384fff8SJason Evans  * drop into kdebug() when:
8720384fff8SJason Evans  *	- a lock heirarchy violation occurs
8730384fff8SJason Evans  *	- locks are held when going to sleep.
8740384fff8SJason Evans  */
8758484de75SJohn Baldwin int	witness_ddb;
876a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
8778484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 1, witness_ddb);
878a5a96a19SJohn Baldwin #else
8798484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 0, witness_ddb);
8800384fff8SJason Evans #endif
881a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
882a5a96a19SJohn Baldwin #endif /* DDB */
8830384fff8SJason Evans 
8848484de75SJohn Baldwin int	witness_skipspin;
885a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
8868484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 1, witness_skipspin);
887a5a96a19SJohn Baldwin #else
8888484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 0, witness_skipspin);
8890384fff8SJason Evans #endif
890a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
891a5a96a19SJohn Baldwin     "");
8920384fff8SJason Evans 
8939ed346baSBosko Milekic /*
8949ed346baSBosko Milekic  * Witness-enabled globals
8959ed346baSBosko Milekic  */
896d1c1b841SJason Evans static struct mtx	w_mtx;
897606f8eb2SJohn Baldwin static struct witness	*w_free;
898606f8eb2SJohn Baldwin static struct witness	*w_all;
8990384fff8SJason Evans static int		 w_inited;
9000384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
9010384fff8SJason Evans 
902606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
9030384fff8SJason Evans 
9049ed346baSBosko Milekic /*
9059ed346baSBosko Milekic  * Internal witness routine prototypes
9069ed346baSBosko Milekic  */
9079ed346baSBosko Milekic static struct witness *enroll(const char *description, int flag);
9089ed346baSBosko Milekic static int itismychild(struct witness *parent, struct witness *child);
9099ed346baSBosko Milekic static void removechild(struct witness *parent, struct witness *child);
9109ed346baSBosko Milekic static int isitmychild(struct witness *parent, struct witness *child);
9119ed346baSBosko Milekic static int isitmydescendant(struct witness *parent, struct witness *child);
9129ed346baSBosko Milekic static int dup_ok(struct witness *);
9139ed346baSBosko Milekic static int blessed(struct witness *, struct witness *);
9149ed346baSBosko Milekic static void
9159ed346baSBosko Milekic     witness_displaydescendants(void(*)(const char *fmt, ...), struct witness *);
9169ed346baSBosko Milekic static void witness_leveldescendents(struct witness *parent, int level);
9179ed346baSBosko Milekic static void witness_levelall(void);
9189ed346baSBosko Milekic static struct witness * witness_get(void);
9199ed346baSBosko Milekic static void witness_free(struct witness *m);
9200384fff8SJason Evans 
9210384fff8SJason Evans static char *ignore_list[] = {
9220384fff8SJason Evans 	"witness lock",
9230384fff8SJason Evans 	NULL
9240384fff8SJason Evans };
9250384fff8SJason Evans 
9260384fff8SJason Evans static char *spin_order_list[] = {
927e910ba59SJohn Baldwin #if defined(__i386__) && defined (SMP)
928e910ba59SJohn Baldwin 	"com",
929e910ba59SJohn Baldwin #endif
930a5a96a19SJohn Baldwin 	"sio",
931e910ba59SJohn Baldwin #ifdef __i386__
932e910ba59SJohn Baldwin 	"cy",
933e910ba59SJohn Baldwin #endif
93425d209f2SJohn Baldwin 	"ithread table lock",
93525d209f2SJohn Baldwin 	"ithread list lock",
9368f838cb5SJohn Baldwin 	"sched lock",
93720cdcc5bSJohn Baldwin #ifdef __i386__
93820cdcc5bSJohn Baldwin 	"clk",
93920cdcc5bSJohn Baldwin #endif
940fa2fbc3dSJake Burkholder 	"callout",
9410384fff8SJason Evans 	/*
9420384fff8SJason Evans 	 * leaf locks
9430384fff8SJason Evans 	 */
94474334661SJulian Elischer 	"ng_node",
94574334661SJulian Elischer 	"ng_worklist",
946e910ba59SJohn Baldwin #ifdef SMP
9471b367556SJason Evans #ifdef __i386__
9481b367556SJason Evans 	"ap boot",
9491b367556SJason Evans 	"imen",
9501b367556SJason Evans #endif
9511b367556SJason Evans 	"smp rendezvous",
952e910ba59SJohn Baldwin #endif
9530384fff8SJason Evans 	NULL
9540384fff8SJason Evans };
9550384fff8SJason Evans 
9560384fff8SJason Evans static char *order_list[] = {
957c75e5182SJohn Baldwin 	"Giant", "proctree", "allproc", "process lock", "uidinfo hash",
958c75e5182SJohn Baldwin 	    "uidinfo struct", NULL,
9590384fff8SJason Evans 	NULL
9600384fff8SJason Evans };
9610384fff8SJason Evans 
9620384fff8SJason Evans static char *dup_list[] = {
9630384fff8SJason Evans 	NULL
9640384fff8SJason Evans };
9650384fff8SJason Evans 
9660384fff8SJason Evans static char *sleep_list[] = {
9677da6f977SJake Burkholder 	"Giant",
9680384fff8SJason Evans 	NULL
9690384fff8SJason Evans };
9700384fff8SJason Evans 
9710384fff8SJason Evans /*
9720384fff8SJason Evans  * Pairs of locks which have been blessed
9730384fff8SJason Evans  * Don't complain about order problems with blessed locks
9740384fff8SJason Evans  */
975606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
9760384fff8SJason Evans };
9779ed346baSBosko Milekic static int blessed_count =
9789ed346baSBosko Milekic 	sizeof(blessed_list) / sizeof(struct witness_blessed);
9790384fff8SJason Evans 
9800cde2e34SJason Evans static void
981606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
9820384fff8SJason Evans {
9830384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
9840384fff8SJason Evans }
9850384fff8SJason Evans 
9860cde2e34SJason Evans static void
987606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
9880384fff8SJason Evans {
989606f8eb2SJohn Baldwin 	struct mtx *m1;
9900384fff8SJason Evans 	struct proc *p;
99127863426SBosko Milekic 	p = curproc;
992e910ba59SJohn Baldwin 	LIST_FOREACH(m1, &p->p_heldmtx, mtx_held) {
9930384fff8SJason Evans 		if (m1 == m) {
9940384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
9950384fff8SJason Evans 			break;
9960384fff8SJason Evans 		}
9970384fff8SJason Evans 	}
9980384fff8SJason Evans 	return;
9990384fff8SJason Evans 
10000384fff8SJason Evans }
10010384fff8SJason Evans 
10020cde2e34SJason Evans static void
10030cde2e34SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
10040cde2e34SJason Evans {
10050cde2e34SJason Evans 	struct witness *w, *w1;
1006e910ba59SJohn Baldwin 	int level, found;
10070cde2e34SJason Evans 
10080cde2e34SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
10090cde2e34SJason Evans 	witness_levelall();
10100cde2e34SJason Evans 
1011e910ba59SJohn Baldwin 	/*
1012e910ba59SJohn Baldwin 	 * First, handle sleep mutexes which have been acquired at least
1013e910ba59SJohn Baldwin 	 * once.
1014e910ba59SJohn Baldwin 	 */
1015e910ba59SJohn Baldwin 	prnt("Sleep mutexes:\n");
10160cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
1017e910ba59SJohn Baldwin 		if (w->w_file == NULL || w->w_spin)
10180cde2e34SJason Evans 			continue;
10190cde2e34SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
10200cde2e34SJason Evans 			if (isitmychild(w1, w))
10210cde2e34SJason Evans 				break;
10220cde2e34SJason Evans 		}
10230cde2e34SJason Evans 		if (w1 != NULL)
10240cde2e34SJason Evans 			continue;
10250cde2e34SJason Evans 		/*
10260cde2e34SJason Evans 		 * This lock has no anscestors, display its descendants.
10270cde2e34SJason Evans 		 */
10280cde2e34SJason Evans 		witness_displaydescendants(prnt, w);
10290cde2e34SJason Evans 	}
1030e910ba59SJohn Baldwin 
1031e910ba59SJohn Baldwin 	/*
1032e910ba59SJohn Baldwin 	 * Now do spin mutexes which have been acquired at least once.
1033e910ba59SJohn Baldwin 	 */
1034e910ba59SJohn Baldwin 	prnt("\nSpin mutexes:\n");
1035e910ba59SJohn Baldwin 	level = 0;
1036e910ba59SJohn Baldwin 	while (level < sizeof(spin_order_list) / sizeof(char *)) {
1037e910ba59SJohn Baldwin 		found = 0;
1038e910ba59SJohn Baldwin 		for (w = w_all; w; w = w->w_next) {
1039e910ba59SJohn Baldwin 			if (w->w_file == NULL || !w->w_spin)
1040e910ba59SJohn Baldwin 				continue;
1041e910ba59SJohn Baldwin 			if (w->w_level == 1 << level) {
1042e910ba59SJohn Baldwin 				witness_displaydescendants(prnt, w);
1043e910ba59SJohn Baldwin 				level++;
1044e910ba59SJohn Baldwin 				found = 1;
1045e910ba59SJohn Baldwin 			}
1046e910ba59SJohn Baldwin 		}
1047e910ba59SJohn Baldwin 		if (found == 0)
1048e910ba59SJohn Baldwin 			level++;
1049e910ba59SJohn Baldwin 	}
1050e910ba59SJohn Baldwin 
1051e910ba59SJohn Baldwin 	/*
1052e910ba59SJohn Baldwin 	 * Finally, any mutexes which have not been acquired yet.
1053e910ba59SJohn Baldwin 	 */
1054e910ba59SJohn Baldwin 	prnt("\nMutexes which were never acquired:\n");
10550cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
10560cde2e34SJason Evans 		if (w->w_file != NULL)
10570cde2e34SJason Evans 			continue;
10580cde2e34SJason Evans 		prnt("%s\n", w->w_description);
10590cde2e34SJason Evans 	}
10600cde2e34SJason Evans }
10610cde2e34SJason Evans 
10620384fff8SJason Evans void
1063606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
10640384fff8SJason Evans {
1065606f8eb2SJohn Baldwin 	struct witness *w, *w1;
1066606f8eb2SJohn Baldwin 	struct mtx *m1;
10670384fff8SJason Evans 	struct proc *p;
10680384fff8SJason Evans 	int i;
1069a5a96a19SJohn Baldwin #ifdef DDB
1070a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
1071a5a96a19SJohn Baldwin #endif /* DDB */
10720384fff8SJason Evans 
10730cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
1074562e4ffeSJohn Baldwin 		return;
10750384fff8SJason Evans 	w = m->mtx_witness;
107627863426SBosko Milekic 	p = curproc;
10770384fff8SJason Evans 
10780384fff8SJason Evans 	if (flags & MTX_SPIN) {
10798484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
10805340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
10815340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
108208812b39SBosko Milekic 		if (mtx_recursed(m)) {
10838484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
108408812b39SBosko Milekic 				panic("mutex_enter: recursion on non-recursive"
108508812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
108608812b39SBosko Milekic 				    file, line);
10870384fff8SJason Evans 			return;
108808812b39SBosko Milekic 		}
10899ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
1090ef73ae4bSJake Burkholder 		i = PCPU_GET(witness_spin_check);
10910384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
10929ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
10935340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
10945340642aSJason Evans 			    " %s:%d already holding %s:%x",
10950384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
10960384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
10970384fff8SJason Evans 		}
10980384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
10999ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
1100bbc7a98aSJohn Baldwin 		w->w_file = file;
1101bbc7a98aSJohn Baldwin 		w->w_line = line;
1102bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1103bbc7a98aSJohn Baldwin 		m->mtx_file = file;
11040384fff8SJason Evans 		return;
11050384fff8SJason Evans 	}
11068484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
11070384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
11080384fff8SJason Evans 		    m->mtx_description, file, line);
11090384fff8SJason Evans 
111008812b39SBosko Milekic 	if (mtx_recursed(m)) {
11118484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
111208812b39SBosko Milekic 			panic("mutex_enter: recursion on non-recursive"
111308812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
111408812b39SBosko Milekic 			    file, line);
11150384fff8SJason Evans 		return;
111608812b39SBosko Milekic 	}
11170384fff8SJason Evans 	if (witness_dead)
11180384fff8SJason Evans 		goto out;
1119562e4ffeSJohn Baldwin 	if (cold)
11200384fff8SJason Evans 		goto out;
11210384fff8SJason Evans 
11220384fff8SJason Evans 	if (!mtx_legal2block())
11239ed346baSBosko Milekic 		panic("blockable mtx_lock() of %s when not legal @ %s:%d",
11240384fff8SJason Evans 			    m->mtx_description, file, line);
11250384fff8SJason Evans 	/*
11260384fff8SJason Evans 	 * Is this the first mutex acquired
11270384fff8SJason Evans 	 */
11280384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
11290384fff8SJason Evans 		goto out;
11300384fff8SJason Evans 
11310384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
11320384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
11330384fff8SJason Evans 			goto out;
11340384fff8SJason Evans 		w->w_same_squawked = 1;
11350384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
11360384fff8SJason Evans 			m->mtx_description);
11370384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
11380384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
1139a5a96a19SJohn Baldwin #ifdef DDB
1140a5a96a19SJohn Baldwin 		go_into_ddb = 1;
1141a5a96a19SJohn Baldwin #endif /* DDB */
11420384fff8SJason Evans 		goto out;
11430384fff8SJason Evans 	}
11440384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
11459ed346baSBosko Milekic 	mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
11460384fff8SJason Evans 	/*
11470384fff8SJason Evans 	 * If we have a known higher number just say ok
11480384fff8SJason Evans 	 */
11490384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
11509ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11510384fff8SJason Evans 		goto out;
11520384fff8SJason Evans 	}
11530384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
11549ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11550384fff8SJason Evans 		goto out;
11560384fff8SJason Evans 	}
11570384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
11580384fff8SJason Evans 
115936412d79SJohn Baldwin 		MPASS(i < 200);
11600384fff8SJason Evans 		w1 = m1->mtx_witness;
11610384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
11629ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11630384fff8SJason Evans 			if (blessed(w, w1))
11640384fff8SJason Evans 				goto out;
11650384fff8SJason Evans 			if (m1 == &Giant) {
11660384fff8SJason Evans 				if (w1->w_Giant_squawked)
11670384fff8SJason Evans 					goto out;
11680384fff8SJason Evans 				else
11690384fff8SJason Evans 					w1->w_Giant_squawked = 1;
11700384fff8SJason Evans 			} else {
11710384fff8SJason Evans 				if (w1->w_other_squawked)
11720384fff8SJason Evans 					goto out;
11730384fff8SJason Evans 				else
11740384fff8SJason Evans 					w1->w_other_squawked = 1;
11750384fff8SJason Evans 			}
11760384fff8SJason Evans 			printf("lock order reversal\n");
11770384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
11780384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
11790384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
11800384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
11810384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
11820384fff8SJason Evans 			    m, w->w_description, file, line);
1183a5a96a19SJohn Baldwin #ifdef DDB
1184a5a96a19SJohn Baldwin 			go_into_ddb = 1;
1185a5a96a19SJohn Baldwin #endif /* DDB */
11860384fff8SJason Evans 			goto out;
11870384fff8SJason Evans 		}
11880384fff8SJason Evans 	}
11890384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
11900384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
11919ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11920384fff8SJason Evans 
11930384fff8SJason Evans out:
1194a5a96a19SJohn Baldwin #ifdef DDB
1195a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
1196a5a96a19SJohn Baldwin 		Debugger("witness_enter");
1197a5a96a19SJohn Baldwin #endif /* DDB */
11980384fff8SJason Evans 	w->w_file = file;
11990384fff8SJason Evans 	w->w_line = line;
12000384fff8SJason Evans 	m->mtx_line = line;
12010384fff8SJason Evans 	m->mtx_file = file;
12020384fff8SJason Evans 
12030384fff8SJason Evans 	/*
12040384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
12050384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
12060384fff8SJason Evans 	 * likely not the mutex this assert fails on.
12070384fff8SJason Evans 	 */
120836412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
12090384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
12100384fff8SJason Evans }
12110384fff8SJason Evans 
12120384fff8SJason Evans void
1213606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
12140384fff8SJason Evans {
12150384fff8SJason Evans 	struct proc *p;
1216606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
12170384fff8SJason Evans 
1218d1c1b841SJason Evans 	if (witness_cold)
1219d1c1b841SJason Evans 		return;
1220562e4ffeSJohn Baldwin 	if (panicstr)
1221562e4ffeSJohn Baldwin 		return;
12220384fff8SJason Evans 	if (flags & MTX_SPIN) {
12238484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
12240384fff8SJason Evans 			panic("mutex_try_enter: "
12250384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
12260384fff8SJason Evans 			    m->mtx_description, file, line);
122708812b39SBosko Milekic 		if (mtx_recursed(m)) {
12288484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
122908812b39SBosko Milekic 				panic("mutex_try_enter: recursion on"
123008812b39SBosko Milekic 				    " non-recursive mutex %s @ %s:%d",
123108812b39SBosko Milekic 				    m->mtx_description, file, line);
12320384fff8SJason Evans 			return;
123308812b39SBosko Milekic 		}
12349ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
1235ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
1236ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) | w->w_level);
12379ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
1238bbc7a98aSJohn Baldwin 		w->w_file = file;
1239bbc7a98aSJohn Baldwin 		w->w_line = line;
1240bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1241bbc7a98aSJohn Baldwin 		m->mtx_file = file;
12420384fff8SJason Evans 		return;
12430384fff8SJason Evans 	}
12440384fff8SJason Evans 
12458484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
12460384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12470384fff8SJason Evans 		    m->mtx_description, file, line);
12480384fff8SJason Evans 
124908812b39SBosko Milekic 	if (mtx_recursed(m)) {
12508484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
125108812b39SBosko Milekic 			panic("mutex_try_enter: recursion on non-recursive"
125208812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description, file,
125308812b39SBosko Milekic 			    line);
12540384fff8SJason Evans 		return;
125508812b39SBosko Milekic 	}
12560384fff8SJason Evans 	w->w_file = file;
12570384fff8SJason Evans 	w->w_line = line;
12580384fff8SJason Evans 	m->mtx_line = line;
12590384fff8SJason Evans 	m->mtx_file = file;
126027863426SBosko Milekic 	p = curproc;
126136412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
12620384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
12630384fff8SJason Evans }
12640384fff8SJason Evans 
12650384fff8SJason Evans void
12660cde2e34SJason Evans witness_exit(struct mtx *m, int flags, const char *file, int line)
12670384fff8SJason Evans {
12680cde2e34SJason Evans 	struct witness *w;
12690384fff8SJason Evans 
12700cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
12710cde2e34SJason Evans 		return;
12720cde2e34SJason Evans 	w = m->mtx_witness;
12730384fff8SJason Evans 
12740cde2e34SJason Evans 	if (flags & MTX_SPIN) {
12758484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
12760cde2e34SJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
12770cde2e34SJason Evans 			    " %s:%d", m->mtx_description, file, line);
12780cde2e34SJason Evans 		if (mtx_recursed(m)) {
12798484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
12800cde2e34SJason Evans 				panic("mutex_exit: recursion on non-recursive"
12810cde2e34SJason Evans 				    " mutex %s @ %s:%d", m->mtx_description,
12820cde2e34SJason Evans 				    file, line);
12830cde2e34SJason Evans 			return;
12840384fff8SJason Evans 		}
12859ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
12860cde2e34SJason Evans 		PCPU_SET(witness_spin_check,
12870cde2e34SJason Evans 		    PCPU_GET(witness_spin_check) & ~w->w_level);
12889ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
12890cde2e34SJason Evans 		return;
12900384fff8SJason Evans 	}
12918484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
12920cde2e34SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12930cde2e34SJason Evans 		    m->mtx_description, file, line);
12940cde2e34SJason Evans 
12950cde2e34SJason Evans 	if (mtx_recursed(m)) {
12968484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
12970cde2e34SJason Evans 			panic("mutex_exit: recursion on non-recursive"
12980cde2e34SJason Evans 			    " mutex %s @ %s:%d", m->mtx_description,
12990cde2e34SJason Evans 			    file, line);
13000cde2e34SJason Evans 		return;
13010384fff8SJason Evans 	}
13020cde2e34SJason Evans 
13030cde2e34SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
13049ed346baSBosko Milekic 		panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
13050cde2e34SJason Evans 			    m->mtx_description, file, line);
13060cde2e34SJason Evans 	LIST_REMOVE(m, mtx_held);
13070cde2e34SJason Evans 	m->mtx_held.le_prev = NULL;
13080384fff8SJason Evans }
13090384fff8SJason Evans 
13100384fff8SJason Evans int
1311606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
13120384fff8SJason Evans {
1313606f8eb2SJohn Baldwin 	struct mtx *m;
13140384fff8SJason Evans 	struct proc *p;
13150384fff8SJason Evans 	char **sleep;
13160384fff8SJason Evans 	int n = 0;
13170384fff8SJason Evans 
1318d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
131927863426SBosko Milekic 	p = curproc;
1320e910ba59SJohn Baldwin 	LIST_FOREACH(m, &p->p_heldmtx, mtx_held) {
13210384fff8SJason Evans 		if (m == mtx)
13220384fff8SJason Evans 			continue;
13230384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
13240384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
13250384fff8SJason Evans 				goto next;
1326e910ba59SJohn Baldwin 		if (n == 0)
1327e910ba59SJohn Baldwin 			printf("Whee!\n");
13280384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
13290384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
13300384fff8SJason Evans 			m->mtx_description,
13310384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
13320384fff8SJason Evans 		n++;
13330384fff8SJason Evans 	next:
13340384fff8SJason Evans 	}
1335a5a96a19SJohn Baldwin #ifdef DDB
1336a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1337a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1338a5a96a19SJohn Baldwin #endif /* DDB */
13390384fff8SJason Evans 	return (n);
13400384fff8SJason Evans }
13410384fff8SJason Evans 
1342606f8eb2SJohn Baldwin static struct witness *
1343b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
13440384fff8SJason Evans {
13450384fff8SJason Evans 	int i;
1346606f8eb2SJohn Baldwin 	struct witness *w, *w1;
13470384fff8SJason Evans 	char **ignore;
13480384fff8SJason Evans 	char **order;
13490384fff8SJason Evans 
13500384fff8SJason Evans 	if (!witness_watch)
13510384fff8SJason Evans 		return (NULL);
13520384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
13530384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
13540384fff8SJason Evans 			return (NULL);
13550384fff8SJason Evans 
13560384fff8SJason Evans 	if (w_inited == 0) {
1357d1c1b841SJason Evans 		mtx_init(&w_mtx, "witness lock", MTX_SPIN);
13580384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
13590384fff8SJason Evans 			w = &w_data[i];
13600384fff8SJason Evans 			witness_free(w);
13610384fff8SJason Evans 		}
13620384fff8SJason Evans 		w_inited = 1;
13630384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
13640384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
13650384fff8SJason Evans 			w->w_file = "order list";
13660384fff8SJason Evans 			for (order++; *order != NULL; order++) {
13670384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
13680384fff8SJason Evans 				w1->w_file = "order list";
13690384fff8SJason Evans 				itismychild(w, w1);
13700384fff8SJason Evans 				w = w1;
13710384fff8SJason Evans     	    	    	}
13720384fff8SJason Evans 		}
13730384fff8SJason Evans 	}
13740384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
13750384fff8SJason Evans 		return (NULL);
13769ed346baSBosko Milekic 	mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
13770384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
13780384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
13799ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
13800384fff8SJason Evans 			return (w);
13810384fff8SJason Evans 		}
13820384fff8SJason Evans 	}
13830384fff8SJason Evans 	if ((w = witness_get()) == NULL)
13840384fff8SJason Evans 		return (NULL);
13850384fff8SJason Evans 	w->w_next = w_all;
13860384fff8SJason Evans 	w_all = w;
13870384fff8SJason Evans 	w->w_description = description;
13889ed346baSBosko Milekic 	mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
13890384fff8SJason Evans 	if (flag & MTX_SPIN) {
13900384fff8SJason Evans 		w->w_spin = 1;
13910384fff8SJason Evans 
13920384fff8SJason Evans 		i = 1;
13930384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
13940384fff8SJason Evans 			if (strcmp(description, *order) == 0)
13950384fff8SJason Evans 				break;
13960384fff8SJason Evans 			i <<= 1;
13970384fff8SJason Evans 		}
13980384fff8SJason Evans 		if (*order == NULL)
13990384fff8SJason Evans 			panic("spin lock %s not in order list", description);
14000384fff8SJason Evans 		w->w_level = i;
14018484de75SJohn Baldwin 	}
140208812b39SBosko Milekic 
14030384fff8SJason Evans 	return (w);
14040384fff8SJason Evans }
14050384fff8SJason Evans 
14060384fff8SJason Evans static int
1407606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
14080384fff8SJason Evans {
14090384fff8SJason Evans 	static int recursed;
14100384fff8SJason Evans 
14110384fff8SJason Evans 	/*
14120384fff8SJason Evans 	 * Insert "child" after "parent"
14130384fff8SJason Evans 	 */
14140384fff8SJason Evans 	while (parent->w_morechildren)
14150384fff8SJason Evans 		parent = parent->w_morechildren;
14160384fff8SJason Evans 
14170384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
14180384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
14190384fff8SJason Evans 			return (1);
14200384fff8SJason Evans 		parent = parent->w_morechildren;
14210384fff8SJason Evans 	}
142236412d79SJohn Baldwin 	MPASS(child != NULL);
14230384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
14240384fff8SJason Evans 	/*
14250384fff8SJason Evans 	 * now prune whole tree
14260384fff8SJason Evans 	 */
14270384fff8SJason Evans 	if (recursed)
14280384fff8SJason Evans 		return (0);
14290384fff8SJason Evans 	recursed = 1;
14300384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
14310384fff8SJason Evans 		for (parent = w_all; parent != NULL;
14320384fff8SJason Evans 		    parent = parent->w_next) {
14330384fff8SJason Evans 			if (!isitmychild(parent, child))
14340384fff8SJason Evans 				continue;
14350384fff8SJason Evans 			removechild(parent, child);
14360384fff8SJason Evans 			if (isitmydescendant(parent, child))
14370384fff8SJason Evans 				continue;
14380384fff8SJason Evans 			itismychild(parent, child);
14390384fff8SJason Evans 		}
14400384fff8SJason Evans 	}
14410384fff8SJason Evans 	recursed = 0;
14420384fff8SJason Evans 	witness_levelall();
14430384fff8SJason Evans 	return (0);
14440384fff8SJason Evans }
14450384fff8SJason Evans 
14460384fff8SJason Evans static void
1447606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
14480384fff8SJason Evans {
1449606f8eb2SJohn Baldwin 	struct witness *w, *w1;
14500384fff8SJason Evans 	int i;
14510384fff8SJason Evans 
14520384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
14530384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
14540384fff8SJason Evans 			if (w->w_children[i] == child)
14550384fff8SJason Evans 				goto found;
14560384fff8SJason Evans 	return;
14570384fff8SJason Evans found:
14580384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
14590384fff8SJason Evans 		continue;
14600384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
146136412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
14620384fff8SJason Evans 
14630384fff8SJason Evans 	if (w1->w_childcnt != 0)
14640384fff8SJason Evans 		return;
14650384fff8SJason Evans 
14660384fff8SJason Evans 	if (w1 == parent)
14670384fff8SJason Evans 		return;
14680384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
14690384fff8SJason Evans 		continue;
14700384fff8SJason Evans 	w->w_morechildren = 0;
14710384fff8SJason Evans 	witness_free(w1);
14720384fff8SJason Evans }
14730384fff8SJason Evans 
14740384fff8SJason Evans static int
1475606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
14760384fff8SJason Evans {
1477606f8eb2SJohn Baldwin 	struct witness *w;
14780384fff8SJason Evans 	int i;
14790384fff8SJason Evans 
14800384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
14810384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
14820384fff8SJason Evans 			if (w->w_children[i] == child)
14830384fff8SJason Evans 				return (1);
14840384fff8SJason Evans 		}
14850384fff8SJason Evans 	}
14860384fff8SJason Evans 	return (0);
14870384fff8SJason Evans }
14880384fff8SJason Evans 
14890384fff8SJason Evans static int
1490606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
14910384fff8SJason Evans {
1492606f8eb2SJohn Baldwin 	struct witness *w;
14930384fff8SJason Evans 	int i;
14940384fff8SJason Evans 	int j;
14950384fff8SJason Evans 
14960384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
149736412d79SJohn Baldwin 		MPASS(j < 1000);
14980384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
14990384fff8SJason Evans 			if (w->w_children[i] == child)
15000384fff8SJason Evans 				return (1);
15010384fff8SJason Evans 		}
15020384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
15030384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
15040384fff8SJason Evans 				return (1);
15050384fff8SJason Evans 		}
15060384fff8SJason Evans 	}
15070384fff8SJason Evans 	return (0);
15080384fff8SJason Evans }
15090384fff8SJason Evans 
15100384fff8SJason Evans void
15110384fff8SJason Evans witness_levelall (void)
15120384fff8SJason Evans {
1513606f8eb2SJohn Baldwin 	struct witness *w, *w1;
15140384fff8SJason Evans 
15150384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
151608812b39SBosko Milekic 		if (!(w->w_spin))
15170384fff8SJason Evans 			w->w_level = 0;
15180384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
15190384fff8SJason Evans 		if (w->w_spin)
15200384fff8SJason Evans 			continue;
15210384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
15220384fff8SJason Evans 			if (isitmychild(w1, w))
15230384fff8SJason Evans 				break;
15240384fff8SJason Evans 		}
15250384fff8SJason Evans 		if (w1 != NULL)
15260384fff8SJason Evans 			continue;
15270384fff8SJason Evans 		witness_leveldescendents(w, 0);
15280384fff8SJason Evans 	}
15290384fff8SJason Evans }
15300384fff8SJason Evans 
15310384fff8SJason Evans static void
1532606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
15330384fff8SJason Evans {
15340384fff8SJason Evans 	int i;
1535606f8eb2SJohn Baldwin 	struct witness *w;
15360384fff8SJason Evans 
15370384fff8SJason Evans 	if (parent->w_level < level)
15380384fff8SJason Evans 		parent->w_level = level;
15390384fff8SJason Evans 	level++;
15400384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15410384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15420384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
15430384fff8SJason Evans }
15440384fff8SJason Evans 
15450384fff8SJason Evans static void
1546606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1547606f8eb2SJohn Baldwin 			   struct witness *parent)
15480384fff8SJason Evans {
1549606f8eb2SJohn Baldwin 	struct witness *w;
15500384fff8SJason Evans 	int i;
1551e910ba59SJohn Baldwin 	int level;
1552e910ba59SJohn Baldwin 
1553e910ba59SJohn Baldwin 	level = parent->w_spin ? ffs(parent->w_level) : parent->w_level;
15540384fff8SJason Evans 
15550384fff8SJason Evans 	prnt("%d", level);
15560384fff8SJason Evans 	if (level < 10)
15570384fff8SJason Evans 		prnt(" ");
15580384fff8SJason Evans 	for (i = 0; i < level; i++)
15590384fff8SJason Evans 		prnt(" ");
15600384fff8SJason Evans 	prnt("%s", parent->w_description);
1561e910ba59SJohn Baldwin 	if (parent->w_file != NULL)
1562e910ba59SJohn Baldwin 		prnt(" -- last acquired @ %s:%d\n", parent->w_file,
1563e910ba59SJohn Baldwin 		    parent->w_line);
15640384fff8SJason Evans 
15650384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15660384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15670384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
15680384fff8SJason Evans     }
15690384fff8SJason Evans 
15700384fff8SJason Evans static int
1571606f8eb2SJohn Baldwin dup_ok(struct witness *w)
15720384fff8SJason Evans {
15730384fff8SJason Evans 	char **dup;
15740384fff8SJason Evans 
15750384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
15760384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
15770384fff8SJason Evans 			return (1);
15780384fff8SJason Evans 	return (0);
15790384fff8SJason Evans }
15800384fff8SJason Evans 
15810384fff8SJason Evans static int
1582606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
15830384fff8SJason Evans {
15840384fff8SJason Evans 	int i;
1585606f8eb2SJohn Baldwin 	struct witness_blessed *b;
15860384fff8SJason Evans 
15870384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
15880384fff8SJason Evans 		b = &blessed_list[i];
15890384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
15900384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
15910384fff8SJason Evans 				return (1);
15920384fff8SJason Evans 			continue;
15930384fff8SJason Evans 		}
15940384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
15950384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
15960384fff8SJason Evans 				return (1);
15970384fff8SJason Evans 	}
15980384fff8SJason Evans 	return (0);
15990384fff8SJason Evans }
16000384fff8SJason Evans 
1601606f8eb2SJohn Baldwin static struct witness *
16020384fff8SJason Evans witness_get()
16030384fff8SJason Evans {
1604606f8eb2SJohn Baldwin 	struct witness *w;
16050384fff8SJason Evans 
16060384fff8SJason Evans 	if ((w = w_free) == NULL) {
16070384fff8SJason Evans 		witness_dead = 1;
16089ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
16090384fff8SJason Evans 		printf("witness exhausted\n");
16100384fff8SJason Evans 		return (NULL);
16110384fff8SJason Evans 	}
16120384fff8SJason Evans 	w_free = w->w_next;
16130384fff8SJason Evans 	bzero(w, sizeof(*w));
16140384fff8SJason Evans 	return (w);
16150384fff8SJason Evans }
16160384fff8SJason Evans 
16170384fff8SJason Evans static void
1618606f8eb2SJohn Baldwin witness_free(struct witness *w)
16190384fff8SJason Evans {
16200384fff8SJason Evans 	w->w_next = w_free;
16210384fff8SJason Evans 	w_free = w;
16220384fff8SJason Evans }
16230384fff8SJason Evans 
162492cf772dSJake Burkholder int
16250384fff8SJason Evans witness_list(struct proc *p)
16260384fff8SJason Evans {
1627606f8eb2SJohn Baldwin 	struct mtx *m;
162892cf772dSJake Burkholder 	int nheld;
16290384fff8SJason Evans 
1630d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
163192cf772dSJake Burkholder 	nheld = 0;
1632e910ba59SJohn Baldwin 	LIST_FOREACH(m, &p->p_heldmtx, mtx_held) {
16330384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
16340384fff8SJason Evans 		    m->mtx_description, m,
16350384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
163692cf772dSJake Burkholder 		nheld++;
16370384fff8SJason Evans 	}
163892cf772dSJake Burkholder 
163992cf772dSJake Burkholder 	return (nheld);
16400384fff8SJason Evans }
16410384fff8SJason Evans 
1642d38b8dbfSJohn Baldwin #ifdef DDB
1643d38b8dbfSJohn Baldwin 
1644e910ba59SJohn Baldwin DB_SHOW_COMMAND(mutexes, db_witness_list)
1645d38b8dbfSJohn Baldwin {
1646d38b8dbfSJohn Baldwin 
164727863426SBosko Milekic 	witness_list(curproc);
1648d38b8dbfSJohn Baldwin }
1649d38b8dbfSJohn Baldwin 
1650e910ba59SJohn Baldwin DB_SHOW_COMMAND(witness, db_witness_display)
1651e910ba59SJohn Baldwin {
1652e910ba59SJohn Baldwin 
1653e910ba59SJohn Baldwin 	witness_display(db_printf);
1654e910ba59SJohn Baldwin }
1655d38b8dbfSJohn Baldwin #endif
1656d38b8dbfSJohn Baldwin 
16570384fff8SJason Evans void
1658606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
16590384fff8SJason Evans {
1660d1c1b841SJason Evans 
1661d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
16620cde2e34SJason Evans 	if (m->mtx_witness == NULL)
16630cde2e34SJason Evans 		return;
16640cde2e34SJason Evans 
16650384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
16660384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
16670384fff8SJason Evans }
16680384fff8SJason Evans 
16690384fff8SJason Evans void
1670606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
16710384fff8SJason Evans {
1672d1c1b841SJason Evans 
1673d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
16740cde2e34SJason Evans 	if (m->mtx_witness == NULL)
16750cde2e34SJason Evans 		return;
16760cde2e34SJason Evans 
16770384fff8SJason Evans 	m->mtx_witness->w_file = file;
16780384fff8SJason Evans 	m->mtx_witness->w_line = line;
16790384fff8SJason Evans }
16800384fff8SJason Evans 
16816936206eSJohn Baldwin #endif	/* WITNESS */
1682