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*69387Smckusick * @(#)kern_lock.c 8.9 (Berkeley) 05/11/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 79*69387Smckusick lockinit(lkp, prio, wmesg, timo, flags) 8068762Smckusick struct lock *lkp; 8168762Smckusick int prio; 8268762Smckusick char *wmesg; 8368762Smckusick int timo; 8468762Smckusick int flags; 8568762Smckusick { 86*69387Smckusick 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 12268945Smckusick lockmgr(lkp, flags, interlkp, pid) 12368945Smckusick __volatile struct lock *lkp; 12468800Smckusick u_int flags; 12568945Smckusick struct simple_lock *interlkp; 12668945Smckusick pid_t pid; 12768762Smckusick { 12868779Smckusick int error; 12968945Smckusick __volatile int extflags; 13068762Smckusick 13168800Smckusick error = 0; 13268933Smckusick simple_lock(&lkp->lk_interlock); 13368945Smckusick if (flags & LK_INTERLOCK) 13468945Smckusick simple_unlock(interlkp); 13568762Smckusick extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 13668945Smckusick if ((lkp->lk_flags & LK_DRAINED) && 13768945Smckusick (((flags & LK_TYPE_MASK) != LK_RELEASE) || 13868945Smckusick lkp->lk_lockholder != pid)) 13968800Smckusick panic("lockmgr: using decommissioned lock"); 14068762Smckusick 14168762Smckusick switch (flags & LK_TYPE_MASK) { 14268762Smckusick 14368762Smckusick case LK_SHARED: 14468762Smckusick if (lkp->lk_lockholder != pid) { 14568762Smckusick /* 14668762Smckusick * If just polling, check to see if we will block. 14768762Smckusick */ 14868762Smckusick if ((extflags & LK_NOWAIT) && (lkp->lk_flags & 14968762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE))) { 15068800Smckusick error = EBUSY; 15168800Smckusick break; 15268762Smckusick } 15368762Smckusick /* 15468762Smckusick * Wait for exclusive locks and upgrades to clear. 15568762Smckusick */ 15668762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_flags & 15768762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)); 15868800Smckusick if (error) 15968800Smckusick break; 16068762Smckusick lkp->lk_sharecount++; 16168800Smckusick break; 16268762Smckusick } 16368762Smckusick /* 16468762Smckusick * We hold an exclusive lock, so downgrade it to shared. 16568762Smckusick * An alternative would be to fail with EDEADLK. 16668762Smckusick */ 16768762Smckusick lkp->lk_sharecount++; 16868762Smckusick /* fall into downgrade */ 16968762Smckusick 17068762Smckusick case LK_DOWNGRADE: 17168762Smckusick if (lkp->lk_lockholder != pid || lkp->lk_exclusivecount == 0) 17268762Smckusick panic("lockmgr: not holding exclusive lock"); 17368762Smckusick lkp->lk_sharecount += lkp->lk_exclusivecount; 17468762Smckusick lkp->lk_exclusivecount = 0; 17568762Smckusick lkp->lk_flags &= ~LK_HAVE_EXCL; 17668762Smckusick lkp->lk_lockholder = LK_NOPROC; 17768800Smckusick if (lkp->lk_waitcount) 17868779Smckusick wakeup((void *)lkp); 17968800Smckusick break; 18068762Smckusick 18168779Smckusick case LK_EXCLUPGRADE: 18268779Smckusick /* 18368779Smckusick * If another process is ahead of us to get an upgrade, 18468779Smckusick * then we want to fail rather than have an intervening 18568779Smckusick * exclusive access. 18668779Smckusick */ 18768779Smckusick if (lkp->lk_flags & LK_WANT_UPGRADE) { 18868779Smckusick lkp->lk_sharecount--; 18968800Smckusick error = EBUSY; 19068800Smckusick break; 19168779Smckusick } 19268779Smckusick /* fall into normal upgrade */ 19368779Smckusick 19468762Smckusick case LK_UPGRADE: 19568762Smckusick /* 19668762Smckusick * Upgrade a shared lock to an exclusive one. If another 19768762Smckusick * shared lock has already requested an upgrade to an 19868762Smckusick * exclusive lock, our shared lock is released and an 19968762Smckusick * exclusive lock is requested (which will be granted 20068775Smckusick * after the upgrade). If we return an error, the file 20168775Smckusick * will always be unlocked. 20268762Smckusick */ 20368762Smckusick if (lkp->lk_lockholder == pid || lkp->lk_sharecount <= 0) 20468762Smckusick panic("lockmgr: upgrade exclusive lock"); 20568775Smckusick lkp->lk_sharecount--; 20668762Smckusick /* 20768762Smckusick * If we are just polling, check to see if we will block. 20868762Smckusick */ 20968762Smckusick if ((extflags & LK_NOWAIT) && 21068762Smckusick ((lkp->lk_flags & LK_WANT_UPGRADE) || 21168762Smckusick lkp->lk_sharecount > 1)) { 21268800Smckusick error = EBUSY; 21368800Smckusick break; 21468762Smckusick } 21568762Smckusick if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) { 21668762Smckusick /* 21768762Smckusick * We are first shared lock to request an upgrade, so 21868762Smckusick * request upgrade and wait for the shared count to 21968762Smckusick * drop to zero, then take exclusive lock. 22068762Smckusick */ 22168762Smckusick lkp->lk_flags |= LK_WANT_UPGRADE; 22268762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_sharecount); 22368762Smckusick lkp->lk_flags &= ~LK_WANT_UPGRADE; 22468800Smckusick if (error) 22568800Smckusick break; 22668762Smckusick lkp->lk_flags |= LK_HAVE_EXCL; 22768762Smckusick lkp->lk_lockholder = pid; 22868762Smckusick if (lkp->lk_exclusivecount != 0) 22968762Smckusick panic("lockmgr: non-zero exclusive count"); 23068762Smckusick lkp->lk_exclusivecount = 1; 23168800Smckusick break; 23268762Smckusick } 23368762Smckusick /* 23468762Smckusick * Someone else has requested upgrade. Release our shared 23568762Smckusick * lock, awaken upgrade requestor if we are the last shared 23668762Smckusick * lock, then request an exclusive lock. 23768762Smckusick */ 23868800Smckusick if (lkp->lk_sharecount == 0 && lkp->lk_waitcount) 23968779Smckusick wakeup((void *)lkp); 24068762Smckusick /* fall into exclusive request */ 24168762Smckusick 24268762Smckusick case LK_EXCLUSIVE: 24368762Smckusick if (lkp->lk_lockholder == pid) { 24468762Smckusick /* 24568762Smckusick * Recursive lock. 24668762Smckusick */ 24768762Smckusick if ((extflags & LK_CANRECURSE) == 0) 24868762Smckusick panic("lockmgr: locking against myself"); 24968762Smckusick lkp->lk_exclusivecount++; 25068800Smckusick break; 25168762Smckusick } 25268762Smckusick /* 25368762Smckusick * If we are just polling, check to see if we will sleep. 25468762Smckusick */ 25568762Smckusick if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & 25668762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 25768762Smckusick lkp->lk_sharecount != 0)) { 25868800Smckusick error = EBUSY; 25968800Smckusick break; 26068762Smckusick } 26168762Smckusick /* 26268762Smckusick * Try to acquire the want_exclusive flag. 26368762Smckusick */ 26468762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_flags & 26568762Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL)); 26668800Smckusick if (error) 26768800Smckusick break; 26868762Smckusick lkp->lk_flags |= LK_WANT_EXCL; 26968762Smckusick /* 27068762Smckusick * Wait for shared locks and upgrades to finish. 27168762Smckusick */ 27268762Smckusick ACQUIRE(lkp, error, extflags, lkp->lk_sharecount != 0 || 27368762Smckusick (lkp->lk_flags & LK_WANT_UPGRADE)); 27468762Smckusick lkp->lk_flags &= ~LK_WANT_EXCL; 27568800Smckusick if (error) 27668800Smckusick break; 27768762Smckusick lkp->lk_flags |= LK_HAVE_EXCL; 27868762Smckusick lkp->lk_lockholder = pid; 27968762Smckusick if (lkp->lk_exclusivecount != 0) 28068762Smckusick panic("lockmgr: non-zero exclusive count"); 28168762Smckusick lkp->lk_exclusivecount = 1; 28268800Smckusick break; 28368762Smckusick 28468762Smckusick case LK_RELEASE: 28568762Smckusick if (lkp->lk_exclusivecount != 0) { 28668800Smckusick if (pid != lkp->lk_lockholder) 28768800Smckusick panic("lockmgr: pid %d, not %s %d unlocking", 28868800Smckusick pid, "exclusive lock holder", 28968800Smckusick lkp->lk_lockholder); 29068762Smckusick lkp->lk_exclusivecount--; 29168762Smckusick if (lkp->lk_exclusivecount == 0) { 29268762Smckusick lkp->lk_flags &= ~LK_HAVE_EXCL; 29368762Smckusick lkp->lk_lockholder = LK_NOPROC; 29468762Smckusick } 29568762Smckusick } else if (lkp->lk_sharecount != 0) 29668762Smckusick lkp->lk_sharecount--; 29768800Smckusick if (lkp->lk_waitcount) 29868779Smckusick wakeup((void *)lkp); 29968800Smckusick break; 30068800Smckusick 30168800Smckusick case LK_DRAIN: 30268800Smckusick /* 30368800Smckusick * If we are just polling, check to see if we will sleep. 30468800Smckusick */ 30568800Smckusick if ((extflags & LK_NOWAIT) && ((lkp->lk_flags & 30668800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 30768800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) { 30868800Smckusick error = EBUSY; 30968800Smckusick break; 31068762Smckusick } 31168800Smckusick PAUSE(lkp, ((lkp->lk_flags & 31268800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 31368800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)); 31468800Smckusick for (error = 0; ((lkp->lk_flags & 31568800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) || 31668800Smckusick lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0); ) { 31768800Smckusick lkp->lk_flags |= LK_WAITDRAIN; 31868933Smckusick simple_unlock(&lkp->lk_interlock); 31968800Smckusick if (error = tsleep((void *)&lkp->lk_flags, lkp->lk_prio, 32068800Smckusick lkp->lk_wmesg, lkp->lk_timo)) 32168800Smckusick return (error); 32268800Smckusick if ((extflags) & LK_SLEEPFAIL) 32368800Smckusick return (ENOLCK); 32468933Smckusick simple_lock(&lkp->lk_interlock); 32568800Smckusick } 32668945Smckusick lkp->lk_flags |= LK_DRAINED | LK_HAVE_EXCL; 32768945Smckusick lkp->lk_lockholder = pid; 32868945Smckusick lkp->lk_exclusivecount = 1; 32968800Smckusick break; 33068762Smckusick 33168762Smckusick default: 33268933Smckusick simple_unlock(&lkp->lk_interlock); 33368762Smckusick panic("lockmgr: unknown locktype request %d", 33468762Smckusick flags & LK_TYPE_MASK); 33568775Smckusick /* NOTREACHED */ 33668762Smckusick } 33768800Smckusick if ((lkp->lk_flags & LK_WAITDRAIN) && ((lkp->lk_flags & 33868800Smckusick (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) == 0 && 33968800Smckusick lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) { 34068800Smckusick lkp->lk_flags &= ~LK_WAITDRAIN; 34168800Smckusick wakeup((void *)&lkp->lk_flags); 34268800Smckusick } 34368933Smckusick simple_unlock(&lkp->lk_interlock); 34468800Smckusick return (error); 34568762Smckusick } 34668945Smckusick 347*69387Smckusick /* 348*69387Smckusick * Print out information about state of a lock. Used by VOP_PRINT 349*69387Smckusick * routines to display ststus about contained locks. 350*69387Smckusick */ 35168945Smckusick lockmgr_printinfo(lkp) 35268945Smckusick struct lock *lkp; 35368945Smckusick { 35468945Smckusick 35568945Smckusick if (lkp->lk_sharecount) 35668945Smckusick printf(" lock type %s: SHARED", lkp->lk_wmesg); 35768945Smckusick else if (lkp->lk_flags & LK_HAVE_EXCL) 35868945Smckusick printf(" lock type %s: EXCL by pid %d", lkp->lk_wmesg, 35968945Smckusick lkp->lk_lockholder); 36068945Smckusick if (lkp->lk_waitcount > 0) 36168945Smckusick printf(" with %d pending", lkp->lk_waitcount); 36268945Smckusick } 363*69387Smckusick 364*69387Smckusick #if defined(DEBUG) && NCPUS == 1 365*69387Smckusick /* 366*69387Smckusick * Simple lock functions so that the debugger can see from whence 367*69387Smckusick * they are being called. 368*69387Smckusick */ 369*69387Smckusick void 370*69387Smckusick simple_lock_init(alp) 371*69387Smckusick struct simple_lock *alp; 372*69387Smckusick { 373*69387Smckusick 374*69387Smckusick alp->lock_data = 0; 375*69387Smckusick } 376*69387Smckusick 377*69387Smckusick void 378*69387Smckusick simple_lock(alp) 379*69387Smckusick __volatile struct simple_lock *alp; 380*69387Smckusick { 381*69387Smckusick 382*69387Smckusick if (alp->lock_data == 1) 383*69387Smckusick panic("simple_lock: lock held"); 384*69387Smckusick alp->lock_data = 1; 385*69387Smckusick } 386*69387Smckusick 387*69387Smckusick int 388*69387Smckusick simple_lock_try(alp) 389*69387Smckusick __volatile struct simple_lock *alp; 390*69387Smckusick { 391*69387Smckusick 392*69387Smckusick if (alp->lock_data == 1) 393*69387Smckusick panic("simple_lock: lock held"); 394*69387Smckusick alp->lock_data = 1; 395*69387Smckusick return (1); 396*69387Smckusick } 397*69387Smckusick 398*69387Smckusick void 399*69387Smckusick simple_unlock(alp) 400*69387Smckusick __volatile struct simple_lock *alp; 401*69387Smckusick { 402*69387Smckusick 403*69387Smckusick if (alp->lock_data == 0) 404*69387Smckusick panic("simple_lock: lock not held"); 405*69387Smckusick alp->lock_data = 0; 406*69387Smckusick } 407*69387Smckusick #endif /* DEBUG && NCPUS == 1 */ 408