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