168762Smckusick /* 268762Smckusick * Copyright (c) 1995 368762Smckusick * The Regents of the University of California. All rights reserved. 468762Smckusick * 568775Smckusick * This code contains ideas from software contributed to Berkeley by 668762Smckusick * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 768762Smckusick * System project at Carnegie-Mellon University. 868762Smckusick * 968762Smckusick * %sccs.include.redist.c% 1068762Smckusick * 11*69461Smckusick * @(#)kern_lock.c 8.11 (Berkeley) 05/14/95 1268762Smckusick */ 1368762Smckusick 1468762Smckusick #include <sys/param.h> 1568762Smckusick #include <sys/proc.h> 1668762Smckusick #include <sys/lock.h> 1768762Smckusick 1868762Smckusick /* 1968762Smckusick * Locking primitives implementation. 2068762Smckusick * Locks provide shared/exclusive sychronization. 2168762Smckusick */ 2268762Smckusick 2368762Smckusick #if NCPUS > 1 2468762Smckusick 2568762Smckusick /* 2668762Smckusick * For multiprocessor system, try spin lock first. 2768762Smckusick * 2868762Smckusick * This should be inline expanded below, but we cannot have #if 2968762Smckusick * inside a multiline define. 3068762Smckusick */ 3168762Smckusick int lock_wait_time = 100; 3268762Smckusick #define PAUSE(lkp, wanted) \ 3368762Smckusick if (lock_wait_time > 0) { \ 3468762Smckusick int i; \ 3568762Smckusick \ 3668933Smckusick simple_unlock(&lkp->lk_interlock); \ 3768762Smckusick for (i = lock_wait_time; i > 0; i--) \ 3868762Smckusick if (!(wanted)) \ 3968762Smckusick break; \ 4068933Smckusick simple_lock(&lkp->lk_interlock); \ 4168762Smckusick } \ 4268762Smckusick if (!(wanted)) \ 4368762Smckusick break; 4468762Smckusick 4568762Smckusick #else /* NCPUS == 1 */ 4668762Smckusick 4768762Smckusick /* 4868762Smckusick * It is an error to spin on a uniprocessor as nothing will ever cause 4968933Smckusick * the simple lock to clear while we are executing. 5068762Smckusick */ 5168762Smckusick #define PAUSE(lkp, wanted) 5268762Smckusick 5368762Smckusick #endif /* NCPUS == 1 */ 5468762Smckusick 5568762Smckusick /* 5668762Smckusick * Acquire a resource. 5768762Smckusick */ 5868762Smckusick #define ACQUIRE(lkp, error, extflags, wanted) \ 5968762Smckusick PAUSE(lkp, wanted); \ 6068762Smckusick for (error = 0; wanted; ) { \ 6168800Smckusick (lkp)->lk_waitcount++; \ 6268933Smckusick simple_unlock(&(lkp)->lk_interlock); \ 6368779Smckusick error = tsleep((void *)lkp, (lkp)->lk_prio, \ 6468779Smckusick (lkp)->lk_wmesg, (lkp)->lk_timo); \ 6568933Smckusick simple_lock(&(lkp)->lk_interlock); \ 6668800Smckusick (lkp)->lk_waitcount--; \ 6768762Smckusick if (error) \ 6868762Smckusick break; \ 6968762Smckusick if ((extflags) & LK_SLEEPFAIL) { \ 7068762Smckusick error = ENOLCK; \ 7168762Smckusick break; \ 7268762Smckusick } \ 7368762Smckusick } 7468762Smckusick 7568762Smckusick /* 7668762Smckusick * Initialize a lock; required before use. 7768762Smckusick */ 7868782Smckusick void 7969387Smckusick lockinit(lkp, prio, wmesg, timo, flags) 8068762Smckusick struct lock *lkp; 8168762Smckusick int prio; 8268762Smckusick char *wmesg; 8368762Smckusick int timo; 8468762Smckusick int flags; 8568762Smckusick { 8669387Smckusick 8768762Smckusick bzero(lkp, sizeof(struct lock)); 8868933Smckusick simple_lock_init(&lkp->lk_interlock); 8968762Smckusick lkp->lk_flags = flags & LK_EXTFLG_MASK; 9068762Smckusick lkp->lk_prio = prio; 9168762Smckusick lkp->lk_timo = timo; 9268762Smckusick lkp->lk_wmesg = wmesg; 9368762Smckusick lkp->lk_lockholder = LK_NOPROC; 9468762Smckusick } 9568762Smckusick 9668762Smckusick /* 9768780Smckusick * Determine the status of a lock. 9868780Smckusick */ 9968780Smckusick int 10068780Smckusick lockstatus(lkp) 10168780Smckusick struct lock *lkp; 10268780Smckusick { 10368780Smckusick int lock_type = 0; 10468780Smckusick 10568933Smckusick simple_lock(&lkp->lk_interlock); 10668780Smckusick if (lkp->lk_exclusivecount != 0) 10768780Smckusick lock_type = LK_EXCLUSIVE; 10868780Smckusick else if (lkp->lk_sharecount != 0) 10968780Smckusick lock_type = LK_SHARED; 11068933Smckusick simple_unlock(&lkp->lk_interlock); 11168780Smckusick return (lock_type); 11268780Smckusick } 11368780Smckusick 11468780Smckusick /* 11568762Smckusick * Set, change, or release a lock. 11668762Smckusick * 11768762Smckusick * Shared requests increment the shared count. Exclusive requests set the 11868762Smckusick * LK_WANT_EXCL flag (preventing further shared locks), and wait for already 11968762Smckusick * accepted shared locks and shared-to-exclusive upgrades to go away. 12068762Smckusick */ 12168782Smckusick int 12269406Smckusick lockmgr(lkp, flags, interlkp, p) 12368945Smckusick __volatile struct lock *lkp; 12468800Smckusick u_int flags; 12569406Smckusick struct simplelock *interlkp; 12669406Smckusick struct proc *p; 12768762Smckusick { 12868779Smckusick int error; 12969406Smckusick pid_t pid; 13069406Smckusick int extflags; 13168762Smckusick 13268800Smckusick error = 0; 13369406Smckusick if (p) 13469406Smckusick pid = p->p_pid; 13569406Smckusick else 13669406Smckusick pid = LK_KERNPROC; 13768933Smckusick simple_lock(&lkp->lk_interlock); 13868945Smckusick if (flags & LK_INTERLOCK) 13968945Smckusick simple_unlock(interlkp); 14068762Smckusick extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 14169406Smckusick #ifdef DIAGNOSTIC 14269406Smckusick /* 14369406Smckusick * Once a lock has drained, the LK_DRAINING flag is set and an 14469406Smckusick * exclusive lock is returned. The only valid operation thereafter 14569406Smckusick * is a single release of that exclusive lock. This final release 14669406Smckusick * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any 14769406Smckusick * further requests of any sort will result in a panic. The bits 14869406Smckusick * selected for these two flags are chosen so that they will be set 14969406Smckusick * in memory that is freed (freed memory is filled with 0xdeadbeef). 15069406Smckusick */ 15169406Smckusick if (lkp->lk_flags & (LK_DRAINING|LK_DRAINED)) { 15269406Smckusick if (lkp->lk_flags & LK_DRAINED) 15369406Smckusick panic("lockmgr: using decommissioned lock"); 15469406Smckusick if ((flags & LK_TYPE_MASK) != LK_RELEASE || 15569406Smckusick lkp->lk_lockholder != pid) 15669406Smckusick panic("lockmgr: non-release on draining lock: %d\n", 15769406Smckusick flags & LK_TYPE_MASK); 15869406Smckusick lkp->lk_flags &= ~LK_DRAINING; 15969406Smckusick lkp->lk_flags |= LK_DRAINED; 16069406Smckusick } 16169406Smckusick #endif DIAGNOSTIC 16268762Smckusick 16368762Smckusick switch (flags & LK_TYPE_MASK) { 16468762Smckusick 16568762Smckusick case LK_SHARED: 16668762Smckusick if (lkp->lk_lockholder != pid) { 16768762Smckusick /* 16868762Smckusick * If just polling, check to see if we will block. 16968762Smckusick */ 17068762Smckusick if ((extflags & LK_NOWAIT) && (lkp->lk_flags & 17168762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE))) { 17268800Smckusick error = EBUSY; 17368800Smckusick break; 17468762Smckusick } 17568762Smckusick /* 17668762Smckusick * Wait for exclusive locks and upgrades to clear. 17768762Smckusick */ 17868762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_flags & 17968762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)); 18068800Smckusick if (error) 18168800Smckusick break; 18268762Smckusick lkp->lk_sharecount++; 18368800Smckusick break; 18468762Smckusick } 18568762Smckusick /* 18668762Smckusick * We hold an exclusive lock, so downgrade it to shared. 18768762Smckusick * An alternative would be to fail with EDEADLK. 18868762Smckusick */ 18968762Smckusick lkp->lk_sharecount++; 19068762Smckusick /* fall into downgrade */ 19168762Smckusick 19268762Smckusick case LK_DOWNGRADE: 19368762Smckusick if (lkp->lk_lockholder != pid || lkp->lk_exclusivecount == 0) 19468762Smckusick panic("lockmgr: not holding exclusive lock"); 19568762Smckusick lkp->lk_sharecount += lkp->lk_exclusivecount; 19668762Smckusick lkp->lk_exclusivecount = 0; 19768762Smckusick lkp->lk_flags &= ~LK_HAVE_EXCL; 19868762Smckusick lkp->lk_lockholder = LK_NOPROC; 19968800Smckusick if (lkp->lk_waitcount) 20068779Smckusick wakeup((void *)lkp); 20168800Smckusick break; 20268762Smckusick 20368779Smckusick case LK_EXCLUPGRADE: 20468779Smckusick /* 20568779Smckusick * If another process is ahead of us to get an upgrade, 20668779Smckusick * then we want to fail rather than have an intervening 20768779Smckusick * exclusive access. 20868779Smckusick */ 20968779Smckusick if (lkp->lk_flags & LK_WANT_UPGRADE) { 21068779Smckusick lkp->lk_sharecount--; 21168800Smckusick error = EBUSY; 21268800Smckusick break; 21368779Smckusick } 21468779Smckusick /* fall into normal upgrade */ 21568779Smckusick 21668762Smckusick case LK_UPGRADE: 21768762Smckusick /* 21868762Smckusick * Upgrade a shared lock to an exclusive one. If another 21968762Smckusick * shared lock has already requested an upgrade to an 22068762Smckusick * exclusive lock, our shared lock is released and an 22168762Smckusick * exclusive lock is requested (which will be granted 22268775Smckusick * after the upgrade). If we return an error, the file 22368775Smckusick * will always be unlocked. 22468762Smckusick */ 22568762Smckusick if (lkp->lk_lockholder == pid || lkp->lk_sharecount <= 0) 22668762Smckusick panic("lockmgr: upgrade exclusive lock"); 22768775Smckusick lkp->lk_sharecount--; 22868762Smckusick /* 22968762Smckusick * If we are just polling, check to see if we will block. 23068762Smckusick */ 23168762Smckusick if ((extflags & LK_NOWAIT) && 23268762Smckusick ((lkp->lk_flags & LK_WANT_UPGRADE) || 23368762Smckusick lkp->lk_sharecount > 1)) { 23468800Smckusick error = EBUSY; 23568800Smckusick break; 23668762Smckusick } 23768762Smckusick if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) { 23868762Smckusick /* 23968762Smckusick * We are first shared lock to request an upgrade, so 24068762Smckusick * request upgrade and wait for the shared count to 24168762Smckusick * drop to zero, then take exclusive lock. 24268762Smckusick */ 24368762Smckusick lkp->lk_flags |= LK_WANT_UPGRADE; 24468762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_sharecount); 24568762Smckusick lkp->lk_flags &= ~LK_WANT_UPGRADE; 24668800Smckusick if (error) 24768800Smckusick break; 24868762Smckusick lkp->lk_flags |= LK_HAVE_EXCL; 24968762Smckusick lkp->lk_lockholder = pid; 25068762Smckusick if (lkp->lk_exclusivecount != 0) 25168762Smckusick panic("lockmgr: non-zero exclusive count"); 25268762Smckusick lkp->lk_exclusivecount = 1; 25368800Smckusick break; 25468762Smckusick } 25568762Smckusick /* 25668762Smckusick * Someone else has requested upgrade. Release our shared 25768762Smckusick * lock, awaken upgrade requestor if we are the last shared 25868762Smckusick * lock, then request an exclusive lock. 25968762Smckusick */ 26068800Smckusick if (lkp->lk_sharecount == 0 && lkp->lk_waitcount) 26168779Smckusick wakeup((void *)lkp); 26268762Smckusick /* fall into exclusive request */ 26368762Smckusick 26468762Smckusick case LK_EXCLUSIVE: 265*69461Smckusick if (lkp->lk_lockholder == pid && pid != LK_KERNPROC) { 26668762Smckusick /* 26768762Smckusick * Recursive lock. 26868762Smckusick */ 26968762Smckusick if ((extflags & LK_CANRECURSE) == 0) 27068762Smckusick panic("lockmgr: locking against myself"); 27168762Smckusick lkp->lk_exclusivecount++; 27268800Smckusick break; 27368762Smckusick } 27468762Smckusick /* 27568762Smckusick * If we are just polling, check to see if we will sleep. 27668762Smckusick */ 27768762Smckusick if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & 27868762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 27968762Smckusick lkp->lk_sharecount != 0)) { 28068800Smckusick error = EBUSY; 28168800Smckusick break; 28268762Smckusick } 28368762Smckusick /* 28468762Smckusick * Try to acquire the want_exclusive flag. 28568762Smckusick */ 28668762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_flags & 28768762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL)); 28868800Smckusick if (error) 28968800Smckusick break; 29068762Smckusick lkp->lk_flags |= LK_WANT_EXCL; 29168762Smckusick /* 29268762Smckusick * Wait for shared locks and upgrades to finish. 29368762Smckusick */ 29468762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_sharecount != 0 || 29568762Smckusick (lkp->lk_flags & LK_WANT_UPGRADE)); 29668762Smckusick lkp->lk_flags &= ~LK_WANT_EXCL; 29768800Smckusick if (error) 29868800Smckusick break; 29968762Smckusick lkp->lk_flags |= LK_HAVE_EXCL; 30068762Smckusick lkp->lk_lockholder = pid; 30168762Smckusick if (lkp->lk_exclusivecount != 0) 30268762Smckusick panic("lockmgr: non-zero exclusive count"); 30368762Smckusick lkp->lk_exclusivecount = 1; 30468800Smckusick break; 30568762Smckusick 30668762Smckusick case LK_RELEASE: 30768762Smckusick if (lkp->lk_exclusivecount != 0) { 30868800Smckusick if (pid != lkp->lk_lockholder) 30968800Smckusick panic("lockmgr: pid %d, not %s %d unlocking", 31068800Smckusick pid, "exclusive lock holder", 31168800Smckusick lkp->lk_lockholder); 31268762Smckusick lkp->lk_exclusivecount--; 31368762Smckusick if (lkp->lk_exclusivecount == 0) { 31468762Smckusick lkp->lk_flags &= ~LK_HAVE_EXCL; 31568762Smckusick lkp->lk_lockholder = LK_NOPROC; 31668762Smckusick } 31768762Smckusick } else if (lkp->lk_sharecount != 0) 31868762Smckusick lkp->lk_sharecount--; 31968800Smckusick if (lkp->lk_waitcount) 32068779Smckusick wakeup((void *)lkp); 32168800Smckusick break; 32268800Smckusick 32368800Smckusick case LK_DRAIN: 32468800Smckusick /* 32569406Smckusick * Check that we do not already hold the lock, as it can 32669406Smckusick * never drain if we do. Unfortunately, we have no way to 32769406Smckusick * check for holding a shared lock, but at least we can 32869406Smckusick * check for an exclusive one. 32969406Smckusick */ 33069406Smckusick if (lkp->lk_lockholder == pid) 33169406Smckusick panic("lockmgr: draining against myself"); 33269406Smckusick /* 33368800Smckusick * If we are just polling, check to see if we will sleep. 33468800Smckusick */ 33568800Smckusick if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & 33668800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 33768800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) { 33868800Smckusick error = EBUSY; 33968800Smckusick break; 34068762Smckusick } 34168800Smckusick PAUSE(lkp, ((lkp->lk_flags & 34268800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 34368800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)); 34468800Smckusick for (error = 0; ((lkp->lk_flags & 34568800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 34668800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0); ) { 34768800Smckusick lkp->lk_flags |= LK_WAITDRAIN; 34868933Smckusick simple_unlock(&lkp->lk_interlock); 34968800Smckusick if (error = tsleep((void *)&lkp->lk_flags, lkp->lk_prio, 35068800Smckusick lkp->lk_wmesg, lkp->lk_timo)) 35168800Smckusick return (error); 35268800Smckusick if ((extflags) & LK_SLEEPFAIL) 35368800Smckusick return (ENOLCK); 35468933Smckusick simple_lock(&lkp->lk_interlock); 35568800Smckusick } 35669406Smckusick lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL; 35768945Smckusick lkp->lk_lockholder = pid; 35868945Smckusick lkp->lk_exclusivecount = 1; 35968800Smckusick break; 36068762Smckusick 36168762Smckusick default: 36268933Smckusick simple_unlock(&lkp->lk_interlock); 36368762Smckusick panic("lockmgr: unknown locktype request %d", 36468762Smckusick flags & LK_TYPE_MASK); 36568775Smckusick /* NOTREACHED */ 36668762Smckusick } 36768800Smckusick if ((lkp->lk_flags & LK_WAITDRAIN) && ((lkp->lk_flags & 36868800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) == 0 && 36968800Smckusick lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) { 37068800Smckusick lkp->lk_flags &= ~LK_WAITDRAIN; 37168800Smckusick wakeup((void *)&lkp->lk_flags); 37268800Smckusick } 37368933Smckusick simple_unlock(&lkp->lk_interlock); 37468800Smckusick return (error); 37568762Smckusick } 37668945Smckusick 37769387Smckusick /* 37869387Smckusick * Print out information about state of a lock. Used by VOP_PRINT 37969387Smckusick * routines to display ststus about contained locks. 38069387Smckusick */ 38168945Smckusick lockmgr_printinfo(lkp) 38268945Smckusick struct lock *lkp; 38368945Smckusick { 38468945Smckusick 38568945Smckusick if (lkp->lk_sharecount) 38668945Smckusick printf(" lock type %s: SHARED", lkp->lk_wmesg); 38768945Smckusick else if (lkp->lk_flags & LK_HAVE_EXCL) 38868945Smckusick printf(" lock type %s: EXCL by pid %d", lkp->lk_wmesg, 38968945Smckusick lkp->lk_lockholder); 39068945Smckusick if (lkp->lk_waitcount > 0) 39168945Smckusick printf(" with %d pending", lkp->lk_waitcount); 39268945Smckusick } 39369387Smckusick 39469387Smckusick #if defined(DEBUG) && NCPUS == 1 395*69461Smckusick #include <sys/kernel.h> 396*69461Smckusick #include <vm/vm.h> 397*69461Smckusick #include <sys/sysctl.h> 398*69461Smckusick int lockpausetime = 1; 399*69461Smckusick struct ctldebug debug2 = { "lockpausetime", &lockpausetime }; 40069387Smckusick /* 40169387Smckusick * Simple lock functions so that the debugger can see from whence 40269387Smckusick * they are being called. 40369387Smckusick */ 40469387Smckusick void 40569387Smckusick simple_lock_init(alp) 40669406Smckusick struct simplelock *alp; 40769387Smckusick { 40869387Smckusick 40969387Smckusick alp->lock_data = 0; 41069387Smckusick } 41169387Smckusick 41269387Smckusick void 41369387Smckusick simple_lock(alp) 41469406Smckusick __volatile struct simplelock *alp; 41569387Smckusick { 41669387Smckusick 417*69461Smckusick if (alp->lock_data == 1) { 418*69461Smckusick if (lockpausetime == -1) 419*69461Smckusick panic("simple_lock: lock held"); 420*69461Smckusick if (lockpausetime > 0) { 421*69461Smckusick printf("simple_lock: lock held..."); 422*69461Smckusick tsleep(&lockpausetime, PCATCH | PPAUSE, "slock", 423*69461Smckusick lockpausetime * hz); 424*69461Smckusick printf(" continuing\n"); 425*69461Smckusick } 426*69461Smckusick } 42769387Smckusick alp->lock_data = 1; 42869387Smckusick } 42969387Smckusick 43069387Smckusick int 43169387Smckusick simple_lock_try(alp) 43269406Smckusick __volatile struct simplelock *alp; 43369387Smckusick { 43469387Smckusick 435*69461Smckusick if (alp->lock_data == 1) { 436*69461Smckusick if (lockpausetime == -1) 437*69461Smckusick panic("simple_lock_try: lock held"); 438*69461Smckusick if (lockpausetime > 0) { 439*69461Smckusick printf("simple_lock_try: lock held..."); 440*69461Smckusick tsleep(&lockpausetime, PCATCH | PPAUSE, "slock", 441*69461Smckusick lockpausetime * hz); 442*69461Smckusick printf(" continuing\n"); 443*69461Smckusick } 444*69461Smckusick } 44569387Smckusick alp->lock_data = 1; 44669387Smckusick return (1); 44769387Smckusick } 44869387Smckusick 44969387Smckusick void 45069387Smckusick simple_unlock(alp) 45169406Smckusick __volatile struct simplelock *alp; 45269387Smckusick { 45369387Smckusick 454*69461Smckusick if (alp->lock_data == 0) { 455*69461Smckusick if (lockpausetime == -1) 456*69461Smckusick panic("simple_unlock: lock not held"); 457*69461Smckusick if (lockpausetime > 0) { 458*69461Smckusick printf("simple_unlock: lock not held..."); 459*69461Smckusick tsleep(&lockpausetime, PCATCH | PPAUSE, "sunlock", 460*69461Smckusick lockpausetime * hz); 461*69461Smckusick printf(" continuing\n"); 462*69461Smckusick } 463*69461Smckusick } 46469387Smckusick alp->lock_data = 0; 46569387Smckusick } 46669387Smckusick #endif /* DEBUG && NCPUS == 1 */ 467