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 46be6847d7SJohn Baldwin #include "opt_ddb.h" 477c0435b9SKip Macy #include "opt_global.h" 48be6847d7SJohn Baldwin 4953bf4bb2SPeter Wemm #include <sys/param.h> 50c30bf5c3SRobert Watson #include <sys/kdb.h> 519722d88fSJason Evans #include <sys/kernel.h> 5261d80e90SJohn Baldwin #include <sys/ktr.h> 5353bf4bb2SPeter Wemm #include <sys/lock.h> 548302d183SBruce Evans #include <sys/lockmgr.h> 55d8881ca3SJohn Baldwin #include <sys/mutex.h> 568302d183SBruce Evans #include <sys/proc.h> 574bdb9b11SPeter Wemm #include <sys/systm.h> 587c0435b9SKip Macy #include <sys/lock_profile.h> 59e8ddb61dSJeff Roberson #ifdef DEBUG_LOCKS 60e8ddb61dSJeff Roberson #include <sys/stack.h> 61e8ddb61dSJeff Roberson #endif 6253bf4bb2SPeter Wemm 63be6847d7SJohn Baldwin #ifdef DDB 64be6847d7SJohn Baldwin #include <ddb/ddb.h> 6561bd5e21SKip Macy static void db_show_lockmgr(struct lock_object *lock); 66be6847d7SJohn Baldwin #endif 67be6847d7SJohn Baldwin 6861bd5e21SKip Macy 6961bd5e21SKip Macy struct lock_class lock_class_lockmgr = { 703ff6d229SJohn Baldwin .lc_name = "lockmgr", 713ff6d229SJohn Baldwin .lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE, 7261bd5e21SKip Macy #ifdef DDB 733ff6d229SJohn Baldwin .lc_ddb_show = db_show_lockmgr 7461bd5e21SKip Macy #endif 7561bd5e21SKip Macy }; 7661bd5e21SKip Macy 7761bd5e21SKip Macy 7853bf4bb2SPeter Wemm /* 7953bf4bb2SPeter Wemm * Locking primitives implementation. 8053bf4bb2SPeter Wemm * Locks provide shared/exclusive sychronization. 8153bf4bb2SPeter Wemm */ 8253bf4bb2SPeter Wemm 83f158df07SJeff Roberson #define COUNT(td, x) if ((td)) (td)->td_locks += (x) 8499448ed1SJohn Dyson #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \ 8599448ed1SJohn Dyson LK_SHARE_NONZERO | LK_WAIT_NONZERO) 8699448ed1SJohn Dyson 87fe68a916SKip Macy static int acquire(struct lock **lkpp, int extflags, int wanted, int *contested, uint64_t *waittime); 8899448ed1SJohn Dyson static int acquiredrain(struct lock *lkp, int extflags) ; 8903e9c6c1SJohn Dyson 90a96ab770SJeff Roberson static __inline void 91f158df07SJeff Roberson sharelock(struct thread *td, struct lock *lkp, int incr) { 9203e9c6c1SJohn Dyson lkp->lk_flags |= LK_SHARE_NONZERO; 9303e9c6c1SJohn Dyson lkp->lk_sharecount += incr; 94f158df07SJeff Roberson COUNT(td, incr); 9503e9c6c1SJohn Dyson } 9603e9c6c1SJohn Dyson 97a96ab770SJeff Roberson static __inline void 98f158df07SJeff Roberson shareunlock(struct thread *td, struct lock *lkp, int decr) { 99219cbf59SEivind Eklund 1005526d2d9SEivind Eklund KASSERT(lkp->lk_sharecount >= decr, ("shareunlock: count < decr")); 10103e9c6c1SJohn Dyson 102f158df07SJeff Roberson COUNT(td, -decr); 1039b2e5badSJohn Dyson if (lkp->lk_sharecount == decr) { 10403e9c6c1SJohn Dyson lkp->lk_flags &= ~LK_SHARE_NONZERO; 1059b2e5badSJohn Dyson if (lkp->lk_flags & (LK_WANT_UPGRADE | LK_WANT_EXCL)) { 1069b2e5badSJohn Dyson wakeup(lkp); 1079b2e5badSJohn Dyson } 1089b2e5badSJohn Dyson lkp->lk_sharecount = 0; 1099b2e5badSJohn Dyson } else { 1109b2e5badSJohn Dyson lkp->lk_sharecount -= decr; 1119b2e5badSJohn Dyson } 11203e9c6c1SJohn Dyson } 11303e9c6c1SJohn Dyson 11403e9c6c1SJohn Dyson static int 115fe68a916SKip Macy acquire(struct lock **lkpp, int extflags, int wanted, int *contested, uint64_t *waittime) 11641bd6c15SJeff Roberson { 117c6964d3bSKirk McKusick struct lock *lkp = *lkpp; 11820728d8fSJeff Roberson int error; 119c06394f5SJohn Baldwin CTR3(KTR_LOCK, 120ff381670SRobert Watson "acquire(): lkp == %p, extflags == 0x%x, wanted == 0x%x", 121a18b1f1dSJason Evans lkp, extflags, wanted); 122a18b1f1dSJason Evans 12320728d8fSJeff Roberson if ((extflags & LK_NOWAIT) && (lkp->lk_flags & wanted)) 12403e9c6c1SJohn Dyson return EBUSY; 12520728d8fSJeff Roberson error = 0; 126fe68a916SKip Macy if ((lkp->lk_flags & wanted) != 0) 127fe68a916SKip Macy lock_profile_obtain_lock_failed(&lkp->lk_object, contested, waittime); 128fe68a916SKip Macy 12903e9c6c1SJohn Dyson while ((lkp->lk_flags & wanted) != 0) { 13020728d8fSJeff Roberson CTR2(KTR_LOCK, 13120728d8fSJeff Roberson "acquire(): lkp == %p, lk_flags == 0x%x sleeping", 13220728d8fSJeff Roberson lkp, lkp->lk_flags); 13303e9c6c1SJohn Dyson lkp->lk_flags |= LK_WAIT_NONZERO; 13403e9c6c1SJohn Dyson lkp->lk_waitcount++; 13596fde7daSJake Burkholder error = msleep(lkp, lkp->lk_interlock, lkp->lk_prio, 13623b59018SMatthew Dillon lkp->lk_wmesg, 13723b59018SMatthew Dillon ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); 1389b2e5badSJohn Dyson lkp->lk_waitcount--; 13920728d8fSJeff Roberson if (lkp->lk_waitcount == 0) 14020728d8fSJeff Roberson lkp->lk_flags &= ~LK_WAIT_NONZERO; 14120728d8fSJeff Roberson if (error) 14220728d8fSJeff Roberson break; 14303e9c6c1SJohn Dyson if (extflags & LK_SLEEPFAIL) { 14420728d8fSJeff Roberson error = ENOLCK; 14520728d8fSJeff Roberson break; 14603e9c6c1SJohn Dyson } 147c6964d3bSKirk McKusick if (lkp->lk_newlock != NULL) { 148c6964d3bSKirk McKusick mtx_lock(lkp->lk_newlock->lk_interlock); 149c6964d3bSKirk McKusick mtx_unlock(lkp->lk_interlock); 150c6964d3bSKirk McKusick if (lkp->lk_waitcount == 0) 151c6964d3bSKirk McKusick wakeup((void *)(&lkp->lk_newlock)); 152c6964d3bSKirk McKusick *lkpp = lkp = lkp->lk_newlock; 153c6964d3bSKirk McKusick } 15403e9c6c1SJohn Dyson } 15520728d8fSJeff Roberson mtx_assert(lkp->lk_interlock, MA_OWNED); 15620728d8fSJeff Roberson return (error); 15703e9c6c1SJohn Dyson } 15803e9c6c1SJohn Dyson 15953bf4bb2SPeter Wemm /* 16053bf4bb2SPeter Wemm * Set, change, or release a lock. 16153bf4bb2SPeter Wemm * 16253bf4bb2SPeter Wemm * Shared requests increment the shared count. Exclusive requests set the 16353bf4bb2SPeter Wemm * LK_WANT_EXCL flag (preventing further shared locks), and wait for already 16453bf4bb2SPeter Wemm * accepted shared locks and shared-to-exclusive upgrades to go away. 16553bf4bb2SPeter Wemm */ 16653bf4bb2SPeter Wemm int 1677c0435b9SKip Macy _lockmgr(struct lock *lkp, int flags, struct mtx *interlkp, 1687c0435b9SKip Macy struct thread *td, char *file, int line) 1697c0435b9SKip Macy 17053bf4bb2SPeter Wemm { 17153bf4bb2SPeter Wemm int error; 172822ded67SJulian Elischer struct thread *thr; 173635962afSJohn Baldwin int extflags, lockflags; 174fe68a916SKip Macy int contested = 0; 175fe68a916SKip Macy uint64_t waitstart = 0; 17653bf4bb2SPeter Wemm 17753bf4bb2SPeter Wemm error = 0; 178b40ce416SJulian Elischer if (td == NULL) 179822ded67SJulian Elischer thr = LK_KERNPROC; 180891e0f24SJohn Dyson else 181822ded67SJulian Elischer thr = td; 18203e9c6c1SJohn Dyson 18317661e5aSJeff Roberson if ((flags & LK_INTERNAL) == 0) 1849ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 18541bd6c15SJeff Roberson CTR6(KTR_LOCK, 18641bd6c15SJeff Roberson "lockmgr(): lkp == %p (lk_wmesg == \"%s\"), owner == %p, exclusivecount == %d, flags == 0x%x, " 18741bd6c15SJeff Roberson "td == %p", lkp, lkp->lk_wmesg, lkp->lk_lockholder, 18841bd6c15SJeff Roberson lkp->lk_exclusivecount, flags, td); 189e8ddb61dSJeff Roberson #ifdef DEBUG_LOCKS 190e8ddb61dSJeff Roberson { 191e8ddb61dSJeff Roberson struct stack stack; /* XXX */ 192e8ddb61dSJeff Roberson stack_save(&stack); 193e37a4994SPawel Jakub Dawidek CTRSTACK(KTR_LOCK, &stack, 0, 1); 194e8ddb61dSJeff Roberson } 19541bd6c15SJeff Roberson #endif 19641bd6c15SJeff Roberson 19798689e1eSAlfred Perlstein if (flags & LK_INTERLOCK) { 1986157b69fSAlfred Perlstein mtx_assert(interlkp, MA_OWNED | MA_NOTRECURSED); 1999ed346baSBosko Milekic mtx_unlock(interlkp); 20098689e1eSAlfred Perlstein } 20103e9c6c1SJohn Dyson 20217661e5aSJeff Roberson if ((flags & (LK_NOWAIT|LK_RELEASE)) == 0) 20326306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 20426306795SJohn Baldwin &lkp->lk_interlock->mtx_object, 20526306795SJohn Baldwin "Acquiring lockmgr lock \"%s\"", lkp->lk_wmesg); 20617661e5aSJeff Roberson 2073f085c22SJohn Baldwin if (panicstr != NULL) { 2083f085c22SJohn Baldwin mtx_unlock(lkp->lk_interlock); 2093f085c22SJohn Baldwin return (0); 2103f085c22SJohn Baldwin } 211c4c0ec5bSJeff Roberson if ((lkp->lk_flags & LK_NOSHARE) && 212c4c0ec5bSJeff Roberson (flags & LK_TYPE_MASK) == LK_SHARED) { 213c4c0ec5bSJeff Roberson flags &= ~LK_TYPE_MASK; 214c4c0ec5bSJeff Roberson flags |= LK_EXCLUSIVE; 215c4c0ec5bSJeff Roberson } 21653bf4bb2SPeter Wemm extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 21753bf4bb2SPeter Wemm 21853bf4bb2SPeter Wemm switch (flags & LK_TYPE_MASK) { 21953bf4bb2SPeter Wemm 22053bf4bb2SPeter Wemm case LK_SHARED: 221beef8a36SJulian Elischer /* 222beef8a36SJulian Elischer * If we are not the exclusive lock holder, we have to block 223beef8a36SJulian Elischer * while there is an exclusive lock holder or while an 224beef8a36SJulian Elischer * exclusive lock request or upgrade request is in progress. 225beef8a36SJulian Elischer * 226fa2a4d05STim J. Robbins * However, if TDP_DEADLKTREAT is set, we override exclusive 227beef8a36SJulian Elischer * lock requests or upgrade requests ( but not the exclusive 228beef8a36SJulian Elischer * lock itself ). 229beef8a36SJulian Elischer */ 230822ded67SJulian Elischer if (lkp->lk_lockholder != thr) { 231635962afSJohn Baldwin lockflags = LK_HAVE_EXCL; 232fa2a4d05STim J. Robbins if (td != NULL && !(td->td_pflags & TDP_DEADLKTREAT)) 233bce98419SJohn Baldwin lockflags |= LK_WANT_EXCL | LK_WANT_UPGRADE; 234fe68a916SKip Macy error = acquire(&lkp, extflags, lockflags, &contested, &waitstart); 23553bf4bb2SPeter Wemm if (error) 23653bf4bb2SPeter Wemm break; 237f158df07SJeff Roberson sharelock(td, lkp, 1); 2387c0435b9SKip Macy if (lkp->lk_sharecount == 1) 239fe68a916SKip Macy lock_profile_obtain_lock_success(&lkp->lk_object, contested, waitstart, file, line); 2407c0435b9SKip Macy 2417181624aSJeff Roberson #if defined(DEBUG_LOCKS) 2427499fd8dSJeff Roberson stack_save(&lkp->lk_stack); 2437181624aSJeff Roberson #endif 24453bf4bb2SPeter Wemm break; 24553bf4bb2SPeter Wemm } 24653bf4bb2SPeter Wemm /* 24753bf4bb2SPeter Wemm * We hold an exclusive lock, so downgrade it to shared. 24853bf4bb2SPeter Wemm * An alternative would be to fail with EDEADLK. 24953bf4bb2SPeter Wemm */ 250f158df07SJeff Roberson sharelock(td, lkp, 1); 2517c0435b9SKip Macy if (lkp->lk_sharecount == 1) 252fe68a916SKip Macy lock_profile_obtain_lock_success(&lkp->lk_object, contested, waitstart, file, line); 25393b0017fSPhilippe Charnier /* FALLTHROUGH downgrade */ 25453bf4bb2SPeter Wemm 25553bf4bb2SPeter Wemm case LK_DOWNGRADE: 256822ded67SJulian Elischer KASSERT(lkp->lk_lockholder == thr && lkp->lk_exclusivecount != 0, 2571375ed7eSAlfred Perlstein ("lockmgr: not holding exclusive lock " 258822ded67SJulian Elischer "(owner thread (%p) != thread (%p), exlcnt (%d) != 0", 259822ded67SJulian Elischer lkp->lk_lockholder, thr, lkp->lk_exclusivecount)); 260f158df07SJeff Roberson sharelock(td, lkp, lkp->lk_exclusivecount); 261f158df07SJeff Roberson COUNT(td, -lkp->lk_exclusivecount); 26253bf4bb2SPeter Wemm lkp->lk_exclusivecount = 0; 26353bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_HAVE_EXCL; 2646f8132a8SJulian Elischer lkp->lk_lockholder = LK_NOPROC; 26553bf4bb2SPeter Wemm if (lkp->lk_waitcount) 26653bf4bb2SPeter Wemm wakeup((void *)lkp); 26753bf4bb2SPeter Wemm break; 26853bf4bb2SPeter Wemm 26953bf4bb2SPeter Wemm case LK_EXCLUPGRADE: 27053bf4bb2SPeter Wemm /* 27153bf4bb2SPeter Wemm * If another process is ahead of us to get an upgrade, 27253bf4bb2SPeter Wemm * then we want to fail rather than have an intervening 27353bf4bb2SPeter Wemm * exclusive access. 27453bf4bb2SPeter Wemm */ 27553bf4bb2SPeter Wemm if (lkp->lk_flags & LK_WANT_UPGRADE) { 276f158df07SJeff Roberson shareunlock(td, lkp, 1); 27753bf4bb2SPeter Wemm error = EBUSY; 27853bf4bb2SPeter Wemm break; 27953bf4bb2SPeter Wemm } 28093b0017fSPhilippe Charnier /* FALLTHROUGH normal upgrade */ 28153bf4bb2SPeter Wemm 28253bf4bb2SPeter Wemm case LK_UPGRADE: 28353bf4bb2SPeter Wemm /* 28453bf4bb2SPeter Wemm * Upgrade a shared lock to an exclusive one. If another 28553bf4bb2SPeter Wemm * shared lock has already requested an upgrade to an 28653bf4bb2SPeter Wemm * exclusive lock, our shared lock is released and an 28753bf4bb2SPeter Wemm * exclusive lock is requested (which will be granted 28853bf4bb2SPeter Wemm * after the upgrade). If we return an error, the file 28953bf4bb2SPeter Wemm * will always be unlocked. 29053bf4bb2SPeter Wemm */ 291436901a8SJeff Roberson if (lkp->lk_lockholder == thr) 29253bf4bb2SPeter Wemm panic("lockmgr: upgrade exclusive lock"); 293436901a8SJeff Roberson if (lkp->lk_sharecount <= 0) 294436901a8SJeff Roberson panic("lockmgr: upgrade without shared"); 295f158df07SJeff Roberson shareunlock(td, lkp, 1); 2967c0435b9SKip Macy if (lkp->lk_sharecount == 0) 2977c0435b9SKip Macy lock_profile_release_lock(&lkp->lk_object); 29853bf4bb2SPeter Wemm /* 29953bf4bb2SPeter Wemm * If we are just polling, check to see if we will block. 30053bf4bb2SPeter Wemm */ 30153bf4bb2SPeter Wemm if ((extflags & LK_NOWAIT) && 30253bf4bb2SPeter Wemm ((lkp->lk_flags & LK_WANT_UPGRADE) || 30353bf4bb2SPeter Wemm lkp->lk_sharecount > 1)) { 30453bf4bb2SPeter Wemm error = EBUSY; 30553bf4bb2SPeter Wemm break; 30653bf4bb2SPeter Wemm } 30753bf4bb2SPeter Wemm if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) { 30853bf4bb2SPeter Wemm /* 30953bf4bb2SPeter Wemm * We are first shared lock to request an upgrade, so 31053bf4bb2SPeter Wemm * request upgrade and wait for the shared count to 31153bf4bb2SPeter Wemm * drop to zero, then take exclusive lock. 31253bf4bb2SPeter Wemm */ 31353bf4bb2SPeter Wemm lkp->lk_flags |= LK_WANT_UPGRADE; 314fe68a916SKip Macy error = acquire(&lkp, extflags, LK_SHARE_NONZERO, &contested, &waitstart); 31553bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WANT_UPGRADE; 3169b2e5badSJohn Dyson 3174cef6d5aSAlexander Kabaev if (error) { 3184cef6d5aSAlexander Kabaev if ((lkp->lk_flags & ( LK_WANT_EXCL | LK_WAIT_NONZERO)) == (LK_WANT_EXCL | LK_WAIT_NONZERO)) 3194cef6d5aSAlexander Kabaev wakeup((void *)lkp); 32053bf4bb2SPeter Wemm break; 3214cef6d5aSAlexander Kabaev } 32253bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) 32353bf4bb2SPeter Wemm panic("lockmgr: non-zero exclusive count"); 324d8b8e875SPaul Saab lkp->lk_flags |= LK_HAVE_EXCL; 325d8b8e875SPaul Saab lkp->lk_lockholder = thr; 32653bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 327f158df07SJeff Roberson COUNT(td, 1); 328fe68a916SKip Macy lock_profile_obtain_lock_success(&lkp->lk_object, contested, waitstart, file, line); 32915a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 3307499fd8dSJeff Roberson stack_save(&lkp->lk_stack); 33115a1057cSEivind Eklund #endif 33253bf4bb2SPeter Wemm break; 33353bf4bb2SPeter Wemm } 33453bf4bb2SPeter Wemm /* 33553bf4bb2SPeter Wemm * Someone else has requested upgrade. Release our shared 33653bf4bb2SPeter Wemm * lock, awaken upgrade requestor if we are the last shared 33753bf4bb2SPeter Wemm * lock, then request an exclusive lock. 33853bf4bb2SPeter Wemm */ 33903e9c6c1SJohn Dyson if ( (lkp->lk_flags & (LK_SHARE_NONZERO|LK_WAIT_NONZERO)) == 34003e9c6c1SJohn Dyson LK_WAIT_NONZERO) 34153bf4bb2SPeter Wemm wakeup((void *)lkp); 34293b0017fSPhilippe Charnier /* FALLTHROUGH exclusive request */ 34353bf4bb2SPeter Wemm 34453bf4bb2SPeter Wemm case LK_EXCLUSIVE: 345822ded67SJulian Elischer if (lkp->lk_lockholder == thr && thr != LK_KERNPROC) { 34653bf4bb2SPeter Wemm /* 34753bf4bb2SPeter Wemm * Recursive lock. 34853bf4bb2SPeter Wemm */ 34933638e93SKirk McKusick if ((extflags & (LK_NOWAIT | LK_CANRECURSE)) == 0) 35053bf4bb2SPeter Wemm panic("lockmgr: locking against myself"); 35133638e93SKirk McKusick if ((extflags & LK_CANRECURSE) != 0) { 35253bf4bb2SPeter Wemm lkp->lk_exclusivecount++; 353f158df07SJeff Roberson COUNT(td, 1); 35453bf4bb2SPeter Wemm break; 35553bf4bb2SPeter Wemm } 35633638e93SKirk McKusick } 35753bf4bb2SPeter Wemm /* 35853bf4bb2SPeter Wemm * If we are just polling, check to see if we will sleep. 35953bf4bb2SPeter Wemm */ 36003e9c6c1SJohn Dyson if ((extflags & LK_NOWAIT) && 36103e9c6c1SJohn Dyson (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO))) { 36253bf4bb2SPeter Wemm error = EBUSY; 36353bf4bb2SPeter Wemm break; 36453bf4bb2SPeter Wemm } 36553bf4bb2SPeter Wemm /* 36653bf4bb2SPeter Wemm * Try to acquire the want_exclusive flag. 36753bf4bb2SPeter Wemm */ 368fe68a916SKip Macy error = acquire(&lkp, extflags, (LK_HAVE_EXCL | LK_WANT_EXCL), &contested, &waitstart); 36953bf4bb2SPeter Wemm if (error) 37053bf4bb2SPeter Wemm break; 37153bf4bb2SPeter Wemm lkp->lk_flags |= LK_WANT_EXCL; 37253bf4bb2SPeter Wemm /* 37353bf4bb2SPeter Wemm * Wait for shared locks and upgrades to finish. 37453bf4bb2SPeter Wemm */ 375fe68a916SKip Macy error = acquire(&lkp, extflags, LK_HAVE_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO, &contested, &waitstart); 37653bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WANT_EXCL; 3774cef6d5aSAlexander Kabaev if (error) { 3784cef6d5aSAlexander Kabaev if (lkp->lk_flags & LK_WAIT_NONZERO) 3794cef6d5aSAlexander Kabaev wakeup((void *)lkp); 38053bf4bb2SPeter Wemm break; 3814cef6d5aSAlexander Kabaev } 38253bf4bb2SPeter Wemm lkp->lk_flags |= LK_HAVE_EXCL; 383822ded67SJulian Elischer lkp->lk_lockholder = thr; 38453bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) 38553bf4bb2SPeter Wemm panic("lockmgr: non-zero exclusive count"); 38653bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 387f158df07SJeff Roberson COUNT(td, 1); 388fe68a916SKip Macy lock_profile_obtain_lock_success(&lkp->lk_object, contested, waitstart, file, line); 38915a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 3907499fd8dSJeff Roberson stack_save(&lkp->lk_stack); 39115a1057cSEivind Eklund #endif 39253bf4bb2SPeter Wemm break; 39353bf4bb2SPeter Wemm 39453bf4bb2SPeter Wemm case LK_RELEASE: 39553bf4bb2SPeter Wemm if (lkp->lk_exclusivecount != 0) { 396822ded67SJulian Elischer if (lkp->lk_lockholder != thr && 397e701df7dSMatthew Dillon lkp->lk_lockholder != LK_KERNPROC) { 398822ded67SJulian Elischer panic("lockmgr: thread %p, not %s %p unlocking", 399822ded67SJulian Elischer thr, "exclusive lock holder", 40053bf4bb2SPeter Wemm lkp->lk_lockholder); 401e701df7dSMatthew Dillon } 402f158df07SJeff Roberson if (lkp->lk_lockholder != LK_KERNPROC) 403f158df07SJeff Roberson COUNT(td, -1); 4049b2e5badSJohn Dyson if (lkp->lk_exclusivecount == 1) { 40553bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_HAVE_EXCL; 40653bf4bb2SPeter Wemm lkp->lk_lockholder = LK_NOPROC; 4079b2e5badSJohn Dyson lkp->lk_exclusivecount = 0; 4087c0435b9SKip Macy lock_profile_release_lock(&lkp->lk_object); 4099b2e5badSJohn Dyson } else { 4109b2e5badSJohn Dyson lkp->lk_exclusivecount--; 41153bf4bb2SPeter Wemm } 4121b367556SJason Evans } else if (lkp->lk_flags & LK_SHARE_NONZERO) 413f158df07SJeff Roberson shareunlock(td, lkp, 1); 4141f71de49SSuleiman Souhlal else { 4151f71de49SSuleiman Souhlal printf("lockmgr: thread %p unlocking unheld lock\n", 4161f71de49SSuleiman Souhlal thr); 4171f71de49SSuleiman Souhlal kdb_backtrace(); 4181f71de49SSuleiman Souhlal } 4191f71de49SSuleiman Souhlal 42003e9c6c1SJohn Dyson if (lkp->lk_flags & LK_WAIT_NONZERO) 42153bf4bb2SPeter Wemm wakeup((void *)lkp); 42253bf4bb2SPeter Wemm break; 42353bf4bb2SPeter Wemm 42453bf4bb2SPeter Wemm case LK_DRAIN: 42553bf4bb2SPeter Wemm /* 42653bf4bb2SPeter Wemm * Check that we do not already hold the lock, as it can 42753bf4bb2SPeter Wemm * never drain if we do. Unfortunately, we have no way to 42853bf4bb2SPeter Wemm * check for holding a shared lock, but at least we can 42953bf4bb2SPeter Wemm * check for an exclusive one. 43053bf4bb2SPeter Wemm */ 431822ded67SJulian Elischer if (lkp->lk_lockholder == thr) 43253bf4bb2SPeter Wemm panic("lockmgr: draining against myself"); 43303e9c6c1SJohn Dyson 43403e9c6c1SJohn Dyson error = acquiredrain(lkp, extflags); 43503e9c6c1SJohn Dyson if (error) 43653bf4bb2SPeter Wemm break; 43753bf4bb2SPeter Wemm lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL; 438822ded67SJulian Elischer lkp->lk_lockholder = thr; 43953bf4bb2SPeter Wemm lkp->lk_exclusivecount = 1; 440f158df07SJeff Roberson COUNT(td, 1); 44115a1057cSEivind Eklund #if defined(DEBUG_LOCKS) 4427499fd8dSJeff Roberson stack_save(&lkp->lk_stack); 44315a1057cSEivind Eklund #endif 44453bf4bb2SPeter Wemm break; 44553bf4bb2SPeter Wemm 44653bf4bb2SPeter Wemm default: 4479ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 44853bf4bb2SPeter Wemm panic("lockmgr: unknown locktype request %d", 44953bf4bb2SPeter Wemm flags & LK_TYPE_MASK); 45053bf4bb2SPeter Wemm /* NOTREACHED */ 45153bf4bb2SPeter Wemm } 45203e9c6c1SJohn Dyson if ((lkp->lk_flags & LK_WAITDRAIN) && 45303e9c6c1SJohn Dyson (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | 45403e9c6c1SJohn Dyson LK_SHARE_NONZERO | LK_WAIT_NONZERO)) == 0) { 45553bf4bb2SPeter Wemm lkp->lk_flags &= ~LK_WAITDRAIN; 45653bf4bb2SPeter Wemm wakeup((void *)&lkp->lk_flags); 45753bf4bb2SPeter Wemm } 4589ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 45953bf4bb2SPeter Wemm return (error); 46053bf4bb2SPeter Wemm } 46153bf4bb2SPeter Wemm 46299448ed1SJohn Dyson static int 46399448ed1SJohn Dyson acquiredrain(struct lock *lkp, int extflags) { 46499448ed1SJohn Dyson int error; 46599448ed1SJohn Dyson 46699448ed1SJohn Dyson if ((extflags & LK_NOWAIT) && (lkp->lk_flags & LK_ALL)) { 46799448ed1SJohn Dyson return EBUSY; 46899448ed1SJohn Dyson } 46999448ed1SJohn Dyson while (lkp->lk_flags & LK_ALL) { 47099448ed1SJohn Dyson lkp->lk_flags |= LK_WAITDRAIN; 47196fde7daSJake Burkholder error = msleep(&lkp->lk_flags, lkp->lk_interlock, lkp->lk_prio, 47223b59018SMatthew Dillon lkp->lk_wmesg, 47323b59018SMatthew Dillon ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); 47499448ed1SJohn Dyson if (error) 47599448ed1SJohn Dyson return error; 47699448ed1SJohn Dyson if (extflags & LK_SLEEPFAIL) { 47799448ed1SJohn Dyson return ENOLCK; 47899448ed1SJohn Dyson } 47999448ed1SJohn Dyson } 48099448ed1SJohn Dyson return 0; 48199448ed1SJohn Dyson } 48299448ed1SJohn Dyson 48399448ed1SJohn Dyson /* 484c6964d3bSKirk McKusick * Transfer any waiting processes from one lock to another. 485c6964d3bSKirk McKusick */ 486c6964d3bSKirk McKusick void 487c6964d3bSKirk McKusick transferlockers(from, to) 488c6964d3bSKirk McKusick struct lock *from; 489c6964d3bSKirk McKusick struct lock *to; 490c6964d3bSKirk McKusick { 491c6964d3bSKirk McKusick 492c6964d3bSKirk McKusick KASSERT(from != to, ("lock transfer to self")); 493c6964d3bSKirk McKusick KASSERT((from->lk_flags&LK_WAITDRAIN) == 0, ("transfer draining lock")); 494f5f0da0aSJeff Roberson 495f5f0da0aSJeff Roberson mtx_lock(from->lk_interlock); 496f5f0da0aSJeff Roberson if (from->lk_waitcount == 0) { 497f5f0da0aSJeff Roberson mtx_unlock(from->lk_interlock); 498c6964d3bSKirk McKusick return; 499f5f0da0aSJeff Roberson } 500c6964d3bSKirk McKusick from->lk_newlock = to; 501c6964d3bSKirk McKusick wakeup((void *)from); 502f5f0da0aSJeff Roberson msleep(&from->lk_newlock, from->lk_interlock, from->lk_prio, 503f5f0da0aSJeff Roberson "lkxfer", 0); 504c6964d3bSKirk McKusick from->lk_newlock = NULL; 505c6964d3bSKirk McKusick from->lk_flags &= ~(LK_WANT_EXCL | LK_WANT_UPGRADE); 506c6964d3bSKirk McKusick KASSERT(from->lk_waitcount == 0, ("active lock")); 507f5f0da0aSJeff Roberson mtx_unlock(from->lk_interlock); 508c6964d3bSKirk McKusick } 509c6964d3bSKirk McKusick 510c6964d3bSKirk McKusick 511c6964d3bSKirk McKusick /* 51299448ed1SJohn Dyson * Initialize a lock; required before use. 51399448ed1SJohn Dyson */ 51499448ed1SJohn Dyson void 51599448ed1SJohn Dyson lockinit(lkp, prio, wmesg, timo, flags) 51699448ed1SJohn Dyson struct lock *lkp; 51799448ed1SJohn Dyson int prio; 51804858e7eSEivind Eklund const char *wmesg; 51999448ed1SJohn Dyson int timo; 52099448ed1SJohn Dyson int flags; 52199448ed1SJohn Dyson { 522c06394f5SJohn Baldwin CTR5(KTR_LOCK, "lockinit(): lkp == %p, prio == %d, wmesg == \"%s\", " 523a18b1f1dSJason Evans "timo == %d, flags = 0x%x\n", lkp, prio, wmesg, timo, flags); 52499448ed1SJohn Dyson 525857d9c60SDon Lewis lkp->lk_interlock = mtx_pool_alloc(mtxpool_lockbuilder); 5269722d88fSJason Evans lkp->lk_flags = (flags & LK_EXTFLG_MASK); 52799448ed1SJohn Dyson lkp->lk_sharecount = 0; 52899448ed1SJohn Dyson lkp->lk_waitcount = 0; 52999448ed1SJohn Dyson lkp->lk_exclusivecount = 0; 53099448ed1SJohn Dyson lkp->lk_prio = prio; 53199448ed1SJohn Dyson lkp->lk_wmesg = wmesg; 53299448ed1SJohn Dyson lkp->lk_timo = timo; 53399448ed1SJohn Dyson lkp->lk_lockholder = LK_NOPROC; 534c6964d3bSKirk McKusick lkp->lk_newlock = NULL; 5353a096f6cSKirk McKusick #ifdef DEBUG_LOCKS 5367499fd8dSJeff Roberson stack_zero(&lkp->lk_stack); 5373a096f6cSKirk McKusick #endif 53861bd5e21SKip Macy lock_profile_object_init(&lkp->lk_object, &lock_class_lockmgr, wmesg); 53999448ed1SJohn Dyson } 54099448ed1SJohn Dyson 54199448ed1SJohn Dyson /* 542a18b1f1dSJason Evans * Destroy a lock. 543a18b1f1dSJason Evans */ 544a18b1f1dSJason Evans void 545a18b1f1dSJason Evans lockdestroy(lkp) 546a18b1f1dSJason Evans struct lock *lkp; 547a18b1f1dSJason Evans { 548c06394f5SJohn Baldwin CTR2(KTR_LOCK, "lockdestroy(): lkp == %p (lk_wmesg == \"%s\")", 549a18b1f1dSJason Evans lkp, lkp->lk_wmesg); 5507c0435b9SKip Macy lock_profile_object_destroy(&lkp->lk_object); 551a18b1f1dSJason Evans } 552a18b1f1dSJason Evans 553a18b1f1dSJason Evans /* 55499448ed1SJohn Dyson * Determine the status of a lock. 55599448ed1SJohn Dyson */ 55699448ed1SJohn Dyson int 557b40ce416SJulian Elischer lockstatus(lkp, td) 55899448ed1SJohn Dyson struct lock *lkp; 559b40ce416SJulian Elischer struct thread *td; 56099448ed1SJohn Dyson { 56199448ed1SJohn Dyson int lock_type = 0; 5622b59d50cSRobert Watson int interlocked; 56399448ed1SJohn Dyson 5642b59d50cSRobert Watson if (!kdb_active) { 5652b59d50cSRobert Watson interlocked = 1; 5669ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 5672b59d50cSRobert Watson } else 5682b59d50cSRobert Watson interlocked = 0; 5696bdfe06aSEivind Eklund if (lkp->lk_exclusivecount != 0) { 570822ded67SJulian Elischer if (td == NULL || lkp->lk_lockholder == td) 57199448ed1SJohn Dyson lock_type = LK_EXCLUSIVE; 5726bdfe06aSEivind Eklund else 5736bdfe06aSEivind Eklund lock_type = LK_EXCLOTHER; 5746bdfe06aSEivind Eklund } else if (lkp->lk_sharecount != 0) 57599448ed1SJohn Dyson lock_type = LK_SHARED; 5762b59d50cSRobert Watson if (interlocked) 5779ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 57899448ed1SJohn Dyson return (lock_type); 57999448ed1SJohn Dyson } 58099448ed1SJohn Dyson 58153bf4bb2SPeter Wemm /* 58267812eacSKirk McKusick * Determine the number of holders of a lock. 58367812eacSKirk McKusick */ 58467812eacSKirk McKusick int 58567812eacSKirk McKusick lockcount(lkp) 58667812eacSKirk McKusick struct lock *lkp; 58767812eacSKirk McKusick { 58867812eacSKirk McKusick int count; 58967812eacSKirk McKusick 5909ed346baSBosko Milekic mtx_lock(lkp->lk_interlock); 59167812eacSKirk McKusick count = lkp->lk_exclusivecount + lkp->lk_sharecount; 5929ed346baSBosko Milekic mtx_unlock(lkp->lk_interlock); 59367812eacSKirk McKusick return (count); 59467812eacSKirk McKusick } 59567812eacSKirk McKusick 59667812eacSKirk McKusick /* 59704aa807cSTor Egge * Determine the number of waiters on a lock. 59804aa807cSTor Egge */ 59904aa807cSTor Egge int 60004aa807cSTor Egge lockwaiters(lkp) 60104aa807cSTor Egge struct lock *lkp; 60204aa807cSTor Egge { 60304aa807cSTor Egge int count; 60404aa807cSTor Egge 60504aa807cSTor Egge mtx_lock(lkp->lk_interlock); 60604aa807cSTor Egge count = lkp->lk_waitcount; 60704aa807cSTor Egge mtx_unlock(lkp->lk_interlock); 60804aa807cSTor Egge return (count); 60904aa807cSTor Egge } 61004aa807cSTor Egge 61104aa807cSTor Egge /* 61253bf4bb2SPeter Wemm * Print out information about state of a lock. Used by VOP_PRINT 6130e61ac7bSPoul-Henning Kamp * routines to display status about contained locks. 61453bf4bb2SPeter Wemm */ 615a1ce9d5cSPeter Wemm void 61653bf4bb2SPeter Wemm lockmgr_printinfo(lkp) 61753bf4bb2SPeter Wemm struct lock *lkp; 61853bf4bb2SPeter Wemm { 61953bf4bb2SPeter Wemm 62053bf4bb2SPeter Wemm if (lkp->lk_sharecount) 62153bf4bb2SPeter Wemm printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg, 62253bf4bb2SPeter Wemm lkp->lk_sharecount); 62353bf4bb2SPeter Wemm else if (lkp->lk_flags & LK_HAVE_EXCL) 624c969c60cSAlexander Kabaev printf(" lock type %s: EXCL (count %d) by thread %p (pid %d)", 625c969c60cSAlexander Kabaev lkp->lk_wmesg, lkp->lk_exclusivecount, 626c969c60cSAlexander Kabaev lkp->lk_lockholder, lkp->lk_lockholder->td_proc->p_pid); 62753bf4bb2SPeter Wemm if (lkp->lk_waitcount > 0) 62853bf4bb2SPeter Wemm printf(" with %d pending", lkp->lk_waitcount); 6297499fd8dSJeff Roberson #ifdef DEBUG_LOCKS 6307499fd8dSJeff Roberson stack_print(&lkp->lk_stack); 6317499fd8dSJeff Roberson #endif 63253bf4bb2SPeter Wemm } 633be6847d7SJohn Baldwin 634be6847d7SJohn Baldwin #ifdef DDB 635462a7addSJohn Baldwin /* 636462a7addSJohn Baldwin * Check to see if a thread that is blocked on a sleep queue is actually 637462a7addSJohn Baldwin * blocked on a 'struct lock'. If so, output some details and return true. 638462a7addSJohn Baldwin * If the lock has an exclusive owner, return that in *ownerp. 639462a7addSJohn Baldwin */ 640462a7addSJohn Baldwin int 641462a7addSJohn Baldwin lockmgr_chain(struct thread *td, struct thread **ownerp) 642462a7addSJohn Baldwin { 643462a7addSJohn Baldwin struct lock *lkp; 644462a7addSJohn Baldwin 645462a7addSJohn Baldwin lkp = td->td_wchan; 646462a7addSJohn Baldwin 647462a7addSJohn Baldwin /* Simple test to see if wchan points to a lockmgr lock. */ 648462a7addSJohn Baldwin if (lkp->lk_wmesg != td->td_wmesg) 649462a7addSJohn Baldwin return (0); 650462a7addSJohn Baldwin 651462a7addSJohn Baldwin /* Ok, we think we have a lockmgr lock, so output some details. */ 652462a7addSJohn Baldwin db_printf("blocked on lk \"%s\" ", lkp->lk_wmesg); 653462a7addSJohn Baldwin if (lkp->lk_sharecount) { 654462a7addSJohn Baldwin db_printf("SHARED (count %d)\n", lkp->lk_sharecount); 655462a7addSJohn Baldwin *ownerp = NULL; 656462a7addSJohn Baldwin } else { 657462a7addSJohn Baldwin db_printf("EXCL (count %d)\n", lkp->lk_exclusivecount); 658462a7addSJohn Baldwin *ownerp = lkp->lk_lockholder; 659462a7addSJohn Baldwin } 660462a7addSJohn Baldwin return (1); 661462a7addSJohn Baldwin } 662462a7addSJohn Baldwin 66361bd5e21SKip Macy void 66461bd5e21SKip Macy db_show_lockmgr(struct lock_object *lock) 665be6847d7SJohn Baldwin { 666be6847d7SJohn Baldwin struct thread *td; 667be6847d7SJohn Baldwin struct lock *lkp; 668be6847d7SJohn Baldwin 66961bd5e21SKip Macy lkp = (struct lock *)lock; 670be6847d7SJohn Baldwin 671be6847d7SJohn Baldwin db_printf("lock type: %s\n", lkp->lk_wmesg); 672be6847d7SJohn Baldwin db_printf("state: "); 673be6847d7SJohn Baldwin if (lkp->lk_sharecount) 674be6847d7SJohn Baldwin db_printf("SHARED (count %d)\n", lkp->lk_sharecount); 675be6847d7SJohn Baldwin else if (lkp->lk_flags & LK_HAVE_EXCL) { 676be6847d7SJohn Baldwin td = lkp->lk_lockholder; 677be6847d7SJohn Baldwin db_printf("EXCL (count %d) %p ", lkp->lk_exclusivecount, td); 678be6847d7SJohn Baldwin db_printf("(tid %d, pid %d, \"%s\")\n", td->td_tid, 679be6847d7SJohn Baldwin td->td_proc->p_pid, td->td_proc->p_comm); 680be6847d7SJohn Baldwin } else 681be6847d7SJohn Baldwin db_printf("UNLOCKED\n"); 682be6847d7SJohn Baldwin if (lkp->lk_waitcount > 0) 683be6847d7SJohn Baldwin db_printf("waiters: %d\n", lkp->lk_waitcount); 684be6847d7SJohn Baldwin } 685be6847d7SJohn Baldwin #endif 686