xref: /freebsd/sys/kern/kern_mutex.c (revision 9ed346bab02c967ac656a58bc024f9505d8e3d7a)
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 
1089ed346baSBosko Milekic #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
1099ed346baSBosko Milekic #define SET_PRIO(p, pri)	(p)->p_priority = (pri)
1100cde2e34SJason Evans 
1110cde2e34SJason Evans /*
1129ed346baSBosko Milekic  * Early WITNESS-enabled declarations.
1130cde2e34SJason Evans  */
1140cde2e34SJason Evans #ifdef WITNESS
1159ed346baSBosko Milekic 
1169ed346baSBosko Milekic /*
1179ed346baSBosko Milekic  * Internal WITNESS routines which must be prototyped early.
1189ed346baSBosko Milekic  *
1199ed346baSBosko Milekic  * XXX: When/if witness code is cleaned up, it would be wise to place all
1209ed346baSBosko Milekic  *	witness prototyping early in this file.
1219ed346baSBosko Milekic  */
1220cde2e34SJason Evans static void witness_init(struct mtx *, int flag);
1230cde2e34SJason Evans static void witness_destroy(struct mtx *);
1240cde2e34SJason Evans static void witness_display(void(*)(const char *fmt, ...));
1250cde2e34SJason Evans 
1269ed346baSBosko Milekic MALLOC_DEFINE(M_WITNESS, "witness", "witness mtx_debug structure");
1279ed346baSBosko Milekic 
1280cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */
1298484de75SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0 };
1300cde2e34SJason Evans 
1310cde2e34SJason Evans /*
1329ed346baSBosko Milekic  * This global is set to 0 once it becomes safe to use the witness code.
1339ed346baSBosko Milekic  */
1349ed346baSBosko Milekic static int witness_cold = 1;
1359ed346baSBosko Milekic 
1369ed346baSBosko Milekic #else	/* WITNESS */
1379ed346baSBosko Milekic 
1389ed346baSBosko Milekic /* XXX XXX XXX
1399ed346baSBosko Milekic  * flag++ is sleazoid way of shuting up warning
1400cde2e34SJason Evans  */
1410cde2e34SJason Evans #define witness_init(m, flag) flag++
1420cde2e34SJason Evans #define witness_destroy(m)
1430cde2e34SJason Evans #define witness_try_enter(m, t, f, l)
1446936206eSJohn Baldwin #endif	/* WITNESS */
14536412d79SJohn Baldwin 
1469ed346baSBosko Milekic /*
1479ed346baSBosko Milekic  * All mutex locks in system are kept on the all_mtx list.
1489ed346baSBosko Milekic  */
1498484de75SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, "All mutexes queue head",
1508484de75SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
1518484de75SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx,
1528484de75SJohn Baldwin #ifdef WITNESS
1538484de75SJohn Baldwin 	&all_mtx_debug
1548484de75SJohn Baldwin #else
1558484de75SJohn Baldwin 	NULL
1568484de75SJohn Baldwin #endif
1578484de75SJohn Baldwin 	 };
1588484de75SJohn Baldwin 
1599ed346baSBosko Milekic /*
1609ed346baSBosko Milekic  * Global variables for book keeping.
1619ed346baSBosko Milekic  */
16236412d79SJohn Baldwin static int	mtx_cur_cnt;
16336412d79SJohn Baldwin static int	mtx_max_cnt;
16436412d79SJohn Baldwin 
1659ed346baSBosko Milekic /*
1669ed346baSBosko Milekic  * Prototypes for non-exported routines.
1679ed346baSBosko Milekic  *
1689ed346baSBosko Milekic  * NOTE: Prototypes for witness routines are placed at the bottom of the file.
1699ed346baSBosko Milekic  */
1701bd0eefbSJohn Baldwin static void	propagate_priority(struct proc *);
17136412d79SJohn Baldwin 
17236412d79SJohn Baldwin static void
17336412d79SJohn Baldwin propagate_priority(struct proc *p)
17436412d79SJohn Baldwin {
17536412d79SJohn Baldwin 	int pri = p->p_priority;
17636412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
17736412d79SJohn Baldwin 
1781bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
17936412d79SJohn Baldwin 	for (;;) {
18036412d79SJohn Baldwin 		struct proc *p1;
18136412d79SJohn Baldwin 
18236412d79SJohn Baldwin 		p = mtx_owner(m);
18336412d79SJohn Baldwin 
18436412d79SJohn Baldwin 		if (p == NULL) {
18536412d79SJohn Baldwin 			/*
18636412d79SJohn Baldwin 			 * This really isn't quite right. Really
18736412d79SJohn Baldwin 			 * ought to bump priority of process that
18836412d79SJohn Baldwin 			 * next acquires the mutex.
18936412d79SJohn Baldwin 			 */
19036412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
19136412d79SJohn Baldwin 			return;
19236412d79SJohn Baldwin 		}
1939ed346baSBosko Milekic 
19436412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
1951bd0eefbSJohn Baldwin 		KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex"));
19636412d79SJohn Baldwin 		if (p->p_priority <= pri)
19736412d79SJohn Baldwin 			return;
1981bd0eefbSJohn Baldwin 
1991bd0eefbSJohn Baldwin 		/*
2001bd0eefbSJohn Baldwin 		 * Bump this process' priority.
2011bd0eefbSJohn Baldwin 		 */
2021bd0eefbSJohn Baldwin 		SET_PRIO(p, pri);
2031bd0eefbSJohn Baldwin 
20436412d79SJohn Baldwin 		/*
20536412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
20636412d79SJohn Baldwin 		 */
2071bd0eefbSJohn Baldwin #ifdef SMP
2081bd0eefbSJohn Baldwin 		/*
2091bd0eefbSJohn Baldwin 		 * For SMP, we can check the p_oncpu field to see if we are
2101bd0eefbSJohn Baldwin 		 * running.
2111bd0eefbSJohn Baldwin 		 */
2121bd0eefbSJohn Baldwin 		if (p->p_oncpu != 0xff) {
21336412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
21436412d79SJohn Baldwin 			return;
21536412d79SJohn Baldwin 		}
2161bd0eefbSJohn Baldwin #else
2171bd0eefbSJohn Baldwin 		/*
2181bd0eefbSJohn Baldwin 		 * For UP, we check to see if p is curproc (this shouldn't
2191bd0eefbSJohn Baldwin 		 * ever happen however as it would mean we are in a deadlock.)
2201bd0eefbSJohn Baldwin 		 */
2211bd0eefbSJohn Baldwin 		if (p == curproc) {
2221bd0eefbSJohn Baldwin 			panic("Deadlock detected");
2231bd0eefbSJohn Baldwin 			return;
2241bd0eefbSJohn Baldwin 		}
2251bd0eefbSJohn Baldwin #endif
22636412d79SJohn Baldwin 		/*
22736412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
22836412d79SJohn Baldwin 		 * quit.
22936412d79SJohn Baldwin 		 */
23036412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
2319ed346baSBosko Milekic 			printf("XXX: moving proc %d(%s) to a new run queue\n",
2321bd0eefbSJohn Baldwin 			       p->p_pid, p->p_comm);
23336412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
23436412d79SJohn Baldwin 			remrunqueue(p);
23536412d79SJohn Baldwin 			setrunqueue(p);
23636412d79SJohn Baldwin 			return;
23736412d79SJohn Baldwin 		}
23836412d79SJohn Baldwin 
23936412d79SJohn Baldwin 		/*
2401bd0eefbSJohn Baldwin 		 * If we aren't blocked on a mutex, we should be.
24136412d79SJohn Baldwin 		 */
2421bd0eefbSJohn Baldwin 		KASSERT(p->p_stat == SMTX, (
2431bd0eefbSJohn Baldwin 		    "process %d(%s):%d holds %s but isn't blocked on a mutex\n",
2441bd0eefbSJohn Baldwin 		    p->p_pid, p->p_comm, p->p_stat,
2451bd0eefbSJohn Baldwin 		    m->mtx_description));
24636412d79SJohn Baldwin 
24736412d79SJohn Baldwin 		/*
24836412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
24936412d79SJohn Baldwin 		 */
25036412d79SJohn Baldwin 		m = p->p_blocked;
25136412d79SJohn Baldwin 		MPASS(m != NULL);
25236412d79SJohn Baldwin 
25336412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
25436412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
2559ed346baSBosko Milekic 
25636412d79SJohn Baldwin 		/*
25736412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
25836412d79SJohn Baldwin 		 * the blocked chain
25936412d79SJohn Baldwin 		 */
2601bd0eefbSJohn Baldwin 		if (p == TAILQ_FIRST(&m->mtx_blocked)) {
2611bd0eefbSJohn Baldwin 			printf("XXX: process at head of run queue\n");
2621bd0eefbSJohn Baldwin 			continue;
2631bd0eefbSJohn Baldwin 		}
2649ed346baSBosko Milekic 
2651bd0eefbSJohn Baldwin 		p1 = TAILQ_PREV(p, rq, p_procq);
2661bd0eefbSJohn Baldwin 		if (p1->p_priority <= pri) {
26736412d79SJohn Baldwin 			printf(
26836412d79SJohn Baldwin 			   "XXX: previous process %d(%s) has higher priority\n",
26936412d79SJohn Baldwin 	                    p->p_pid, p->p_comm);
27036412d79SJohn Baldwin 			continue;
27136412d79SJohn Baldwin 		}
27236412d79SJohn Baldwin 
27336412d79SJohn Baldwin 		/*
2741bd0eefbSJohn Baldwin 		 * Remove proc from blocked chain and determine where
2751bd0eefbSJohn Baldwin 		 * it should be moved up to.  Since we know that p1 has
2761bd0eefbSJohn Baldwin 		 * a lower priority than p, we know that at least one
2771bd0eefbSJohn Baldwin 		 * process in the chain has a lower priority and that
2781bd0eefbSJohn Baldwin 		 * p1 will thus not be NULL after the loop.
27936412d79SJohn Baldwin 		 */
28036412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
28136412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
28236412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
28336412d79SJohn Baldwin 			if (p1->p_priority > pri)
28436412d79SJohn Baldwin 				break;
28536412d79SJohn Baldwin 		}
2869ed346baSBosko Milekic 
2871bd0eefbSJohn Baldwin 		MPASS(p1 != NULL);
28836412d79SJohn Baldwin 		TAILQ_INSERT_BEFORE(p1, p, p_procq);
28936412d79SJohn Baldwin 		CTR4(KTR_LOCK,
2908484de75SJohn Baldwin 		    "propagate_priority: p %p moved before %p on [%p] %s",
29136412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
29236412d79SJohn Baldwin 	}
29336412d79SJohn Baldwin }
29436412d79SJohn Baldwin 
2950cde2e34SJason Evans /*
2969ed346baSBosko Milekic  * The important part of mtx_trylock{,_flags}()
2979ed346baSBosko Milekic  * Tries to acquire lock `m.' We do NOT handle recursion here; we assume that
2989ed346baSBosko Milekic  * if we're called, it's because we know we don't already own this lock.
2990cde2e34SJason Evans  */
3000cde2e34SJason Evans int
3019ed346baSBosko Milekic _mtx_trylock(struct mtx *m, int opts, const char *file, int line)
3020cde2e34SJason Evans {
3030cde2e34SJason Evans 	int rval;
3040cde2e34SJason Evans 
3059ed346baSBosko Milekic 	KASSERT(CURPROC != NULL, ("curproc is NULL in _mtx_trylock"));
3069ed346baSBosko Milekic 
3079ed346baSBosko Milekic 	/*
3089ed346baSBosko Milekic 	 * _mtx_trylock does not accept MTX_NOSWITCH option.
3099ed346baSBosko Milekic 	 */
3109ed346baSBosko Milekic 	MPASS((opts & MTX_NOSWITCH) == 0);
3119ed346baSBosko Milekic 
3129ed346baSBosko Milekic 	rval = _obtain_lock(m, CURTHD);
3139ed346baSBosko Milekic 
3140cde2e34SJason Evans #ifdef WITNESS
3159ed346baSBosko Milekic 	if (rval && m->mtx_witness != NULL) {
3169ed346baSBosko Milekic 		/*
3179ed346baSBosko Milekic 		 * We do not handle recursion in _mtx_trylock; see the
3189ed346baSBosko Milekic 		 * note at the top of the routine.
3199ed346baSBosko Milekic 		 */
3209ed346baSBosko Milekic 		MPASS(!mtx_recursed(m));
3219ed346baSBosko Milekic 		witness_try_enter(m, (opts | m->mtx_flags), file, line);
3220cde2e34SJason Evans 	}
3230cde2e34SJason Evans #endif	/* WITNESS */
3249ed346baSBosko Milekic 
3259ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
3269ed346baSBosko Milekic 		CTR5(KTR_LOCK, "TRY_ENTER %s [%p] result=%d at %s:%d",
3279ed346baSBosko Milekic 		    m->mtx_description, m, rval, file, line);
3280cde2e34SJason Evans 
3290cde2e34SJason Evans 	return rval;
3300cde2e34SJason Evans }
3310cde2e34SJason Evans 
3320cde2e34SJason Evans /*
3339ed346baSBosko Milekic  * _mtx_lock_sleep: the tougher part of acquiring an MTX_DEF lock.
3349ed346baSBosko Milekic  *
3359ed346baSBosko Milekic  * We call this if the lock is either contested (i.e. we need to go to
3369ed346baSBosko Milekic  * sleep waiting for it), or if we need to recurse on it.
3370cde2e34SJason Evans  */
3380cde2e34SJason Evans void
3399ed346baSBosko Milekic _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
34036412d79SJohn Baldwin {
34136412d79SJohn Baldwin 	struct proc *p = CURPROC;
34236412d79SJohn Baldwin 
34336412d79SJohn Baldwin 	if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
34436412d79SJohn Baldwin 		m->mtx_recurse++;
34508812b39SBosko Milekic 		atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
3469ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
3479ed346baSBosko Milekic 			CTR1(KTR_LOCK, "_mtx_lock_sleep: %p recurse", m);
34836412d79SJohn Baldwin 		return;
34936412d79SJohn Baldwin 	}
3509ed346baSBosko Milekic 
3519ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
3529ed346baSBosko Milekic 		CTR3(KTR_LOCK, "mtx_lock: %p contested (lock=%p) [%p]", m,
3539ed346baSBosko Milekic 		    (void *)m->mtx_lock, (void *)RETIP(m));
3541bd0eefbSJohn Baldwin 
3551bd0eefbSJohn Baldwin 	/*
3569ed346baSBosko Milekic 	 * Save our priority. Even though p_nativepri is protected by
3579ed346baSBosko Milekic 	 * sched_lock, we don't obtain it here as it can be expensive.
3589ed346baSBosko Milekic 	 * Since this is the only place p_nativepri is set, and since two
3599ed346baSBosko Milekic 	 * CPUs will not be executing the same process concurrently, we know
3609ed346baSBosko Milekic 	 * that no other CPU is going to be messing with this. Also,
3619ed346baSBosko Milekic 	 * p_nativepri is only read when we are blocked on a mutex, so that
3629ed346baSBosko Milekic 	 * can't be happening right now either.
3631bd0eefbSJohn Baldwin 	 */
3641bd0eefbSJohn Baldwin 	p->p_nativepri = p->p_priority;
3659ed346baSBosko Milekic 
36636412d79SJohn Baldwin 	while (!_obtain_lock(m, p)) {
367f5271ebcSJohn Baldwin 		uintptr_t v;
36836412d79SJohn Baldwin 		struct proc *p1;
36936412d79SJohn Baldwin 
3709ed346baSBosko Milekic 		mtx_lock_spin(&sched_lock);
37136412d79SJohn Baldwin 		/*
3729ed346baSBosko Milekic 		 * Check if the lock has been released while spinning for
3739ed346baSBosko Milekic 		 * the sched_lock.
37436412d79SJohn Baldwin 		 */
37536412d79SJohn Baldwin 		if ((v = m->mtx_lock) == MTX_UNOWNED) {
3769ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
37736412d79SJohn Baldwin 			continue;
37836412d79SJohn Baldwin 		}
3799ed346baSBosko Milekic 
38036412d79SJohn Baldwin 		/*
3819ed346baSBosko Milekic 		 * The mutex was marked contested on release. This means that
3829ed346baSBosko Milekic 		 * there are processes blocked on it.
38336412d79SJohn Baldwin 		 */
38436412d79SJohn Baldwin 		if (v == MTX_CONTESTED) {
38536412d79SJohn Baldwin 			p1 = TAILQ_FIRST(&m->mtx_blocked);
3869ed346baSBosko Milekic 			KASSERT(p1 != NULL,
3879ed346baSBosko Milekic 			    ("contested mutex has no contesters"));
38836412d79SJohn Baldwin 			m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
3899ed346baSBosko Milekic 
3909ed346baSBosko Milekic 			if (p1->p_priority < p->p_priority)
39136412d79SJohn Baldwin 				SET_PRIO(p, p1->p_priority);
3929ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
39336412d79SJohn Baldwin 			return;
39436412d79SJohn Baldwin 		}
3959ed346baSBosko Milekic 
39636412d79SJohn Baldwin 		/*
3979ed346baSBosko Milekic 		 * If the mutex isn't already contested and a failure occurs
3989ed346baSBosko Milekic 		 * setting the contested bit, the mutex was either released
3999ed346baSBosko Milekic 		 * or the state of the MTX_RECURSED bit changed.
40036412d79SJohn Baldwin 		 */
40136412d79SJohn Baldwin 		if ((v & MTX_CONTESTED) == 0 &&
40236412d79SJohn Baldwin 		    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
40336412d79SJohn Baldwin 			(void *)(v | MTX_CONTESTED))) {
4049ed346baSBosko Milekic 			mtx_unlock_spin(&sched_lock);
40536412d79SJohn Baldwin 			continue;
40636412d79SJohn Baldwin 		}
40736412d79SJohn Baldwin 
4089ed346baSBosko Milekic 		/*
4099ed346baSBosko Milekic 		 * We deffinately must sleep for this lock.
4109ed346baSBosko Milekic 		 */
41136412d79SJohn Baldwin 		mtx_assert(m, MA_NOTOWNED);
41236412d79SJohn Baldwin 
41336412d79SJohn Baldwin #ifdef notyet
41436412d79SJohn Baldwin 		/*
4159ed346baSBosko Milekic 		 * If we're borrowing an interrupted thread's VM context, we
4169ed346baSBosko Milekic 		 * must clean up before going to sleep.
41736412d79SJohn Baldwin 		 */
41836412d79SJohn Baldwin 		if (p->p_flag & (P_ITHD | P_SITHD)) {
41936412d79SJohn Baldwin 			ithd_t *it = (ithd_t *)p;
42036412d79SJohn Baldwin 
42136412d79SJohn Baldwin 			if (it->it_interrupted) {
4229ed346baSBosko Milekic 				if ((opts & MTX_QUIET) == 0)
42336412d79SJohn Baldwin 					CTR2(KTR_LOCK,
4249ed346baSBosko Milekic 					    "mtx_lock: 0x%x interrupted 0x%x",
42536412d79SJohn Baldwin 					    it, it->it_interrupted);
42636412d79SJohn Baldwin 				intr_thd_fixup(it);
42736412d79SJohn Baldwin 			}
42836412d79SJohn Baldwin 		}
42936412d79SJohn Baldwin #endif
43036412d79SJohn Baldwin 
4319ed346baSBosko Milekic 		/*
4329ed346baSBosko Milekic 		 * Put us on the list of threads blocked on this mutex.
4339ed346baSBosko Milekic 		 */
43436412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
4359ed346baSBosko Milekic 			p1 = (struct proc *)(m->mtx_lock & MTX_FLAGMASK);
4369ed346baSBosko Milekic 			LIST_INSERT_HEAD(&p1->p_contested, m, mtx_contested);
43736412d79SJohn Baldwin 			TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
43836412d79SJohn Baldwin 		} else {
43936412d79SJohn Baldwin 			TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
44036412d79SJohn Baldwin 				if (p1->p_priority > p->p_priority)
44136412d79SJohn Baldwin 					break;
44236412d79SJohn Baldwin 			if (p1)
44336412d79SJohn Baldwin 				TAILQ_INSERT_BEFORE(p1, p, p_procq);
44436412d79SJohn Baldwin 			else
4459ed346baSBosko Milekic 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
44636412d79SJohn Baldwin 		}
44736412d79SJohn Baldwin 
4489ed346baSBosko Milekic 		/*
4499ed346baSBosko Milekic 		 * Save who we're blocked on.
4509ed346baSBosko Milekic 		 */
4519ed346baSBosko Milekic 		p->p_blocked = m;
45286327ad8SJohn Baldwin 		p->p_mtxname = m->mtx_description;
45336412d79SJohn Baldwin 		p->p_stat = SMTX;
45436412d79SJohn Baldwin #if 0
45536412d79SJohn Baldwin 		propagate_priority(p);
45636412d79SJohn Baldwin #endif
4579ed346baSBosko Milekic 
4589ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
459562e4ffeSJohn Baldwin 			CTR3(KTR_LOCK,
4609ed346baSBosko Milekic 			    "_mtx_lock_sleep: p %p blocked on [%p] %s", p, m,
4619ed346baSBosko Milekic 			    m->mtx_description);
4629ed346baSBosko Milekic 
46320cdcc5bSJohn Baldwin 		mi_switch();
4649ed346baSBosko Milekic 
4659ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
46636412d79SJohn Baldwin 			CTR3(KTR_LOCK,
4679ed346baSBosko Milekic 			  "_mtx_lock_sleep: p %p free from blocked on [%p] %s",
46836412d79SJohn Baldwin 			  p, m, m->mtx_description);
4699ed346baSBosko Milekic 
4709ed346baSBosko Milekic 		mtx_unlock_spin(&sched_lock);
47136412d79SJohn Baldwin 	}
4729ed346baSBosko Milekic 
47336412d79SJohn Baldwin 	return;
4749ed346baSBosko Milekic }
4759ed346baSBosko Milekic 
4769ed346baSBosko Milekic /*
4779ed346baSBosko Milekic  * _mtx_lock_spin: the tougher part of acquiring an MTX_SPIN lock.
4789ed346baSBosko Milekic  *
4799ed346baSBosko Milekic  * This is only called if we need to actually spin for the lock. Recursion
4809ed346baSBosko Milekic  * is handled inline.
4819ed346baSBosko Milekic  */
4829ed346baSBosko Milekic void
4839ed346baSBosko Milekic _mtx_lock_spin(struct mtx *m, int opts, u_int mtx_intr, const char *file,
4849ed346baSBosko Milekic 	       int line)
48536412d79SJohn Baldwin {
48636412d79SJohn Baldwin 	int i = 0;
48736412d79SJohn Baldwin 
4889ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
4899ed346baSBosko Milekic 		CTR1(KTR_LOCK, "mtx_lock_spin: %p spinning", m);
4909ed346baSBosko Milekic 
49136412d79SJohn Baldwin 	for (;;) {
4929ed346baSBosko Milekic 		if (_obtain_lock(m, CURPROC))
49336412d79SJohn Baldwin 			break;
4949ed346baSBosko Milekic 
49536412d79SJohn Baldwin 		while (m->mtx_lock != MTX_UNOWNED) {
49636412d79SJohn Baldwin 			if (i++ < 1000000)
49736412d79SJohn Baldwin 				continue;
49836412d79SJohn Baldwin 			if (i++ < 6000000)
49936412d79SJohn Baldwin 				DELAY(1);
50036412d79SJohn Baldwin #ifdef DDB
50136412d79SJohn Baldwin 			else if (!db_active)
50236412d79SJohn Baldwin #else
50336412d79SJohn Baldwin 			else
50436412d79SJohn Baldwin #endif
5059ed346baSBosko Milekic 			panic("spin lock %s held by %p for > 5 seconds",
5069ed346baSBosko Milekic 			    m->mtx_description, (void *)m->mtx_lock);
50736412d79SJohn Baldwin 		}
50836412d79SJohn Baldwin 	}
50936412d79SJohn Baldwin 
5109ed346baSBosko Milekic 	m->mtx_saveintr = mtx_intr;
5119ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5129ed346baSBosko Milekic 		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
5139ed346baSBosko Milekic 
51436412d79SJohn Baldwin 	return;
51536412d79SJohn Baldwin }
51636412d79SJohn Baldwin 
5179ed346baSBosko Milekic /*
5189ed346baSBosko Milekic  * _mtx_unlock_sleep: the tougher part of releasing an MTX_DEF lock.
5199ed346baSBosko Milekic  *
5209ed346baSBosko Milekic  * We are only called here if the lock is recursed or contested (i.e. we
5219ed346baSBosko Milekic  * need to wake up a blocked thread).
5229ed346baSBosko Milekic  */
52336412d79SJohn Baldwin void
5249ed346baSBosko Milekic _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
52536412d79SJohn Baldwin {
52636412d79SJohn Baldwin 	struct proc *p, *p1;
52736412d79SJohn Baldwin 	struct mtx *m1;
52836412d79SJohn Baldwin 	int pri;
52936412d79SJohn Baldwin 
53036412d79SJohn Baldwin 	p = CURPROC;
5319ed346baSBosko Milekic 	MPASS4(mtx_owned(m), "mtx_owned(mpp)", file, line);
5329ed346baSBosko Milekic 
5339ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5349ed346baSBosko Milekic 		CTR5(KTR_LOCK, "REL %s [%p] r=%d at %s:%d", m->mtx_description,
5359ed346baSBosko Milekic 		    m, m->mtx_recurse, file, line);
5369ed346baSBosko Milekic 
53708812b39SBosko Milekic 	if (mtx_recursed(m)) {
53836412d79SJohn Baldwin 		if (--(m->mtx_recurse) == 0)
53908812b39SBosko Milekic 			atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
5409ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
5419ed346baSBosko Milekic 			CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p unrecurse", m);
54236412d79SJohn Baldwin 		return;
54336412d79SJohn Baldwin 	}
5449ed346baSBosko Milekic 
5459ed346baSBosko Milekic 	mtx_lock_spin(&sched_lock);
5469ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5479ed346baSBosko Milekic 		CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m);
5489ed346baSBosko Milekic 
54936412d79SJohn Baldwin 	p1 = TAILQ_FIRST(&m->mtx_blocked);
55036412d79SJohn Baldwin 	MPASS(p->p_magic == P_MAGIC);
55136412d79SJohn Baldwin 	MPASS(p1->p_magic == P_MAGIC);
5529ed346baSBosko Milekic 
55336412d79SJohn Baldwin 	TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
5549ed346baSBosko Milekic 
55536412d79SJohn Baldwin 	if (TAILQ_EMPTY(&m->mtx_blocked)) {
55636412d79SJohn Baldwin 		LIST_REMOVE(m, mtx_contested);
55736412d79SJohn Baldwin 		_release_lock_quick(m);
5589ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
5599ed346baSBosko Milekic 			CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
56036412d79SJohn Baldwin 	} else
5619ed346baSBosko Milekic 		atomic_store_rel_ptr(&m->mtx_lock, (void *)MTX_CONTESTED);
5629ed346baSBosko Milekic 
56336412d79SJohn Baldwin 	pri = MAXPRI;
56436412d79SJohn Baldwin 	LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
56536412d79SJohn Baldwin 		int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
56636412d79SJohn Baldwin 		if (cp < pri)
56736412d79SJohn Baldwin 			pri = cp;
56836412d79SJohn Baldwin 	}
5699ed346baSBosko Milekic 
57036412d79SJohn Baldwin 	if (pri > p->p_nativepri)
57136412d79SJohn Baldwin 		pri = p->p_nativepri;
57236412d79SJohn Baldwin 	SET_PRIO(p, pri);
5739ed346baSBosko Milekic 
5749ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
5759ed346baSBosko Milekic 		CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p contested setrunqueue %p",
5769ed346baSBosko Milekic 		    m, p1);
5779ed346baSBosko Milekic 
57836412d79SJohn Baldwin 	p1->p_blocked = NULL;
57986327ad8SJohn Baldwin 	p1->p_mtxname = NULL;
58036412d79SJohn Baldwin 	p1->p_stat = SRUN;
58136412d79SJohn Baldwin 	setrunqueue(p1);
5829ed346baSBosko Milekic 
5839ed346baSBosko Milekic 	if ((opts & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
58436412d79SJohn Baldwin #ifdef notyet
58536412d79SJohn Baldwin 		if (p->p_flag & (P_ITHD | P_SITHD)) {
58636412d79SJohn Baldwin 			ithd_t *it = (ithd_t *)p;
58736412d79SJohn Baldwin 
58836412d79SJohn Baldwin 			if (it->it_interrupted) {
5899ed346baSBosko Milekic 				if ((opts & MTX_QUIET) == 0)
59036412d79SJohn Baldwin 					CTR2(KTR_LOCK,
5919ed346baSBosko Milekic 				    "_mtx_unlock_sleep: 0x%x interrupted 0x%x",
59236412d79SJohn Baldwin 					    it, it->it_interrupted);
59336412d79SJohn Baldwin 				intr_thd_fixup(it);
59436412d79SJohn Baldwin 			}
59536412d79SJohn Baldwin 		}
59636412d79SJohn Baldwin #endif
59736412d79SJohn Baldwin 		setrunqueue(p);
5989ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
599562e4ffeSJohn Baldwin 			CTR2(KTR_LOCK,
6009ed346baSBosko Milekic 			    "_mtx_unlock_sleep: %p switching out lock=%p", m,
6019ed346baSBosko Milekic 			    (void *)m->mtx_lock);
6029ed346baSBosko Milekic 
60336412d79SJohn Baldwin 		mi_switch();
6049ed346baSBosko Milekic 		if ((opts & MTX_QUIET) == 0)
6059ed346baSBosko Milekic 			CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p resuming lock=%p",
60631271627SJohn Baldwin 			    m, (void *)m->mtx_lock);
60736412d79SJohn Baldwin 	}
60836412d79SJohn Baldwin 
6099ed346baSBosko Milekic 	mtx_unlock_spin(&sched_lock);
6109ed346baSBosko Milekic 
6119ed346baSBosko Milekic 	return;
6129ed346baSBosko Milekic }
6139ed346baSBosko Milekic 
6149ed346baSBosko Milekic /*
6159ed346baSBosko Milekic  * All the unlocking of MTX_SPIN locks is done inline.
6169ed346baSBosko Milekic  * See the _rel_spin_lock() macro for the details.
6179ed346baSBosko Milekic  */
6189ed346baSBosko Milekic 
6199ed346baSBosko Milekic /*
6209ed346baSBosko Milekic  * The INVARIANTS-enabled mtx_assert()
6219ed346baSBosko Milekic  */
6220cde2e34SJason Evans #ifdef INVARIANTS
6230cde2e34SJason Evans void
62456771ca7SJason Evans _mtx_assert(struct mtx *m, int what, const char *file, int line)
6250cde2e34SJason Evans {
6260cde2e34SJason Evans 	switch ((what)) {
6270cde2e34SJason Evans 	case MA_OWNED:
6280cde2e34SJason Evans 	case MA_OWNED | MA_RECURSED:
6290cde2e34SJason Evans 	case MA_OWNED | MA_NOTRECURSED:
6300cde2e34SJason Evans 		if (!mtx_owned((m)))
6310cde2e34SJason Evans 			panic("mutex %s not owned at %s:%d",
63256771ca7SJason Evans 			    (m)->mtx_description, file, line);
6330cde2e34SJason Evans 		if (mtx_recursed((m))) {
6340cde2e34SJason Evans 			if (((what) & MA_NOTRECURSED) != 0)
6350cde2e34SJason Evans 				panic("mutex %s recursed at %s:%d",
63656771ca7SJason Evans 				    (m)->mtx_description, file, line);
6370cde2e34SJason Evans 		} else if (((what) & MA_RECURSED) != 0) {
6380cde2e34SJason Evans 			panic("mutex %s unrecursed at %s:%d",
63956771ca7SJason Evans 			    (m)->mtx_description, file, line);
6400cde2e34SJason Evans 		}
6410cde2e34SJason Evans 		break;
6420cde2e34SJason Evans 	case MA_NOTOWNED:
6430cde2e34SJason Evans 		if (mtx_owned((m)))
6440cde2e34SJason Evans 			panic("mutex %s owned at %s:%d",
64556771ca7SJason Evans 			    (m)->mtx_description, file, line);
6460cde2e34SJason Evans 		break;
6470cde2e34SJason Evans 	default:
64856771ca7SJason Evans 		panic("unknown mtx_assert at %s:%d", file, line);
6490cde2e34SJason Evans 	}
6500cde2e34SJason Evans }
6510cde2e34SJason Evans #endif
6520cde2e34SJason Evans 
6539ed346baSBosko Milekic /*
6549ed346baSBosko Milekic  * The MUTEX_DEBUG-enabled mtx_validate()
6559ed346baSBosko Milekic  */
65636412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
65736412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
65836412d79SJohn Baldwin 
65936412d79SJohn Baldwin #ifdef MUTEX_DEBUG
66036412d79SJohn Baldwin 
66136412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
66236412d79SJohn Baldwin 
66336412d79SJohn Baldwin int
66436412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
66536412d79SJohn Baldwin {
66636412d79SJohn Baldwin 	struct mtx *mp;
66736412d79SJohn Baldwin 	int i;
66836412d79SJohn Baldwin 	int retval = 0;
66936412d79SJohn Baldwin 
670d1c1b841SJason Evans #ifdef WITNESS
671d1c1b841SJason Evans 	if (witness_cold)
672d1c1b841SJason Evans 		return 0;
673d1c1b841SJason Evans #endif
67436412d79SJohn Baldwin 	if (m == &all_mtx || cold)
67536412d79SJohn Baldwin 		return 0;
67636412d79SJohn Baldwin 
6779ed346baSBosko Milekic 	mtx_lock(&all_mtx);
67836412d79SJohn Baldwin /*
67936412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
68036412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
68136412d79SJohn Baldwin  */
68236412d79SJohn Baldwin #ifndef __alpha__
68336412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
68436412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
68536412d79SJohn Baldwin #endif
68636412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
68736412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
68836412d79SJohn Baldwin #ifndef __alpha__
68936412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
69036412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
69136412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
69236412d79SJohn Baldwin 			    mp, mp->mtx_next);
69336412d79SJohn Baldwin 		}
69436412d79SJohn Baldwin #endif
69536412d79SJohn Baldwin 		i++;
69636412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
69736412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
69836412d79SJohn Baldwin 			    mtx_cur_cnt);
69936412d79SJohn Baldwin 		}
70036412d79SJohn Baldwin 	}
70136412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
70236412d79SJohn Baldwin 	switch (when) {
70336412d79SJohn Baldwin 	case MV_DESTROY:
70436412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
70536412d79SJohn Baldwin 			if (mp == m)
70636412d79SJohn Baldwin 				break;
70736412d79SJohn Baldwin 		MPASS(mp == m);
70836412d79SJohn Baldwin 		break;
70936412d79SJohn Baldwin 	case MV_INIT:
71036412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
71136412d79SJohn Baldwin 		if (mp == m) {
71236412d79SJohn Baldwin 			/*
71336412d79SJohn Baldwin 			 * Not good. This mutex already exists.
71436412d79SJohn Baldwin 			 */
71536412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
71636412d79SJohn Baldwin 			    m->mtx_description);
71736412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
71836412d79SJohn Baldwin 			retval = 1;
71936412d79SJohn Baldwin 		}
72036412d79SJohn Baldwin 	}
7219ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
72236412d79SJohn Baldwin 	return (retval);
72336412d79SJohn Baldwin }
72436412d79SJohn Baldwin #endif
72536412d79SJohn Baldwin 
7269ed346baSBosko Milekic /*
7279ed346baSBosko Milekic  * Mutex initialization routine; initialize lock `m' of type contained in
7289ed346baSBosko Milekic  * `opts' with options contained in `opts' and description `description.'
7299ed346baSBosko Milekic  * Place on "all_mtx" queue.
7309ed346baSBosko Milekic  */
73136412d79SJohn Baldwin void
7329ed346baSBosko Milekic mtx_init(struct mtx *m, const char *description, int opts)
73336412d79SJohn Baldwin {
7349ed346baSBosko Milekic 
7359ed346baSBosko Milekic 	if ((opts & MTX_QUIET) == 0)
7369ed346baSBosko Milekic 		CTR2(KTR_LOCK, "mtx_init %p (%s)", m, description);
7379ed346baSBosko Milekic 
73836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
7399ed346baSBosko Milekic 	/* Diagnostic and error correction */
7409ed346baSBosko Milekic 	if (mtx_validate(m, MV_INIT))
74136412d79SJohn Baldwin 		return;
7426936206eSJohn Baldwin #endif
74336412d79SJohn Baldwin 
74436412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
74536412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
7469ed346baSBosko Milekic 
7476936206eSJohn Baldwin #ifdef WITNESS
748d1c1b841SJason Evans 	if (!witness_cold) {
7498484de75SJohn Baldwin 		m->mtx_debug = malloc(sizeof(struct mtx_debug),
7509ed346baSBosko Milekic 		    M_WITNESS, M_NOWAIT | M_ZERO);
7518484de75SJohn Baldwin 		MPASS(m->mtx_debug != NULL);
752d1c1b841SJason Evans 	}
753d1c1b841SJason Evans #endif
754d1c1b841SJason Evans 
7559ed346baSBosko Milekic 	m->mtx_description = description;
7569ed346baSBosko Milekic 	m->mtx_flags = opts;
75736412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
7589ed346baSBosko Milekic 
75936412d79SJohn Baldwin 	/* Put on all mutex queue */
7609ed346baSBosko Milekic 	mtx_lock(&all_mtx);
76136412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
76236412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
76336412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
76436412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
76536412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
76636412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
7679ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
7689ed346baSBosko Milekic 
769d1c1b841SJason Evans #ifdef WITNESS
770d1c1b841SJason Evans 	if (!witness_cold)
7719ed346baSBosko Milekic 		witness_init(m, opts);
772d1c1b841SJason Evans #endif
77336412d79SJohn Baldwin }
77436412d79SJohn Baldwin 
7759ed346baSBosko Milekic /*
7769ed346baSBosko Milekic  * Remove lock `m' from all_mtx queue.
7779ed346baSBosko Milekic  */
77836412d79SJohn Baldwin void
77936412d79SJohn Baldwin mtx_destroy(struct mtx *m)
78036412d79SJohn Baldwin {
78136412d79SJohn Baldwin 
782d1c1b841SJason Evans #ifdef WITNESS
783d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n",
784d1c1b841SJason Evans 	    __FUNCTION__));
785d1c1b841SJason Evans #endif
7869ed346baSBosko Milekic 
7878484de75SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy %p (%s)", m, m->mtx_description);
7889ed346baSBosko Milekic 
78936412d79SJohn Baldwin #ifdef MUTEX_DEBUG
79036412d79SJohn Baldwin 	if (m->mtx_next == NULL)
79136412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
79236412d79SJohn Baldwin 		    m, m->mtx_description);
79336412d79SJohn Baldwin 
79436412d79SJohn Baldwin 	if (!mtx_owned(m)) {
79536412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
79636412d79SJohn Baldwin 	} else {
79708812b39SBosko Milekic 		MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
79836412d79SJohn Baldwin 	}
7999ed346baSBosko Milekic 
8009ed346baSBosko Milekic 	/* diagnostic */
8019ed346baSBosko Milekic 	mtx_validate(m, MV_DESTROY);
80236412d79SJohn Baldwin #endif
80336412d79SJohn Baldwin 
80436412d79SJohn Baldwin #ifdef WITNESS
80536412d79SJohn Baldwin 	if (m->mtx_witness)
80636412d79SJohn Baldwin 		witness_destroy(m);
80736412d79SJohn Baldwin #endif /* WITNESS */
80836412d79SJohn Baldwin 
80936412d79SJohn Baldwin 	/* Remove from the all mutex queue */
8109ed346baSBosko Milekic 	mtx_lock(&all_mtx);
81136412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
81236412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
8139ed346baSBosko Milekic 
81436412d79SJohn Baldwin #ifdef MUTEX_DEBUG
81536412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
8166936206eSJohn Baldwin #endif
8179ed346baSBosko Milekic 
8186936206eSJohn Baldwin #ifdef WITNESS
8199ed346baSBosko Milekic 	free(m->mtx_debug, M_WITNESS);
8208484de75SJohn Baldwin 	m->mtx_debug = NULL;
82136412d79SJohn Baldwin #endif
8229ed346baSBosko Milekic 
82336412d79SJohn Baldwin 	mtx_cur_cnt--;
8249ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
82536412d79SJohn Baldwin }
8260384fff8SJason Evans 
8278484de75SJohn Baldwin 
8289ed346baSBosko Milekic /*
8299ed346baSBosko Milekic  * The WITNESS-enabled diagnostic code.
8309ed346baSBosko Milekic  */
8316936206eSJohn Baldwin #ifdef WITNESS
8328484de75SJohn Baldwin static void
8338484de75SJohn Baldwin witness_fixup(void *dummy __unused)
8348484de75SJohn Baldwin {
8358484de75SJohn Baldwin 	struct mtx *mp;
8368484de75SJohn Baldwin 
8378484de75SJohn Baldwin 	/*
8388484de75SJohn Baldwin 	 * We have to release Giant before initializing its witness
8398484de75SJohn Baldwin 	 * structure so that WITNESS doesn't get confused.
8408484de75SJohn Baldwin 	 */
8419ed346baSBosko Milekic 	mtx_unlock(&Giant);
8428484de75SJohn Baldwin 	mtx_assert(&Giant, MA_NOTOWNED);
8439ed346baSBosko Milekic 
8449ed346baSBosko Milekic 	mtx_lock(&all_mtx);
8458484de75SJohn Baldwin 
8468484de75SJohn Baldwin 	/* Iterate through all mutexes and finish up mutex initialization. */
8478484de75SJohn Baldwin 	for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
8488484de75SJohn Baldwin 
8498484de75SJohn Baldwin 		mp->mtx_debug = malloc(sizeof(struct mtx_debug),
8509ed346baSBosko Milekic 		    M_WITNESS, M_NOWAIT | M_ZERO);
8518484de75SJohn Baldwin 		MPASS(mp->mtx_debug != NULL);
8528484de75SJohn Baldwin 
8538484de75SJohn Baldwin 		witness_init(mp, mp->mtx_flags);
8548484de75SJohn Baldwin 	}
8559ed346baSBosko Milekic 	mtx_unlock(&all_mtx);
8568484de75SJohn Baldwin 
8578484de75SJohn Baldwin 	/* Mark the witness code as being ready for use. */
8588484de75SJohn Baldwin 	atomic_store_rel_int(&witness_cold, 0);
8598484de75SJohn Baldwin 
8609ed346baSBosko Milekic 	mtx_lock(&Giant);
8618484de75SJohn Baldwin }
8628484de75SJohn Baldwin SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL)
8630384fff8SJason Evans 
8640384fff8SJason Evans #define WITNESS_COUNT 200
8650384fff8SJason Evans #define	WITNESS_NCHILDREN 2
8660384fff8SJason Evans 
86778f0da03SJohn Baldwin int witness_watch = 1;
8680384fff8SJason Evans 
869606f8eb2SJohn Baldwin struct witness {
8700384fff8SJason Evans 	struct witness	*w_next;
871b67a3e6eSJohn Baldwin 	const char	*w_description;
87212473b76SJason Evans 	const char	*w_file;
8730384fff8SJason Evans 	int		 w_line;
8740384fff8SJason Evans 	struct witness	*w_morechildren;
8750384fff8SJason Evans 	u_char		 w_childcnt;
8760384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
8770384fff8SJason Evans 	u_char		 w_other_squawked:1;
8780384fff8SJason Evans 	u_char		 w_same_squawked:1;
87908812b39SBosko Milekic 	u_char		 w_spin:1;	/* MTX_SPIN type mutex. */
8800384fff8SJason Evans 	u_int		 w_level;
8810384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
882606f8eb2SJohn Baldwin };
8830384fff8SJason Evans 
884606f8eb2SJohn Baldwin struct witness_blessed {
8850384fff8SJason Evans 	char 	*b_lock1;
8860384fff8SJason Evans 	char	*b_lock2;
887606f8eb2SJohn Baldwin };
8880384fff8SJason Evans 
889a5a96a19SJohn Baldwin #ifdef DDB
8900384fff8SJason Evans /*
891a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
8920384fff8SJason Evans  * drop into kdebug() when:
8930384fff8SJason Evans  *	- a lock heirarchy violation occurs
8940384fff8SJason Evans  *	- locks are held when going to sleep.
8950384fff8SJason Evans  */
8968484de75SJohn Baldwin int	witness_ddb;
897a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
8988484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 1, witness_ddb);
899a5a96a19SJohn Baldwin #else
9008484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_ddb", 0, witness_ddb);
9010384fff8SJason Evans #endif
902a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
903a5a96a19SJohn Baldwin #endif /* DDB */
9040384fff8SJason Evans 
9058484de75SJohn Baldwin int	witness_skipspin;
906a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
9078484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 1, witness_skipspin);
908a5a96a19SJohn Baldwin #else
9098484de75SJohn Baldwin TUNABLE_INT_DECL("debug.witness_skipspin", 0, witness_skipspin);
9100384fff8SJason Evans #endif
911a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
912a5a96a19SJohn Baldwin     "");
9130384fff8SJason Evans 
9149ed346baSBosko Milekic /*
9159ed346baSBosko Milekic  * Witness-enabled globals
9169ed346baSBosko Milekic  */
917d1c1b841SJason Evans static struct mtx	w_mtx;
918606f8eb2SJohn Baldwin static struct witness	*w_free;
919606f8eb2SJohn Baldwin static struct witness	*w_all;
9200384fff8SJason Evans static int		 w_inited;
9210384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
9220384fff8SJason Evans 
923606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
9240384fff8SJason Evans 
9259ed346baSBosko Milekic /*
9269ed346baSBosko Milekic  * Internal witness routine prototypes
9279ed346baSBosko Milekic  */
9289ed346baSBosko Milekic static struct witness *enroll(const char *description, int flag);
9299ed346baSBosko Milekic static int itismychild(struct witness *parent, struct witness *child);
9309ed346baSBosko Milekic static void removechild(struct witness *parent, struct witness *child);
9319ed346baSBosko Milekic static int isitmychild(struct witness *parent, struct witness *child);
9329ed346baSBosko Milekic static int isitmydescendant(struct witness *parent, struct witness *child);
9339ed346baSBosko Milekic static int dup_ok(struct witness *);
9349ed346baSBosko Milekic static int blessed(struct witness *, struct witness *);
9359ed346baSBosko Milekic static void
9369ed346baSBosko Milekic     witness_displaydescendants(void(*)(const char *fmt, ...), struct witness *);
9379ed346baSBosko Milekic static void witness_leveldescendents(struct witness *parent, int level);
9389ed346baSBosko Milekic static void witness_levelall(void);
9399ed346baSBosko Milekic static struct witness * witness_get(void);
9409ed346baSBosko Milekic static void witness_free(struct witness *m);
9410384fff8SJason Evans 
9420384fff8SJason Evans static char *ignore_list[] = {
9430384fff8SJason Evans 	"witness lock",
9440384fff8SJason Evans 	NULL
9450384fff8SJason Evans };
9460384fff8SJason Evans 
9470384fff8SJason Evans static char *spin_order_list[] = {
948a5a96a19SJohn Baldwin 	"sio",
9498f838cb5SJohn Baldwin 	"sched lock",
95020cdcc5bSJohn Baldwin #ifdef __i386__
95120cdcc5bSJohn Baldwin 	"clk",
95220cdcc5bSJohn Baldwin #endif
953fa2fbc3dSJake Burkholder 	"callout",
9540384fff8SJason Evans 	/*
9550384fff8SJason Evans 	 * leaf locks
9560384fff8SJason Evans 	 */
9571b367556SJason Evans #ifdef __i386__
9581b367556SJason Evans 	"ap boot",
9591b367556SJason Evans 	"imen",
9601b367556SJason Evans #endif
9611b367556SJason Evans 	"com",
9621b367556SJason Evans 	"smp rendezvous",
9630384fff8SJason Evans 	NULL
9640384fff8SJason Evans };
9650384fff8SJason Evans 
9660384fff8SJason Evans static char *order_list[] = {
9678484de75SJohn Baldwin 	"Giant", "uidinfo hash", "uidinfo struct", NULL,
9688484de75SJohn Baldwin 	"Giant", "proctree", "allproc", "process lock", NULL,
9690384fff8SJason Evans 	NULL
9700384fff8SJason Evans };
9710384fff8SJason Evans 
9720384fff8SJason Evans static char *dup_list[] = {
9730384fff8SJason Evans 	NULL
9740384fff8SJason Evans };
9750384fff8SJason Evans 
9760384fff8SJason Evans static char *sleep_list[] = {
9777da6f977SJake Burkholder 	"Giant",
9780384fff8SJason Evans 	NULL
9790384fff8SJason Evans };
9800384fff8SJason Evans 
9810384fff8SJason Evans /*
9820384fff8SJason Evans  * Pairs of locks which have been blessed
9830384fff8SJason Evans  * Don't complain about order problems with blessed locks
9840384fff8SJason Evans  */
985606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
9860384fff8SJason Evans };
9879ed346baSBosko Milekic static int blessed_count =
9889ed346baSBosko Milekic 	sizeof(blessed_list) / sizeof(struct witness_blessed);
9890384fff8SJason Evans 
9900cde2e34SJason Evans static void
991606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
9920384fff8SJason Evans {
9930384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
9940384fff8SJason Evans }
9950384fff8SJason Evans 
9960cde2e34SJason Evans static void
997606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
9980384fff8SJason Evans {
999606f8eb2SJohn Baldwin 	struct mtx *m1;
10000384fff8SJason Evans 	struct proc *p;
10010384fff8SJason Evans 	p = CURPROC;
10020384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
10030384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
10040384fff8SJason Evans 		if (m1 == m) {
10050384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
10060384fff8SJason Evans 			break;
10070384fff8SJason Evans 		}
10080384fff8SJason Evans 	}
10090384fff8SJason Evans 	return;
10100384fff8SJason Evans 
10110384fff8SJason Evans }
10120384fff8SJason Evans 
10130cde2e34SJason Evans static void
10140cde2e34SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
10150cde2e34SJason Evans {
10160cde2e34SJason Evans 	struct witness *w, *w1;
10170cde2e34SJason Evans 
10180cde2e34SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
10190cde2e34SJason Evans 	witness_levelall();
10200cde2e34SJason Evans 
10210cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
10220cde2e34SJason Evans 		if (w->w_file == NULL)
10230cde2e34SJason Evans 			continue;
10240cde2e34SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
10250cde2e34SJason Evans 			if (isitmychild(w1, w))
10260cde2e34SJason Evans 				break;
10270cde2e34SJason Evans 		}
10280cde2e34SJason Evans 		if (w1 != NULL)
10290cde2e34SJason Evans 			continue;
10300cde2e34SJason Evans 		/*
10310cde2e34SJason Evans 		 * This lock has no anscestors, display its descendants.
10320cde2e34SJason Evans 		 */
10330cde2e34SJason Evans 		witness_displaydescendants(prnt, w);
10340cde2e34SJason Evans 	}
10350cde2e34SJason Evans 	prnt("\nMutex which were never acquired\n");
10360cde2e34SJason Evans 	for (w = w_all; w; w = w->w_next) {
10370cde2e34SJason Evans 		if (w->w_file != NULL)
10380cde2e34SJason Evans 			continue;
10390cde2e34SJason Evans 		prnt("%s\n", w->w_description);
10400cde2e34SJason Evans 	}
10410cde2e34SJason Evans }
10420cde2e34SJason Evans 
10430384fff8SJason Evans void
1044606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
10450384fff8SJason Evans {
1046606f8eb2SJohn Baldwin 	struct witness *w, *w1;
1047606f8eb2SJohn Baldwin 	struct mtx *m1;
10480384fff8SJason Evans 	struct proc *p;
10490384fff8SJason Evans 	int i;
1050a5a96a19SJohn Baldwin #ifdef DDB
1051a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
1052a5a96a19SJohn Baldwin #endif /* DDB */
10530384fff8SJason Evans 
10540cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
1055562e4ffeSJohn Baldwin 		return;
10560384fff8SJason Evans 	w = m->mtx_witness;
10570384fff8SJason Evans 	p = CURPROC;
10580384fff8SJason Evans 
10590384fff8SJason Evans 	if (flags & MTX_SPIN) {
10608484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
10615340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
10625340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
106308812b39SBosko Milekic 		if (mtx_recursed(m)) {
10648484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
106508812b39SBosko Milekic 				panic("mutex_enter: recursion on non-recursive"
106608812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
106708812b39SBosko Milekic 				    file, line);
10680384fff8SJason Evans 			return;
106908812b39SBosko Milekic 		}
10709ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
1071ef73ae4bSJake Burkholder 		i = PCPU_GET(witness_spin_check);
10720384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
10739ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
10745340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
10755340642aSJason Evans 			    " %s:%d already holding %s:%x",
10760384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
10770384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
10780384fff8SJason Evans 		}
10790384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
10809ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
1081bbc7a98aSJohn Baldwin 		w->w_file = file;
1082bbc7a98aSJohn Baldwin 		w->w_line = line;
1083bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1084bbc7a98aSJohn Baldwin 		m->mtx_file = file;
10850384fff8SJason Evans 		return;
10860384fff8SJason Evans 	}
10878484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
10880384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
10890384fff8SJason Evans 		    m->mtx_description, file, line);
10900384fff8SJason Evans 
109108812b39SBosko Milekic 	if (mtx_recursed(m)) {
10928484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
109308812b39SBosko Milekic 			panic("mutex_enter: recursion on non-recursive"
109408812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
109508812b39SBosko Milekic 			    file, line);
10960384fff8SJason Evans 		return;
109708812b39SBosko Milekic 	}
10980384fff8SJason Evans 	if (witness_dead)
10990384fff8SJason Evans 		goto out;
1100562e4ffeSJohn Baldwin 	if (cold)
11010384fff8SJason Evans 		goto out;
11020384fff8SJason Evans 
11030384fff8SJason Evans 	if (!mtx_legal2block())
11049ed346baSBosko Milekic 		panic("blockable mtx_lock() of %s when not legal @ %s:%d",
11050384fff8SJason Evans 			    m->mtx_description, file, line);
11060384fff8SJason Evans 	/*
11070384fff8SJason Evans 	 * Is this the first mutex acquired
11080384fff8SJason Evans 	 */
11090384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
11100384fff8SJason Evans 		goto out;
11110384fff8SJason Evans 
11120384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
11130384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
11140384fff8SJason Evans 			goto out;
11150384fff8SJason Evans 		w->w_same_squawked = 1;
11160384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
11170384fff8SJason Evans 			m->mtx_description);
11180384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
11190384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
1120a5a96a19SJohn Baldwin #ifdef DDB
1121a5a96a19SJohn Baldwin 		go_into_ddb = 1;
1122a5a96a19SJohn Baldwin #endif /* DDB */
11230384fff8SJason Evans 		goto out;
11240384fff8SJason Evans 	}
11250384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
11269ed346baSBosko Milekic 	mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
11270384fff8SJason Evans 	/*
11280384fff8SJason Evans 	 * If we have a known higher number just say ok
11290384fff8SJason Evans 	 */
11300384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
11319ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11320384fff8SJason Evans 		goto out;
11330384fff8SJason Evans 	}
11340384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
11359ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11360384fff8SJason Evans 		goto out;
11370384fff8SJason Evans 	}
11380384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
11390384fff8SJason Evans 
114036412d79SJohn Baldwin 		MPASS(i < 200);
11410384fff8SJason Evans 		w1 = m1->mtx_witness;
11420384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
11439ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11440384fff8SJason Evans 			if (blessed(w, w1))
11450384fff8SJason Evans 				goto out;
11460384fff8SJason Evans 			if (m1 == &Giant) {
11470384fff8SJason Evans 				if (w1->w_Giant_squawked)
11480384fff8SJason Evans 					goto out;
11490384fff8SJason Evans 				else
11500384fff8SJason Evans 					w1->w_Giant_squawked = 1;
11510384fff8SJason Evans 			} else {
11520384fff8SJason Evans 				if (w1->w_other_squawked)
11530384fff8SJason Evans 					goto out;
11540384fff8SJason Evans 				else
11550384fff8SJason Evans 					w1->w_other_squawked = 1;
11560384fff8SJason Evans 			}
11570384fff8SJason Evans 			printf("lock order reversal\n");
11580384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
11590384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
11600384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
11610384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
11620384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
11630384fff8SJason Evans 			    m, w->w_description, file, line);
1164a5a96a19SJohn Baldwin #ifdef DDB
1165a5a96a19SJohn Baldwin 			go_into_ddb = 1;
1166a5a96a19SJohn Baldwin #endif /* DDB */
11670384fff8SJason Evans 			goto out;
11680384fff8SJason Evans 		}
11690384fff8SJason Evans 	}
11700384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
11710384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
11729ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
11730384fff8SJason Evans 
11740384fff8SJason Evans out:
1175a5a96a19SJohn Baldwin #ifdef DDB
1176a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
1177a5a96a19SJohn Baldwin 		Debugger("witness_enter");
1178a5a96a19SJohn Baldwin #endif /* DDB */
11790384fff8SJason Evans 	w->w_file = file;
11800384fff8SJason Evans 	w->w_line = line;
11810384fff8SJason Evans 	m->mtx_line = line;
11820384fff8SJason Evans 	m->mtx_file = file;
11830384fff8SJason Evans 
11840384fff8SJason Evans 	/*
11850384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
11860384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
11870384fff8SJason Evans 	 * likely not the mutex this assert fails on.
11880384fff8SJason Evans 	 */
118936412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
11900384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
11910384fff8SJason Evans }
11920384fff8SJason Evans 
11930384fff8SJason Evans void
1194606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
11950384fff8SJason Evans {
11960384fff8SJason Evans 	struct proc *p;
1197606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
11980384fff8SJason Evans 
1199d1c1b841SJason Evans 	if (witness_cold)
1200d1c1b841SJason Evans 		return;
1201562e4ffeSJohn Baldwin 	if (panicstr)
1202562e4ffeSJohn Baldwin 		return;
12030384fff8SJason Evans 	if (flags & MTX_SPIN) {
12048484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
12050384fff8SJason Evans 			panic("mutex_try_enter: "
12060384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
12070384fff8SJason Evans 			    m->mtx_description, file, line);
120808812b39SBosko Milekic 		if (mtx_recursed(m)) {
12098484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
121008812b39SBosko Milekic 				panic("mutex_try_enter: recursion on"
121108812b39SBosko Milekic 				    " non-recursive mutex %s @ %s:%d",
121208812b39SBosko Milekic 				    m->mtx_description, file, line);
12130384fff8SJason Evans 			return;
121408812b39SBosko Milekic 		}
12159ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
1216ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
1217ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) | w->w_level);
12189ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
1219bbc7a98aSJohn Baldwin 		w->w_file = file;
1220bbc7a98aSJohn Baldwin 		w->w_line = line;
1221bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1222bbc7a98aSJohn Baldwin 		m->mtx_file = file;
12230384fff8SJason Evans 		return;
12240384fff8SJason Evans 	}
12250384fff8SJason Evans 
12268484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
12270384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12280384fff8SJason Evans 		    m->mtx_description, file, line);
12290384fff8SJason Evans 
123008812b39SBosko Milekic 	if (mtx_recursed(m)) {
12318484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
123208812b39SBosko Milekic 			panic("mutex_try_enter: recursion on non-recursive"
123308812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description, file,
123408812b39SBosko Milekic 			    line);
12350384fff8SJason Evans 		return;
123608812b39SBosko Milekic 	}
12370384fff8SJason Evans 	w->w_file = file;
12380384fff8SJason Evans 	w->w_line = line;
12390384fff8SJason Evans 	m->mtx_line = line;
12400384fff8SJason Evans 	m->mtx_file = file;
12410384fff8SJason Evans 	p = CURPROC;
124236412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
12430384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
12440384fff8SJason Evans }
12450384fff8SJason Evans 
12460384fff8SJason Evans void
12470cde2e34SJason Evans witness_exit(struct mtx *m, int flags, const char *file, int line)
12480384fff8SJason Evans {
12490cde2e34SJason Evans 	struct witness *w;
12500384fff8SJason Evans 
12510cde2e34SJason Evans 	if (witness_cold || m->mtx_witness == NULL || panicstr)
12520cde2e34SJason Evans 		return;
12530cde2e34SJason Evans 	w = m->mtx_witness;
12540384fff8SJason Evans 
12550cde2e34SJason Evans 	if (flags & MTX_SPIN) {
12568484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_SPIN) == 0)
12570cde2e34SJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
12580cde2e34SJason Evans 			    " %s:%d", m->mtx_description, file, line);
12590cde2e34SJason Evans 		if (mtx_recursed(m)) {
12608484de75SJohn Baldwin 			if ((m->mtx_flags & MTX_RECURSE) == 0)
12610cde2e34SJason Evans 				panic("mutex_exit: recursion on non-recursive"
12620cde2e34SJason Evans 				    " mutex %s @ %s:%d", m->mtx_description,
12630cde2e34SJason Evans 				    file, line);
12640cde2e34SJason Evans 			return;
12650384fff8SJason Evans 		}
12669ed346baSBosko Milekic 		mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
12670cde2e34SJason Evans 		PCPU_SET(witness_spin_check,
12680cde2e34SJason Evans 		    PCPU_GET(witness_spin_check) & ~w->w_level);
12699ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
12700cde2e34SJason Evans 		return;
12710384fff8SJason Evans 	}
12728484de75SJohn Baldwin 	if ((m->mtx_flags & MTX_SPIN) != 0)
12730cde2e34SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
12740cde2e34SJason Evans 		    m->mtx_description, file, line);
12750cde2e34SJason Evans 
12760cde2e34SJason Evans 	if (mtx_recursed(m)) {
12778484de75SJohn Baldwin 		if ((m->mtx_flags & MTX_RECURSE) == 0)
12780cde2e34SJason Evans 			panic("mutex_exit: recursion on non-recursive"
12790cde2e34SJason Evans 			    " mutex %s @ %s:%d", m->mtx_description,
12800cde2e34SJason Evans 			    file, line);
12810cde2e34SJason Evans 		return;
12820384fff8SJason Evans 	}
12830cde2e34SJason Evans 
12840cde2e34SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
12859ed346baSBosko Milekic 		panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
12860cde2e34SJason Evans 			    m->mtx_description, file, line);
12870cde2e34SJason Evans 	LIST_REMOVE(m, mtx_held);
12880cde2e34SJason Evans 	m->mtx_held.le_prev = NULL;
12890384fff8SJason Evans }
12900384fff8SJason Evans 
12910384fff8SJason Evans int
1292606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
12930384fff8SJason Evans {
1294606f8eb2SJohn Baldwin 	struct mtx *m;
12950384fff8SJason Evans 	struct proc *p;
12960384fff8SJason Evans 	char **sleep;
12970384fff8SJason Evans 	int n = 0;
12980384fff8SJason Evans 
1299d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
13000384fff8SJason Evans 	p = CURPROC;
13010384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
13020384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
13030384fff8SJason Evans 		if (m == mtx)
13040384fff8SJason Evans 			continue;
13050384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
13060384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
13070384fff8SJason Evans 				goto next;
13080384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
13090384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
13100384fff8SJason Evans 			m->mtx_description,
13110384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
13120384fff8SJason Evans 		n++;
13130384fff8SJason Evans 	next:
13140384fff8SJason Evans 	}
1315a5a96a19SJohn Baldwin #ifdef DDB
1316a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1317a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1318a5a96a19SJohn Baldwin #endif /* DDB */
13190384fff8SJason Evans 	return (n);
13200384fff8SJason Evans }
13210384fff8SJason Evans 
1322606f8eb2SJohn Baldwin static struct witness *
1323b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
13240384fff8SJason Evans {
13250384fff8SJason Evans 	int i;
1326606f8eb2SJohn Baldwin 	struct witness *w, *w1;
13270384fff8SJason Evans 	char **ignore;
13280384fff8SJason Evans 	char **order;
13290384fff8SJason Evans 
13300384fff8SJason Evans 	if (!witness_watch)
13310384fff8SJason Evans 		return (NULL);
13320384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
13330384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
13340384fff8SJason Evans 			return (NULL);
13350384fff8SJason Evans 
13360384fff8SJason Evans 	if (w_inited == 0) {
1337d1c1b841SJason Evans 		mtx_init(&w_mtx, "witness lock", MTX_SPIN);
13380384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
13390384fff8SJason Evans 			w = &w_data[i];
13400384fff8SJason Evans 			witness_free(w);
13410384fff8SJason Evans 		}
13420384fff8SJason Evans 		w_inited = 1;
13430384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
13440384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
13450384fff8SJason Evans 			w->w_file = "order list";
13460384fff8SJason Evans 			for (order++; *order != NULL; order++) {
13470384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
13480384fff8SJason Evans 				w1->w_file = "order list";
13490384fff8SJason Evans 				itismychild(w, w1);
13500384fff8SJason Evans 				w = w1;
13510384fff8SJason Evans     	    	    	}
13520384fff8SJason Evans 		}
13530384fff8SJason Evans 	}
13540384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
13550384fff8SJason Evans 		return (NULL);
13569ed346baSBosko Milekic 	mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
13570384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
13580384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
13599ed346baSBosko Milekic 			mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
13600384fff8SJason Evans 			return (w);
13610384fff8SJason Evans 		}
13620384fff8SJason Evans 	}
13630384fff8SJason Evans 	if ((w = witness_get()) == NULL)
13640384fff8SJason Evans 		return (NULL);
13650384fff8SJason Evans 	w->w_next = w_all;
13660384fff8SJason Evans 	w_all = w;
13670384fff8SJason Evans 	w->w_description = description;
13689ed346baSBosko Milekic 	mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
13690384fff8SJason Evans 	if (flag & MTX_SPIN) {
13700384fff8SJason Evans 		w->w_spin = 1;
13710384fff8SJason Evans 
13720384fff8SJason Evans 		i = 1;
13730384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
13740384fff8SJason Evans 			if (strcmp(description, *order) == 0)
13750384fff8SJason Evans 				break;
13760384fff8SJason Evans 			i <<= 1;
13770384fff8SJason Evans 		}
13780384fff8SJason Evans 		if (*order == NULL)
13790384fff8SJason Evans 			panic("spin lock %s not in order list", description);
13800384fff8SJason Evans 		w->w_level = i;
13818484de75SJohn Baldwin 	}
138208812b39SBosko Milekic 
13830384fff8SJason Evans 	return (w);
13840384fff8SJason Evans }
13850384fff8SJason Evans 
13860384fff8SJason Evans static int
1387606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
13880384fff8SJason Evans {
13890384fff8SJason Evans 	static int recursed;
13900384fff8SJason Evans 
13910384fff8SJason Evans 	/*
13920384fff8SJason Evans 	 * Insert "child" after "parent"
13930384fff8SJason Evans 	 */
13940384fff8SJason Evans 	while (parent->w_morechildren)
13950384fff8SJason Evans 		parent = parent->w_morechildren;
13960384fff8SJason Evans 
13970384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
13980384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
13990384fff8SJason Evans 			return (1);
14000384fff8SJason Evans 		parent = parent->w_morechildren;
14010384fff8SJason Evans 	}
140236412d79SJohn Baldwin 	MPASS(child != NULL);
14030384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
14040384fff8SJason Evans 	/*
14050384fff8SJason Evans 	 * now prune whole tree
14060384fff8SJason Evans 	 */
14070384fff8SJason Evans 	if (recursed)
14080384fff8SJason Evans 		return (0);
14090384fff8SJason Evans 	recursed = 1;
14100384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
14110384fff8SJason Evans 		for (parent = w_all; parent != NULL;
14120384fff8SJason Evans 		    parent = parent->w_next) {
14130384fff8SJason Evans 			if (!isitmychild(parent, child))
14140384fff8SJason Evans 				continue;
14150384fff8SJason Evans 			removechild(parent, child);
14160384fff8SJason Evans 			if (isitmydescendant(parent, child))
14170384fff8SJason Evans 				continue;
14180384fff8SJason Evans 			itismychild(parent, child);
14190384fff8SJason Evans 		}
14200384fff8SJason Evans 	}
14210384fff8SJason Evans 	recursed = 0;
14220384fff8SJason Evans 	witness_levelall();
14230384fff8SJason Evans 	return (0);
14240384fff8SJason Evans }
14250384fff8SJason Evans 
14260384fff8SJason Evans static void
1427606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
14280384fff8SJason Evans {
1429606f8eb2SJohn Baldwin 	struct witness *w, *w1;
14300384fff8SJason Evans 	int i;
14310384fff8SJason Evans 
14320384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
14330384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
14340384fff8SJason Evans 			if (w->w_children[i] == child)
14350384fff8SJason Evans 				goto found;
14360384fff8SJason Evans 	return;
14370384fff8SJason Evans found:
14380384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
14390384fff8SJason Evans 		continue;
14400384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
144136412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
14420384fff8SJason Evans 
14430384fff8SJason Evans 	if (w1->w_childcnt != 0)
14440384fff8SJason Evans 		return;
14450384fff8SJason Evans 
14460384fff8SJason Evans 	if (w1 == parent)
14470384fff8SJason Evans 		return;
14480384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
14490384fff8SJason Evans 		continue;
14500384fff8SJason Evans 	w->w_morechildren = 0;
14510384fff8SJason Evans 	witness_free(w1);
14520384fff8SJason Evans }
14530384fff8SJason Evans 
14540384fff8SJason Evans static int
1455606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
14560384fff8SJason Evans {
1457606f8eb2SJohn Baldwin 	struct witness *w;
14580384fff8SJason Evans 	int i;
14590384fff8SJason Evans 
14600384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
14610384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
14620384fff8SJason Evans 			if (w->w_children[i] == child)
14630384fff8SJason Evans 				return (1);
14640384fff8SJason Evans 		}
14650384fff8SJason Evans 	}
14660384fff8SJason Evans 	return (0);
14670384fff8SJason Evans }
14680384fff8SJason Evans 
14690384fff8SJason Evans static int
1470606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
14710384fff8SJason Evans {
1472606f8eb2SJohn Baldwin 	struct witness *w;
14730384fff8SJason Evans 	int i;
14740384fff8SJason Evans 	int j;
14750384fff8SJason Evans 
14760384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
147736412d79SJohn Baldwin 		MPASS(j < 1000);
14780384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
14790384fff8SJason Evans 			if (w->w_children[i] == child)
14800384fff8SJason Evans 				return (1);
14810384fff8SJason Evans 		}
14820384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
14830384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
14840384fff8SJason Evans 				return (1);
14850384fff8SJason Evans 		}
14860384fff8SJason Evans 	}
14870384fff8SJason Evans 	return (0);
14880384fff8SJason Evans }
14890384fff8SJason Evans 
14900384fff8SJason Evans void
14910384fff8SJason Evans witness_levelall (void)
14920384fff8SJason Evans {
1493606f8eb2SJohn Baldwin 	struct witness *w, *w1;
14940384fff8SJason Evans 
14950384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
149608812b39SBosko Milekic 		if (!(w->w_spin))
14970384fff8SJason Evans 			w->w_level = 0;
14980384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
14990384fff8SJason Evans 		if (w->w_spin)
15000384fff8SJason Evans 			continue;
15010384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
15020384fff8SJason Evans 			if (isitmychild(w1, w))
15030384fff8SJason Evans 				break;
15040384fff8SJason Evans 		}
15050384fff8SJason Evans 		if (w1 != NULL)
15060384fff8SJason Evans 			continue;
15070384fff8SJason Evans 		witness_leveldescendents(w, 0);
15080384fff8SJason Evans 	}
15090384fff8SJason Evans }
15100384fff8SJason Evans 
15110384fff8SJason Evans static void
1512606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
15130384fff8SJason Evans {
15140384fff8SJason Evans 	int i;
1515606f8eb2SJohn Baldwin 	struct witness *w;
15160384fff8SJason Evans 
15170384fff8SJason Evans 	if (parent->w_level < level)
15180384fff8SJason Evans 		parent->w_level = level;
15190384fff8SJason Evans 	level++;
15200384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15210384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15220384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
15230384fff8SJason Evans }
15240384fff8SJason Evans 
15250384fff8SJason Evans static void
1526606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1527606f8eb2SJohn Baldwin 			   struct witness *parent)
15280384fff8SJason Evans {
1529606f8eb2SJohn Baldwin 	struct witness *w;
15300384fff8SJason Evans 	int i;
15310384fff8SJason Evans 	int level = parent->w_level;
15320384fff8SJason Evans 
15330384fff8SJason Evans 	prnt("%d", level);
15340384fff8SJason Evans 	if (level < 10)
15350384fff8SJason Evans 		prnt(" ");
15360384fff8SJason Evans 	for (i = 0; i < level; i++)
15370384fff8SJason Evans 		prnt(" ");
15380384fff8SJason Evans 	prnt("%s", parent->w_description);
15390384fff8SJason Evans 	if (parent->w_file != NULL) {
15400384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
15410384fff8SJason Evans #ifndef W_USE_WHERE
15420384fff8SJason Evans 		prnt(":%d", parent->w_line);
15430384fff8SJason Evans #endif
15440384fff8SJason Evans 		prnt("\n");
15450384fff8SJason Evans 	}
15460384fff8SJason Evans 
15470384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
15480384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
15490384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
15500384fff8SJason Evans     }
15510384fff8SJason Evans 
15520384fff8SJason Evans static int
1553606f8eb2SJohn Baldwin dup_ok(struct witness *w)
15540384fff8SJason Evans {
15550384fff8SJason Evans 	char **dup;
15560384fff8SJason Evans 
15570384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
15580384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
15590384fff8SJason Evans 			return (1);
15600384fff8SJason Evans 	return (0);
15610384fff8SJason Evans }
15620384fff8SJason Evans 
15630384fff8SJason Evans static int
1564606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
15650384fff8SJason Evans {
15660384fff8SJason Evans 	int i;
1567606f8eb2SJohn Baldwin 	struct witness_blessed *b;
15680384fff8SJason Evans 
15690384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
15700384fff8SJason Evans 		b = &blessed_list[i];
15710384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
15720384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
15730384fff8SJason Evans 				return (1);
15740384fff8SJason Evans 			continue;
15750384fff8SJason Evans 		}
15760384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
15770384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
15780384fff8SJason Evans 				return (1);
15790384fff8SJason Evans 	}
15800384fff8SJason Evans 	return (0);
15810384fff8SJason Evans }
15820384fff8SJason Evans 
1583606f8eb2SJohn Baldwin static struct witness *
15840384fff8SJason Evans witness_get()
15850384fff8SJason Evans {
1586606f8eb2SJohn Baldwin 	struct witness *w;
15870384fff8SJason Evans 
15880384fff8SJason Evans 	if ((w = w_free) == NULL) {
15890384fff8SJason Evans 		witness_dead = 1;
15909ed346baSBosko Milekic 		mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
15910384fff8SJason Evans 		printf("witness exhausted\n");
15920384fff8SJason Evans 		return (NULL);
15930384fff8SJason Evans 	}
15940384fff8SJason Evans 	w_free = w->w_next;
15950384fff8SJason Evans 	bzero(w, sizeof(*w));
15960384fff8SJason Evans 	return (w);
15970384fff8SJason Evans }
15980384fff8SJason Evans 
15990384fff8SJason Evans static void
1600606f8eb2SJohn Baldwin witness_free(struct witness *w)
16010384fff8SJason Evans {
16020384fff8SJason Evans 	w->w_next = w_free;
16030384fff8SJason Evans 	w_free = w;
16040384fff8SJason Evans }
16050384fff8SJason Evans 
160692cf772dSJake Burkholder int
16070384fff8SJason Evans witness_list(struct proc *p)
16080384fff8SJason Evans {
1609606f8eb2SJohn Baldwin 	struct mtx *m;
161092cf772dSJake Burkholder 	int nheld;
16110384fff8SJason Evans 
1612d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
161392cf772dSJake Burkholder 	nheld = 0;
16140384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
16150384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
16160384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
16170384fff8SJason Evans 		    m->mtx_description, m,
16180384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
161992cf772dSJake Burkholder 		nheld++;
16200384fff8SJason Evans 	}
162192cf772dSJake Burkholder 
162292cf772dSJake Burkholder 	return (nheld);
16230384fff8SJason Evans }
16240384fff8SJason Evans 
1625d38b8dbfSJohn Baldwin #ifdef DDB
1626d38b8dbfSJohn Baldwin 
1627d38b8dbfSJohn Baldwin DB_COMMAND(witness_list, db_witness_list)
1628d38b8dbfSJohn Baldwin {
1629d38b8dbfSJohn Baldwin 
1630d38b8dbfSJohn Baldwin 	witness_list(CURPROC);
1631d38b8dbfSJohn Baldwin }
1632d38b8dbfSJohn Baldwin 
1633d38b8dbfSJohn Baldwin #endif
1634d38b8dbfSJohn Baldwin 
16350384fff8SJason Evans void
1636606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
16370384fff8SJason Evans {
1638d1c1b841SJason Evans 
1639d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
16400cde2e34SJason Evans 	if (m->mtx_witness == NULL)
16410cde2e34SJason Evans 		return;
16420cde2e34SJason Evans 
16430384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
16440384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
16450384fff8SJason Evans }
16460384fff8SJason Evans 
16470384fff8SJason Evans void
1648606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
16490384fff8SJason Evans {
1650d1c1b841SJason Evans 
1651d1c1b841SJason Evans 	KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
16520cde2e34SJason Evans 	if (m->mtx_witness == NULL)
16530cde2e34SJason Evans 		return;
16540cde2e34SJason Evans 
16550384fff8SJason Evans 	m->mtx_witness->w_file = file;
16560384fff8SJason Evans 	m->mtx_witness->w_line = line;
16570384fff8SJason Evans }
16580384fff8SJason Evans 
16596936206eSJohn Baldwin #endif	/* WITNESS */
1660