vfs_lockf.c revision 1.4
1/*
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Scooter Morris at Genentech Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	from: @(#)ufs_lockf.c	8.3 (Berkeley) 1/6/94
37 *	$Id: vfs_lockf.c,v 1.4 1994/05/19 06:13:50 mycroft Exp $
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/file.h>
44#include <sys/proc.h>
45#include <sys/vnode.h>
46#include <sys/malloc.h>
47#include <sys/fcntl.h>
48#include <sys/lockf.h>
49
50/*
51 * Do an advisory lock operation.
52 */
53int
54lf_advlock(head, size, id, op, fl, flags)
55	struct lockf **head;
56	off_t size;
57	caddr_t id;
58	int op;
59	register struct flock *fl;
60	int flags;
61{
62	register struct lockf *lock;
63	off_t start, end;
64	int error;
65
66	/*
67	 * Avoid the common case of unlocking when inode has no locks.
68	 */
69	if (*head == (struct lockf *)0) {
70		if (op != F_SETLK) {
71			fl->l_type = F_UNLCK;
72			return (0);
73		}
74	}
75	/*
76	 * Convert the flock structure into a start and end.
77	 */
78	switch (fl->l_whence) {
79
80	case SEEK_SET:
81	case SEEK_CUR:
82		/*
83		 * Caller is responsible for adding any necessary offset
84		 * when SEEK_CUR is used.
85		 */
86		start = fl->l_start;
87		break;
88
89	case SEEK_END:
90		start = size + fl->l_start;
91		break;
92
93	default:
94		return (EINVAL);
95	}
96	if (start < 0)
97		return (EINVAL);
98	if (fl->l_len == 0)
99		end = -1;
100	else
101		end = start + fl->l_len - 1;
102	/*
103	 * Create the lockf structure.
104	 */
105	MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
106	lock->lf_start = start;
107	lock->lf_end = end;
108	lock->lf_id = id;
109	lock->lf_head = head;
110	lock->lf_type = fl->l_type;
111	lock->lf_next = (struct lockf *)0;
112	lock->lf_block = (struct lockf *)0;
113	lock->lf_flags = flags;
114	/*
115	 * Do the requested operation.
116	 */
117	switch (op) {
118
119	case F_SETLK:
120		return (lf_setlock(lock));
121
122	case F_UNLCK:
123		error = lf_clearlock(lock);
124		FREE(lock, M_LOCKF);
125		return (error);
126
127	case F_GETLK:
128		error = lf_getlock(lock, fl);
129		FREE(lock, M_LOCKF);
130		return (error);
131
132	default:
133		FREE(lock, M_LOCKF);
134		return (EINVAL);
135	}
136	/* NOTREACHED */
137}
138
139/*
140 * This variable controls the maximum number of processes that will
141 * be checked in doing deadlock detection.
142 */
143int maxlockdepth = MAXDEPTH;
144
145#ifdef LOCKF_DEBUG
146int	lockf_debug = 0;
147#endif
148
149#define NOLOCKF (struct lockf *)0
150#define SELF	0x1
151#define OTHERS	0x2
152
153/*
154 * Set a byte-range lock.
155 */
156int
157lf_setlock(lock)
158	register struct lockf *lock;
159{
160	register struct lockf *block;
161	struct lockf **head = lock->lf_head;
162	struct lockf **prev, *overlap, *ltmp;
163	static char lockstr[] = "lockf";
164	int ovcase, priority, needtolink, error;
165
166#ifdef LOCKF_DEBUG
167	if (lockf_debug & 1)
168		lf_print("lf_setlock", lock);
169#endif /* LOCKF_DEBUG */
170
171	/*
172	 * Set the priority
173	 */
174	priority = PLOCK;
175	if (lock->lf_type == F_WRLCK)
176		priority += 4;
177	priority |= PCATCH;
178	/*
179	 * Scan lock list for this file looking for locks that would block us.
180	 */
181	while (block = lf_getblock(lock)) {
182		/*
183		 * Free the structure and return if nonblocking.
184		 */
185		if ((lock->lf_flags & F_WAIT) == 0) {
186			FREE(lock, M_LOCKF);
187			return (EAGAIN);
188		}
189		/*
190		 * We are blocked. Since flock style locks cover
191		 * the whole file, there is no chance for deadlock.
192		 * For byte-range locks we must check for deadlock.
193		 *
194		 * Deadlock detection is done by looking through the
195		 * wait channels to see if there are any cycles that
196		 * involve us. MAXDEPTH is set just to make sure we
197		 * do not go off into neverland.
198		 */
199		if ((lock->lf_flags & F_POSIX) &&
200		    (block->lf_flags & F_POSIX)) {
201			register struct proc *wproc;
202			register struct lockf *waitblock;
203			int i = 0;
204
205			/* The block is waiting on something */
206			wproc = (struct proc *)block->lf_id;
207			while (wproc->p_wchan &&
208			       (wproc->p_wmesg == lockstr) &&
209			       (i++ < maxlockdepth)) {
210				waitblock = (struct lockf *)wproc->p_wchan;
211				/* Get the owner of the blocking lock */
212				waitblock = waitblock->lf_next;
213				if ((waitblock->lf_flags & F_POSIX) == 0)
214					break;
215				wproc = (struct proc *)waitblock->lf_id;
216				if (wproc == (struct proc *)lock->lf_id) {
217					free(lock, M_LOCKF);
218					return (EDEADLK);
219				}
220			}
221		}
222		/*
223		 * For flock type locks, we must first remove
224		 * any shared locks that we hold before we sleep
225		 * waiting for an exclusive lock.
226		 */
227		if ((lock->lf_flags & F_FLOCK) &&
228		    lock->lf_type == F_WRLCK) {
229			lock->lf_type = F_UNLCK;
230			(void) lf_clearlock(lock);
231			lock->lf_type = F_WRLCK;
232		}
233		/*
234		 * Add our lock to the blocked list and sleep until we're free.
235		 * Remember who blocked us (for deadlock detection).
236		 */
237		lock->lf_next = block;
238		lf_addblock(block, lock);
239#ifdef LOCKF_DEBUG
240		if (lockf_debug & 1) {
241			lf_print("lf_setlock: blocking on", block);
242			lf_printlist("lf_setlock", block);
243		}
244#endif /* LOCKF_DEBUG */
245		if (error = tsleep((caddr_t)lock, priority, lockstr, 0)) {
246			/*
247			 * Delete ourselves from the waiting to lock list.
248			 */
249			for (block = lock->lf_next;
250			     block != NOLOCKF;
251			     block = block->lf_block) {
252				if (block->lf_block != lock)
253					continue;
254				block->lf_block = block->lf_block->lf_block;
255				break;
256			}
257			/*
258			 * If we did not find ourselves on the list, but
259			 * are still linked onto a lock list, then something
260			 * is very wrong.
261			 */
262			if (block == NOLOCKF && lock->lf_next != NOLOCKF)
263				panic("lf_setlock: lost lock");
264			free(lock, M_LOCKF);
265			return (error);
266		}
267	}
268	/*
269	 * No blocks!!  Add the lock.  Note that we will
270	 * downgrade or upgrade any overlapping locks this
271	 * process already owns.
272	 *
273	 * Skip over locks owned by other processes.
274	 * Handle any locks that overlap and are owned by ourselves.
275	 */
276	prev = head;
277	block = *head;
278	needtolink = 1;
279	for (;;) {
280		if (ovcase = lf_findoverlap(block, lock, SELF, &prev, &overlap))
281			block = overlap->lf_next;
282		/*
283		 * Six cases:
284		 *	0) no overlap
285		 *	1) overlap == lock
286		 *	2) overlap contains lock
287		 *	3) lock contains overlap
288		 *	4) overlap starts before lock
289		 *	5) overlap ends after lock
290		 */
291		switch (ovcase) {
292		case 0: /* no overlap */
293			if (needtolink) {
294				*prev = lock;
295				lock->lf_next = overlap;
296			}
297			break;
298
299		case 1: /* overlap == lock */
300			/*
301			 * If downgrading lock, others may be
302			 * able to acquire it.
303			 */
304			if (lock->lf_type == F_RDLCK &&
305			    overlap->lf_type == F_WRLCK)
306				lf_wakelock(overlap);
307			overlap->lf_type = lock->lf_type;
308			FREE(lock, M_LOCKF);
309			lock = overlap; /* for debug output below */
310			break;
311
312		case 2: /* overlap contains lock */
313			/*
314			 * Check for common starting point and different types.
315			 */
316			if (overlap->lf_type == lock->lf_type) {
317				free(lock, M_LOCKF);
318				lock = overlap; /* for debug output below */
319				break;
320			}
321			if (overlap->lf_start == lock->lf_start) {
322				*prev = lock;
323				lock->lf_next = overlap;
324				overlap->lf_start = lock->lf_end + 1;
325			} else
326				lf_split(overlap, lock);
327			lf_wakelock(overlap);
328			break;
329
330		case 3: /* lock contains overlap */
331			/*
332			 * If downgrading lock, others may be able to
333			 * acquire it, otherwise take the list.
334			 */
335			if (lock->lf_type == F_RDLCK &&
336			    overlap->lf_type == F_WRLCK) {
337				lf_wakelock(overlap);
338			} else {
339				ltmp = lock->lf_block;
340				lock->lf_block = overlap->lf_block;
341				lf_addblock(lock, ltmp);
342			}
343			/*
344			 * Add the new lock if necessary and delete the overlap.
345			 */
346			if (needtolink) {
347				*prev = lock;
348				lock->lf_next = overlap->lf_next;
349				prev = &lock->lf_next;
350				needtolink = 0;
351			} else
352				*prev = overlap->lf_next;
353			free(overlap, M_LOCKF);
354			continue;
355
356		case 4: /* overlap starts before lock */
357			/*
358			 * Add lock after overlap on the list.
359			 */
360			lock->lf_next = overlap->lf_next;
361			overlap->lf_next = lock;
362			overlap->lf_end = lock->lf_start - 1;
363			prev = &lock->lf_next;
364			lf_wakelock(overlap);
365			needtolink = 0;
366			continue;
367
368		case 5: /* overlap ends after lock */
369			/*
370			 * Add the new lock before overlap.
371			 */
372			if (needtolink) {
373				*prev = lock;
374				lock->lf_next = overlap;
375			}
376			overlap->lf_start = lock->lf_end + 1;
377			lf_wakelock(overlap);
378			break;
379		}
380		break;
381	}
382#ifdef LOCKF_DEBUG
383	if (lockf_debug & 1) {
384		lf_print("lf_setlock: got the lock", lock);
385		lf_printlist("lf_setlock", lock);
386	}
387#endif /* LOCKF_DEBUG */
388	return (0);
389}
390
391/*
392 * Remove a byte-range lock on an inode.
393 *
394 * Generally, find the lock (or an overlap to that lock)
395 * and remove it (or shrink it), then wakeup anyone we can.
396 */
397int
398lf_clearlock(unlock)
399	register struct lockf *unlock;
400{
401	struct lockf **head = unlock->lf_head;
402	register struct lockf *lf = *head;
403	struct lockf *overlap, **prev;
404	int ovcase;
405
406	if (lf == NOLOCKF)
407		return (0);
408#ifdef LOCKF_DEBUG
409	if (unlock->lf_type != F_UNLCK)
410		panic("lf_clearlock: bad type");
411	if (lockf_debug & 1)
412		lf_print("lf_clearlock", unlock);
413#endif /* LOCKF_DEBUG */
414	prev = head;
415	while (ovcase = lf_findoverlap(lf, unlock, SELF, &prev, &overlap)) {
416		/*
417		 * Wakeup the list of locks to be retried.
418		 */
419		lf_wakelock(overlap);
420
421		switch (ovcase) {
422
423		case 1: /* overlap == lock */
424			*prev = overlap->lf_next;
425			FREE(overlap, M_LOCKF);
426			break;
427
428		case 2: /* overlap contains lock: split it */
429			if (overlap->lf_start == unlock->lf_start) {
430				overlap->lf_start = unlock->lf_end + 1;
431				break;
432			}
433			lf_split(overlap, unlock);
434			overlap->lf_next = unlock->lf_next;
435			break;
436
437		case 3: /* lock contains overlap */
438			*prev = overlap->lf_next;
439			lf = overlap->lf_next;
440			free(overlap, M_LOCKF);
441			continue;
442
443		case 4: /* overlap starts before lock */
444			overlap->lf_end = unlock->lf_start - 1;
445			prev = &overlap->lf_next;
446			lf = overlap->lf_next;
447			continue;
448
449		case 5: /* overlap ends after lock */
450			overlap->lf_start = unlock->lf_end + 1;
451			break;
452		}
453		break;
454	}
455#ifdef LOCKF_DEBUG
456	if (lockf_debug & 1)
457		lf_printlist("lf_clearlock", unlock);
458#endif /* LOCKF_DEBUG */
459	return (0);
460}
461
462/*
463 * Check whether there is a blocking lock,
464 * and if so return its process identifier.
465 */
466int
467lf_getlock(lock, fl)
468	register struct lockf *lock;
469	register struct flock *fl;
470{
471	register struct lockf *block;
472
473#ifdef LOCKF_DEBUG
474	if (lockf_debug & 1)
475		lf_print("lf_getlock", lock);
476#endif /* LOCKF_DEBUG */
477
478	if (block = lf_getblock(lock)) {
479		fl->l_type = block->lf_type;
480		fl->l_whence = SEEK_SET;
481		fl->l_start = block->lf_start;
482		if (block->lf_end == -1)
483			fl->l_len = 0;
484		else
485			fl->l_len = block->lf_end - block->lf_start + 1;
486		if (block->lf_flags & F_POSIX)
487			fl->l_pid = ((struct proc *)(block->lf_id))->p_pid;
488		else
489			fl->l_pid = -1;
490	} else {
491		fl->l_type = F_UNLCK;
492	}
493	return (0);
494}
495
496/*
497 * Walk the list of locks for an inode and
498 * return the first blocking lock.
499 */
500struct lockf *
501lf_getblock(lock)
502	register struct lockf *lock;
503{
504	struct lockf **prev, *overlap, *lf = *(lock->lf_head);
505	int ovcase;
506
507	prev = lock->lf_head;
508	while (ovcase = lf_findoverlap(lf, lock, OTHERS, &prev, &overlap)) {
509		/*
510		 * We've found an overlap, see if it blocks us
511		 */
512		if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK))
513			return (overlap);
514		/*
515		 * Nope, point to the next one on the list and
516		 * see if it blocks us
517		 */
518		lf = overlap->lf_next;
519	}
520	return (NOLOCKF);
521}
522
523/*
524 * Walk the list of locks for an inode to
525 * find an overlapping lock (if any).
526 *
527 * NOTE: this returns only the FIRST overlapping lock.  There
528 *	 may be more than one.
529 */
530int
531lf_findoverlap(lf, lock, type, prev, overlap)
532	register struct lockf *lf;
533	struct lockf *lock;
534	int type;
535	struct lockf ***prev;
536	struct lockf **overlap;
537{
538	off_t start, end;
539
540	*overlap = lf;
541	if (lf == NOLOCKF)
542		return (0);
543#ifdef LOCKF_DEBUG
544	if (lockf_debug & 2)
545		lf_print("lf_findoverlap: looking for overlap in", lock);
546#endif /* LOCKF_DEBUG */
547	start = lock->lf_start;
548	end = lock->lf_end;
549	while (lf != NOLOCKF) {
550		if (((type & SELF) && lf->lf_id != lock->lf_id) ||
551		    ((type & OTHERS) && lf->lf_id == lock->lf_id)) {
552			*prev = &lf->lf_next;
553			*overlap = lf = lf->lf_next;
554			continue;
555		}
556#ifdef LOCKF_DEBUG
557		if (lockf_debug & 2)
558			lf_print("\tchecking", lf);
559#endif /* LOCKF_DEBUG */
560		/*
561		 * OK, check for overlap
562		 *
563		 * Six cases:
564		 *	0) no overlap
565		 *	1) overlap == lock
566		 *	2) overlap contains lock
567		 *	3) lock contains overlap
568		 *	4) overlap starts before lock
569		 *	5) overlap ends after lock
570		 */
571		if ((lf->lf_end != -1 && start > lf->lf_end) ||
572		    (end != -1 && lf->lf_start > end)) {
573			/* Case 0 */
574#ifdef LOCKF_DEBUG
575			if (lockf_debug & 2)
576				printf("no overlap\n");
577#endif /* LOCKF_DEBUG */
578			if ((type & SELF) && end != -1 && lf->lf_start > end)
579				return (0);
580			*prev = &lf->lf_next;
581			*overlap = lf = lf->lf_next;
582			continue;
583		}
584		if ((lf->lf_start == start) && (lf->lf_end == end)) {
585			/* Case 1 */
586#ifdef LOCKF_DEBUG
587			if (lockf_debug & 2)
588				printf("overlap == lock\n");
589#endif /* LOCKF_DEBUG */
590			return (1);
591		}
592		if ((lf->lf_start <= start) &&
593		    (end != -1) &&
594		    ((lf->lf_end >= end) || (lf->lf_end == -1))) {
595			/* Case 2 */
596#ifdef LOCKF_DEBUG
597			if (lockf_debug & 2)
598				printf("overlap contains lock\n");
599#endif /* LOCKF_DEBUG */
600			return (2);
601		}
602		if (start <= lf->lf_start &&
603		           (end == -1 ||
604			   (lf->lf_end != -1 && end >= lf->lf_end))) {
605			/* Case 3 */
606#ifdef LOCKF_DEBUG
607			if (lockf_debug & 2)
608				printf("lock contains overlap\n");
609#endif /* LOCKF_DEBUG */
610			return (3);
611		}
612		if ((lf->lf_start < start) &&
613			((lf->lf_end >= start) || (lf->lf_end == -1))) {
614			/* Case 4 */
615#ifdef LOCKF_DEBUG
616			if (lockf_debug & 2)
617				printf("overlap starts before lock\n");
618#endif /* LOCKF_DEBUG */
619			return (4);
620		}
621		if ((lf->lf_start > start) &&
622			(end != -1) &&
623			((lf->lf_end > end) || (lf->lf_end == -1))) {
624			/* Case 5 */
625#ifdef LOCKF_DEBUG
626			if (lockf_debug & 2)
627				printf("overlap ends after lock\n");
628#endif /* LOCKF_DEBUG */
629			return (5);
630		}
631		panic("lf_findoverlap: default");
632	}
633	return (0);
634}
635
636/*
637 * Add a lock to the end of the blocked list.
638 */
639void
640lf_addblock(lock, blocked)
641	struct lockf *lock;
642	struct lockf *blocked;
643{
644	register struct lockf *lf;
645
646	if (blocked == NOLOCKF)
647		return;
648#ifdef LOCKF_DEBUG
649	if (lockf_debug & 2) {
650		lf_print("addblock: adding", blocked);
651		lf_print("to blocked list of", lock);
652	}
653#endif /* LOCKF_DEBUG */
654	if ((lf = lock->lf_block) == NOLOCKF) {
655		lock->lf_block = blocked;
656		return;
657	}
658	while (lf->lf_block != NOLOCKF)
659		lf = lf->lf_block;
660	lf->lf_block = blocked;
661	return;
662}
663
664/*
665 * Split a lock and a contained region into
666 * two or three locks as necessary.
667 */
668void
669lf_split(lock1, lock2)
670	register struct lockf *lock1;
671	register struct lockf *lock2;
672{
673	register struct lockf *splitlock;
674
675#ifdef LOCKF_DEBUG
676	if (lockf_debug & 2) {
677		lf_print("lf_split", lock1);
678		lf_print("splitting from", lock2);
679	}
680#endif /* LOCKF_DEBUG */
681	/*
682	 * Check to see if spliting into only two pieces.
683	 */
684	if (lock1->lf_start == lock2->lf_start) {
685		lock1->lf_start = lock2->lf_end + 1;
686		lock2->lf_next = lock1;
687		return;
688	}
689	if (lock1->lf_end == lock2->lf_end) {
690		lock1->lf_end = lock2->lf_start - 1;
691		lock2->lf_next = lock1->lf_next;
692		lock1->lf_next = lock2;
693		return;
694	}
695	/*
696	 * Make a new lock consisting of the last part of
697	 * the encompassing lock
698	 */
699	MALLOC(splitlock, struct lockf *, sizeof *splitlock, M_LOCKF, M_WAITOK);
700	bcopy((caddr_t)lock1, (caddr_t)splitlock, sizeof *splitlock);
701	splitlock->lf_start = lock2->lf_end + 1;
702	splitlock->lf_block = NOLOCKF;
703	lock1->lf_end = lock2->lf_start - 1;
704	/*
705	 * OK, now link it in
706	 */
707	splitlock->lf_next = lock1->lf_next;
708	lock2->lf_next = splitlock;
709	lock1->lf_next = lock2;
710}
711
712/*
713 * Wakeup a blocklist
714 */
715void
716lf_wakelock(listhead)
717	struct lockf *listhead;
718{
719	register struct lockf *blocklist, *wakelock;
720
721	blocklist = listhead->lf_block;
722	listhead->lf_block = NOLOCKF;
723	while (blocklist != NOLOCKF) {
724		wakelock = blocklist;
725		blocklist = blocklist->lf_block;
726		wakelock->lf_block = NOLOCKF;
727		wakelock->lf_next = NOLOCKF;
728#ifdef LOCKF_DEBUG
729		if (lockf_debug & 2)
730			lf_print("lf_wakelock: awakening", wakelock);
731#endif /* LOCKF_DEBUG */
732		wakeup((caddr_t)wakelock);
733	}
734}
735
736#ifdef LOCKF_DEBUG
737/*
738 * Print out a lock.
739 */
740void
741lf_print(tag, lock)
742	char *tag;
743	register struct lockf *lock;
744{
745
746	printf("%s: lock 0x%lx for ", tag, lock);
747	if (lock->lf_flags & F_POSIX)
748		printf("proc %d", ((struct proc *)(lock->lf_id))->p_pid);
749	else
750		printf("id 0x%x", lock->lf_id);
751	printf(" in ino %d on dev <%d, %d>, %s, start %d, end %d",
752		lock->lf_inode->i_number,
753		major(lock->lf_inode->i_dev),
754		minor(lock->lf_inode->i_dev),
755		lock->lf_type == F_RDLCK ? "shared" :
756		lock->lf_type == F_WRLCK ? "exclusive" :
757		lock->lf_type == F_UNLCK ? "unlock" :
758		"unknown", lock->lf_start, lock->lf_end);
759	if (lock->lf_block)
760		printf(" block 0x%x\n", lock->lf_block);
761	else
762		printf("\n");
763}
764
765void
766lf_printlist(tag, lock)
767	char *tag;
768	struct lockf *lock;
769{
770	register struct lockf *lf;
771
772	printf("%s: Lock list for ino %d on dev <%d, %d>:\n",
773		tag, lock->lf_inode->i_number,
774		major(lock->lf_inode->i_dev),
775		minor(lock->lf_inode->i_dev));
776	for (lf = lock->lf_inode->i_lockf; lf; lf = lf->lf_next) {
777		printf("\tlock 0x%lx for ", lf);
778		if (lf->lf_flags & F_POSIX)
779			printf("proc %d", ((struct proc *)(lf->lf_id))->p_pid);
780		else
781			printf("id 0x%x", lf->lf_id);
782		printf(", %s, start %d, end %d",
783			lf->lf_type == F_RDLCK ? "shared" :
784			lf->lf_type == F_WRLCK ? "exclusive" :
785			lf->lf_type == F_UNLCK ? "unlock" :
786			"unknown", lf->lf_start, lf->lf_end);
787		if (lf->lf_block)
788			printf(" block 0x%x\n", lf->lf_block);
789		else
790			printf("\n");
791	}
792}
793#endif /* LOCKF_DEBUG */
794