xref: /freebsd/sys/kern/kern_mutex.c (revision 08812b3925ae0a1a184e562499deb9a3cc59ec40)
10384fff8SJason Evans /*-
20384fff8SJason Evans  * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
30384fff8SJason Evans  *
40384fff8SJason Evans  * Redistribution and use in source and binary forms, with or without
50384fff8SJason Evans  * modification, are permitted provided that the following conditions
60384fff8SJason Evans  * are met:
70384fff8SJason Evans  * 1. Redistributions of source code must retain the above copyright
80384fff8SJason Evans  *    notice, this list of conditions and the following disclaimer.
90384fff8SJason Evans  * 2. Redistributions in binary form must reproduce the above copyright
100384fff8SJason Evans  *    notice, this list of conditions and the following disclaimer in the
110384fff8SJason Evans  *    documentation and/or other materials provided with the distribution.
120384fff8SJason Evans  * 3. Berkeley Software Design Inc's name may not be used to endorse or
130384fff8SJason Evans  *    promote products derived from this software without specific prior
140384fff8SJason Evans  *    written permission.
150384fff8SJason Evans  *
160384fff8SJason Evans  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
170384fff8SJason Evans  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180384fff8SJason Evans  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190384fff8SJason Evans  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
200384fff8SJason Evans  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210384fff8SJason Evans  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220384fff8SJason Evans  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230384fff8SJason Evans  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240384fff8SJason Evans  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250384fff8SJason Evans  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260384fff8SJason Evans  * SUCH DAMAGE.
270384fff8SJason Evans  *
280384fff8SJason Evans  *	from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $
2936412d79SJohn Baldwin  *	and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $
300384fff8SJason Evans  * $FreeBSD$
310384fff8SJason Evans  */
320384fff8SJason Evans 
330384fff8SJason Evans /*
340384fff8SJason Evans  *	Main Entry: witness
350384fff8SJason Evans  *	Pronunciation: 'wit-n&s
360384fff8SJason Evans  *	Function: noun
370384fff8SJason Evans  *	Etymology: Middle English witnesse, from Old English witnes knowledge,
380384fff8SJason Evans  *	    testimony, witness, from 2wit
390384fff8SJason Evans  *	Date: before 12th century
400384fff8SJason Evans  *	1 : attestation of a fact or event : TESTIMONY
410384fff8SJason Evans  *	2 : one that gives evidence; specifically : one who testifies in
420384fff8SJason Evans  *	    a cause or before a judicial tribunal
430384fff8SJason Evans  *	3 : one asked to be present at a transaction so as to be able to
440384fff8SJason Evans  *	    testify to its having taken place
450384fff8SJason Evans  *	4 : one who has personal knowledge of something
460384fff8SJason Evans  *	5 a : something serving as evidence or proof : SIGN
470384fff8SJason Evans  *	  b : public affirmation by word or example of usually
480384fff8SJason Evans  *	      religious faith or conviction <the heroic witness to divine
490384fff8SJason Evans  *	      life -- Pilot>
500384fff8SJason Evans  *	6 capitalized : a member of the Jehovah's Witnesses
510384fff8SJason Evans  */
520384fff8SJason Evans 
539c36c934SJohn Baldwin #include "opt_ddb.h"
54a5a96a19SJohn Baldwin #include "opt_witness.h"
55a5a96a19SJohn Baldwin 
560931dcefSAlfred Perlstein /*
570931dcefSAlfred Perlstein  * Cause non-inlined mtx_*() to be compiled.
580931dcefSAlfred Perlstein  * Must be defined early because other system headers may include mutex.h.
590931dcefSAlfred Perlstein  */
600931dcefSAlfred Perlstein #define _KERN_MUTEX_C_
610931dcefSAlfred Perlstein 
620384fff8SJason Evans #include <sys/param.h>
6336412d79SJohn Baldwin #include <sys/bus.h>
6436412d79SJohn Baldwin #include <sys/kernel.h>
6536412d79SJohn Baldwin #include <sys/malloc.h>
660384fff8SJason Evans #include <sys/proc.h>
67a5a96a19SJohn Baldwin #include <sys/sysctl.h>
680384fff8SJason Evans #include <sys/systm.h>
6936412d79SJohn Baldwin #include <sys/vmmeter.h>
700384fff8SJason Evans #include <sys/ktr.h>
710384fff8SJason Evans 
7236412d79SJohn Baldwin #include <machine/atomic.h>
7336412d79SJohn Baldwin #include <machine/bus.h>
7436412d79SJohn Baldwin #include <machine/clock.h>
750384fff8SJason Evans #include <machine/cpu.h>
7636412d79SJohn Baldwin 
779c36c934SJohn Baldwin #include <ddb/ddb.h>
789c36c934SJohn Baldwin 
7936412d79SJohn Baldwin #include <vm/vm.h>
8036412d79SJohn Baldwin #include <vm/vm_extern.h>
8136412d79SJohn Baldwin 
8236412d79SJohn Baldwin #include <sys/mutex.h>
8336412d79SJohn Baldwin 
8436412d79SJohn Baldwin /*
8536412d79SJohn Baldwin  * Machine independent bits of the mutex implementation
8636412d79SJohn Baldwin  */
8736412d79SJohn Baldwin /* All mutexes in system (used for debug/panic) */
886936206eSJohn Baldwin #ifdef WITNESS
8936412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0,
9036412d79SJohn Baldwin 	"All mutexes queue head" };
9136412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, &all_mtx_debug,
9236412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
9336412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
946936206eSJohn Baldwin #else	/* WITNESS */
9536412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, "All mutexes queue head",
9636412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
9736412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
986936206eSJohn Baldwin #endif	/* WITNESS */
9936412d79SJohn Baldwin 
10036412d79SJohn Baldwin static int	mtx_cur_cnt;
10136412d79SJohn Baldwin static int	mtx_max_cnt;
10236412d79SJohn Baldwin 
10336412d79SJohn Baldwin void	_mtx_enter_giant_def(void);
10436412d79SJohn Baldwin void	_mtx_exit_giant_def(void);
1051bd0eefbSJohn Baldwin static void propagate_priority(struct proc *);
10636412d79SJohn Baldwin 
10736412d79SJohn Baldwin #define	mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
10836412d79SJohn Baldwin #define	mtx_owner(m)	(mtx_unowned(m) ? NULL \
10936412d79SJohn Baldwin 			    : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
11036412d79SJohn Baldwin 
11136412d79SJohn Baldwin #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
11236412d79SJohn Baldwin #define	SET_PRIO(p, pri)	(p)->p_priority = (pri)
11336412d79SJohn Baldwin 
11436412d79SJohn Baldwin /*
11536412d79SJohn Baldwin  * XXX Temporary, for use from assembly language
11636412d79SJohn Baldwin  */
11736412d79SJohn Baldwin 
11836412d79SJohn Baldwin void
11936412d79SJohn Baldwin _mtx_enter_giant_def(void)
12036412d79SJohn Baldwin {
12136412d79SJohn Baldwin 
12236412d79SJohn Baldwin 	mtx_enter(&Giant, MTX_DEF);
12336412d79SJohn Baldwin }
12436412d79SJohn Baldwin 
12536412d79SJohn Baldwin void
12636412d79SJohn Baldwin _mtx_exit_giant_def(void)
12736412d79SJohn Baldwin {
12836412d79SJohn Baldwin 
12936412d79SJohn Baldwin 	mtx_exit(&Giant, MTX_DEF);
13036412d79SJohn Baldwin }
13136412d79SJohn Baldwin 
13236412d79SJohn Baldwin static void
13336412d79SJohn Baldwin propagate_priority(struct proc *p)
13436412d79SJohn Baldwin {
13536412d79SJohn Baldwin 	int pri = p->p_priority;
13636412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
13736412d79SJohn Baldwin 
1381bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
13936412d79SJohn Baldwin 	for (;;) {
14036412d79SJohn Baldwin 		struct proc *p1;
14136412d79SJohn Baldwin 
14236412d79SJohn Baldwin 		p = mtx_owner(m);
14336412d79SJohn Baldwin 
14436412d79SJohn Baldwin 		if (p == NULL) {
14536412d79SJohn Baldwin 			/*
14636412d79SJohn Baldwin 			 * This really isn't quite right. Really
14736412d79SJohn Baldwin 			 * ought to bump priority of process that
14836412d79SJohn Baldwin 			 * next acquires the mutex.
14936412d79SJohn Baldwin 			 */
15036412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
15136412d79SJohn Baldwin 			return;
15236412d79SJohn Baldwin 		}
15336412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
1541bd0eefbSJohn Baldwin 		KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex"));
15536412d79SJohn Baldwin 		if (p->p_priority <= pri)
15636412d79SJohn Baldwin 			return;
1571bd0eefbSJohn Baldwin 
1581bd0eefbSJohn Baldwin 		/*
1591bd0eefbSJohn Baldwin 		 * Bump this process' priority.
1601bd0eefbSJohn Baldwin 		 */
1611bd0eefbSJohn Baldwin 		SET_PRIO(p, pri);
1621bd0eefbSJohn Baldwin 
16336412d79SJohn Baldwin 		/*
16436412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
16536412d79SJohn Baldwin 		 */
1661bd0eefbSJohn Baldwin #ifdef SMP
1671bd0eefbSJohn Baldwin 		/*
1681bd0eefbSJohn Baldwin 		 * For SMP, we can check the p_oncpu field to see if we are
1691bd0eefbSJohn Baldwin 		 * running.
1701bd0eefbSJohn Baldwin 		 */
1711bd0eefbSJohn Baldwin 		if (p->p_oncpu != 0xff) {
17236412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
17336412d79SJohn Baldwin 			return;
17436412d79SJohn Baldwin 		}
1751bd0eefbSJohn Baldwin #else
1761bd0eefbSJohn Baldwin 		/*
1771bd0eefbSJohn Baldwin 		 * For UP, we check to see if p is curproc (this shouldn't
1781bd0eefbSJohn Baldwin 		 * ever happen however as it would mean we are in a deadlock.)
1791bd0eefbSJohn Baldwin 		 */
1801bd0eefbSJohn Baldwin 		if (p == curproc) {
1811bd0eefbSJohn Baldwin 			panic("Deadlock detected");
1821bd0eefbSJohn Baldwin 			return;
1831bd0eefbSJohn Baldwin 		}
1841bd0eefbSJohn Baldwin #endif
18536412d79SJohn Baldwin 		/*
18636412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
18736412d79SJohn Baldwin 		 * quit.
18836412d79SJohn Baldwin 		 */
18936412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
1901bd0eefbSJohn Baldwin 			printf("XXX: moving process %d(%s) to a new run queue\n",
1911bd0eefbSJohn Baldwin 			       p->p_pid, p->p_comm);
19236412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
19336412d79SJohn Baldwin 			remrunqueue(p);
19436412d79SJohn Baldwin 			setrunqueue(p);
19536412d79SJohn Baldwin 			return;
19636412d79SJohn Baldwin 		}
19736412d79SJohn Baldwin 
19836412d79SJohn Baldwin 		/*
1991bd0eefbSJohn Baldwin 		 * If we aren't blocked on a mutex, we should be.
20036412d79SJohn Baldwin 		 */
2011bd0eefbSJohn Baldwin 		KASSERT(p->p_stat == SMTX, (
2021bd0eefbSJohn Baldwin 		    "process %d(%s):%d holds %s but isn't blocked on a mutex\n",
2031bd0eefbSJohn Baldwin 		    p->p_pid, p->p_comm, p->p_stat,
2041bd0eefbSJohn Baldwin 		    m->mtx_description));
20536412d79SJohn Baldwin 
20636412d79SJohn Baldwin 		/*
20736412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
20836412d79SJohn Baldwin 		 */
20936412d79SJohn Baldwin 		m = p->p_blocked;
21036412d79SJohn Baldwin 		MPASS(m != NULL);
21136412d79SJohn Baldwin 
21236412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
21336412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
21436412d79SJohn Baldwin 		/*
21536412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
21636412d79SJohn Baldwin 		 * the blocked chain
21736412d79SJohn Baldwin 		 */
2181bd0eefbSJohn Baldwin 		if (p == TAILQ_FIRST(&m->mtx_blocked)) {
2191bd0eefbSJohn Baldwin 			printf("XXX: process at head of run queue\n");
2201bd0eefbSJohn Baldwin 			continue;
2211bd0eefbSJohn Baldwin 		}
2221bd0eefbSJohn Baldwin 		p1 = TAILQ_PREV(p, rq, p_procq);
2231bd0eefbSJohn Baldwin 		if (p1->p_priority <= pri) {
22436412d79SJohn Baldwin 			printf(
22536412d79SJohn Baldwin 	"XXX: previous process %d(%s) has higher priority\n",
22636412d79SJohn Baldwin 	                    p->p_pid, p->p_comm);
22736412d79SJohn Baldwin 			continue;
22836412d79SJohn Baldwin 		}
22936412d79SJohn Baldwin 
23036412d79SJohn Baldwin 		/*
2311bd0eefbSJohn Baldwin 		 * Remove proc from blocked chain and determine where
2321bd0eefbSJohn Baldwin 		 * it should be moved up to.  Since we know that p1 has
2331bd0eefbSJohn Baldwin 		 * a lower priority than p, we know that at least one
2341bd0eefbSJohn Baldwin 		 * process in the chain has a lower priority and that
2351bd0eefbSJohn Baldwin 		 * p1 will thus not be NULL after the loop.
23636412d79SJohn Baldwin 		 */
23736412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
23836412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
23936412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
24036412d79SJohn Baldwin 			if (p1->p_priority > pri)
24136412d79SJohn Baldwin 				break;
24236412d79SJohn Baldwin 		}
2431bd0eefbSJohn Baldwin 		MPASS(p1 != NULL);
24436412d79SJohn Baldwin 		TAILQ_INSERT_BEFORE(p1, p, p_procq);
24536412d79SJohn Baldwin 		CTR4(KTR_LOCK,
2461bd0eefbSJohn Baldwin 		    "propagate_priority: p 0x%p moved before 0x%p on [0x%p] %s",
24736412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
24836412d79SJohn Baldwin 	}
24936412d79SJohn Baldwin }
25036412d79SJohn Baldwin 
25136412d79SJohn Baldwin void
25236412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr)
25336412d79SJohn Baldwin {
25436412d79SJohn Baldwin 	struct proc *p = CURPROC;
25536412d79SJohn Baldwin 
25636412d79SJohn Baldwin 	KASSERT(p != NULL, ("curproc is NULL in mutex"));
25736412d79SJohn Baldwin 
25836412d79SJohn Baldwin 	switch (type) {
25936412d79SJohn Baldwin 	case MTX_DEF:
26036412d79SJohn Baldwin 		if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
26136412d79SJohn Baldwin 			m->mtx_recurse++;
26208812b39SBosko Milekic 			atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
263562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
26436412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m);
26536412d79SJohn Baldwin 			return;
26636412d79SJohn Baldwin 		}
267562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
268562e4ffeSJohn Baldwin 			CTR3(KTR_LOCK,
269562e4ffeSJohn Baldwin 			    "mtx_enter: 0x%p contested (lock=%p) [0x%p]",
27031271627SJohn Baldwin 			    m, (void *)m->mtx_lock, (void *)RETIP(m));
2711bd0eefbSJohn Baldwin 
2721bd0eefbSJohn Baldwin 		/*
2731bd0eefbSJohn Baldwin 		 * Save our priority.  Even though p_nativepri is protected
2741bd0eefbSJohn Baldwin 		 * by sched_lock, we don't obtain it here as it can be
2751bd0eefbSJohn Baldwin 		 * expensive.  Since this is the only place p_nativepri is
2761bd0eefbSJohn Baldwin 		 * set, and since two CPUs will not be executing the same
2771bd0eefbSJohn Baldwin 		 * process concurrently, we know that no other CPU is going
2781bd0eefbSJohn Baldwin 		 * to be messing with this.  Also, p_nativepri is only read
2791bd0eefbSJohn Baldwin 		 * when we are blocked on a mutex, so that can't be happening
2801bd0eefbSJohn Baldwin 		 * right now either.
2811bd0eefbSJohn Baldwin 		 */
2821bd0eefbSJohn Baldwin 		p->p_nativepri = p->p_priority;
28336412d79SJohn Baldwin 		while (!_obtain_lock(m, p)) {
284f5271ebcSJohn Baldwin 			uintptr_t v;
28536412d79SJohn Baldwin 			struct proc *p1;
28636412d79SJohn Baldwin 
28736412d79SJohn Baldwin 			mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY);
28836412d79SJohn Baldwin 			/*
28936412d79SJohn Baldwin 			 * check if the lock has been released while
29036412d79SJohn Baldwin 			 * waiting for the schedlock.
29136412d79SJohn Baldwin 			 */
29236412d79SJohn Baldwin 			if ((v = m->mtx_lock) == MTX_UNOWNED) {
29336412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
29436412d79SJohn Baldwin 				continue;
29536412d79SJohn Baldwin 			}
29636412d79SJohn Baldwin 			/*
29736412d79SJohn Baldwin 			 * The mutex was marked contested on release. This
29836412d79SJohn Baldwin 			 * means that there are processes blocked on it.
29936412d79SJohn Baldwin 			 */
30036412d79SJohn Baldwin 			if (v == MTX_CONTESTED) {
30136412d79SJohn Baldwin 				p1 = TAILQ_FIRST(&m->mtx_blocked);
30236412d79SJohn Baldwin 				KASSERT(p1 != NULL, ("contested mutex has no contesters"));
30336412d79SJohn Baldwin 				KASSERT(p != NULL, ("curproc is NULL for contested mutex"));
30436412d79SJohn Baldwin 				m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
30536412d79SJohn Baldwin 				if (p1->p_priority < p->p_priority) {
30636412d79SJohn Baldwin 					SET_PRIO(p, p1->p_priority);
30736412d79SJohn Baldwin 				}
30836412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
30936412d79SJohn Baldwin 				return;
31036412d79SJohn Baldwin 			}
31136412d79SJohn Baldwin 			/*
31236412d79SJohn Baldwin 			 * If the mutex isn't already contested and
31336412d79SJohn Baldwin 			 * a failure occurs setting the contested bit the
31436412d79SJohn Baldwin 			 * mutex was either release or the
31536412d79SJohn Baldwin 			 * state of the RECURSION bit changed.
31636412d79SJohn Baldwin 			 */
31736412d79SJohn Baldwin 			if ((v & MTX_CONTESTED) == 0 &&
31836412d79SJohn Baldwin 			    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
31936412d79SJohn Baldwin 				               (void *)(v | MTX_CONTESTED))) {
32036412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
32136412d79SJohn Baldwin 				continue;
32236412d79SJohn Baldwin 			}
32336412d79SJohn Baldwin 
32436412d79SJohn Baldwin 			/* We definitely have to sleep for this lock */
32536412d79SJohn Baldwin 			mtx_assert(m, MA_NOTOWNED);
32636412d79SJohn Baldwin 
32736412d79SJohn Baldwin #ifdef notyet
32836412d79SJohn Baldwin 			/*
32936412d79SJohn Baldwin 			 * If we're borrowing an interrupted thread's VM
33036412d79SJohn Baldwin 			 * context must clean up before going to sleep.
33136412d79SJohn Baldwin 			 */
33236412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
33336412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
33436412d79SJohn Baldwin 
33536412d79SJohn Baldwin 				if (it->it_interrupted) {
336562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
33736412d79SJohn Baldwin 						CTR2(KTR_LOCK,
33836412d79SJohn Baldwin 					    "mtx_enter: 0x%x interrupted 0x%x",
33936412d79SJohn Baldwin 						    it, it->it_interrupted);
34036412d79SJohn Baldwin 					intr_thd_fixup(it);
34136412d79SJohn Baldwin 				}
34236412d79SJohn Baldwin 			}
34336412d79SJohn Baldwin #endif
34436412d79SJohn Baldwin 
34536412d79SJohn Baldwin 			/* Put us on the list of procs blocked on this mutex */
34636412d79SJohn Baldwin 			if (TAILQ_EMPTY(&m->mtx_blocked)) {
34736412d79SJohn Baldwin 				p1 = (struct proc *)(m->mtx_lock &
34836412d79SJohn Baldwin 						     MTX_FLAGMASK);
34936412d79SJohn Baldwin 				LIST_INSERT_HEAD(&p1->p_contested, m,
35036412d79SJohn Baldwin 						 mtx_contested);
35136412d79SJohn Baldwin 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
35236412d79SJohn Baldwin 			} else {
35336412d79SJohn Baldwin 				TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
35436412d79SJohn Baldwin 					if (p1->p_priority > p->p_priority)
35536412d79SJohn Baldwin 						break;
35636412d79SJohn Baldwin 				if (p1)
35736412d79SJohn Baldwin 					TAILQ_INSERT_BEFORE(p1, p, p_procq);
35836412d79SJohn Baldwin 				else
35936412d79SJohn Baldwin 					TAILQ_INSERT_TAIL(&m->mtx_blocked, p,
36036412d79SJohn Baldwin 							  p_procq);
36136412d79SJohn Baldwin 			}
36236412d79SJohn Baldwin 
36336412d79SJohn Baldwin 			p->p_blocked = m;	/* Who we're blocked on */
36486327ad8SJohn Baldwin 			p->p_mtxname = m->mtx_description;
36536412d79SJohn Baldwin 			p->p_stat = SMTX;
36636412d79SJohn Baldwin #if 0
36736412d79SJohn Baldwin 			propagate_priority(p);
36836412d79SJohn Baldwin #endif
369562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
370562e4ffeSJohn Baldwin 				CTR3(KTR_LOCK,
371562e4ffeSJohn Baldwin 				    "mtx_enter: p 0x%p blocked on [0x%p] %s",
37236412d79SJohn Baldwin 				    p, m, m->mtx_description);
37320cdcc5bSJohn Baldwin 			mi_switch();
374562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
37536412d79SJohn Baldwin 				CTR3(KTR_LOCK,
37636412d79SJohn Baldwin 			    "mtx_enter: p 0x%p free from blocked on [0x%p] %s",
37736412d79SJohn Baldwin 				    p, m, m->mtx_description);
37836412d79SJohn Baldwin 			mtx_exit(&sched_lock, MTX_SPIN);
37936412d79SJohn Baldwin 		}
38036412d79SJohn Baldwin 		return;
38136412d79SJohn Baldwin 	case MTX_SPIN:
38236412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
38336412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
38436412d79SJohn Baldwin 	    {
38536412d79SJohn Baldwin 		int i = 0;
38636412d79SJohn Baldwin 
38736412d79SJohn Baldwin 		if (m->mtx_lock == (uintptr_t)p) {
38836412d79SJohn Baldwin 			m->mtx_recurse++;
38936412d79SJohn Baldwin 			return;
39036412d79SJohn Baldwin 		}
391562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
39236412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: %p spinning", m);
39336412d79SJohn Baldwin 		for (;;) {
39436412d79SJohn Baldwin 			if (_obtain_lock(m, p))
39536412d79SJohn Baldwin 				break;
39636412d79SJohn Baldwin 			while (m->mtx_lock != MTX_UNOWNED) {
39736412d79SJohn Baldwin 				if (i++ < 1000000)
39836412d79SJohn Baldwin 					continue;
39936412d79SJohn Baldwin 				if (i++ < 6000000)
40036412d79SJohn Baldwin 					DELAY (1);
40136412d79SJohn Baldwin #ifdef DDB
40236412d79SJohn Baldwin 				else if (!db_active)
40336412d79SJohn Baldwin #else
40436412d79SJohn Baldwin 				else
40536412d79SJohn Baldwin #endif
40636412d79SJohn Baldwin 					panic(
40736412d79SJohn Baldwin 				"spin lock %s held by 0x%p for > 5 seconds",
40836412d79SJohn Baldwin 					    m->mtx_description,
40936412d79SJohn Baldwin 					    (void *)m->mtx_lock);
41036412d79SJohn Baldwin 			}
41136412d79SJohn Baldwin 		}
41236412d79SJohn Baldwin 
41336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
41436412d79SJohn Baldwin 		if (type != MTX_SPIN)
41536412d79SJohn Baldwin 			m->mtx_saveintr = 0xbeefface;
41636412d79SJohn Baldwin 		else
41736412d79SJohn Baldwin #endif
41836412d79SJohn Baldwin 			m->mtx_saveintr = saveintr;
419562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
42036412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m);
42136412d79SJohn Baldwin 		return;
42236412d79SJohn Baldwin 	    }
42336412d79SJohn Baldwin 	}
42436412d79SJohn Baldwin }
42536412d79SJohn Baldwin 
42636412d79SJohn Baldwin void
42736412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type)
42836412d79SJohn Baldwin {
42936412d79SJohn Baldwin 	struct proc *p, *p1;
43036412d79SJohn Baldwin 	struct mtx *m1;
43136412d79SJohn Baldwin 	int pri;
43236412d79SJohn Baldwin 
43336412d79SJohn Baldwin 	p = CURPROC;
43436412d79SJohn Baldwin 	switch (type) {
43536412d79SJohn Baldwin 	case MTX_DEF:
43636412d79SJohn Baldwin 	case MTX_DEF | MTX_NOSWITCH:
43708812b39SBosko Milekic 		if (mtx_recursed(m)) {
43836412d79SJohn Baldwin 			if (--(m->mtx_recurse) == 0)
43908812b39SBosko Milekic 				atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
440562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
44136412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m);
44236412d79SJohn Baldwin 			return;
44336412d79SJohn Baldwin 		}
44436412d79SJohn Baldwin 		mtx_enter(&sched_lock, MTX_SPIN);
445562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
44636412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m);
44736412d79SJohn Baldwin 		p1 = TAILQ_FIRST(&m->mtx_blocked);
44836412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
44936412d79SJohn Baldwin 		MPASS(p1->p_magic == P_MAGIC);
45036412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
45136412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
45236412d79SJohn Baldwin 			LIST_REMOVE(m, mtx_contested);
45336412d79SJohn Baldwin 			_release_lock_quick(m);
454562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
45536412d79SJohn Baldwin 				CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m);
45636412d79SJohn Baldwin 		} else
457f404050eSJohn Baldwin 			atomic_store_rel_ptr(&m->mtx_lock,
458f404050eSJohn Baldwin 			    (void *)MTX_CONTESTED);
45936412d79SJohn Baldwin 		pri = MAXPRI;
46036412d79SJohn Baldwin 		LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
46136412d79SJohn Baldwin 			int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
46236412d79SJohn Baldwin 			if (cp < pri)
46336412d79SJohn Baldwin 				pri = cp;
46436412d79SJohn Baldwin 		}
46536412d79SJohn Baldwin 		if (pri > p->p_nativepri)
46636412d79SJohn Baldwin 			pri = p->p_nativepri;
46736412d79SJohn Baldwin 		SET_PRIO(p, pri);
468562e4ffeSJohn Baldwin 		if ((type & MTX_QUIET) == 0)
469562e4ffeSJohn Baldwin 			CTR2(KTR_LOCK,
470562e4ffeSJohn Baldwin 			    "mtx_exit: 0x%p contested setrunqueue 0x%p", m, p1);
47136412d79SJohn Baldwin 		p1->p_blocked = NULL;
47286327ad8SJohn Baldwin 		p1->p_mtxname = NULL;
47336412d79SJohn Baldwin 		p1->p_stat = SRUN;
47436412d79SJohn Baldwin 		setrunqueue(p1);
47536412d79SJohn Baldwin 		if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
47636412d79SJohn Baldwin #ifdef notyet
47736412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
47836412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
47936412d79SJohn Baldwin 
48036412d79SJohn Baldwin 				if (it->it_interrupted) {
481562e4ffeSJohn Baldwin 					if ((type & MTX_QUIET) == 0)
48236412d79SJohn Baldwin 						CTR2(KTR_LOCK,
48336412d79SJohn Baldwin 					    "mtx_exit: 0x%x interruped 0x%x",
48436412d79SJohn Baldwin 						    it, it->it_interrupted);
48536412d79SJohn Baldwin 					intr_thd_fixup(it);
48636412d79SJohn Baldwin 				}
48736412d79SJohn Baldwin 			}
48836412d79SJohn Baldwin #endif
48936412d79SJohn Baldwin 			setrunqueue(p);
490562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
491562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
492562e4ffeSJohn Baldwin 				    "mtx_exit: 0x%p switching out lock=0x%p",
49331271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
49436412d79SJohn Baldwin 			mi_switch();
495562e4ffeSJohn Baldwin 			if ((type & MTX_QUIET) == 0)
496562e4ffeSJohn Baldwin 				CTR2(KTR_LOCK,
497562e4ffeSJohn Baldwin 				    "mtx_exit: 0x%p resuming lock=0x%p",
49831271627SJohn Baldwin 				    m, (void *)m->mtx_lock);
49936412d79SJohn Baldwin 		}
50036412d79SJohn Baldwin 		mtx_exit(&sched_lock, MTX_SPIN);
50136412d79SJohn Baldwin 		break;
50236412d79SJohn Baldwin 	case MTX_SPIN:
50336412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
50408812b39SBosko Milekic 		if (mtx_recursed(m)) {
50536412d79SJohn Baldwin 			m->mtx_recurse--;
50636412d79SJohn Baldwin 			return;
50736412d79SJohn Baldwin 		}
50836412d79SJohn Baldwin 		MPASS(mtx_owned(m));
50936412d79SJohn Baldwin 		_release_lock_quick(m);
51036412d79SJohn Baldwin 		if (type & MTX_FIRST)
51136412d79SJohn Baldwin 			enable_intr();	/* XXX is this kosher? */
51236412d79SJohn Baldwin 		else {
51336412d79SJohn Baldwin 			MPASS(m->mtx_saveintr != 0xbeefface);
51436412d79SJohn Baldwin 			restore_intr(m->mtx_saveintr);
51536412d79SJohn Baldwin 		}
51636412d79SJohn Baldwin 		break;
51736412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
51808812b39SBosko Milekic 		if (mtx_recursed(m)) {
51936412d79SJohn Baldwin 			m->mtx_recurse--;
52036412d79SJohn Baldwin 			return;
52136412d79SJohn Baldwin 		}
52236412d79SJohn Baldwin 		MPASS(mtx_owned(m));
52336412d79SJohn Baldwin 		_release_lock_quick(m);
52436412d79SJohn Baldwin 		break;
52536412d79SJohn Baldwin 	default:
52636412d79SJohn Baldwin 		panic("mtx_exit_hard: unsupported type 0x%x\n", type);
52736412d79SJohn Baldwin 	}
52836412d79SJohn Baldwin }
52936412d79SJohn Baldwin 
53036412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
53136412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
53236412d79SJohn Baldwin 
53336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
53436412d79SJohn Baldwin 
53536412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
53636412d79SJohn Baldwin 
53736412d79SJohn Baldwin int
53836412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
53936412d79SJohn Baldwin {
54036412d79SJohn Baldwin 	struct mtx *mp;
54136412d79SJohn Baldwin 	int i;
54236412d79SJohn Baldwin 	int retval = 0;
54336412d79SJohn Baldwin 
54436412d79SJohn Baldwin 	if (m == &all_mtx || cold)
54536412d79SJohn Baldwin 		return 0;
54636412d79SJohn Baldwin 
54736412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
54836412d79SJohn Baldwin /*
54936412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
55036412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
55136412d79SJohn Baldwin  */
55236412d79SJohn Baldwin #ifndef __alpha__
55336412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
55436412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
55536412d79SJohn Baldwin #endif
55636412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
55736412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
55836412d79SJohn Baldwin #ifndef __alpha__
55936412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
56036412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
56136412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
56236412d79SJohn Baldwin 			    mp, mp->mtx_next);
56336412d79SJohn Baldwin 		}
56436412d79SJohn Baldwin #endif
56536412d79SJohn Baldwin 		i++;
56636412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
56736412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
56836412d79SJohn Baldwin 			    mtx_cur_cnt);
56936412d79SJohn Baldwin 		}
57036412d79SJohn Baldwin 	}
57136412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
57236412d79SJohn Baldwin 	switch (when) {
57336412d79SJohn Baldwin 	case MV_DESTROY:
57436412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
57536412d79SJohn Baldwin 			if (mp == m)
57636412d79SJohn Baldwin 				break;
57736412d79SJohn Baldwin 		MPASS(mp == m);
57836412d79SJohn Baldwin 		break;
57936412d79SJohn Baldwin 	case MV_INIT:
58036412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
58136412d79SJohn Baldwin 		if (mp == m) {
58236412d79SJohn Baldwin 			/*
58336412d79SJohn Baldwin 			 * Not good. This mutex already exists.
58436412d79SJohn Baldwin 			 */
58536412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
58636412d79SJohn Baldwin 			    m->mtx_description);
58736412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
58836412d79SJohn Baldwin 			retval = 1;
58936412d79SJohn Baldwin 		}
59036412d79SJohn Baldwin 	}
59136412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
59236412d79SJohn Baldwin 	return (retval);
59336412d79SJohn Baldwin }
59436412d79SJohn Baldwin #endif
59536412d79SJohn Baldwin 
59636412d79SJohn Baldwin void
59736412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag)
59836412d79SJohn Baldwin {
5996936206eSJohn Baldwin #ifdef WITNESS
60036412d79SJohn Baldwin 	struct mtx_debug *debug;
60136412d79SJohn Baldwin #endif
60236412d79SJohn Baldwin 
603562e4ffeSJohn Baldwin 	if ((flag & MTX_QUIET) == 0)
60436412d79SJohn Baldwin 		CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t);
60536412d79SJohn Baldwin #ifdef MUTEX_DEBUG
60636412d79SJohn Baldwin 	if (mtx_validate(m, MV_INIT))	/* diagnostic and error correction */
60736412d79SJohn Baldwin 		return;
6086936206eSJohn Baldwin #endif
6096936206eSJohn Baldwin #ifdef WITNESS
61036412d79SJohn Baldwin 	if (flag & MTX_COLD)
61136412d79SJohn Baldwin 		debug = m->mtx_debug;
61236412d79SJohn Baldwin 	else
61336412d79SJohn Baldwin 		debug = NULL;
61436412d79SJohn Baldwin 	if (debug == NULL) {
61536412d79SJohn Baldwin #ifdef DIAGNOSTIC
61636412d79SJohn Baldwin 		if(cold && bootverbose)
61736412d79SJohn Baldwin 			printf("malloc'ing mtx_debug while cold for %s\n", t);
61836412d79SJohn Baldwin #endif
61936412d79SJohn Baldwin 
62036412d79SJohn Baldwin 		/* XXX - should not use DEVBUF */
6217cc0979fSDavid Malone 		debug = malloc(sizeof(struct mtx_debug), M_DEVBUF,
6227cc0979fSDavid Malone 		    M_NOWAIT | M_ZERO);
62336412d79SJohn Baldwin 		MPASS(debug != NULL);
62436412d79SJohn Baldwin 	}
62536412d79SJohn Baldwin #endif
62636412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
62736412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
6286936206eSJohn Baldwin #ifdef WITNESS
62936412d79SJohn Baldwin 	m->mtx_debug = debug;
63036412d79SJohn Baldwin #endif
63136412d79SJohn Baldwin 	m->mtx_description = t;
63236412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
63336412d79SJohn Baldwin 	/* Put on all mutex queue */
63436412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
63536412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
63636412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
63736412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
63836412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
63936412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
64036412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
64136412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
64236412d79SJohn Baldwin 	witness_init(m, flag);
64336412d79SJohn Baldwin }
64436412d79SJohn Baldwin 
64536412d79SJohn Baldwin void
64636412d79SJohn Baldwin mtx_destroy(struct mtx *m)
64736412d79SJohn Baldwin {
64836412d79SJohn Baldwin 
64936412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description);
65036412d79SJohn Baldwin #ifdef MUTEX_DEBUG
65136412d79SJohn Baldwin 	if (m->mtx_next == NULL)
65236412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
65336412d79SJohn Baldwin 		    m, m->mtx_description);
65436412d79SJohn Baldwin 
65536412d79SJohn Baldwin 	if (!mtx_owned(m)) {
65636412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
65736412d79SJohn Baldwin 	} else {
65808812b39SBosko Milekic 		MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
65936412d79SJohn Baldwin 	}
66036412d79SJohn Baldwin 	mtx_validate(m, MV_DESTROY);		/* diagnostic */
66136412d79SJohn Baldwin #endif
66236412d79SJohn Baldwin 
66336412d79SJohn Baldwin #ifdef WITNESS
66436412d79SJohn Baldwin 	if (m->mtx_witness)
66536412d79SJohn Baldwin 		witness_destroy(m);
66636412d79SJohn Baldwin #endif /* WITNESS */
66736412d79SJohn Baldwin 
66836412d79SJohn Baldwin 	/* Remove from the all mutex queue */
66936412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
67036412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
67136412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
67236412d79SJohn Baldwin #ifdef MUTEX_DEBUG
67336412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
6746936206eSJohn Baldwin #endif
6756936206eSJohn Baldwin #ifdef WITNESS
67636412d79SJohn Baldwin 	free(m->mtx_debug, M_DEVBUF);
67736412d79SJohn Baldwin 	m->mtx_debug = NULL;
67836412d79SJohn Baldwin #endif
67936412d79SJohn Baldwin 	mtx_cur_cnt--;
68036412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
68136412d79SJohn Baldwin }
6820384fff8SJason Evans 
6830384fff8SJason Evans /*
6840384fff8SJason Evans  * The non-inlined versions of the mtx_*() functions are always built (above),
6856936206eSJohn Baldwin  * but the witness code depends on the WITNESS kernel option being specified.
6860384fff8SJason Evans  */
6876936206eSJohn Baldwin #ifdef WITNESS
6880384fff8SJason Evans 
6890384fff8SJason Evans #define WITNESS_COUNT 200
6900384fff8SJason Evans #define	WITNESS_NCHILDREN 2
6910384fff8SJason Evans 
69278f0da03SJohn Baldwin int witness_watch = 1;
6930384fff8SJason Evans 
694606f8eb2SJohn Baldwin struct witness {
6950384fff8SJason Evans 	struct witness	*w_next;
696b67a3e6eSJohn Baldwin 	const char	*w_description;
69712473b76SJason Evans 	const char	*w_file;
6980384fff8SJason Evans 	int		 w_line;
6990384fff8SJason Evans 	struct witness	*w_morechildren;
7000384fff8SJason Evans 	u_char		 w_childcnt;
7010384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
7020384fff8SJason Evans 	u_char		 w_other_squawked:1;
7030384fff8SJason Evans 	u_char		 w_same_squawked:1;
70408812b39SBosko Milekic 	u_char		 w_sleep:1;	/* MTX_DEF type mutex. */
70508812b39SBosko Milekic 	u_char		 w_spin:1;	/* MTX_SPIN type mutex. */
70608812b39SBosko Milekic 	u_char		 w_recurse:1;	/* MTX_RECURSE mutex option. */
7070384fff8SJason Evans 	u_int		 w_level;
7080384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
709606f8eb2SJohn Baldwin };
7100384fff8SJason Evans 
711606f8eb2SJohn Baldwin struct witness_blessed {
7120384fff8SJason Evans 	char 	*b_lock1;
7130384fff8SJason Evans 	char	*b_lock2;
714606f8eb2SJohn Baldwin };
7150384fff8SJason Evans 
716a5a96a19SJohn Baldwin #ifdef DDB
7170384fff8SJason Evans /*
718a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
7190384fff8SJason Evans  * drop into kdebug() when:
7200384fff8SJason Evans  *	- a lock heirarchy violation occurs
7210384fff8SJason Evans  *	- locks are held when going to sleep.
7220384fff8SJason Evans  */
723a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
724a5a96a19SJohn Baldwin int	witness_ddb = 1;
725a5a96a19SJohn Baldwin #else
726a5a96a19SJohn Baldwin int	witness_ddb = 0;
7270384fff8SJason Evans #endif
728a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
729a5a96a19SJohn Baldwin #endif /* DDB */
7300384fff8SJason Evans 
731a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
732a5a96a19SJohn Baldwin int	witness_skipspin = 1;
733a5a96a19SJohn Baldwin #else
734a5a96a19SJohn Baldwin int	witness_skipspin = 0;
7350384fff8SJason Evans #endif
736a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
737a5a96a19SJohn Baldwin     "");
7380384fff8SJason Evans 
739a5a96a19SJohn Baldwin MUTEX_DECLARE(static,w_mtx);
740606f8eb2SJohn Baldwin static struct witness	*w_free;
741606f8eb2SJohn Baldwin static struct witness	*w_all;
7420384fff8SJason Evans static int		 w_inited;
7430384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
7440384fff8SJason Evans 
745606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
7460384fff8SJason Evans 
747b67a3e6eSJohn Baldwin static struct witness	 *enroll __P((const char *description, int flag));
748606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child));
749606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child));
750606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child));
751606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child));
752606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *));
753606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *));
7540384fff8SJason Evans static void witness_displaydescendants
755606f8eb2SJohn Baldwin     __P((void(*)(const char *fmt, ...), struct witness *));
756606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level));
7570384fff8SJason Evans static void witness_levelall __P((void));
758606f8eb2SJohn Baldwin static struct witness * witness_get __P((void));
759606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m));
7600384fff8SJason Evans 
7610384fff8SJason Evans 
7620384fff8SJason Evans static char *ignore_list[] = {
7630384fff8SJason Evans 	"witness lock",
7640384fff8SJason Evans 	NULL
7650384fff8SJason Evans };
7660384fff8SJason Evans 
7670384fff8SJason Evans static char *spin_order_list[] = {
768a5a96a19SJohn Baldwin 	"sio",
7698f838cb5SJohn Baldwin 	"sched lock",
77020cdcc5bSJohn Baldwin #ifdef __i386__
77120cdcc5bSJohn Baldwin 	"clk",
77220cdcc5bSJohn Baldwin #endif
773fa2fbc3dSJake Burkholder 	"callout",
7740384fff8SJason Evans 	/*
7750384fff8SJason Evans 	 * leaf locks
7760384fff8SJason Evans 	 */
7770384fff8SJason Evans 	NULL
7780384fff8SJason Evans };
7790384fff8SJason Evans 
7800384fff8SJason Evans static char *order_list[] = {
781a5d5c61cSJake Burkholder 	"uidinfo hash", "uidinfo struct", NULL,
7820384fff8SJason Evans 	NULL
7830384fff8SJason Evans };
7840384fff8SJason Evans 
7850384fff8SJason Evans static char *dup_list[] = {
7860384fff8SJason Evans 	NULL
7870384fff8SJason Evans };
7880384fff8SJason Evans 
7890384fff8SJason Evans static char *sleep_list[] = {
7907da6f977SJake Burkholder 	"Giant",
7910384fff8SJason Evans 	NULL
7920384fff8SJason Evans };
7930384fff8SJason Evans 
7940384fff8SJason Evans /*
7950384fff8SJason Evans  * Pairs of locks which have been blessed
7960384fff8SJason Evans  * Don't complain about order problems with blessed locks
7970384fff8SJason Evans  */
798606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
7990384fff8SJason Evans };
800606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed);
8010384fff8SJason Evans 
8020384fff8SJason Evans void
803606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
8040384fff8SJason Evans {
8050384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
8060384fff8SJason Evans }
8070384fff8SJason Evans 
8080384fff8SJason Evans void
809606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
8100384fff8SJason Evans {
811606f8eb2SJohn Baldwin 	struct mtx *m1;
8120384fff8SJason Evans 	struct proc *p;
8130384fff8SJason Evans 	p = CURPROC;
8140384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
8150384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
8160384fff8SJason Evans 		if (m1 == m) {
8170384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
8180384fff8SJason Evans 			break;
8190384fff8SJason Evans 		}
8200384fff8SJason Evans 	}
8210384fff8SJason Evans 	return;
8220384fff8SJason Evans 
8230384fff8SJason Evans }
8240384fff8SJason Evans 
8250384fff8SJason Evans void
826606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
8270384fff8SJason Evans {
828606f8eb2SJohn Baldwin 	struct witness *w, *w1;
829606f8eb2SJohn Baldwin 	struct mtx *m1;
8300384fff8SJason Evans 	struct proc *p;
8310384fff8SJason Evans 	int i;
832a5a96a19SJohn Baldwin #ifdef DDB
833a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
834a5a96a19SJohn Baldwin #endif /* DDB */
8350384fff8SJason Evans 
836562e4ffeSJohn Baldwin 	if (panicstr)
837562e4ffeSJohn Baldwin 		return;
8380384fff8SJason Evans 	w = m->mtx_witness;
8390384fff8SJason Evans 	p = CURPROC;
8400384fff8SJason Evans 
8410384fff8SJason Evans 	if (flags & MTX_SPIN) {
84208812b39SBosko Milekic 		if (!(w->w_spin))
8435340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
8445340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
84508812b39SBosko Milekic 		if (mtx_recursed(m)) {
84608812b39SBosko Milekic 			if (!(w->w_recurse))
84708812b39SBosko Milekic 				panic("mutex_enter: recursion on non-recursive"
84808812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
84908812b39SBosko Milekic 				    file, line);
8500384fff8SJason Evans 			return;
85108812b39SBosko Milekic 		}
852562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
853ef73ae4bSJake Burkholder 		i = PCPU_GET(witness_spin_check);
8540384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
855562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
8565340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
8575340642aSJason Evans 			    " %s:%d already holding %s:%x",
8580384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
8590384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
8600384fff8SJason Evans 		}
8610384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
862562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
863bbc7a98aSJohn Baldwin 		w->w_file = file;
864bbc7a98aSJohn Baldwin 		w->w_line = line;
865bbc7a98aSJohn Baldwin 		m->mtx_line = line;
866bbc7a98aSJohn Baldwin 		m->mtx_file = file;
8670384fff8SJason Evans 		return;
8680384fff8SJason Evans 	}
8690384fff8SJason Evans 	if (w->w_spin)
8700384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
8710384fff8SJason Evans 		    m->mtx_description, file, line);
8720384fff8SJason Evans 
87308812b39SBosko Milekic 	if (mtx_recursed(m)) {
87408812b39SBosko Milekic 		if (!(w->w_recurse))
87508812b39SBosko Milekic 			panic("mutex_enter: recursion on non-recursive"
87608812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
87708812b39SBosko Milekic 			    file, line);
8780384fff8SJason Evans 		return;
87908812b39SBosko Milekic 	}
8800384fff8SJason Evans 	if (witness_dead)
8810384fff8SJason Evans 		goto out;
882562e4ffeSJohn Baldwin 	if (cold)
8830384fff8SJason Evans 		goto out;
8840384fff8SJason Evans 
8850384fff8SJason Evans 	if (!mtx_legal2block())
8860384fff8SJason Evans 		panic("blockable mtx_enter() of %s when not legal @ %s:%d",
8870384fff8SJason Evans 			    m->mtx_description, file, line);
8880384fff8SJason Evans 	/*
8890384fff8SJason Evans 	 * Is this the first mutex acquired
8900384fff8SJason Evans 	 */
8910384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
8920384fff8SJason Evans 		goto out;
8930384fff8SJason Evans 
8940384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
8950384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
8960384fff8SJason Evans 			goto out;
8970384fff8SJason Evans 		w->w_same_squawked = 1;
8980384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
8990384fff8SJason Evans 			m->mtx_description);
9000384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
9010384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
902a5a96a19SJohn Baldwin #ifdef DDB
903a5a96a19SJohn Baldwin 		go_into_ddb = 1;
904a5a96a19SJohn Baldwin #endif /* DDB */
9050384fff8SJason Evans 		goto out;
9060384fff8SJason Evans 	}
9070384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
908562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
9090384fff8SJason Evans 	/*
9100384fff8SJason Evans 	 * If we have a known higher number just say ok
9110384fff8SJason Evans 	 */
9120384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
913562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
9140384fff8SJason Evans 		goto out;
9150384fff8SJason Evans 	}
9160384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
917562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
9180384fff8SJason Evans 		goto out;
9190384fff8SJason Evans 	}
9200384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
9210384fff8SJason Evans 
92236412d79SJohn Baldwin 		MPASS(i < 200);
9230384fff8SJason Evans 		w1 = m1->mtx_witness;
9240384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
925562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
9260384fff8SJason Evans 			if (blessed(w, w1))
9270384fff8SJason Evans 				goto out;
9280384fff8SJason Evans 			if (m1 == &Giant) {
9290384fff8SJason Evans 				if (w1->w_Giant_squawked)
9300384fff8SJason Evans 					goto out;
9310384fff8SJason Evans 				else
9320384fff8SJason Evans 					w1->w_Giant_squawked = 1;
9330384fff8SJason Evans 			} else {
9340384fff8SJason Evans 				if (w1->w_other_squawked)
9350384fff8SJason Evans 					goto out;
9360384fff8SJason Evans 				else
9370384fff8SJason Evans 					w1->w_other_squawked = 1;
9380384fff8SJason Evans 			}
9390384fff8SJason Evans 			printf("lock order reversal\n");
9400384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
9410384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
9420384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
9430384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
9440384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
9450384fff8SJason Evans 			    m, w->w_description, file, line);
946a5a96a19SJohn Baldwin #ifdef DDB
947a5a96a19SJohn Baldwin 			go_into_ddb = 1;
948a5a96a19SJohn Baldwin #endif /* DDB */
9490384fff8SJason Evans 			goto out;
9500384fff8SJason Evans 		}
9510384fff8SJason Evans 	}
9520384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
9530384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
954562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
9550384fff8SJason Evans 
9560384fff8SJason Evans out:
957a5a96a19SJohn Baldwin #ifdef DDB
958a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
959a5a96a19SJohn Baldwin 		Debugger("witness_enter");
960a5a96a19SJohn Baldwin #endif /* DDB */
9610384fff8SJason Evans 	w->w_file = file;
9620384fff8SJason Evans 	w->w_line = line;
9630384fff8SJason Evans 	m->mtx_line = line;
9640384fff8SJason Evans 	m->mtx_file = file;
9650384fff8SJason Evans 
9660384fff8SJason Evans 	/*
9670384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
9680384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
9690384fff8SJason Evans 	 * likely not the mutex this assert fails on.
9700384fff8SJason Evans 	 */
97136412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
9720384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
9730384fff8SJason Evans }
9740384fff8SJason Evans 
9750384fff8SJason Evans void
976606f8eb2SJohn Baldwin witness_exit(struct mtx *m, int flags, const char *file, int line)
9770384fff8SJason Evans {
978606f8eb2SJohn Baldwin 	struct witness *w;
9790384fff8SJason Evans 
980562e4ffeSJohn Baldwin 	if (panicstr)
981562e4ffeSJohn Baldwin 		return;
9820384fff8SJason Evans 	w = m->mtx_witness;
9830384fff8SJason Evans 
9840384fff8SJason Evans 	if (flags & MTX_SPIN) {
98508812b39SBosko Milekic 		if (!(w->w_spin))
9865340642aSJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
9875340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
98808812b39SBosko Milekic 		if (mtx_recursed(m)) {
98908812b39SBosko Milekic 			if (!(w->w_recurse))
99008812b39SBosko Milekic 				panic("mutex_exit: recursion on non-recursive"
99108812b39SBosko Milekic 				    " mutex %s @ %s:%d", m->mtx_description,
99208812b39SBosko Milekic 				    file, line);
9930384fff8SJason Evans 			return;
99408812b39SBosko Milekic 		}
995562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
996ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
997ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) & ~w->w_level);
998562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
9990384fff8SJason Evans 		return;
10000384fff8SJason Evans 	}
10010384fff8SJason Evans 	if (w->w_spin)
10020384fff8SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
10030384fff8SJason Evans 		    m->mtx_description, file, line);
10040384fff8SJason Evans 
100508812b39SBosko Milekic 	if (mtx_recursed(m)) {
100608812b39SBosko Milekic 		if (!(w->w_recurse))
100708812b39SBosko Milekic 			panic("mutex_exit: recursion on non-recursive"
100808812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description,
100908812b39SBosko Milekic 			    file, line);
10100384fff8SJason Evans 		return;
101108812b39SBosko Milekic 	}
10120384fff8SJason Evans 
10130384fff8SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
10140384fff8SJason Evans 		panic("switchable mtx_exit() of %s when not legal @ %s:%d",
10150384fff8SJason Evans 			    m->mtx_description, file, line);
10160384fff8SJason Evans 	LIST_REMOVE(m, mtx_held);
10170384fff8SJason Evans 	m->mtx_held.le_prev = NULL;
10180384fff8SJason Evans }
10190384fff8SJason Evans 
10200384fff8SJason Evans void
1021606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
10220384fff8SJason Evans {
10230384fff8SJason Evans 	struct proc *p;
1024606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
10250384fff8SJason Evans 
1026562e4ffeSJohn Baldwin 	if (panicstr)
1027562e4ffeSJohn Baldwin 		return;
10280384fff8SJason Evans 	if (flags & MTX_SPIN) {
102908812b39SBosko Milekic 		if (!(w->w_spin))
10300384fff8SJason Evans 			panic("mutex_try_enter: "
10310384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
10320384fff8SJason Evans 			    m->mtx_description, file, line);
103308812b39SBosko Milekic 		if (mtx_recursed(m)) {
103408812b39SBosko Milekic 			if (!(w->w_recurse))
103508812b39SBosko Milekic 				panic("mutex_try_enter: recursion on"
103608812b39SBosko Milekic 				    " non-recursive mutex %s @ %s:%d",
103708812b39SBosko Milekic 				    m->mtx_description, file, line);
10380384fff8SJason Evans 			return;
103908812b39SBosko Milekic 		}
1040562e4ffeSJohn Baldwin 		mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
1041ef73ae4bSJake Burkholder 		PCPU_SET(witness_spin_check,
1042ef73ae4bSJake Burkholder 		    PCPU_GET(witness_spin_check) | w->w_level);
1043562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
1044bbc7a98aSJohn Baldwin 		w->w_file = file;
1045bbc7a98aSJohn Baldwin 		w->w_line = line;
1046bbc7a98aSJohn Baldwin 		m->mtx_line = line;
1047bbc7a98aSJohn Baldwin 		m->mtx_file = file;
10480384fff8SJason Evans 		return;
10490384fff8SJason Evans 	}
10500384fff8SJason Evans 
10510384fff8SJason Evans 	if (w->w_spin)
10520384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
10530384fff8SJason Evans 		    m->mtx_description, file, line);
10540384fff8SJason Evans 
105508812b39SBosko Milekic 	if (mtx_recursed(m)) {
105608812b39SBosko Milekic 		if (!(w->w_recurse))
105708812b39SBosko Milekic 			panic("mutex_try_enter: recursion on non-recursive"
105808812b39SBosko Milekic 			    " mutex %s @ %s:%d", m->mtx_description, file,
105908812b39SBosko Milekic 			    line);
10600384fff8SJason Evans 		return;
106108812b39SBosko Milekic 	}
10620384fff8SJason Evans 	w->w_file = file;
10630384fff8SJason Evans 	w->w_line = line;
10640384fff8SJason Evans 	m->mtx_line = line;
10650384fff8SJason Evans 	m->mtx_file = file;
10660384fff8SJason Evans 	p = CURPROC;
106736412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
10680384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
10690384fff8SJason Evans }
10700384fff8SJason Evans 
10710384fff8SJason Evans void
10720384fff8SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
10730384fff8SJason Evans {
1074606f8eb2SJohn Baldwin 	struct witness *w, *w1;
10750384fff8SJason Evans 
10760384fff8SJason Evans 	witness_levelall();
10770384fff8SJason Evans 
10780384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10790384fff8SJason Evans 		if (w->w_file == NULL)
10800384fff8SJason Evans 			continue;
10810384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
10820384fff8SJason Evans 			if (isitmychild(w1, w))
10830384fff8SJason Evans 				break;
10840384fff8SJason Evans 		}
10850384fff8SJason Evans 		if (w1 != NULL)
10860384fff8SJason Evans 			continue;
10870384fff8SJason Evans 		/*
10880384fff8SJason Evans 		 * This lock has no anscestors, display its descendants.
10890384fff8SJason Evans 		 */
10900384fff8SJason Evans 		witness_displaydescendants(prnt, w);
10910384fff8SJason Evans 	}
10920384fff8SJason Evans 	prnt("\nMutex which were never acquired\n");
10930384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10940384fff8SJason Evans 		if (w->w_file != NULL)
10950384fff8SJason Evans 			continue;
10960384fff8SJason Evans 		prnt("%s\n", w->w_description);
10970384fff8SJason Evans 	}
10980384fff8SJason Evans }
10990384fff8SJason Evans 
11000384fff8SJason Evans int
1101606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
11020384fff8SJason Evans {
1103606f8eb2SJohn Baldwin 	struct mtx *m;
11040384fff8SJason Evans 	struct proc *p;
11050384fff8SJason Evans 	char **sleep;
11060384fff8SJason Evans 	int n = 0;
11070384fff8SJason Evans 
11080384fff8SJason Evans 	p = CURPROC;
11090384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
11100384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
11110384fff8SJason Evans 		if (m == mtx)
11120384fff8SJason Evans 			continue;
11130384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
11140384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
11150384fff8SJason Evans 				goto next;
11160384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
11170384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
11180384fff8SJason Evans 			m->mtx_description,
11190384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
11200384fff8SJason Evans 		n++;
11210384fff8SJason Evans 	next:
11220384fff8SJason Evans 	}
1123a5a96a19SJohn Baldwin #ifdef DDB
1124a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1125a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1126a5a96a19SJohn Baldwin #endif /* DDB */
11270384fff8SJason Evans 	return (n);
11280384fff8SJason Evans }
11290384fff8SJason Evans 
1130606f8eb2SJohn Baldwin static struct witness *
1131b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
11320384fff8SJason Evans {
11330384fff8SJason Evans 	int i;
1134606f8eb2SJohn Baldwin 	struct witness *w, *w1;
11350384fff8SJason Evans 	char **ignore;
11360384fff8SJason Evans 	char **order;
11370384fff8SJason Evans 
11380384fff8SJason Evans 	if (!witness_watch)
11390384fff8SJason Evans 		return (NULL);
11400384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
11410384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
11420384fff8SJason Evans 			return (NULL);
11430384fff8SJason Evans 
11440384fff8SJason Evans 	if (w_inited == 0) {
1145428b4b55SJohn Baldwin 		mtx_init(&w_mtx, "witness lock", MTX_COLD | MTX_SPIN);
11460384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
11470384fff8SJason Evans 			w = &w_data[i];
11480384fff8SJason Evans 			witness_free(w);
11490384fff8SJason Evans 		}
11500384fff8SJason Evans 		w_inited = 1;
11510384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
11520384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
11530384fff8SJason Evans 			w->w_file = "order list";
11540384fff8SJason Evans 			for (order++; *order != NULL; order++) {
11550384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
11560384fff8SJason Evans 				w1->w_file = "order list";
11570384fff8SJason Evans 				itismychild(w, w1);
11580384fff8SJason Evans 				w = w1;
11590384fff8SJason Evans     	    	    	}
11600384fff8SJason Evans 		}
11610384fff8SJason Evans 	}
11620384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
11630384fff8SJason Evans 		return (NULL);
1164562e4ffeSJohn Baldwin 	mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET);
11650384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
11660384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
1167562e4ffeSJohn Baldwin 			mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
11680384fff8SJason Evans 			return (w);
11690384fff8SJason Evans 		}
11700384fff8SJason Evans 	}
11710384fff8SJason Evans 	if ((w = witness_get()) == NULL)
11720384fff8SJason Evans 		return (NULL);
11730384fff8SJason Evans 	w->w_next = w_all;
11740384fff8SJason Evans 	w_all = w;
11750384fff8SJason Evans 	w->w_description = description;
1176562e4ffeSJohn Baldwin 	mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
11770384fff8SJason Evans 	if (flag & MTX_SPIN) {
11780384fff8SJason Evans 		w->w_spin = 1;
11790384fff8SJason Evans 
11800384fff8SJason Evans 		i = 1;
11810384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
11820384fff8SJason Evans 			if (strcmp(description, *order) == 0)
11830384fff8SJason Evans 				break;
11840384fff8SJason Evans 			i <<= 1;
11850384fff8SJason Evans 		}
11860384fff8SJason Evans 		if (*order == NULL)
11870384fff8SJason Evans 			panic("spin lock %s not in order list", description);
11880384fff8SJason Evans 		w->w_level = i;
118908812b39SBosko Milekic 	} else
119008812b39SBosko Milekic 		w->w_sleep = 1;
119108812b39SBosko Milekic 
119208812b39SBosko Milekic 	if (flag & MTX_RECURSE)
119308812b39SBosko Milekic 		w->w_recurse = 1;
119408812b39SBosko Milekic 
11950384fff8SJason Evans 	return (w);
11960384fff8SJason Evans }
11970384fff8SJason Evans 
11980384fff8SJason Evans static int
1199606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
12000384fff8SJason Evans {
12010384fff8SJason Evans 	static int recursed;
12020384fff8SJason Evans 
12030384fff8SJason Evans 	/*
12040384fff8SJason Evans 	 * Insert "child" after "parent"
12050384fff8SJason Evans 	 */
12060384fff8SJason Evans 	while (parent->w_morechildren)
12070384fff8SJason Evans 		parent = parent->w_morechildren;
12080384fff8SJason Evans 
12090384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
12100384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
12110384fff8SJason Evans 			return (1);
12120384fff8SJason Evans 		parent = parent->w_morechildren;
12130384fff8SJason Evans 	}
121436412d79SJohn Baldwin 	MPASS(child != NULL);
12150384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
12160384fff8SJason Evans 	/*
12170384fff8SJason Evans 	 * now prune whole tree
12180384fff8SJason Evans 	 */
12190384fff8SJason Evans 	if (recursed)
12200384fff8SJason Evans 		return (0);
12210384fff8SJason Evans 	recursed = 1;
12220384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
12230384fff8SJason Evans 		for (parent = w_all; parent != NULL;
12240384fff8SJason Evans 		    parent = parent->w_next) {
12250384fff8SJason Evans 			if (!isitmychild(parent, child))
12260384fff8SJason Evans 				continue;
12270384fff8SJason Evans 			removechild(parent, child);
12280384fff8SJason Evans 			if (isitmydescendant(parent, child))
12290384fff8SJason Evans 				continue;
12300384fff8SJason Evans 			itismychild(parent, child);
12310384fff8SJason Evans 		}
12320384fff8SJason Evans 	}
12330384fff8SJason Evans 	recursed = 0;
12340384fff8SJason Evans 	witness_levelall();
12350384fff8SJason Evans 	return (0);
12360384fff8SJason Evans }
12370384fff8SJason Evans 
12380384fff8SJason Evans static void
1239606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
12400384fff8SJason Evans {
1241606f8eb2SJohn Baldwin 	struct witness *w, *w1;
12420384fff8SJason Evans 	int i;
12430384fff8SJason Evans 
12440384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
12450384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
12460384fff8SJason Evans 			if (w->w_children[i] == child)
12470384fff8SJason Evans 				goto found;
12480384fff8SJason Evans 	return;
12490384fff8SJason Evans found:
12500384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
12510384fff8SJason Evans 		continue;
12520384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
125336412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
12540384fff8SJason Evans 
12550384fff8SJason Evans 	if (w1->w_childcnt != 0)
12560384fff8SJason Evans 		return;
12570384fff8SJason Evans 
12580384fff8SJason Evans 	if (w1 == parent)
12590384fff8SJason Evans 		return;
12600384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
12610384fff8SJason Evans 		continue;
12620384fff8SJason Evans 	w->w_morechildren = 0;
12630384fff8SJason Evans 	witness_free(w1);
12640384fff8SJason Evans }
12650384fff8SJason Evans 
12660384fff8SJason Evans static int
1267606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
12680384fff8SJason Evans {
1269606f8eb2SJohn Baldwin 	struct witness *w;
12700384fff8SJason Evans 	int i;
12710384fff8SJason Evans 
12720384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
12730384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12740384fff8SJason Evans 			if (w->w_children[i] == child)
12750384fff8SJason Evans 				return (1);
12760384fff8SJason Evans 		}
12770384fff8SJason Evans 	}
12780384fff8SJason Evans 	return (0);
12790384fff8SJason Evans }
12800384fff8SJason Evans 
12810384fff8SJason Evans static int
1282606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
12830384fff8SJason Evans {
1284606f8eb2SJohn Baldwin 	struct witness *w;
12850384fff8SJason Evans 	int i;
12860384fff8SJason Evans 	int j;
12870384fff8SJason Evans 
12880384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
128936412d79SJohn Baldwin 		MPASS(j < 1000);
12900384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12910384fff8SJason Evans 			if (w->w_children[i] == child)
12920384fff8SJason Evans 				return (1);
12930384fff8SJason Evans 		}
12940384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12950384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
12960384fff8SJason Evans 				return (1);
12970384fff8SJason Evans 		}
12980384fff8SJason Evans 	}
12990384fff8SJason Evans 	return (0);
13000384fff8SJason Evans }
13010384fff8SJason Evans 
13020384fff8SJason Evans void
13030384fff8SJason Evans witness_levelall (void)
13040384fff8SJason Evans {
1305606f8eb2SJohn Baldwin 	struct witness *w, *w1;
13060384fff8SJason Evans 
13070384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
130808812b39SBosko Milekic 		if (!(w->w_spin))
13090384fff8SJason Evans 			w->w_level = 0;
13100384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
13110384fff8SJason Evans 		if (w->w_spin)
13120384fff8SJason Evans 			continue;
13130384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
13140384fff8SJason Evans 			if (isitmychild(w1, w))
13150384fff8SJason Evans 				break;
13160384fff8SJason Evans 		}
13170384fff8SJason Evans 		if (w1 != NULL)
13180384fff8SJason Evans 			continue;
13190384fff8SJason Evans 		witness_leveldescendents(w, 0);
13200384fff8SJason Evans 	}
13210384fff8SJason Evans }
13220384fff8SJason Evans 
13230384fff8SJason Evans static void
1324606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
13250384fff8SJason Evans {
13260384fff8SJason Evans 	int i;
1327606f8eb2SJohn Baldwin 	struct witness *w;
13280384fff8SJason Evans 
13290384fff8SJason Evans 	if (parent->w_level < level)
13300384fff8SJason Evans 		parent->w_level = level;
13310384fff8SJason Evans 	level++;
13320384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
13330384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
13340384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
13350384fff8SJason Evans }
13360384fff8SJason Evans 
13370384fff8SJason Evans static void
1338606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1339606f8eb2SJohn Baldwin 			   struct witness *parent)
13400384fff8SJason Evans {
1341606f8eb2SJohn Baldwin 	struct witness *w;
13420384fff8SJason Evans 	int i;
13430384fff8SJason Evans 	int level = parent->w_level;
13440384fff8SJason Evans 
13450384fff8SJason Evans 	prnt("%d", level);
13460384fff8SJason Evans 	if (level < 10)
13470384fff8SJason Evans 		prnt(" ");
13480384fff8SJason Evans 	for (i = 0; i < level; i++)
13490384fff8SJason Evans 		prnt(" ");
13500384fff8SJason Evans 	prnt("%s", parent->w_description);
13510384fff8SJason Evans 	if (parent->w_file != NULL) {
13520384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
13530384fff8SJason Evans #ifndef W_USE_WHERE
13540384fff8SJason Evans 		prnt(":%d", parent->w_line);
13550384fff8SJason Evans #endif
13560384fff8SJason Evans 		prnt("\n");
13570384fff8SJason Evans 	}
13580384fff8SJason Evans 
13590384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
13600384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
13610384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
13620384fff8SJason Evans     }
13630384fff8SJason Evans 
13640384fff8SJason Evans static int
1365606f8eb2SJohn Baldwin dup_ok(struct witness *w)
13660384fff8SJason Evans {
13670384fff8SJason Evans 	char **dup;
13680384fff8SJason Evans 
13690384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
13700384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
13710384fff8SJason Evans 			return (1);
13720384fff8SJason Evans 	return (0);
13730384fff8SJason Evans }
13740384fff8SJason Evans 
13750384fff8SJason Evans static int
1376606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
13770384fff8SJason Evans {
13780384fff8SJason Evans 	int i;
1379606f8eb2SJohn Baldwin 	struct witness_blessed *b;
13800384fff8SJason Evans 
13810384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
13820384fff8SJason Evans 		b = &blessed_list[i];
13830384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
13840384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
13850384fff8SJason Evans 				return (1);
13860384fff8SJason Evans 			continue;
13870384fff8SJason Evans 		}
13880384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
13890384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
13900384fff8SJason Evans 				return (1);
13910384fff8SJason Evans 	}
13920384fff8SJason Evans 	return (0);
13930384fff8SJason Evans }
13940384fff8SJason Evans 
1395606f8eb2SJohn Baldwin static struct witness *
13960384fff8SJason Evans witness_get()
13970384fff8SJason Evans {
1398606f8eb2SJohn Baldwin 	struct witness *w;
13990384fff8SJason Evans 
14000384fff8SJason Evans 	if ((w = w_free) == NULL) {
14010384fff8SJason Evans 		witness_dead = 1;
1402562e4ffeSJohn Baldwin 		mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET);
14030384fff8SJason Evans 		printf("witness exhausted\n");
14040384fff8SJason Evans 		return (NULL);
14050384fff8SJason Evans 	}
14060384fff8SJason Evans 	w_free = w->w_next;
14070384fff8SJason Evans 	bzero(w, sizeof(*w));
14080384fff8SJason Evans 	return (w);
14090384fff8SJason Evans }
14100384fff8SJason Evans 
14110384fff8SJason Evans static void
1412606f8eb2SJohn Baldwin witness_free(struct witness *w)
14130384fff8SJason Evans {
14140384fff8SJason Evans 	w->w_next = w_free;
14150384fff8SJason Evans 	w_free = w;
14160384fff8SJason Evans }
14170384fff8SJason Evans 
141892cf772dSJake Burkholder int
14190384fff8SJason Evans witness_list(struct proc *p)
14200384fff8SJason Evans {
1421606f8eb2SJohn Baldwin 	struct mtx *m;
142292cf772dSJake Burkholder 	int nheld;
14230384fff8SJason Evans 
142492cf772dSJake Burkholder 	nheld = 0;
14250384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
14260384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
14270384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
14280384fff8SJason Evans 		    m->mtx_description, m,
14290384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
143092cf772dSJake Burkholder 		nheld++;
14310384fff8SJason Evans 	}
143292cf772dSJake Burkholder 
143392cf772dSJake Burkholder 	return (nheld);
14340384fff8SJason Evans }
14350384fff8SJason Evans 
14360384fff8SJason Evans void
1437606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
14380384fff8SJason Evans {
14390384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
14400384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
14410384fff8SJason Evans }
14420384fff8SJason Evans 
14430384fff8SJason Evans void
1444606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
14450384fff8SJason Evans {
14460384fff8SJason Evans 	m->mtx_witness->w_file = file;
14470384fff8SJason Evans 	m->mtx_witness->w_line = line;
14480384fff8SJason Evans }
14490384fff8SJason Evans 
14506936206eSJohn Baldwin #endif	/* WITNESS */
1451