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