19454b2d8SWarner Losh /*- 253bf4bb2SPeter Wemm * Copyright (c) 1995 353bf4bb2SPeter Wemm * The Regents of the University of California. All rights reserved. 453bf4bb2SPeter Wemm * 503e9c6c1SJohn Dyson * Copyright (C) 1997 603e9c6c1SJohn Dyson * John S. Dyson. All rights reserved. 703e9c6c1SJohn Dyson * 853bf4bb2SPeter Wemm * This code contains ideas from software contributed to Berkeley by 953bf4bb2SPeter Wemm * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 1053bf4bb2SPeter Wemm * System project at Carnegie-Mellon University. 1153bf4bb2SPeter Wemm * 1253bf4bb2SPeter Wemm * Redistribution and use in source and binary forms, with or without 1353bf4bb2SPeter Wemm * modification, are permitted provided that the following conditions 1453bf4bb2SPeter Wemm * are met: 1553bf4bb2SPeter Wemm * 1. Redistributions of source code must retain the above copyright 1653bf4bb2SPeter Wemm * notice, this list of conditions and the following disclaimer. 1753bf4bb2SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 1853bf4bb2SPeter Wemm * notice, this list of conditions and the following disclaimer in the 1953bf4bb2SPeter Wemm * documentation and/or other materials provided with the distribution. 2053bf4bb2SPeter Wemm * 3. All advertising materials mentioning features or use of this software 2153bf4bb2SPeter Wemm * must display the following acknowledgement: 2253bf4bb2SPeter Wemm * This product includes software developed by the University of 2353bf4bb2SPeter Wemm * California, Berkeley and its contributors. 2453bf4bb2SPeter Wemm * 4. Neither the name of the University nor the names of its contributors 2553bf4bb2SPeter Wemm * may be used to endorse or promote products derived from this software 2653bf4bb2SPeter Wemm * without specific prior written permission. 2753bf4bb2SPeter Wemm * 2853bf4bb2SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2953bf4bb2SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3053bf4bb2SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3153bf4bb2SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3253bf4bb2SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3353bf4bb2SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3453bf4bb2SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3553bf4bb2SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3653bf4bb2SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3753bf4bb2SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3853bf4bb2SPeter Wemm * SUCH DAMAGE. 3953bf4bb2SPeter Wemm * 4053bf4bb2SPeter Wemm * @(#)kern_lock.c 8.18 (Berkeley) 5/21/95 4153bf4bb2SPeter Wemm */ 4253bf4bb2SPeter Wemm 43677b542eSDavid E. O'Brien #include <sys/cdefs.h> 44677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 45677b542eSDavid E. O'Brien 4653bf4bb2SPeter Wemm #include <sys/param.h> 479722d88fSJason Evans #include <sys/kernel.h> 4861d80e90SJohn Baldwin #include <sys/ktr.h> 4953bf4bb2SPeter Wemm #include <sys/lock.h> 508302d183SBruce Evans #include <sys/lockmgr.h> 51d8881ca3SJohn Baldwin #include <sys/mutex.h> 528302d183SBruce Evans #include <sys/proc.h> 534bdb9b11SPeter Wemm #include <sys/systm.h> 5453bf4bb2SPeter Wemm 5553bf4bb2SPeter Wemm /* 5653bf4bb2SPeter Wemm * Locking primitives implementation. 5753bf4bb2SPeter Wemm * Locks provide shared/exclusive sychronization. 5853bf4bb2SPeter Wemm */ 5953bf4bb2SPeter Wemm 6003e9c6c1SJohn Dyson #define LOCK_WAIT_TIME 100 6103e9c6c1SJohn Dyson #define LOCK_SAMPLE_WAIT 7 6253bf4bb2SPeter Wemm 6303e9c6c1SJohn Dyson #if defined(DIAGNOSTIC) 6403e9c6c1SJohn Dyson #define LOCK_INLINE 6503e9c6c1SJohn Dyson #else 66ab36c3d3SBruce Evans #define LOCK_INLINE __inline 6703e9c6c1SJohn Dyson #endif 6803e9c6c1SJohn Dyson 6999448ed1SJohn Dyson #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \ 7099448ed1SJohn Dyson LK_SHARE_NONZERO | LK_WAIT_NONZERO) 7199448ed1SJohn Dyson 729722d88fSJason Evans /* 739722d88fSJason Evans * Mutex array variables. Rather than each lockmgr lock having its own mutex, 749722d88fSJason Evans * share a fixed (at boot time) number of mutexes across all lockmgr locks in 759722d88fSJason Evans * order to keep sizeof(struct lock) down. 769722d88fSJason Evans */ 77d1c1b841SJason Evans static struct mtx lock_mtx; 789722d88fSJason Evans 79c6964d3bSKirk McKusick static int acquire(struct lock **lkpp, int extflags, int wanted); 8099448ed1SJohn Dyson static int apause(struct lock *lkp, int flags); 8199448ed1SJohn Dyson static int acquiredrain(struct lock *lkp, int extflags) ; 8203e9c6c1SJohn Dyson 839722d88fSJason Evans static void 849722d88fSJason Evans lockmgr_init(void *dummy __unused) 859722d88fSJason Evans { 866008862bSJohn Baldwin mtx_init(&lock_mtx, "lockmgr", NULL, MTX_DEF); 879722d88fSJason Evans } 886ff1481dSDon Lewis SYSINIT(lmgrinit, SI_SUB_LOCKMGR, SI_ORDER_FIRST, lockmgr_init, NULL) 899722d88fSJason Evans 9003e9c6c1SJohn Dyson static LOCK_INLINE void 9103e9c6c1SJohn Dyson sharelock(struct lock *lkp, int incr) { 9203e9c6c1SJohn Dyson lkp->lk_flags |= LK_SHARE_NONZERO; 9303e9c6c1SJohn Dyson lkp->lk_sharecount += incr; 9403e9c6c1SJohn Dyson } 9503e9c6c1SJohn Dyson 9603e9c6c1SJohn Dyson static LOCK_INLINE void 9703e9c6c1SJohn Dyson shareunlock(struct lock *lkp, int decr) { 98219cbf59SEivind Eklund 995526d2d9SEivind Eklund KASSERT(lkp->lk_sharecount >= decr, ("shareunlock: count < decr")); 10003e9c6c1SJohn Dyson 1019b2e5badSJohn Dyson if (lkp->lk_sharecount == decr) { 10203e9c6c1SJohn Dyson lkp->lk_flags &= ~LK_SHARE_NONZERO; 1039b2e5badSJohn Dyson if (lkp->lk_flags & (LK_WANT_UPGRADE | LK_WANT_EXCL)) { 1049b2e5badSJohn Dyson wakeup(lkp); 1059b2e5badSJohn Dyson } 1069b2e5badSJohn Dyson lkp->lk_sharecount = 0; 1079b2e5badSJohn Dyson } else { 1089b2e5badSJohn Dyson lkp->lk_sharecount -= decr; 1099b2e5badSJohn Dyson } 11003e9c6c1SJohn Dyson } 11103e9c6c1SJohn Dyson 11299448ed1SJohn Dyson /* 1131b367556SJason Evans * This is the waitloop optimization. 11499448ed1SJohn Dyson */ 11503e9c6c1SJohn Dyson static int 11699c9d349SAlan Cox apause(struct lock *lkp, int flags) 11799c9d349SAlan Cox { 11899c9d349SAlan Cox #ifdef SMP 11999c9d349SAlan Cox int i, lock_wait; 12099c9d349SAlan Cox #endif 12199c9d349SAlan Cox 12203e9c6c1SJohn Dyson if ((lkp->lk_flags & flags) == 0) 12303e9c6c1SJohn Dyson return 0; 12499c9d349SAlan Cox #ifdef SMP 12599c9d349SAlan Cox for (lock_wait = LOCK_WAIT_TIME; lock_wait > 0; lock_wait--) { 1269ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 12799c9d349SAlan Cox for (i = LOCK_SAMPLE_WAIT; i > 0; i--) 12899c9d349SAlan Cox if ((lkp->lk_flags & flags) == 0) 12999c9d349SAlan Cox break; 1309ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 13103e9c6c1SJohn Dyson if ((lkp->lk_flags & flags) == 0) 13203e9c6c1SJohn Dyson return 0; 13303e9c6c1SJohn Dyson } 13499c9d349SAlan Cox #endif 13503e9c6c1SJohn Dyson return 1; 13603e9c6c1SJohn Dyson } 13753bf4bb2SPeter Wemm 13803e9c6c1SJohn Dyson static int 139c6964d3bSKirk McKusick acquire(struct lock **lkpp, int extflags, int wanted) { 140c6964d3bSKirk McKusick struct lock *lkp = *lkpp; 1419b2e5badSJohn Dyson int s, error; 14253bf4bb2SPeter Wemm 143c06394f5SJohn Baldwin CTR3(KTR_LOCK, 144ff381670SRobert Watson "acquire(): lkp == %p, extflags == 0x%x, wanted == 0x%x", 145a18b1f1dSJason Evans lkp, extflags, wanted); 146a18b1f1dSJason Evans 14703e9c6c1SJohn Dyson if ((extflags & LK_NOWAIT) && (lkp->lk_flags & wanted)) { 14803e9c6c1SJohn Dyson return EBUSY; 14903e9c6c1SJohn Dyson } 15053bf4bb2SPeter Wemm 15199448ed1SJohn Dyson if (((lkp->lk_flags | extflags) & LK_NOPAUSE) == 0) { 15203e9c6c1SJohn Dyson error = apause(lkp, wanted); 15303e9c6c1SJohn Dyson if (error == 0) 15403e9c6c1SJohn Dyson return 0; 15599448ed1SJohn Dyson } 15603e9c6c1SJohn Dyson 1579b2e5badSJohn Dyson s = splhigh(); 15803e9c6c1SJohn Dyson while ((lkp->lk_flags & wanted) != 0) { 15903e9c6c1SJohn Dyson lkp->lk_flags |= LK_WAIT_NONZERO; 16003e9c6c1SJohn Dyson lkp->lk_waitcount++; 16196fde7daSJake Burkholder error = msleep(lkp, lkp->lk_interlock, lkp->lk_prio, 16223b59018SMatthew Dillon lkp->lk_wmesg, 16323b59018SMatthew Dillon ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); 1649b2e5badSJohn Dyson if (lkp->lk_waitcount == 1) { 16503e9c6c1SJohn Dyson lkp->lk_flags &= ~LK_WAIT_NONZERO; 1669b2e5badSJohn Dyson lkp->lk_waitcount = 0; 1679b2e5badSJohn Dyson } else { 1689b2e5badSJohn Dyson lkp->lk_waitcount--; 1699b2e5badSJohn Dyson } 1709b2e5badSJohn Dyson if (error) { 1719b2e5badSJohn Dyson splx(s); 17203e9c6c1SJohn Dyson return error; 1739b2e5badSJohn Dyson } 17403e9c6c1SJohn Dyson if (extflags & LK_SLEEPFAIL) { 1759b2e5badSJohn Dyson splx(s); 17603e9c6c1SJohn Dyson return ENOLCK; 17703e9c6c1SJohn Dyson } 178c6964d3bSKirk McKusick if (lkp->lk_newlock != NULL) { 179c6964d3bSKirk McKusick mtx_lock(lkp->lk_newlock->lk_interlock); 180c6964d3bSKirk McKusick mtx_unlock(lkp->lk_interlock); 181c6964d3bSKirk McKusick if (lkp->lk_waitcount == 0) 182c6964d3bSKirk McKusick wakeup((void *)(&lkp->lk_newlock)); 183c6964d3bSKirk McKusick *lkpp = lkp = lkp->lk_newlock; 184c6964d3bSKirk McKusick } 18503e9c6c1SJohn Dyson } 1869b2e5badSJohn Dyson splx(s); 18703e9c6c1SJohn Dyson return 0; 18803e9c6c1SJohn Dyson } 18903e9c6c1SJohn Dyson 19053bf4bb2SPeter Wemm /* 19153bf4bb2SPeter Wemm * Set, change, or release a lock. 19253bf4bb2SPeter Wemm * 19353bf4bb2SPeter Wemm * Shared requests increment the shared count. Exclusive requests set the 19453bf4bb2SPeter Wemm * LK_WANT_EXCL flag (preventing further shared locks), and wait for already 19553bf4bb2SPeter Wemm * accepted shared locks and shared-to-exclusive upgrades to go away. 19653bf4bb2SPeter Wemm */ 19753bf4bb2SPeter Wemm int 19815a1057cSEivind Eklund #ifndef DEBUG_LOCKS 199b40ce416SJulian Elischer lockmgr(lkp, flags, interlkp, td) 20015a1057cSEivind Eklund #else 201b40ce416SJulian Elischer debuglockmgr(lkp, flags, interlkp, td, name, file, line) 20215a1057cSEivind Eklund #endif 203248fcb66SSteve Passe struct lock *lkp; 20453bf4bb2SPeter Wemm u_int flags; 205a18b1f1dSJason Evans struct mtx *interlkp; 206b40ce416SJulian Elischer struct thread *td; 20715a1057cSEivind Eklund #ifdef DEBUG_LOCKS 20815a1057cSEivind Eklund const char *name; /* Name of lock function */ 20915a1057cSEivind Eklund const char *file; /* Name of file call is from */ 21015a1057cSEivind Eklund int line; /* Line number in file */ 21115a1057cSEivind Eklund #endif 21253bf4bb2SPeter Wemm { 21353bf4bb2SPeter Wemm int error; 214822ded67SJulian Elischer struct thread *thr; 215635962afSJohn Baldwin int extflags, lockflags; 21653bf4bb2SPeter Wemm 217c06394f5SJohn Baldwin CTR5(KTR_LOCK, 218a18b1f1dSJason Evans "lockmgr(): lkp == %p (lk_wmesg == \"%s\"), flags == 0x%x, " 219b40ce416SJulian Elischer "interlkp == %p, td == %p", lkp, lkp->lk_wmesg, flags, interlkp, td); 220a18b1f1dSJason Evans 22153bf4bb2SPeter Wemm error = 0; 222b40ce416SJulian Elischer if (td == NULL) 223822ded67SJulian Elischer thr = LK_KERNPROC; 224891e0f24SJohn Dyson else 225822ded67SJulian Elischer thr = td; 22603e9c6c1SJohn Dyson 22717661e5aSJeff Roberson if ((flags & LK_INTERNAL) == 0) 2289ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 22998689e1eSAlfred Perlstein if (flags & LK_INTERLOCK) { 2306157b69fSAlfred Perlstein mtx_assert(interlkp, MA_OWNED | MA_NOTRECURSED); 2319ed346baSBosko Milekic mtx_unlock(interlkp); 23298689e1eSAlfred Perlstein } 23303e9c6c1SJohn Dyson 23417661e5aSJeff Roberson if ((flags & (LK_NOWAIT|LK_RELEASE)) == 0) 23526306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 23626306795SJohn Baldwin &lkp->lk_interlock->mtx_object, 23726306795SJohn Baldwin "Acquiring lockmgr lock \"%s\"", lkp->lk_wmesg); 23817661e5aSJeff Roberson 2393f085c22SJohn Baldwin if (panicstr != NULL) { 2403f085c22SJohn Baldwin mtx_unlock(lkp->lk_interlock); 2413f085c22SJohn Baldwin return (0); 2423f085c22SJohn Baldwin } 2433f085c22SJohn Baldwin 24453bf4bb2SPeter Wemm extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 24553bf4bb2SPeter Wemm 24653bf4bb2SPeter Wemm switch (flags & LK_TYPE_MASK) { 24753bf4bb2SPeter Wemm 24853bf4bb2SPeter Wemm case LK_SHARED: 249beef8a36SJulian Elischer /* 250beef8a36SJulian Elischer * If we are not the exclusive lock holder, we have to block 251beef8a36SJulian Elischer * while there is an exclusive lock holder or while an 252beef8a36SJulian Elischer * exclusive lock request or upgrade request is in progress. 253beef8a36SJulian Elischer * 254fa2a4d05STim J. Robbins * However, if TDP_DEADLKTREAT is set, we override exclusive 255beef8a36SJulian Elischer * lock requests or upgrade requests ( but not the exclusive 256beef8a36SJulian Elischer * lock itself ). 257beef8a36SJulian Elischer */ 258822ded67SJulian Elischer if (lkp->lk_lockholder != thr) { 259635962afSJohn Baldwin lockflags = LK_HAVE_EXCL; 260fa2a4d05STim J. Robbins if (td != NULL && !(td->td_pflags & TDP_DEADLKTREAT)) 261bce98419SJohn Baldwin lockflags |= LK_WANT_EXCL | LK_WANT_UPGRADE; 262c6964d3bSKirk McKusick error = acquire(&lkp, extflags, lockflags); 26353bf4bb2SPeter Wemm if (error) 26453bf4bb2SPeter Wemm break; 26503e9c6c1SJohn Dyson sharelock(lkp, 1); 2667181624aSJeff Roberson #if defined(DEBUG_LOCKS) 267822ded67SJulian Elischer lkp->lk_slockholder = thr; 2687181624aSJeff Roberson lkp->lk_sfilename = file; 2697181624aSJeff Roberson lkp->lk_slineno = line; 2707181624aSJeff Roberson lkp->lk_slockername = name; 2717181624aSJeff Roberson #endif 27253bf4bb2SPeter Wemm break; 27353bf4bb2SPeter Wemm } 27453bf4bb2SPeter Wemm /* 27553bf4bb2SPeter Wemm * We hold an exclusive lock, so downgrade it to shared. 27653bf4bb2SPeter Wemm * An alternative would be to fail with EDEADLK. 27753bf4bb2SPeter Wemm */ 27803e9c6c1SJohn Dyson sharelock(lkp, 1); 27993b0017fSPhilippe Charnier /* FALLTHROUGH downgrade */ 28053bf4bb2SPeter Wemm 28153bf4bb2SPeter Wemm case LK_DOWNGRADE: 282822ded67SJulian Elischer KASSERT(lkp->lk_lockholder == thr && lkp->lk_exclusivecount != 0, 2831375ed7eSAlfred Perlstein ("lockmgr: not holding exclusive lock " 284822ded67SJulian Elischer "(owner thread (%p) != thread (%p), exlcnt (%d) != 0", 285822ded67SJulian Elischer lkp->lk_lockholder, thr, lkp->lk_exclusivecount)); 28603e9c6c1SJohn Dyson sharelock(lkp, lkp->lk_exclusivecount); 28753bf4bb2SPeter Wemm lkp->lk_exclusivecount = 0; 28853bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_HAVE_EXCL; 2896f8132a8SJulian Elischer lkp->lk_lockholder = LK_NOPROC; 29053bf4bb2SPeter Wemm if (lkp->lk_waitcount) 29153bf4bb2SPeter Wemm wakeup((void *)lkp); 29253bf4bb2SPeter Wemm break; 29353bf4bb2SPeter Wemm 29453bf4bb2SPeter Wemm case LK_EXCLUPGRADE: 29553bf4bb2SPeter Wemm /* 29653bf4bb2SPeter Wemm * If another process is ahead of us to get an upgrade, 29753bf4bb2SPeter Wemm * then we want to fail rather than have an intervening 29853bf4bb2SPeter Wemm * exclusive access. 29953bf4bb2SPeter Wemm */ 30053bf4bb2SPeter Wemm if (lkp->lk_flags & LK_WANT_UPGRADE) { 30103e9c6c1SJohn Dyson shareunlock(lkp, 1); 30253bf4bb2SPeter Wemm error = EBUSY; 30353bf4bb2SPeter Wemm break; 30453bf4bb2SPeter Wemm } 30593b0017fSPhilippe Charnier /* FALLTHROUGH normal upgrade */ 30653bf4bb2SPeter Wemm 30753bf4bb2SPeter Wemm case LK_UPGRADE: 30853bf4bb2SPeter Wemm /* 30953bf4bb2SPeter Wemm * Upgrade a shared lock to an exclusive one. If another 31053bf4bb2SPeter Wemm * shared lock has already requested an upgrade to an 31153bf4bb2SPeter Wemm * exclusive lock, our shared lock is released and an 31253bf4bb2SPeter Wemm * exclusive lock is requested (which will be granted 31353bf4bb2SPeter Wemm * after the upgrade). If we return an error, the file 31453bf4bb2SPeter Wemm * will always be unlocked. 31553bf4bb2SPeter Wemm */ 316822ded67SJulian Elischer if ((lkp->lk_lockholder == thr) || (lkp->lk_sharecount <= 0)) 31753bf4bb2SPeter Wemm panic("lockmgr: upgrade exclusive lock"); 31803e9c6c1SJohn Dyson shareunlock(lkp, 1); 31953bf4bb2SPeter Wemm /* 32053bf4bb2SPeter Wemm * If we are just polling, check to see if we will block. 32153bf4bb2SPeter Wemm */ 32253bf4bb2SPeter Wemm if ((extflags & LK_NOWAIT) && 32353bf4bb2SPeter Wemm ((lkp->lk_flags & LK_WANT_UPGRADE) || 32453bf4bb2SPeter Wemm lkp->lk_sharecount > 1)) { 32553bf4bb2SPeter Wemm error = EBUSY; 32653bf4bb2SPeter Wemm break; 32753bf4bb2SPeter Wemm } 32853bf4bb2SPeter Wemm if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) { 32953bf4bb2SPeter Wemm /* 33053bf4bb2SPeter Wemm * We are first shared lock to request an upgrade, so 33153bf4bb2SPeter Wemm * request upgrade and wait for the shared count to 33253bf4bb2SPeter Wemm * drop to zero, then take exclusive lock. 33353bf4bb2SPeter Wemm */ 33453bf4bb2SPeter Wemm lkp->lk_flags |= LK_WANT_UPGRADE; 335c6964d3bSKirk McKusick error = acquire(&lkp, extflags, LK_SHARE_NONZERO); 33653bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WANT_UPGRADE; 3379b2e5badSJohn Dyson 3384cef6d5aSAlexander Kabaev if (error) { 3394cef6d5aSAlexander Kabaev if ((lkp->lk_flags & ( LK_WANT_EXCL | LK_WAIT_NONZERO)) == (LK_WANT_EXCL | LK_WAIT_NONZERO)) 3404cef6d5aSAlexander Kabaev wakeup((void *)lkp); 34153bf4bb2SPeter Wemm break; 3424cef6d5aSAlexander Kabaev } 34353bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) 34453bf4bb2SPeter Wemm panic("lockmgr: non-zero exclusive count"); 345d8b8e875SPaul Saab lkp->lk_flags |= LK_HAVE_EXCL; 346d8b8e875SPaul Saab lkp->lk_lockholder = thr; 34753bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 34815a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 34915a1057cSEivind Eklund lkp->lk_filename = file; 35015a1057cSEivind Eklund lkp->lk_lineno = line; 35115a1057cSEivind Eklund lkp->lk_lockername = name; 35215a1057cSEivind Eklund #endif 35353bf4bb2SPeter Wemm break; 35453bf4bb2SPeter Wemm } 35553bf4bb2SPeter Wemm /* 35653bf4bb2SPeter Wemm * Someone else has requested upgrade. Release our shared 35753bf4bb2SPeter Wemm * lock, awaken upgrade requestor if we are the last shared 35853bf4bb2SPeter Wemm * lock, then request an exclusive lock. 35953bf4bb2SPeter Wemm */ 36003e9c6c1SJohn Dyson if ( (lkp->lk_flags & (LK_SHARE_NONZERO|LK_WAIT_NONZERO)) == 36103e9c6c1SJohn Dyson LK_WAIT_NONZERO) 36253bf4bb2SPeter Wemm wakeup((void *)lkp); 36393b0017fSPhilippe Charnier /* FALLTHROUGH exclusive request */ 36453bf4bb2SPeter Wemm 36553bf4bb2SPeter Wemm case LK_EXCLUSIVE: 366822ded67SJulian Elischer if (lkp->lk_lockholder == thr && thr != LK_KERNPROC) { 36753bf4bb2SPeter Wemm /* 36853bf4bb2SPeter Wemm * Recursive lock. 36953bf4bb2SPeter Wemm */ 37033638e93SKirk McKusick if ((extflags & (LK_NOWAIT | LK_CANRECURSE)) == 0) 37153bf4bb2SPeter Wemm panic("lockmgr: locking against myself"); 37233638e93SKirk McKusick if ((extflags & LK_CANRECURSE) != 0) { 37353bf4bb2SPeter Wemm lkp->lk_exclusivecount++; 37453bf4bb2SPeter Wemm break; 37553bf4bb2SPeter Wemm } 37633638e93SKirk McKusick } 37753bf4bb2SPeter Wemm /* 37853bf4bb2SPeter Wemm * If we are just polling, check to see if we will sleep. 37953bf4bb2SPeter Wemm */ 38003e9c6c1SJohn Dyson if ((extflags & LK_NOWAIT) && 38103e9c6c1SJohn Dyson (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO))) { 38253bf4bb2SPeter Wemm error = EBUSY; 38353bf4bb2SPeter Wemm break; 38453bf4bb2SPeter Wemm } 38553bf4bb2SPeter Wemm /* 38653bf4bb2SPeter Wemm * Try to acquire the want_exclusive flag. 38753bf4bb2SPeter Wemm */ 388cffdaf2dSAlexander Kabaev error = acquire(&lkp, extflags, (LK_HAVE_EXCL | LK_WANT_EXCL)); 38953bf4bb2SPeter Wemm if (error) 39053bf4bb2SPeter Wemm break; 39153bf4bb2SPeter Wemm lkp->lk_flags |= LK_WANT_EXCL; 39253bf4bb2SPeter Wemm /* 39353bf4bb2SPeter Wemm * Wait for shared locks and upgrades to finish. 39453bf4bb2SPeter Wemm */ 3954cef6d5aSAlexander Kabaev error = acquire(&lkp, extflags, LK_HAVE_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO); 39653bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WANT_EXCL; 3974cef6d5aSAlexander Kabaev if (error) { 3984cef6d5aSAlexander Kabaev if (lkp->lk_flags & LK_WAIT_NONZERO) 3994cef6d5aSAlexander Kabaev wakeup((void *)lkp); 40053bf4bb2SPeter Wemm break; 4014cef6d5aSAlexander Kabaev } 40253bf4bb2SPeter Wemm lkp->lk_flags |= LK_HAVE_EXCL; 403822ded67SJulian Elischer lkp->lk_lockholder = thr; 40453bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) 40553bf4bb2SPeter Wemm panic("lockmgr: non-zero exclusive count"); 40653bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 40715a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 40815a1057cSEivind Eklund lkp->lk_filename = file; 40915a1057cSEivind Eklund lkp->lk_lineno = line; 41015a1057cSEivind Eklund lkp->lk_lockername = name; 41115a1057cSEivind Eklund #endif 41253bf4bb2SPeter Wemm break; 41353bf4bb2SPeter Wemm 41453bf4bb2SPeter Wemm case LK_RELEASE: 41553bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) { 416822ded67SJulian Elischer if (lkp->lk_lockholder != thr && 417e701df7dSMatthew Dillon lkp->lk_lockholder != LK_KERNPROC) { 418822ded67SJulian Elischer panic("lockmgr: thread %p, not %s %p unlocking", 419822ded67SJulian Elischer thr, "exclusive lock holder", 42053bf4bb2SPeter Wemm lkp->lk_lockholder); 421e701df7dSMatthew Dillon } 4229b2e5badSJohn Dyson if (lkp->lk_exclusivecount == 1) { 42353bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_HAVE_EXCL; 42453bf4bb2SPeter Wemm lkp->lk_lockholder = LK_NOPROC; 4259b2e5badSJohn Dyson lkp->lk_exclusivecount = 0; 4269b2e5badSJohn Dyson } else { 4279b2e5badSJohn Dyson lkp->lk_exclusivecount--; 42853bf4bb2SPeter Wemm } 4291b367556SJason Evans } else if (lkp->lk_flags & LK_SHARE_NONZERO) 43003e9c6c1SJohn Dyson shareunlock(lkp, 1); 43103e9c6c1SJohn Dyson if (lkp->lk_flags & LK_WAIT_NONZERO) 43253bf4bb2SPeter Wemm wakeup((void *)lkp); 43353bf4bb2SPeter Wemm break; 43453bf4bb2SPeter Wemm 43553bf4bb2SPeter Wemm case LK_DRAIN: 43653bf4bb2SPeter Wemm /* 43753bf4bb2SPeter Wemm * Check that we do not already hold the lock, as it can 43853bf4bb2SPeter Wemm * never drain if we do. Unfortunately, we have no way to 43953bf4bb2SPeter Wemm * check for holding a shared lock, but at least we can 44053bf4bb2SPeter Wemm * check for an exclusive one. 44153bf4bb2SPeter Wemm */ 442822ded67SJulian Elischer if (lkp->lk_lockholder == thr) 44353bf4bb2SPeter Wemm panic("lockmgr: draining against myself"); 44403e9c6c1SJohn Dyson 44503e9c6c1SJohn Dyson error = acquiredrain(lkp, extflags); 44603e9c6c1SJohn Dyson if (error) 44753bf4bb2SPeter Wemm break; 44853bf4bb2SPeter Wemm lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL; 449822ded67SJulian Elischer lkp->lk_lockholder = thr; 45053bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 45115a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 45215a1057cSEivind Eklund lkp->lk_filename = file; 45315a1057cSEivind Eklund lkp->lk_lineno = line; 45415a1057cSEivind Eklund lkp->lk_lockername = name; 45515a1057cSEivind Eklund #endif 45653bf4bb2SPeter Wemm break; 45753bf4bb2SPeter Wemm 45853bf4bb2SPeter Wemm default: 4599ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 46053bf4bb2SPeter Wemm panic("lockmgr: unknown locktype request %d", 46153bf4bb2SPeter Wemm flags & LK_TYPE_MASK); 46253bf4bb2SPeter Wemm /* NOTREACHED */ 46353bf4bb2SPeter Wemm } 46403e9c6c1SJohn Dyson if ((lkp->lk_flags & LK_WAITDRAIN) && 46503e9c6c1SJohn Dyson (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | 46603e9c6c1SJohn Dyson LK_SHARE_NONZERO | LK_WAIT_NONZERO)) == 0) { 46753bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WAITDRAIN; 46853bf4bb2SPeter Wemm wakeup((void *)&lkp->lk_flags); 46953bf4bb2SPeter Wemm } 4709ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 47153bf4bb2SPeter Wemm return (error); 47253bf4bb2SPeter Wemm } 47353bf4bb2SPeter Wemm 47499448ed1SJohn Dyson static int 47599448ed1SJohn Dyson acquiredrain(struct lock *lkp, int extflags) { 47699448ed1SJohn Dyson int error; 47799448ed1SJohn Dyson 47899448ed1SJohn Dyson if ((extflags & LK_NOWAIT) && (lkp->lk_flags & LK_ALL)) { 47999448ed1SJohn Dyson return EBUSY; 48099448ed1SJohn Dyson } 48199448ed1SJohn Dyson 48299448ed1SJohn Dyson error = apause(lkp, LK_ALL); 48399448ed1SJohn Dyson if (error == 0) 48499448ed1SJohn Dyson return 0; 48599448ed1SJohn Dyson 48699448ed1SJohn Dyson while (lkp->lk_flags & LK_ALL) { 48799448ed1SJohn Dyson lkp->lk_flags |= LK_WAITDRAIN; 48896fde7daSJake Burkholder error = msleep(&lkp->lk_flags, lkp->lk_interlock, lkp->lk_prio, 48923b59018SMatthew Dillon lkp->lk_wmesg, 49023b59018SMatthew Dillon ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); 49199448ed1SJohn Dyson if (error) 49299448ed1SJohn Dyson return error; 49399448ed1SJohn Dyson if (extflags & LK_SLEEPFAIL) { 49499448ed1SJohn Dyson return ENOLCK; 49599448ed1SJohn Dyson } 49699448ed1SJohn Dyson } 49799448ed1SJohn Dyson return 0; 49899448ed1SJohn Dyson } 49999448ed1SJohn Dyson 50099448ed1SJohn Dyson /* 501c6964d3bSKirk McKusick * Transfer any waiting processes from one lock to another. 502c6964d3bSKirk McKusick */ 503c6964d3bSKirk McKusick void 504c6964d3bSKirk McKusick transferlockers(from, to) 505c6964d3bSKirk McKusick struct lock *from; 506c6964d3bSKirk McKusick struct lock *to; 507c6964d3bSKirk McKusick { 508c6964d3bSKirk McKusick 509c6964d3bSKirk McKusick KASSERT(from != to, ("lock transfer to self")); 510c6964d3bSKirk McKusick KASSERT((from->lk_flags&LK_WAITDRAIN) == 0, ("transfer draining lock")); 511c6964d3bSKirk McKusick if (from->lk_waitcount == 0) 512c6964d3bSKirk McKusick return; 513c6964d3bSKirk McKusick from->lk_newlock = to; 514c6964d3bSKirk McKusick wakeup((void *)from); 515c6964d3bSKirk McKusick msleep(&from->lk_newlock, NULL, from->lk_prio, "lkxfer", 0); 516c6964d3bSKirk McKusick from->lk_newlock = NULL; 517c6964d3bSKirk McKusick from->lk_flags &= ~(LK_WANT_EXCL | LK_WANT_UPGRADE); 518c6964d3bSKirk McKusick KASSERT(from->lk_waitcount == 0, ("active lock")); 519c6964d3bSKirk McKusick } 520c6964d3bSKirk McKusick 521c6964d3bSKirk McKusick 522c6964d3bSKirk McKusick /* 52399448ed1SJohn Dyson * Initialize a lock; required before use. 52499448ed1SJohn Dyson */ 52599448ed1SJohn Dyson void 52699448ed1SJohn Dyson lockinit(lkp, prio, wmesg, timo, flags) 52799448ed1SJohn Dyson struct lock *lkp; 52899448ed1SJohn Dyson int prio; 52904858e7eSEivind Eklund const char *wmesg; 53099448ed1SJohn Dyson int timo; 53199448ed1SJohn Dyson int flags; 53299448ed1SJohn Dyson { 533c06394f5SJohn Baldwin CTR5(KTR_LOCK, "lockinit(): lkp == %p, prio == %d, wmesg == \"%s\", " 534a18b1f1dSJason Evans "timo == %d, flags = 0x%x\n", lkp, prio, wmesg, timo, flags); 53599448ed1SJohn Dyson 536857d9c60SDon Lewis lkp->lk_interlock = mtx_pool_alloc(mtxpool_lockbuilder); 5379722d88fSJason Evans lkp->lk_flags = (flags & LK_EXTFLG_MASK); 53899448ed1SJohn Dyson lkp->lk_sharecount = 0; 53999448ed1SJohn Dyson lkp->lk_waitcount = 0; 54099448ed1SJohn Dyson lkp->lk_exclusivecount = 0; 54199448ed1SJohn Dyson lkp->lk_prio = prio; 54299448ed1SJohn Dyson lkp->lk_wmesg = wmesg; 54399448ed1SJohn Dyson lkp->lk_timo = timo; 54499448ed1SJohn Dyson lkp->lk_lockholder = LK_NOPROC; 545c6964d3bSKirk McKusick lkp->lk_newlock = NULL; 5463a096f6cSKirk McKusick #ifdef DEBUG_LOCKS 5473a096f6cSKirk McKusick lkp->lk_filename = "none"; 5483a096f6cSKirk McKusick lkp->lk_lockername = "never exclusive locked"; 5493a096f6cSKirk McKusick lkp->lk_lineno = 0; 5503a096f6cSKirk McKusick lkp->lk_slockholder = LK_NOPROC; 5513a096f6cSKirk McKusick lkp->lk_sfilename = "none"; 5523a096f6cSKirk McKusick lkp->lk_slockername = "never share locked"; 5533a096f6cSKirk McKusick lkp->lk_slineno = 0; 5543a096f6cSKirk McKusick #endif 55599448ed1SJohn Dyson } 55699448ed1SJohn Dyson 55799448ed1SJohn Dyson /* 558a18b1f1dSJason Evans * Destroy a lock. 559a18b1f1dSJason Evans */ 560a18b1f1dSJason Evans void 561a18b1f1dSJason Evans lockdestroy(lkp) 562a18b1f1dSJason Evans struct lock *lkp; 563a18b1f1dSJason Evans { 564c06394f5SJohn Baldwin CTR2(KTR_LOCK, "lockdestroy(): lkp == %p (lk_wmesg == \"%s\")", 565a18b1f1dSJason Evans lkp, lkp->lk_wmesg); 566a18b1f1dSJason Evans } 567a18b1f1dSJason Evans 568a18b1f1dSJason Evans /* 56999448ed1SJohn Dyson * Determine the status of a lock. 57099448ed1SJohn Dyson */ 57199448ed1SJohn Dyson int 572b40ce416SJulian Elischer lockstatus(lkp, td) 57399448ed1SJohn Dyson struct lock *lkp; 574b40ce416SJulian Elischer struct thread *td; 57599448ed1SJohn Dyson { 57699448ed1SJohn Dyson int lock_type = 0; 57799448ed1SJohn Dyson 5789ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 5796bdfe06aSEivind Eklund if (lkp->lk_exclusivecount != 0) { 580822ded67SJulian Elischer if (td == NULL || lkp->lk_lockholder == td) 58199448ed1SJohn Dyson lock_type = LK_EXCLUSIVE; 5826bdfe06aSEivind Eklund else 5836bdfe06aSEivind Eklund lock_type = LK_EXCLOTHER; 5846bdfe06aSEivind Eklund } else if (lkp->lk_sharecount != 0) 58599448ed1SJohn Dyson lock_type = LK_SHARED; 5869ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 58799448ed1SJohn Dyson return (lock_type); 58899448ed1SJohn Dyson } 58999448ed1SJohn Dyson 59053bf4bb2SPeter Wemm /* 59167812eacSKirk McKusick * Determine the number of holders of a lock. 59267812eacSKirk McKusick */ 59367812eacSKirk McKusick int 59467812eacSKirk McKusick lockcount(lkp) 59567812eacSKirk McKusick struct lock *lkp; 59667812eacSKirk McKusick { 59767812eacSKirk McKusick int count; 59867812eacSKirk McKusick 5999ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 60067812eacSKirk McKusick count = lkp->lk_exclusivecount + lkp->lk_sharecount; 6019ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 60267812eacSKirk McKusick return (count); 60367812eacSKirk McKusick } 60467812eacSKirk McKusick 60567812eacSKirk McKusick /* 60653bf4bb2SPeter Wemm * Print out information about state of a lock. Used by VOP_PRINT 6070e61ac7bSPoul-Henning Kamp * routines to display status about contained locks. 60853bf4bb2SPeter Wemm */ 609a1ce9d5cSPeter Wemm void 61053bf4bb2SPeter Wemm lockmgr_printinfo(lkp) 61153bf4bb2SPeter Wemm struct lock *lkp; 61253bf4bb2SPeter Wemm { 61353bf4bb2SPeter Wemm 61453bf4bb2SPeter Wemm if (lkp->lk_sharecount) 61553bf4bb2SPeter Wemm printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg, 61653bf4bb2SPeter Wemm lkp->lk_sharecount); 61753bf4bb2SPeter Wemm else if (lkp->lk_flags & LK_HAVE_EXCL) 618c969c60cSAlexander Kabaev printf(" lock type %s: EXCL (count %d) by thread %p (pid %d)", 619c969c60cSAlexander Kabaev lkp->lk_wmesg, lkp->lk_exclusivecount, 620c969c60cSAlexander Kabaev lkp->lk_lockholder, lkp->lk_lockholder->td_proc->p_pid); 62153bf4bb2SPeter Wemm if (lkp->lk_waitcount > 0) 62253bf4bb2SPeter Wemm printf(" with %d pending", lkp->lk_waitcount); 62353bf4bb2SPeter Wemm } 624