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