xref: /freebsd/sys/kern/kern_lock.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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.11 1997/08/22 07:16:46 phk 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 
73 #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \
74 	LK_SHARE_NONZERO | LK_WAIT_NONZERO)
75 
76 static int acquire(struct lock *lkp, int extflags, int wanted);
77 static int apause(struct lock *lkp, int flags);
78 static int acquiredrain(struct lock *lkp, int extflags) ;
79 
80 static LOCK_INLINE void
81 sharelock(struct lock *lkp, int incr) {
82 	lkp->lk_flags |= LK_SHARE_NONZERO;
83 	lkp->lk_sharecount += incr;
84 }
85 
86 static LOCK_INLINE void
87 shareunlock(struct lock *lkp, int decr) {
88 #if defined(DIAGNOSTIC)
89 	if (lkp->lk_sharecount < decr)
90 #if defined(DDB)
91 		Debugger("shareunlock: count < decr");
92 #else
93 		panic("shareunlock: count < decr");
94 #endif
95 #endif
96 
97 	lkp->lk_sharecount -= decr;
98 	if (lkp->lk_sharecount == 0)
99 		lkp->lk_flags &= ~LK_SHARE_NONZERO;
100 }
101 
102 /*
103  * This is the waitloop optimization, and note for this to work
104  * simple_lock and simple_unlock should be subroutines to avoid
105  * optimization troubles.
106  */
107 static int
108 apause(struct lock *lkp, int flags) {
109 	int lock_wait;
110 	lock_wait = LOCK_WAIT_TIME;
111 	for (; lock_wait > 0; lock_wait--) {
112 		int i;
113 		if ((lkp->lk_flags & flags) == 0)
114 			return 0;
115 		simple_unlock(&lkp->lk_interlock);
116 		for (i = LOCK_SAMPLE_WAIT; i > 0; i--) {
117 			if ((lkp->lk_flags & flags) == 0) {
118 				simple_lock(&lkp->lk_interlock);
119 				if ((lkp->lk_flags & flags) == 0)
120 					return 0;
121 				break;
122 			}
123 		}
124 	}
125 	return 1;
126 }
127 
128 static int
129 acquire(struct lock *lkp, int extflags, int wanted) {
130 	int error;
131 	int lock_wait;
132 
133 	if ((extflags & LK_NOWAIT) && (lkp->lk_flags & wanted)) {
134 		return EBUSY;
135 	}
136 
137 	if (((lkp->lk_flags | extflags) & LK_NOPAUSE) == 0) {
138 		error = apause(lkp, wanted);
139 		if (error == 0)
140 			return 0;
141 	}
142 
143 	while ((lkp->lk_flags & wanted) != 0) {
144 		lkp->lk_flags |= LK_WAIT_NONZERO;
145 		lkp->lk_waitcount++;
146 		simple_unlock(&lkp->lk_interlock);
147 		error = tsleep(lkp, lkp->lk_prio, lkp->lk_wmesg, lkp->lk_timo);
148 		simple_lock(&lkp->lk_interlock);
149 		lkp->lk_waitcount--;
150 		if (lkp->lk_waitcount == 0)
151 			lkp->lk_flags &= ~LK_WAIT_NONZERO;
152 		if (error)
153 			return error;
154 		if (extflags & LK_SLEEPFAIL) {
155 			return ENOLCK;
156 		}
157 	}
158 	return 0;
159 }
160 
161 /*
162  * Set, change, or release a lock.
163  *
164  * Shared requests increment the shared count. Exclusive requests set the
165  * LK_WANT_EXCL flag (preventing further shared locks), and wait for already
166  * accepted shared locks and shared-to-exclusive upgrades to go away.
167  */
168 int
169 lockmgr(lkp, flags, interlkp, p)
170 	struct lock *lkp;
171 	u_int flags;
172 	struct simplelock *interlkp;
173 	struct proc *p;
174 {
175 	int error;
176 	pid_t pid;
177 	int extflags;
178 
179 	error = 0;
180 	if (p == NULL)
181 		pid = LK_KERNPROC;
182 	else
183 		pid = p->p_pid;
184 
185 	simple_lock(&lkp->lk_interlock);
186 	if (flags & LK_INTERLOCK)
187 		simple_unlock(interlkp);
188 
189 	extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
190 
191 	switch (flags & LK_TYPE_MASK) {
192 
193 	case LK_SHARED:
194 		if (lkp->lk_lockholder != pid) {
195 			error = acquire(lkp, extflags,
196 				LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE);
197 			if (error)
198 				break;
199 			sharelock(lkp, 1);
200 			COUNT(p, 1);
201 			break;
202 		}
203 		/*
204 		 * We hold an exclusive lock, so downgrade it to shared.
205 		 * An alternative would be to fail with EDEADLK.
206 		 */
207 		sharelock(lkp, 1);
208 		COUNT(p, 1);
209 		/* fall into downgrade */
210 
211 	case LK_DOWNGRADE:
212 		if (lkp->lk_lockholder != pid || lkp->lk_exclusivecount == 0)
213 			panic("lockmgr: not holding exclusive lock");
214 		sharelock(lkp, lkp->lk_exclusivecount);
215 		lkp->lk_exclusivecount = 0;
216 		lkp->lk_flags &= ~LK_HAVE_EXCL;
217 		lkp->lk_lockholder = LK_NOPROC;
218 		if (lkp->lk_waitcount)
219 			wakeup((void *)lkp);
220 		break;
221 
222 	case LK_EXCLUPGRADE:
223 		/*
224 		 * If another process is ahead of us to get an upgrade,
225 		 * then we want to fail rather than have an intervening
226 		 * exclusive access.
227 		 */
228 		if (lkp->lk_flags & LK_WANT_UPGRADE) {
229 			shareunlock(lkp, 1);
230 			COUNT(p, -1);
231 			error = EBUSY;
232 			break;
233 		}
234 		/* fall into normal upgrade */
235 
236 	case LK_UPGRADE:
237 		/*
238 		 * Upgrade a shared lock to an exclusive one. If another
239 		 * shared lock has already requested an upgrade to an
240 		 * exclusive lock, our shared lock is released and an
241 		 * exclusive lock is requested (which will be granted
242 		 * after the upgrade). If we return an error, the file
243 		 * will always be unlocked.
244 		 */
245 		if ((lkp->lk_lockholder == pid) || (lkp->lk_sharecount <= 0))
246 			panic("lockmgr: upgrade exclusive lock");
247 		shareunlock(lkp, 1);
248 		COUNT(p, -1);
249 		/*
250 		 * If we are just polling, check to see if we will block.
251 		 */
252 		if ((extflags & LK_NOWAIT) &&
253 		    ((lkp->lk_flags & LK_WANT_UPGRADE) ||
254 		     lkp->lk_sharecount > 1)) {
255 			error = EBUSY;
256 			break;
257 		}
258 		if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) {
259 			/*
260 			 * We are first shared lock to request an upgrade, so
261 			 * request upgrade and wait for the shared count to
262 			 * drop to zero, then take exclusive lock.
263 			 */
264 			lkp->lk_flags |= LK_WANT_UPGRADE;
265 			error = acquire(lkp, extflags , LK_SHARE_NONZERO);
266 			lkp->lk_flags &= ~LK_WANT_UPGRADE;
267 			if (error)
268 				break;
269 			lkp->lk_flags |= LK_HAVE_EXCL;
270 			lkp->lk_lockholder = pid;
271 			if (lkp->lk_exclusivecount != 0)
272 				panic("lockmgr: non-zero exclusive count");
273 			lkp->lk_exclusivecount = 1;
274 			COUNT(p, 1);
275 			break;
276 		}
277 		/*
278 		 * Someone else has requested upgrade. Release our shared
279 		 * lock, awaken upgrade requestor if we are the last shared
280 		 * lock, then request an exclusive lock.
281 		 */
282 		if ( (lkp->lk_flags & (LK_SHARE_NONZERO|LK_WAIT_NONZERO)) ==
283 			LK_WAIT_NONZERO)
284 			wakeup((void *)lkp);
285 		/* fall into exclusive request */
286 
287 	case LK_EXCLUSIVE:
288 		if (lkp->lk_lockholder == pid && pid != LK_KERNPROC) {
289 			/*
290 			 *	Recursive lock.
291 			 */
292 			if ((extflags & LK_CANRECURSE) == 0)
293 				panic("lockmgr: locking against myself");
294 			lkp->lk_exclusivecount++;
295 			COUNT(p, 1);
296 			break;
297 		}
298 		/*
299 		 * If we are just polling, check to see if we will sleep.
300 		 */
301 		if ((extflags & LK_NOWAIT) &&
302 		    (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | LK_SHARE_NONZERO))) {
303 			error = EBUSY;
304 			break;
305 		}
306 		/*
307 		 * Try to acquire the want_exclusive flag.
308 		 */
309 		error = acquire(lkp, extflags, (LK_HAVE_EXCL | LK_WANT_EXCL));
310 		if (error)
311 			break;
312 		lkp->lk_flags |= LK_WANT_EXCL;
313 		/*
314 		 * Wait for shared locks and upgrades to finish.
315 		 */
316 		error = acquire(lkp, extflags, LK_WANT_UPGRADE | LK_SHARE_NONZERO);
317 		lkp->lk_flags &= ~LK_WANT_EXCL;
318 		if (error)
319 			break;
320 		lkp->lk_flags |= LK_HAVE_EXCL;
321 		lkp->lk_lockholder = pid;
322 		if (lkp->lk_exclusivecount != 0)
323 			panic("lockmgr: non-zero exclusive count");
324 		lkp->lk_exclusivecount = 1;
325 		COUNT(p, 1);
326 		break;
327 
328 	case LK_RELEASE:
329 		if (lkp->lk_exclusivecount != 0) {
330 			if (pid != lkp->lk_lockholder)
331 				panic("lockmgr: pid %d, not %s %d unlocking",
332 				    pid, "exclusive lock holder",
333 				    lkp->lk_lockholder);
334 			lkp->lk_exclusivecount--;
335 			COUNT(p, -1);
336 			if (lkp->lk_exclusivecount == 0) {
337 				lkp->lk_flags &= ~LK_HAVE_EXCL;
338 				lkp->lk_lockholder = LK_NOPROC;
339 			}
340 		} else if (lkp->lk_flags & LK_SHARE_NONZERO) {
341 			shareunlock(lkp, 1);
342 			COUNT(p, -1);
343 		}
344 		if (lkp->lk_flags & LK_WAIT_NONZERO)
345 			wakeup((void *)lkp);
346 		break;
347 
348 	case LK_DRAIN:
349 		/*
350 		 * Check that we do not already hold the lock, as it can
351 		 * never drain if we do. Unfortunately, we have no way to
352 		 * check for holding a shared lock, but at least we can
353 		 * check for an exclusive one.
354 		 */
355 		if (lkp->lk_lockholder == pid)
356 			panic("lockmgr: draining against myself");
357 
358 		error = acquiredrain(lkp, extflags);
359 		if (error)
360 			break;
361 		lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
362 		lkp->lk_lockholder = pid;
363 		lkp->lk_exclusivecount = 1;
364 		COUNT(p, 1);
365 		break;
366 
367 	default:
368 		simple_unlock(&lkp->lk_interlock);
369 		panic("lockmgr: unknown locktype request %d",
370 		    flags & LK_TYPE_MASK);
371 		/* NOTREACHED */
372 	}
373 	if ((lkp->lk_flags & LK_WAITDRAIN) &&
374 	    (lkp->lk_flags & (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE |
375 		LK_SHARE_NONZERO | LK_WAIT_NONZERO)) == 0) {
376 		lkp->lk_flags &= ~LK_WAITDRAIN;
377 		wakeup((void *)&lkp->lk_flags);
378 	}
379 	simple_unlock(&lkp->lk_interlock);
380 	return (error);
381 }
382 
383 static int
384 acquiredrain(struct lock *lkp, int extflags) {
385 	int error;
386 	int lock_wait;
387 
388 	if ((extflags & LK_NOWAIT) && (lkp->lk_flags & LK_ALL)) {
389 		return EBUSY;
390 	}
391 
392 	error = apause(lkp, LK_ALL);
393 	if (error == 0)
394 		return 0;
395 
396 	while (lkp->lk_flags & LK_ALL) {
397 		lkp->lk_flags |= LK_WAITDRAIN;
398 		simple_unlock(&lkp->lk_interlock);
399 		error = tsleep(&lkp->lk_flags, lkp->lk_prio,
400 			lkp->lk_wmesg, lkp->lk_timo);
401 		simple_lock(&lkp->lk_interlock);
402 		if (error)
403 			return error;
404 		if (extflags & LK_SLEEPFAIL) {
405 			return ENOLCK;
406 		}
407 	}
408 	return 0;
409 }
410 
411 /*
412  * Initialize a lock; required before use.
413  */
414 void
415 lockinit(lkp, prio, wmesg, timo, flags)
416 	struct lock *lkp;
417 	int prio;
418 	char *wmesg;
419 	int timo;
420 	int flags;
421 {
422 
423 	simple_lock_init(&lkp->lk_interlock);
424 	lkp->lk_flags = (flags & LK_EXTFLG_MASK);
425 	lkp->lk_sharecount = 0;
426 	lkp->lk_waitcount = 0;
427 	lkp->lk_exclusivecount = 0;
428 	lkp->lk_prio = prio;
429 	lkp->lk_wmesg = wmesg;
430 	lkp->lk_timo = timo;
431 	lkp->lk_lockholder = LK_NOPROC;
432 }
433 
434 /*
435  * Determine the status of a lock.
436  */
437 int
438 lockstatus(lkp)
439 	struct lock *lkp;
440 {
441 	int lock_type = 0;
442 
443 	simple_lock(&lkp->lk_interlock);
444 	if (lkp->lk_exclusivecount != 0)
445 		lock_type = LK_EXCLUSIVE;
446 	else if (lkp->lk_sharecount != 0)
447 		lock_type = LK_SHARED;
448 	simple_unlock(&lkp->lk_interlock);
449 	return (lock_type);
450 }
451 
452 /*
453  * Print out information about state of a lock. Used by VOP_PRINT
454  * routines to display status about contained locks.
455  */
456 void
457 lockmgr_printinfo(lkp)
458 	struct lock *lkp;
459 {
460 
461 	if (lkp->lk_sharecount)
462 		printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg,
463 		    lkp->lk_sharecount);
464 	else if (lkp->lk_flags & LK_HAVE_EXCL)
465 		printf(" lock type %s: EXCL (count %d) by pid %d",
466 		    lkp->lk_wmesg, lkp->lk_exclusivecount, lkp->lk_lockholder);
467 	if (lkp->lk_waitcount > 0)
468 		printf(" with %d pending", lkp->lk_waitcount);
469 }
470 
471 #if defined(SIMPLELOCK_DEBUG) && NCPUS == 1
472 #include <sys/kernel.h>
473 #include <sys/sysctl.h>
474 
475 static int lockpausetime = 0;
476 SYSCTL_INT(_debug, OID_AUTO, lockpausetime, CTLFLAG_RW, &lockpausetime, 0, "");
477 
478 int simplelockrecurse;
479 
480 /*
481  * Simple lock functions so that the debugger can see from whence
482  * they are being called.
483  */
484 void
485 simple_lock_init(alp)
486 	struct simplelock *alp;
487 {
488 
489 	alp->lock_data = 0;
490 }
491 
492 void
493 _simple_lock(alp, id, l)
494 	struct simplelock *alp;
495 	const char *id;
496 	int l;
497 {
498 
499 	if (simplelockrecurse)
500 		return;
501 	if (alp->lock_data == 1) {
502 		if (lockpausetime == -1)
503 			panic("%s:%d: simple_lock: lock held", id, l);
504 		printf("%s:%d: simple_lock: lock held\n", id, l);
505 		if (lockpausetime == 1) {
506 			Debugger("simple_lock");
507 			/*BACKTRACE(curproc); */
508 		} else if (lockpausetime > 1) {
509 			printf("%s:%d: simple_lock: lock held...", id, l);
510 			tsleep(&lockpausetime, PCATCH | PPAUSE, "slock",
511 			    lockpausetime * hz);
512 			printf(" continuing\n");
513 		}
514 	}
515 	alp->lock_data = 1;
516 	if (curproc)
517 		curproc->p_simple_locks++;
518 }
519 
520 int
521 _simple_lock_try(alp, id, l)
522 	struct simplelock *alp;
523 	const char *id;
524 	int l;
525 {
526 
527 	if (alp->lock_data)
528 		return (0);
529 	if (simplelockrecurse)
530 		return (1);
531 	alp->lock_data = 1;
532 	if (curproc)
533 		curproc->p_simple_locks++;
534 	return (1);
535 }
536 
537 void
538 _simple_unlock(alp, id, l)
539 	struct simplelock *alp;
540 	const char *id;
541 	int l;
542 {
543 
544 	if (simplelockrecurse)
545 		return;
546 	if (alp->lock_data == 0) {
547 		if (lockpausetime == -1)
548 			panic("%s:%d: simple_unlock: lock not held", id, l);
549 		printf("%s:%d: simple_unlock: lock not held\n", id, l);
550 		if (lockpausetime == 1) {
551 			Debugger("simple_unlock");
552 			/* BACKTRACE(curproc); */
553 		} else if (lockpausetime > 1) {
554 			printf("%s:%d: simple_unlock: lock not held...", id, l);
555 			tsleep(&lockpausetime, PCATCH | PPAUSE, "sunlock",
556 			    lockpausetime * hz);
557 			printf(" continuing\n");
558 		}
559 	}
560 	alp->lock_data = 0;
561 	if (curproc)
562 		curproc->p_simple_locks--;
563 }
564 #endif /* SIMPLELOCK_DEBUG && NCPUS == 1 */
565