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