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