1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vfs_subr.c 7.60 (Berkeley) 06/21/91 8 */ 9 10 /* 11 * External virtual filesystem routines 12 */ 13 14 #include "param.h" 15 #include "proc.h" 16 #include "mount.h" 17 #include "time.h" 18 #include "vnode.h" 19 #include "specdev.h" 20 #include "namei.h" 21 #include "ucred.h" 22 #include "buf.h" 23 #include "errno.h" 24 #include "malloc.h" 25 26 /* 27 * Remove a mount point from the list of mounted filesystems. 28 * Unmount of the root is illegal. 29 */ 30 void 31 vfs_remove(mp) 32 register struct mount *mp; 33 { 34 35 if (mp == rootfs) 36 panic("vfs_remove: unmounting root"); 37 mp->mnt_prev->mnt_next = mp->mnt_next; 38 mp->mnt_next->mnt_prev = mp->mnt_prev; 39 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 40 vfs_unlock(mp); 41 } 42 43 /* 44 * Lock a filesystem. 45 * Used to prevent access to it while mounting and unmounting. 46 */ 47 vfs_lock(mp) 48 register struct mount *mp; 49 { 50 51 while(mp->mnt_flag & MNT_MLOCK) { 52 mp->mnt_flag |= MNT_MWAIT; 53 sleep((caddr_t)mp, PVFS); 54 } 55 mp->mnt_flag |= MNT_MLOCK; 56 return (0); 57 } 58 59 /* 60 * Unlock a locked filesystem. 61 * Panic if filesystem is not locked. 62 */ 63 void 64 vfs_unlock(mp) 65 register struct mount *mp; 66 { 67 68 if ((mp->mnt_flag & MNT_MLOCK) == 0) 69 panic("vfs_unlock: not locked"); 70 mp->mnt_flag &= ~MNT_MLOCK; 71 if (mp->mnt_flag & MNT_MWAIT) { 72 mp->mnt_flag &= ~MNT_MWAIT; 73 wakeup((caddr_t)mp); 74 } 75 } 76 77 /* 78 * Mark a mount point as busy. 79 * Used to synchronize access and to delay unmounting. 80 */ 81 vfs_busy(mp) 82 register struct mount *mp; 83 { 84 85 while(mp->mnt_flag & MNT_MPBUSY) { 86 mp->mnt_flag |= MNT_MPWANT; 87 sleep((caddr_t)&mp->mnt_flag, PVFS); 88 } 89 if (mp->mnt_flag & MNT_UNMOUNT) 90 return (1); 91 mp->mnt_flag |= MNT_MPBUSY; 92 return (0); 93 } 94 95 /* 96 * Free a busy filesystem. 97 * Panic if filesystem is not busy. 98 */ 99 vfs_unbusy(mp) 100 register struct mount *mp; 101 { 102 103 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 104 panic("vfs_unbusy: not busy"); 105 mp->mnt_flag &= ~MNT_MPBUSY; 106 if (mp->mnt_flag & MNT_MPWANT) { 107 mp->mnt_flag &= ~MNT_MPWANT; 108 wakeup((caddr_t)&mp->mnt_flag); 109 } 110 } 111 112 /* 113 * Lookup a mount point by filesystem identifier. 114 */ 115 struct mount * 116 getvfs(fsid) 117 fsid_t *fsid; 118 { 119 register struct mount *mp; 120 121 mp = rootfs; 122 do { 123 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 124 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 125 return (mp); 126 } 127 mp = mp->mnt_next; 128 } while (mp != rootfs); 129 return ((struct mount *)0); 130 } 131 132 /* 133 * Set vnode attributes to VNOVAL 134 */ 135 void vattr_null(vap) 136 register struct vattr *vap; 137 { 138 139 vap->va_type = VNON; 140 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 141 vap->va_fsid = vap->va_fileid = vap->va_size = 142 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 143 vap->va_bytes = vap->va_bytes_rsv = 144 vap->va_atime.tv_sec = vap->va_atime.tv_usec = 145 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 146 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 147 vap->va_flags = vap->va_gen = VNOVAL; 148 } 149 150 /* 151 * Routines having to do with the management of the vnode table. 152 */ 153 struct vnode *vfreeh, **vfreet; 154 extern struct vnodeops dead_vnodeops, spec_vnodeops; 155 extern void vclean(); 156 long numvnodes; 157 struct vattr va_null; 158 159 /* 160 * Initialize the vnode structures and initialize each file system type. 161 */ 162 vfsinit() 163 { 164 struct vfsops **vfsp; 165 166 /* 167 * Initialize the vnode name cache 168 */ 169 nchinit(); 170 /* 171 * Initialize each file system type. 172 */ 173 vattr_null(&va_null); 174 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 175 if (*vfsp == NULL) 176 continue; 177 (*(*vfsp)->vfs_init)(); 178 } 179 } 180 181 /* 182 * Return the next vnode from the free list. 183 */ 184 getnewvnode(tag, mp, vops, vpp) 185 enum vtagtype tag; 186 struct mount *mp; 187 struct vnodeops *vops; 188 struct vnode **vpp; 189 { 190 register struct vnode *vp, *vq; 191 192 if (numvnodes < desiredvnodes) { 193 vp = (struct vnode *)malloc((u_long)sizeof *vp, 194 M_VNODE, M_WAITOK); 195 bzero((char *)vp, sizeof *vp); 196 numvnodes++; 197 } else { 198 if ((vp = vfreeh) == NULL) { 199 tablefull("vnode"); 200 *vpp = 0; 201 return (ENFILE); 202 } 203 if (vp->v_usecount) 204 panic("free vnode isn't"); 205 if (vq = vp->v_freef) 206 vq->v_freeb = &vfreeh; 207 else 208 vfreet = &vfreeh; 209 vfreeh = vq; 210 vp->v_freef = NULL; 211 vp->v_freeb = NULL; 212 if (vp->v_type != VBAD) 213 vgone(vp); 214 vp->v_flag = 0; 215 vp->v_lastr = 0; 216 vp->v_socket = 0; 217 } 218 vp->v_type = VNON; 219 cache_purge(vp); 220 vp->v_tag = tag; 221 vp->v_op = vops; 222 insmntque(vp, mp); 223 VREF(vp); 224 *vpp = vp; 225 return (0); 226 } 227 228 /* 229 * Move a vnode from one mount queue to another. 230 */ 231 insmntque(vp, mp) 232 register struct vnode *vp; 233 register struct mount *mp; 234 { 235 register struct vnode *vq; 236 237 /* 238 * Delete from old mount point vnode list, if on one. 239 */ 240 if (vp->v_mountb) { 241 if (vq = vp->v_mountf) 242 vq->v_mountb = vp->v_mountb; 243 *vp->v_mountb = vq; 244 } 245 /* 246 * Insert into list of vnodes for the new mount point, if available. 247 */ 248 vp->v_mount = mp; 249 if (mp == NULL) { 250 vp->v_mountf = NULL; 251 vp->v_mountb = NULL; 252 return; 253 } 254 if (vq = mp->mnt_mounth) 255 vq->v_mountb = &vp->v_mountf; 256 vp->v_mountf = vq; 257 vp->v_mountb = &mp->mnt_mounth; 258 mp->mnt_mounth = vp; 259 } 260 261 /* 262 * Make sure all write-behind blocks associated 263 * with mount point are flushed out (from sync). 264 */ 265 mntflushbuf(mountp, flags) 266 struct mount *mountp; 267 int flags; 268 { 269 register struct vnode *vp; 270 271 if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 272 panic("mntflushbuf: not busy"); 273 loop: 274 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 275 if (VOP_ISLOCKED(vp)) 276 continue; 277 if (vget(vp)) 278 goto loop; 279 vflushbuf(vp, flags); 280 vput(vp); 281 if (vp->v_mount != mountp) 282 goto loop; 283 } 284 } 285 286 /* 287 * Flush all dirty buffers associated with a vnode. 288 */ 289 vflushbuf(vp, flags) 290 register struct vnode *vp; 291 int flags; 292 { 293 register struct buf *bp; 294 struct buf *nbp; 295 int s; 296 297 loop: 298 s = splbio(); 299 for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 300 nbp = bp->b_blockf; 301 if ((bp->b_flags & B_BUSY)) 302 continue; 303 if ((bp->b_flags & B_DELWRI) == 0) 304 panic("vflushbuf: not dirty"); 305 bremfree(bp); 306 bp->b_flags |= B_BUSY; 307 splx(s); 308 /* 309 * Wait for I/O associated with indirect blocks to complete, 310 * since there is no way to quickly wait for them below. 311 * NB: This is really specific to ufs, but is done here 312 * as it is easier and quicker. 313 */ 314 if (bp->b_vp == vp || (flags & B_SYNC) == 0) 315 (void) bawrite(bp); 316 else 317 (void) bwrite(bp); 318 goto loop; 319 } 320 splx(s); 321 if ((flags & B_SYNC) == 0) 322 return; 323 s = splbio(); 324 while (vp->v_numoutput) { 325 vp->v_flag |= VBWAIT; 326 sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 327 } 328 splx(s); 329 if (vp->v_dirtyblkhd) { 330 vprint("vflushbuf: dirty", vp); 331 goto loop; 332 } 333 } 334 335 /* 336 * Update outstanding I/O count and do wakeup if requested. 337 */ 338 vwakeup(bp) 339 register struct buf *bp; 340 { 341 register struct vnode *vp; 342 343 bp->b_dirtyoff = bp->b_dirtyend = 0; 344 if (vp = bp->b_vp) { 345 vp->v_numoutput--; 346 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 347 if (vp->v_numoutput < 0) 348 panic("vwakeup: neg numoutput"); 349 vp->v_flag &= ~VBWAIT; 350 wakeup((caddr_t)&vp->v_numoutput); 351 } 352 } 353 } 354 355 /* 356 * Invalidate in core blocks belonging to closed or umounted filesystem 357 * 358 * Go through the list of vnodes associated with the file system; 359 * for each vnode invalidate any buffers that it holds. Normally 360 * this routine is preceeded by a bflush call, so that on a quiescent 361 * filesystem there will be no dirty buffers when we are done. Binval 362 * returns the count of dirty buffers when it is finished. 363 */ 364 mntinvalbuf(mountp) 365 struct mount *mountp; 366 { 367 register struct vnode *vp; 368 int dirty = 0; 369 370 if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 371 panic("mntinvalbuf: not busy"); 372 loop: 373 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 374 if (vget(vp)) 375 goto loop; 376 dirty += vinvalbuf(vp, 1); 377 vput(vp); 378 if (vp->v_mount != mountp) 379 goto loop; 380 } 381 return (dirty); 382 } 383 384 /* 385 * Flush out and invalidate all buffers associated with a vnode. 386 * Called with the underlying object locked. 387 */ 388 vinvalbuf(vp, save) 389 register struct vnode *vp; 390 int save; 391 { 392 register struct buf *bp; 393 struct buf *nbp, *blist; 394 int s, dirty = 0; 395 396 for (;;) { 397 if (blist = vp->v_dirtyblkhd) 398 /* void */; 399 else if (blist = vp->v_cleanblkhd) 400 /* void */; 401 else 402 break; 403 for (bp = blist; bp; bp = nbp) { 404 nbp = bp->b_blockf; 405 s = splbio(); 406 if (bp->b_flags & B_BUSY) { 407 bp->b_flags |= B_WANTED; 408 sleep((caddr_t)bp, PRIBIO + 1); 409 splx(s); 410 break; 411 } 412 bremfree(bp); 413 bp->b_flags |= B_BUSY; 414 splx(s); 415 if (save && (bp->b_flags & B_DELWRI)) { 416 dirty++; 417 (void) bwrite(bp); 418 break; 419 } 420 if (bp->b_vp != vp) 421 reassignbuf(bp, bp->b_vp); 422 else 423 bp->b_flags |= B_INVAL; 424 brelse(bp); 425 } 426 } 427 if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 428 panic("vinvalbuf: flush failed"); 429 return (dirty); 430 } 431 432 /* 433 * Associate a buffer with a vnode. 434 */ 435 bgetvp(vp, bp) 436 register struct vnode *vp; 437 register struct buf *bp; 438 { 439 register struct vnode *vq; 440 register struct buf *bq; 441 442 if (bp->b_vp) 443 panic("bgetvp: not free"); 444 VHOLD(vp); 445 bp->b_vp = vp; 446 if (vp->v_type == VBLK || vp->v_type == VCHR) 447 bp->b_dev = vp->v_rdev; 448 else 449 bp->b_dev = NODEV; 450 /* 451 * Insert onto list for new vnode. 452 */ 453 if (bq = vp->v_cleanblkhd) 454 bq->b_blockb = &bp->b_blockf; 455 bp->b_blockf = bq; 456 bp->b_blockb = &vp->v_cleanblkhd; 457 vp->v_cleanblkhd = bp; 458 } 459 460 /* 461 * Disassociate a buffer from a vnode. 462 */ 463 brelvp(bp) 464 register struct buf *bp; 465 { 466 struct buf *bq; 467 struct vnode *vp; 468 469 if (bp->b_vp == (struct vnode *) 0) 470 panic("brelvp: NULL"); 471 /* 472 * Delete from old vnode list, if on one. 473 */ 474 if (bp->b_blockb) { 475 if (bq = bp->b_blockf) 476 bq->b_blockb = bp->b_blockb; 477 *bp->b_blockb = bq; 478 bp->b_blockf = NULL; 479 bp->b_blockb = NULL; 480 } 481 vp = bp->b_vp; 482 bp->b_vp = (struct vnode *) 0; 483 HOLDRELE(vp); 484 } 485 486 /* 487 * Reassign a buffer from one vnode to another. 488 * Used to assign file specific control information 489 * (indirect blocks) to the vnode to which they belong. 490 */ 491 reassignbuf(bp, newvp) 492 register struct buf *bp; 493 register struct vnode *newvp; 494 { 495 register struct buf *bq, **listheadp; 496 497 if (newvp == NULL) 498 panic("reassignbuf: NULL"); 499 /* 500 * Delete from old vnode list, if on one. 501 */ 502 if (bp->b_blockb) { 503 if (bq = bp->b_blockf) 504 bq->b_blockb = bp->b_blockb; 505 *bp->b_blockb = bq; 506 } 507 /* 508 * If dirty, put on list of dirty buffers; 509 * otherwise insert onto list of clean buffers. 510 */ 511 if (bp->b_flags & B_DELWRI) 512 listheadp = &newvp->v_dirtyblkhd; 513 else 514 listheadp = &newvp->v_cleanblkhd; 515 if (bq = *listheadp) 516 bq->b_blockb = &bp->b_blockf; 517 bp->b_blockf = bq; 518 bp->b_blockb = listheadp; 519 *listheadp = bp; 520 } 521 522 /* 523 * Create a vnode for a block device. 524 * Used for root filesystem, argdev, and swap areas. 525 * Also used for memory file system special devices. 526 */ 527 bdevvp(dev, vpp) 528 dev_t dev; 529 struct vnode **vpp; 530 { 531 register struct vnode *vp; 532 struct vnode *nvp; 533 int error; 534 535 if (dev == NODEV) 536 return (0); 537 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 538 if (error) { 539 *vpp = 0; 540 return (error); 541 } 542 vp = nvp; 543 vp->v_type = VBLK; 544 if (nvp = checkalias(vp, dev, (struct mount *)0)) { 545 vput(vp); 546 vp = nvp; 547 } 548 *vpp = vp; 549 return (0); 550 } 551 552 /* 553 * Check to see if the new vnode represents a special device 554 * for which we already have a vnode (either because of 555 * bdevvp() or because of a different vnode representing 556 * the same block device). If such an alias exists, deallocate 557 * the existing contents and return the aliased vnode. The 558 * caller is responsible for filling it with its new contents. 559 */ 560 struct vnode * 561 checkalias(nvp, nvp_rdev, mp) 562 register struct vnode *nvp; 563 dev_t nvp_rdev; 564 struct mount *mp; 565 { 566 register struct vnode *vp; 567 struct vnode **vpp; 568 569 if (nvp->v_type != VBLK && nvp->v_type != VCHR) 570 return (NULLVP); 571 572 vpp = &speclisth[SPECHASH(nvp_rdev)]; 573 loop: 574 for (vp = *vpp; vp; vp = vp->v_specnext) { 575 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 576 continue; 577 /* 578 * Alias, but not in use, so flush it out. 579 */ 580 if (vp->v_usecount == 0) { 581 vgone(vp); 582 goto loop; 583 } 584 if (vget(vp)) 585 goto loop; 586 break; 587 } 588 if (vp == NULL || vp->v_tag != VT_NON) { 589 MALLOC(nvp->v_specinfo, struct specinfo *, 590 sizeof(struct specinfo), M_VNODE, M_WAITOK); 591 nvp->v_rdev = nvp_rdev; 592 nvp->v_hashchain = vpp; 593 nvp->v_specnext = *vpp; 594 nvp->v_specflags = 0; 595 *vpp = nvp; 596 if (vp != NULL) { 597 nvp->v_flag |= VALIASED; 598 vp->v_flag |= VALIASED; 599 vput(vp); 600 } 601 return (NULLVP); 602 } 603 VOP_UNLOCK(vp); 604 vclean(vp, 0); 605 vp->v_op = nvp->v_op; 606 vp->v_tag = nvp->v_tag; 607 nvp->v_type = VNON; 608 insmntque(vp, mp); 609 return (vp); 610 } 611 612 /* 613 * Grab a particular vnode from the free list, increment its 614 * reference count and lock it. The vnode lock bit is set the 615 * vnode is being eliminated in vgone. The process is awakened 616 * when the transition is completed, and an error returned to 617 * indicate that the vnode is no longer usable (possibly having 618 * been changed to a new file system type). 619 */ 620 vget(vp) 621 register struct vnode *vp; 622 { 623 register struct vnode *vq; 624 625 if (vp->v_flag & VXLOCK) { 626 vp->v_flag |= VXWANT; 627 sleep((caddr_t)vp, PINOD); 628 return (1); 629 } 630 if (vp->v_usecount == 0) { 631 if (vq = vp->v_freef) 632 vq->v_freeb = vp->v_freeb; 633 else 634 vfreet = vp->v_freeb; 635 *vp->v_freeb = vq; 636 vp->v_freef = NULL; 637 vp->v_freeb = NULL; 638 } 639 VREF(vp); 640 VOP_LOCK(vp); 641 return (0); 642 } 643 644 /* 645 * Vnode reference, just increment the count 646 */ 647 void vref(vp) 648 struct vnode *vp; 649 { 650 651 vp->v_usecount++; 652 } 653 654 /* 655 * vput(), just unlock and vrele() 656 */ 657 void vput(vp) 658 register struct vnode *vp; 659 { 660 VOP_UNLOCK(vp); 661 vrele(vp); 662 } 663 664 /* 665 * Vnode release. 666 * If count drops to zero, call inactive routine and return to freelist. 667 */ 668 void vrele(vp) 669 register struct vnode *vp; 670 { 671 struct proc *p = curproc; /* XXX */ 672 673 #ifdef DIAGNOSTIC 674 if (vp == NULL) 675 panic("vrele: null vp"); 676 #endif 677 vp->v_usecount--; 678 if (vp->v_usecount > 0) 679 return; 680 #ifdef DIAGNOSTIC 681 if (vp->v_usecount != 0 || vp->v_writecount != 0) { 682 vprint("vrele: bad ref count", vp); 683 panic("vrele: ref cnt"); 684 } 685 #endif 686 if (vfreeh == NULLVP) { 687 /* 688 * insert into empty list 689 */ 690 vfreeh = vp; 691 vp->v_freeb = &vfreeh; 692 } else { 693 /* 694 * insert at tail of list 695 */ 696 *vfreet = vp; 697 vp->v_freeb = vfreet; 698 } 699 vp->v_freef = NULL; 700 vfreet = &vp->v_freef; 701 VOP_INACTIVE(vp, p); 702 } 703 704 /* 705 * Page or buffer structure gets a reference. 706 */ 707 vhold(vp) 708 register struct vnode *vp; 709 { 710 711 vp->v_holdcnt++; 712 } 713 714 /* 715 * Page or buffer structure frees a reference. 716 */ 717 holdrele(vp) 718 register struct vnode *vp; 719 { 720 721 if (vp->v_holdcnt <= 0) 722 panic("holdrele: holdcnt"); 723 vp->v_holdcnt--; 724 } 725 726 /* 727 * Remove any vnodes in the vnode table belonging to mount point mp. 728 * 729 * If MNT_NOFORCE is specified, there should not be any active ones, 730 * return error if any are found (nb: this is a user error, not a 731 * system error). If MNT_FORCE is specified, detach any active vnodes 732 * that are found. 733 */ 734 int busyprt = 0; /* patch to print out busy vnodes */ 735 736 vflush(mp, skipvp, flags) 737 struct mount *mp; 738 struct vnode *skipvp; 739 int flags; 740 { 741 register struct vnode *vp, *nvp; 742 int busy = 0; 743 744 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 745 panic("vflush: not busy"); 746 loop: 747 for (vp = mp->mnt_mounth; vp; vp = nvp) { 748 if (vp->v_mount != mp) 749 goto loop; 750 nvp = vp->v_mountf; 751 /* 752 * Skip over a selected vnode. 753 */ 754 if (vp == skipvp) 755 continue; 756 /* 757 * Skip over a vnodes marked VSYSTEM. 758 */ 759 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 760 continue; 761 /* 762 * With v_usecount == 0, all we need to do is clear 763 * out the vnode data structures and we are done. 764 */ 765 if (vp->v_usecount == 0) { 766 vgone(vp); 767 continue; 768 } 769 /* 770 * For block or character devices, revert to an 771 * anonymous device. For all other files, just kill them. 772 */ 773 if (flags & FORCECLOSE) { 774 if (vp->v_type != VBLK && vp->v_type != VCHR) { 775 vgone(vp); 776 } else { 777 vclean(vp, 0); 778 vp->v_op = &spec_vnodeops; 779 insmntque(vp, (struct mount *)0); 780 } 781 continue; 782 } 783 if (busyprt) 784 vprint("vflush: busy vnode", vp); 785 busy++; 786 } 787 if (busy) 788 return (EBUSY); 789 return (0); 790 } 791 792 /* 793 * Disassociate the underlying file system from a vnode. 794 */ 795 void vclean(vp, flags) 796 register struct vnode *vp; 797 int flags; 798 { 799 struct vnodeops *origops; 800 int active; 801 struct proc *p = curproc; /* XXX */ 802 803 /* 804 * Check to see if the vnode is in use. 805 * If so we have to reference it before we clean it out 806 * so that its count cannot fall to zero and generate a 807 * race against ourselves to recycle it. 808 */ 809 if (active = vp->v_usecount) 810 VREF(vp); 811 /* 812 * Prevent the vnode from being recycled or 813 * brought into use while we clean it out. 814 */ 815 if (vp->v_flag & VXLOCK) 816 panic("vclean: deadlock"); 817 vp->v_flag |= VXLOCK; 818 /* 819 * Even if the count is zero, the VOP_INACTIVE routine may still 820 * have the object locked while it cleans it out. The VOP_LOCK 821 * ensures that the VOP_INACTIVE routine is done with its work. 822 * For active vnodes, it ensures that no other activity can 823 * occur while the buffer list is being cleaned out. 824 */ 825 VOP_LOCK(vp); 826 if (flags & DOCLOSE) 827 vinvalbuf(vp, 1); 828 /* 829 * Prevent any further operations on the vnode from 830 * being passed through to the old file system. 831 */ 832 origops = vp->v_op; 833 vp->v_op = &dead_vnodeops; 834 vp->v_tag = VT_NON; 835 /* 836 * If purging an active vnode, it must be unlocked, closed, 837 * and deactivated before being reclaimed. 838 */ 839 (*(origops->vop_unlock))(vp); 840 if (active) { 841 if (flags & DOCLOSE) 842 (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 843 (*(origops->vop_inactive))(vp, p); 844 } 845 /* 846 * Reclaim the vnode. 847 */ 848 if ((*(origops->vop_reclaim))(vp)) 849 panic("vclean: cannot reclaim"); 850 if (active) 851 vrele(vp); 852 /* 853 * Done with purge, notify sleepers in vget of the grim news. 854 */ 855 vp->v_flag &= ~VXLOCK; 856 if (vp->v_flag & VXWANT) { 857 vp->v_flag &= ~VXWANT; 858 wakeup((caddr_t)vp); 859 } 860 } 861 862 /* 863 * Eliminate all activity associated with the requested vnode 864 * and with all vnodes aliased to the requested vnode. 865 */ 866 void vgoneall(vp) 867 register struct vnode *vp; 868 { 869 register struct vnode *vq; 870 871 if (vp->v_flag & VALIASED) { 872 /* 873 * If a vgone (or vclean) is already in progress, 874 * wait until it is done and return. 875 */ 876 if (vp->v_flag & VXLOCK) { 877 vp->v_flag |= VXWANT; 878 sleep((caddr_t)vp, PINOD); 879 return; 880 } 881 /* 882 * Ensure that vp will not be vgone'd while we 883 * are eliminating its aliases. 884 */ 885 vp->v_flag |= VXLOCK; 886 while (vp->v_flag & VALIASED) { 887 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 888 if (vq->v_rdev != vp->v_rdev || 889 vq->v_type != vp->v_type || vp == vq) 890 continue; 891 vgone(vq); 892 break; 893 } 894 } 895 /* 896 * Remove the lock so that vgone below will 897 * really eliminate the vnode after which time 898 * vgone will awaken any sleepers. 899 */ 900 vp->v_flag &= ~VXLOCK; 901 } 902 vgone(vp); 903 } 904 905 /* 906 * Eliminate all activity associated with a vnode 907 * in preparation for reuse. 908 */ 909 void vgone(vp) 910 register struct vnode *vp; 911 { 912 register struct vnode *vq; 913 struct vnode *vx; 914 long count; 915 916 /* 917 * If a vgone (or vclean) is already in progress, 918 * wait until it is done and return. 919 */ 920 if (vp->v_flag & VXLOCK) { 921 vp->v_flag |= VXWANT; 922 sleep((caddr_t)vp, PINOD); 923 return; 924 } 925 /* 926 * Clean out the filesystem specific data. 927 */ 928 vclean(vp, DOCLOSE); 929 /* 930 * Delete from old mount point vnode list, if on one. 931 */ 932 if (vp->v_mountb) { 933 if (vq = vp->v_mountf) 934 vq->v_mountb = vp->v_mountb; 935 *vp->v_mountb = vq; 936 vp->v_mountf = NULL; 937 vp->v_mountb = NULL; 938 } 939 /* 940 * If special device, remove it from special device alias list. 941 */ 942 if (vp->v_type == VBLK || vp->v_type == VCHR) { 943 if (*vp->v_hashchain == vp) { 944 *vp->v_hashchain = vp->v_specnext; 945 } else { 946 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 947 if (vq->v_specnext != vp) 948 continue; 949 vq->v_specnext = vp->v_specnext; 950 break; 951 } 952 if (vq == NULL) 953 panic("missing bdev"); 954 } 955 if (vp->v_flag & VALIASED) { 956 count = 0; 957 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 958 if (vq->v_rdev != vp->v_rdev || 959 vq->v_type != vp->v_type) 960 continue; 961 count++; 962 vx = vq; 963 } 964 if (count == 0) 965 panic("missing alias"); 966 if (count == 1) 967 vx->v_flag &= ~VALIASED; 968 vp->v_flag &= ~VALIASED; 969 } 970 FREE(vp->v_specinfo, M_VNODE); 971 vp->v_specinfo = NULL; 972 } 973 /* 974 * If it is on the freelist, move it to the head of the list. 975 */ 976 if (vp->v_freeb) { 977 if (vq = vp->v_freef) 978 vq->v_freeb = vp->v_freeb; 979 else 980 vfreet = vp->v_freeb; 981 *vp->v_freeb = vq; 982 vp->v_freef = vfreeh; 983 vp->v_freeb = &vfreeh; 984 vfreeh->v_freeb = &vp->v_freef; 985 vfreeh = vp; 986 } 987 vp->v_type = VBAD; 988 } 989 990 /* 991 * Lookup a vnode by device number. 992 */ 993 vfinddev(dev, type, vpp) 994 dev_t dev; 995 enum vtype type; 996 struct vnode **vpp; 997 { 998 register struct vnode *vp; 999 1000 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 1001 if (dev != vp->v_rdev || type != vp->v_type) 1002 continue; 1003 *vpp = vp; 1004 return (0); 1005 } 1006 return (1); 1007 } 1008 1009 /* 1010 * Calculate the total number of references to a special device. 1011 */ 1012 vcount(vp) 1013 register struct vnode *vp; 1014 { 1015 register struct vnode *vq; 1016 int count; 1017 1018 if ((vp->v_flag & VALIASED) == 0) 1019 return (vp->v_usecount); 1020 loop: 1021 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1022 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 1023 continue; 1024 /* 1025 * Alias, but not in use, so flush it out. 1026 */ 1027 if (vq->v_usecount == 0) { 1028 vgone(vq); 1029 goto loop; 1030 } 1031 count += vq->v_usecount; 1032 } 1033 return (count); 1034 } 1035 1036 /* 1037 * Print out a description of a vnode. 1038 */ 1039 static char *typename[] = 1040 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 1041 1042 vprint(label, vp) 1043 char *label; 1044 register struct vnode *vp; 1045 { 1046 char buf[64]; 1047 1048 if (label != NULL) 1049 printf("%s: ", label); 1050 printf("type %s, usecount %d, writecount %d, refcount %d,", 1051 typename[vp->v_type], vp->v_usecount, vp->v_writecount, 1052 vp->v_holdcnt); 1053 buf[0] = '\0'; 1054 if (vp->v_flag & VROOT) 1055 strcat(buf, "|VROOT"); 1056 if (vp->v_flag & VTEXT) 1057 strcat(buf, "|VTEXT"); 1058 if (vp->v_flag & VSYSTEM) 1059 strcat(buf, "|VSYSTEM"); 1060 if (vp->v_flag & VXLOCK) 1061 strcat(buf, "|VXLOCK"); 1062 if (vp->v_flag & VXWANT) 1063 strcat(buf, "|VXWANT"); 1064 if (vp->v_flag & VBWAIT) 1065 strcat(buf, "|VBWAIT"); 1066 if (vp->v_flag & VALIASED) 1067 strcat(buf, "|VALIASED"); 1068 if (buf[0] != '\0') 1069 printf(" flags (%s)", &buf[1]); 1070 printf("\n\t"); 1071 VOP_PRINT(vp); 1072 } 1073 1074 #ifdef DEBUG 1075 /* 1076 * List all of the locked vnodes in the system. 1077 * Called when debugging the kernel. 1078 */ 1079 printlockedvnodes() 1080 { 1081 register struct mount *mp; 1082 register struct vnode *vp; 1083 1084 printf("Locked vnodes\n"); 1085 mp = rootfs; 1086 do { 1087 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 1088 if (VOP_ISLOCKED(vp)) 1089 vprint((char *)0, vp); 1090 mp = mp->mnt_next; 1091 } while (mp != rootfs); 1092 } 1093 #endif 1094 1095 int kinfo_vdebug = 1; 1096 int kinfo_vgetfailed; 1097 #define KINFO_VNODESLOP 10 1098 /* 1099 * Dump vnode list (via kinfo). 1100 * Copyout address of vnode followed by vnode. 1101 */ 1102 /* ARGSUSED */ 1103 kinfo_vnode(op, where, acopysize, arg, aneeded) 1104 int op; 1105 char *where; 1106 int *acopysize, arg, *aneeded; 1107 { 1108 register struct mount *mp = rootfs; 1109 struct mount *omp; 1110 struct vnode *vp; 1111 register char *bp = where, *savebp; 1112 char *ewhere = where + *acopysize; 1113 int error; 1114 1115 #define VPTRSZ sizeof (struct vnode *) 1116 #define VNODESZ sizeof (struct vnode) 1117 if (where == NULL) { 1118 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 1119 return (0); 1120 } 1121 1122 do { 1123 if (vfs_busy(mp)) { 1124 mp = mp->mnt_next; 1125 continue; 1126 } 1127 savebp = bp; 1128 again: 1129 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 1130 /* 1131 * Check that the vp is still associated with 1132 * this filesystem. RACE: could have been 1133 * recycled onto the same filesystem. 1134 */ 1135 if (vp->v_mount != mp) { 1136 if (kinfo_vdebug) 1137 printf("kinfo: vp changed\n"); 1138 bp = savebp; 1139 goto again; 1140 } 1141 if ((bp + VPTRSZ + VNODESZ <= ewhere) && 1142 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 1143 (error = copyout((caddr_t)vp, bp + VPTRSZ, 1144 VNODESZ)))) 1145 return (error); 1146 bp += VPTRSZ + VNODESZ; 1147 } 1148 omp = mp; 1149 mp = mp->mnt_next; 1150 vfs_unbusy(omp); 1151 } while (mp != rootfs); 1152 1153 *aneeded = bp - where; 1154 if (bp > ewhere) 1155 *acopysize = ewhere - where; 1156 else 1157 *acopysize = bp - where; 1158 return (0); 1159 } 1160