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