kern_lock.c revision 28393
1/* 2 * Copyright (c) 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Copyright (C) 1997 6 * John S. Dyson. All rights reserved. 7 * 8 * This code contains ideas from software contributed to Berkeley by 9 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 10 * System project at Carnegie-Mellon University. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)kern_lock.c 8.18 (Berkeley) 5/21/95 41 * $Id: kern_lock.c,v 1.9 1997/08/18 03:29:15 fsmp Exp $ 42 */ 43 44#include <sys/param.h> 45#include <sys/proc.h> 46#include <sys/lock.h> 47#include <sys/systm.h> 48 49#ifdef SMP 50#include <machine/smp.h> 51#endif 52 53/* 54 * Locking primitives implementation. 55 * Locks provide shared/exclusive sychronization. 56 */ 57 58#ifdef SIMPLELOCK_DEBUG 59#define COUNT(p, x) if (p) (p)->p_locks += (x) 60#else 61#define COUNT(p, x) 62#endif 63 64#define LOCK_WAIT_TIME 100 65#define LOCK_SAMPLE_WAIT 7 66 67#if defined(DIAGNOSTIC) 68#define LOCK_INLINE 69#else 70#define LOCK_INLINE inline 71#endif 72 73static int acquire(struct lock *lkp, int extflags, int wanted); 74 75static LOCK_INLINE void 76sharelock(struct lock *lkp, int incr) { 77 lkp->lk_flags |= LK_SHARE_NONZERO; 78 lkp->lk_sharecount += incr; 79} 80 81static LOCK_INLINE void 82shareunlock(struct lock *lkp, int decr) { 83#if defined(DIAGNOSTIC) 84 if (lkp->lk_sharecount < decr) 85#if defined(DDB) 86 Debugger("shareunlock: count < decr"); 87#else 88 panic("shareunlock: count < decr"); 89#endif 90#endif 91 92 lkp->lk_sharecount -= decr; 93 if (lkp->lk_sharecount == 0) 94 lkp->lk_flags &= ~LK_SHARE_NONZERO; 95} 96 97static int 98apause(struct lock *lkp, int flags) { 99 int lock_wait; 100 lock_wait = LOCK_WAIT_TIME; 101 for (; lock_wait > 0; lock_wait--) { 102 int i; 103 if ((lkp->lk_flags & flags) == 0) 104 return 0; 105 simple_unlock(&lkp->lk_interlock); 106 for (i = LOCK_SAMPLE_WAIT; i > 0; i--) { 107 if ((lkp->lk_flags & flags) == 0) { 108 simple_lock(&lkp->lk_interlock); 109 if ((lkp->lk_flags & flags) == 0) 110 return 0; 111 break; 112 } 113 } 114 } 115 return 1; 116} 117 118 119static int 120acquire(struct lock *lkp, int extflags, int wanted) { 121 int error; 122 int lock_wait; 123 124 if ((extflags & LK_NOWAIT) && (lkp->lk_flags & wanted)) { 125 return EBUSY; 126 } 127 128 error = apause(lkp, wanted); 129 if (error == 0) 130 return 0; 131 132 while ((lkp->lk_flags & wanted) != 0) { 133 lkp->lk_flags |= LK_WAIT_NONZERO; 134 lkp->lk_waitcount++; 135 simple_unlock(&lkp->lk_interlock); 136 error = tsleep(lkp, lkp->lk_prio, lkp->lk_wmesg, lkp->lk_timo); 137 simple_lock(&lkp->lk_interlock); 138 lkp->lk_waitcount--; 139 if (lkp->lk_waitcount == 0) 140 lkp->lk_flags &= ~LK_WAIT_NONZERO; 141 if (error) 142 return error; 143 if (extflags & LK_SLEEPFAIL) { 144 return ENOLCK; 145 } 146 } 147 return 0; 148} 149 150#define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \ 151 LK_SHARE_NONZERO | LK_WAIT_NONZERO) 152 153static int 154acquiredrain(struct lock *lkp, int extflags) { 155 int error; 156 int lock_wait; 157 158 if ((extflags & LK_NOWAIT) && (lkp->lk_flags & LK_ALL)) { 159 return EBUSY; 160 } 161 162 error = apause(lkp, LK_ALL); 163 if (error == 0) 164 return 0; 165 166 while (lkp->lk_flags & LK_ALL) { 167 lkp->lk_flags |= LK_WAITDRAIN; 168 simple_unlock(&lkp->lk_interlock); 169 error = tsleep(&lkp->lk_flags, lkp->lk_prio, 170 lkp->lk_wmesg, lkp->lk_timo); 171 simple_lock(&lkp->lk_interlock); 172 if (error) 173 return error; 174 if (extflags & LK_SLEEPFAIL) { 175 return ENOLCK; 176 } 177 } 178 return 0; 179} 180 181/* 182 * Initialize a lock; required before use. 183 */ 184void 185lockinit(lkp, prio, wmesg, timo, flags) 186 struct lock *lkp; 187 int prio; 188 char *wmesg; 189 int timo; 190 int flags; 191{ 192 193 simple_lock_init(&lkp->lk_interlock); 194 lkp->lk_flags = (flags & LK_EXTFLG_MASK); 195 lkp->lk_sharecount = 0; 196 lkp->lk_waitcount = 0; 197 lkp->lk_exclusivecount = 0; 198 lkp->lk_prio = prio; 199 lkp->lk_wmesg = wmesg; 200 lkp->lk_timo = timo; 201 lkp->lk_lockholder = LK_NOPROC; 202} 203 204/* 205 * Determine the status of a lock. 206 */ 207int 208lockstatus(lkp) 209 struct lock *lkp; 210{ 211 int lock_type = 0; 212 213 simple_lock(&lkp->lk_interlock); 214 if (lkp->lk_exclusivecount != 0) 215 lock_type = LK_EXCLUSIVE; 216 else if (lkp->lk_sharecount != 0) 217 lock_type = LK_SHARED; 218 simple_unlock(&lkp->lk_interlock); 219 return (lock_type); 220} 221 222/* 223 * Set, change, or release a lock. 224 * 225 * Shared requests increment the shared count. Exclusive requests set the 226 * LK_WANT_EXCL flag (preventing further shared locks), and wait for already 227 * accepted shared locks and shared-to-exclusive upgrades to go away. 228 */ 229int 230lockmgr(lkp, flags, interlkp, p) 231 struct lock *lkp; 232 u_int flags; 233 struct simplelock *interlkp; 234 struct proc *p; 235{ 236 int error; 237 pid_t pid; 238 int extflags; 239 240 error = 0; 241 if (p == NULL) 242 pid = LK_KERNPROC; 243 else 244 pid = p->p_pid; 245 246 simple_lock(&lkp->lk_interlock); 247 if (flags & LK_INTERLOCK) 248 simple_unlock(interlkp); 249 250 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; 251 252 switch (flags & LK_TYPE_MASK) { 253 254 case LK_SHARED: 255 if (lkp->lk_lockholder != pid) { 256 error = acquire(lkp, extflags, 257 LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE); 258 if (error) 259 break; 260 sharelock(lkp, 1); 261 COUNT(p, 1); 262 break; 263 } 264 /* 265 * We hold an exclusive lock, so downgrade it to shared. 266 * An alternative would be to fail with EDEADLK. 267 */ 268 sharelock(lkp, 1); 269 COUNT(p, 1); 270 /* fall into downgrade */ 271 272 case LK_DOWNGRADE: 273 if (lkp->lk_lockholder != pid || lkp->lk_exclusivecount == 0) 274 panic("lockmgr: not holding exclusive lock"); 275 sharelock(lkp, lkp->lk_exclusivecount); 276 lkp->lk_exclusivecount = 0; 277 lkp->lk_flags &= ~LK_HAVE_EXCL; 278 lkp->lk_lockholder = LK_NOPROC; 279 if (lkp->lk_waitcount) 280 wakeup((void *)lkp); 281 break; 282 283 case LK_EXCLUPGRADE: 284 /* 285 * If another process is ahead of us to get an upgrade, 286 * then we want to fail rather than have an intervening 287 * exclusive access. 288 */ 289 if (lkp->lk_flags & LK_WANT_UPGRADE) { 290 shareunlock(lkp, 1); 291 COUNT(p, -1); 292 error = EBUSY; 293 break; 294 } 295 /* fall into normal upgrade */ 296 297 case LK_UPGRADE: 298 /* 299 * Upgrade a shared lock to an exclusive one. If another 300 * shared lock has already requested an upgrade to an 301 * exclusive lock, our shared lock is released and an 302 * exclusive lock is requested (which will be granted 303 * after the upgrade). If we return an error, the file 304 * will always be unlocked. 305 */ 306 if ((lkp->lk_lockholder == pid) || (lkp->lk_sharecount <= 0)) 307 panic("lockmgr: upgrade exclusive lock"); 308 shareunlock(lkp, 1); 309 COUNT(p, -1); 310 /* 311 * If we are just polling, check to see if we will block. 312 */ 313 if ((extflags & LK_NOWAIT) && 314 ((lkp->lk_flags & LK_WANT_UPGRADE) || 315 lkp->lk_sharecount > 1)) { 316 error = EBUSY; 317 break; 318 } 319 if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) { 320 /* 321 * We are first shared lock to request an upgrade, so 322 * request upgrade and wait for the shared count to 323 * drop to zero, then take exclusive lock. 324 */ 325 lkp->lk_flags |= LK_WANT_UPGRADE; 326 error = acquire(lkp, extflags , LK_SHARE_NONZERO); 327 lkp->lk_flags &= ~LK_WANT_UPGRADE; 328 if (error) 329 break; 330 lkp->lk_flags |= LK_HAVE_EXCL; 331 lkp->lk_lockholder = pid; 332 if (lkp->lk_exclusivecount != 0) 333 panic("lockmgr: non-zero exclusive count"); 334 lkp->lk_exclusivecount = 1; 335 COUNT(p, 1); 336 break; 337 } 338 /* 339 * Someone else has requested upgrade. Release our shared 340 * lock, awaken upgrade requestor if we are the last shared 341 * lock, then request an exclusive lock. 342 */ 343 if ( (lkp->lk_flags & (LK_SHARE_NONZERO|LK_WAIT_NONZERO)) == 344 LK_WAIT_NONZERO) 345 wakeup((void *)lkp); 346 /* fall into exclusive request */ 347 348 case LK_EXCLUSIVE: 349 if (lkp->lk_lockholder == pid && pid != LK_KERNPROC) { 350 /* 351 * Recursive lock. 352 */ 353 if ((extflags & LK_CANRECURSE) == 0) 354 panic("lockmgr: locking against myself"); 355 lkp->lk_exclusivecount++; 356 COUNT(p, 1); 357 break; 358 } 359 /* 360 * If we are just polling, check to see if we will sleep. 361 */ 362 if ((extflags & LK_NOWAIT) && 363 (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO))) { 364 error = EBUSY; 365 break; 366 } 367 /* 368 * Try to acquire the want_exclusive flag. 369 */ 370 error = acquire(lkp, extflags, (LK_HAVE_EXCL | LK_WANT_EXCL)); 371 if (error) 372 break; 373 lkp->lk_flags |= LK_WANT_EXCL; 374 /* 375 * Wait for shared locks and upgrades to finish. 376 */ 377 error = acquire(lkp, extflags, LK_WANT_UPGRADE | LK_SHARE_NONZERO); 378 lkp->lk_flags &= ~LK_WANT_EXCL; 379 if (error) 380 break; 381 lkp->lk_flags |= LK_HAVE_EXCL; 382 lkp->lk_lockholder = pid; 383 if (lkp->lk_exclusivecount != 0) 384 panic("lockmgr: non-zero exclusive count"); 385 lkp->lk_exclusivecount = 1; 386 COUNT(p, 1); 387 break; 388 389 case LK_RELEASE: 390 if (lkp->lk_exclusivecount != 0) { 391 if (pid != lkp->lk_lockholder) 392 panic("lockmgr: pid %d, not %s %d unlocking", 393 pid, "exclusive lock holder", 394 lkp->lk_lockholder); 395 lkp->lk_exclusivecount--; 396 COUNT(p, -1); 397 if (lkp->lk_exclusivecount == 0) { 398 lkp->lk_flags &= ~LK_HAVE_EXCL; 399 lkp->lk_lockholder = LK_NOPROC; 400 } 401 } else if (lkp->lk_flags & LK_SHARE_NONZERO) { 402 shareunlock(lkp, 1); 403 COUNT(p, -1); 404 } 405 if (lkp->lk_flags & LK_WAIT_NONZERO) 406 wakeup((void *)lkp); 407 break; 408 409 case LK_DRAIN: 410 /* 411 * Check that we do not already hold the lock, as it can 412 * never drain if we do. Unfortunately, we have no way to 413 * check for holding a shared lock, but at least we can 414 * check for an exclusive one. 415 */ 416 if (lkp->lk_lockholder == pid) 417 panic("lockmgr: draining against myself"); 418 419 error = acquiredrain(lkp, extflags); 420 if (error) 421 break; 422 lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL; 423 lkp->lk_lockholder = pid; 424 lkp->lk_exclusivecount = 1; 425 COUNT(p, 1); 426 break; 427 428 default: 429 simple_unlock(&lkp->lk_interlock); 430 panic("lockmgr: unknown locktype request %d", 431 flags & LK_TYPE_MASK); 432 /* NOTREACHED */ 433 } 434 if ((lkp->lk_flags & LK_WAITDRAIN) && 435 (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | 436 LK_SHARE_NONZERO | LK_WAIT_NONZERO)) == 0) { 437 lkp->lk_flags &= ~LK_WAITDRAIN; 438 wakeup((void *)&lkp->lk_flags); 439 } 440 simple_unlock(&lkp->lk_interlock); 441 return (error); 442} 443 444/* 445 * Print out information about state of a lock. Used by VOP_PRINT 446 * routines to display ststus about contained locks. 447 */ 448void 449lockmgr_printinfo(lkp) 450 struct lock *lkp; 451{ 452 453 if (lkp->lk_sharecount) 454 printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg, 455 lkp->lk_sharecount); 456 else if (lkp->lk_flags & LK_HAVE_EXCL) 457 printf(" lock type %s: EXCL (count %d) by pid %d", 458 lkp->lk_wmesg, lkp->lk_exclusivecount, lkp->lk_lockholder); 459 if (lkp->lk_waitcount > 0) 460 printf(" with %d pending", lkp->lk_waitcount); 461} 462 463#if defined(SIMPLELOCK_DEBUG) && NCPUS == 1 464#include <sys/kernel.h> 465#include <sys/sysctl.h> 466 467static int lockpausetime = 0; 468SYSCTL_INT(_debug, OID_AUTO, lockpausetime, CTLFLAG_RW, &lockpausetime, 0, ""); 469 470int simplelockrecurse; 471 472/* 473 * Simple lock functions so that the debugger can see from whence 474 * they are being called. 475 */ 476void 477simple_lock_init(alp) 478 struct simplelock *alp; 479{ 480 481 alp->lock_data = 0; 482} 483 484void 485_simple_lock(alp, id, l) 486 struct simplelock *alp; 487 const char *id; 488 int l; 489{ 490 491 if (simplelockrecurse) 492 return; 493 if (alp->lock_data == 1) { 494 if (lockpausetime == -1) 495 panic("%s:%d: simple_lock: lock held", id, l); 496 printf("%s:%d: simple_lock: lock held\n", id, l); 497 if (lockpausetime == 1) { 498 Debugger("simple_lock"); 499 /*BACKTRACE(curproc); */ 500 } else if (lockpausetime > 1) { 501 printf("%s:%d: simple_lock: lock held...", id, l); 502 tsleep(&lockpausetime, PCATCH | PPAUSE, "slock", 503 lockpausetime * hz); 504 printf(" continuing\n"); 505 } 506 } 507 alp->lock_data = 1; 508 if (curproc) 509 curproc->p_simple_locks++; 510} 511 512int 513_simple_lock_try(alp, id, l) 514 struct simplelock *alp; 515 const char *id; 516 int l; 517{ 518 519 if (alp->lock_data) 520 return (0); 521 if (simplelockrecurse) 522 return (1); 523 alp->lock_data = 1; 524 if (curproc) 525 curproc->p_simple_locks++; 526 return (1); 527} 528 529void 530_simple_unlock(alp, id, l) 531 struct simplelock *alp; 532 const char *id; 533 int l; 534{ 535 536 if (simplelockrecurse) 537 return; 538 if (alp->lock_data == 0) { 539 if (lockpausetime == -1) 540 panic("%s:%d: simple_unlock: lock not held", id, l); 541 printf("%s:%d: simple_unlock: lock not held\n", id, l); 542 if (lockpausetime == 1) { 543 Debugger("simple_unlock"); 544 /* BACKTRACE(curproc); */ 545 } else if (lockpausetime > 1) { 546 printf("%s:%d: simple_unlock: lock not held...", id, l); 547 tsleep(&lockpausetime, PCATCH | PPAUSE, "sunlock", 548 lockpausetime * hz); 549 printf(" continuing\n"); 550 } 551 } 552 alp->lock_data = 0; 553 if (curproc) 554 curproc->p_simple_locks--; 555} 556#endif /* SIMPLELOCK_DEBUG && NCPUS == 1 */ 557