1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)vfs_subr.c 7.42 (Berkeley) 05/04/90 18 */ 19 20 /* 21 * External virtual filesystem routines 22 */ 23 24 #include "param.h" 25 #include "mount.h" 26 #include "time.h" 27 #include "vnode.h" 28 #include "specdev.h" 29 #include "namei.h" 30 #include "ucred.h" 31 #include "errno.h" 32 #include "malloc.h" 33 34 /* 35 * Remove a mount point from the list of mounted filesystems. 36 * Unmount of the root is illegal. 37 */ 38 void 39 vfs_remove(mp) 40 register struct mount *mp; 41 { 42 43 if (mp == rootfs) 44 panic("vfs_remove: unmounting root"); 45 mp->mnt_prev->mnt_next = mp->mnt_next; 46 mp->mnt_next->mnt_prev = mp->mnt_prev; 47 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 48 vfs_unlock(mp); 49 } 50 51 /* 52 * Lock a filesystem. 53 * Used to prevent access to it while mounting and unmounting. 54 */ 55 vfs_lock(mp) 56 register struct mount *mp; 57 { 58 59 while(mp->mnt_flag & MNT_MLOCK) { 60 mp->mnt_flag |= MNT_MWAIT; 61 sleep((caddr_t)mp, PVFS); 62 } 63 mp->mnt_flag |= MNT_MLOCK; 64 return (0); 65 } 66 67 /* 68 * Unlock a locked filesystem. 69 * Panic if filesystem is not locked. 70 */ 71 void 72 vfs_unlock(mp) 73 register struct mount *mp; 74 { 75 76 if ((mp->mnt_flag & MNT_MLOCK) == 0) 77 panic("vfs_unlock: not locked"); 78 mp->mnt_flag &= ~MNT_MLOCK; 79 if (mp->mnt_flag & MNT_MWAIT) { 80 mp->mnt_flag &= ~MNT_MWAIT; 81 wakeup((caddr_t)mp); 82 } 83 } 84 85 /* 86 * Mark a mount point as busy. 87 * Used to synchronize access and to delay unmounting. 88 */ 89 vfs_busy(mp) 90 register struct mount *mp; 91 { 92 93 if (mp->mnt_flag & MNT_UNMOUNT) 94 return (1); 95 while(mp->mnt_flag & MNT_MPBUSY) { 96 mp->mnt_flag |= MNT_MPWANT; 97 sleep((caddr_t)&mp->mnt_flag, PVFS); 98 } 99 mp->mnt_flag |= MNT_MPBUSY; 100 return (0); 101 } 102 103 /* 104 * Free a busy filesystem. 105 * Panic if filesystem is not busy. 106 */ 107 void 108 vfs_unbusy(mp) 109 register struct mount *mp; 110 { 111 112 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 113 panic("vfs_unbusy: not busy"); 114 mp->mnt_flag &= ~MNT_MPBUSY; 115 if (mp->mnt_flag & MNT_MPWANT) { 116 mp->mnt_flag &= ~MNT_MPWANT; 117 wakeup((caddr_t)&mp->mnt_flag); 118 } 119 } 120 121 /* 122 * Lookup a mount point by filesystem identifier. 123 */ 124 struct mount * 125 getvfs(fsid) 126 fsid_t *fsid; 127 { 128 register struct mount *mp; 129 130 mp = rootfs; 131 do { 132 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 133 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 134 return (mp); 135 } 136 mp = mp->mnt_next; 137 } while (mp != rootfs); 138 return ((struct mount *)0); 139 } 140 141 /* 142 * Set vnode attributes to VNOVAL 143 */ 144 void vattr_null(vap) 145 register struct vattr *vap; 146 { 147 148 vap->va_type = VNON; 149 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 150 vap->va_fsid = vap->va_fileid = vap->va_size = 151 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 152 vap->va_bytes = vap->va_bytes_rsv = 153 vap->va_atime.tv_sec = vap->va_atime.tv_usec = 154 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 155 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 156 vap->va_flags = vap->va_gen = VNOVAL; 157 } 158 159 /* 160 * Initialize a nameidata structure 161 */ 162 ndinit(ndp) 163 register struct nameidata *ndp; 164 { 165 166 bzero((caddr_t)ndp, sizeof(struct nameidata)); 167 ndp->ni_iov = &ndp->ni_nd.nd_iovec; 168 ndp->ni_iovcnt = 1; 169 ndp->ni_base = (caddr_t)&ndp->ni_dent; 170 ndp->ni_rw = UIO_WRITE; 171 ndp->ni_uioseg = UIO_SYSSPACE; 172 } 173 174 /* 175 * Duplicate a nameidata structure 176 */ 177 nddup(ndp, newndp) 178 register struct nameidata *ndp, *newndp; 179 { 180 181 ndinit(newndp); 182 newndp->ni_cdir = ndp->ni_cdir; 183 VREF(newndp->ni_cdir); 184 newndp->ni_rdir = ndp->ni_rdir; 185 if (newndp->ni_rdir) 186 VREF(newndp->ni_rdir); 187 newndp->ni_cred = ndp->ni_cred; 188 crhold(newndp->ni_cred); 189 } 190 191 /* 192 * Release a nameidata structure 193 */ 194 ndrele(ndp) 195 register struct nameidata *ndp; 196 { 197 198 vrele(ndp->ni_cdir); 199 if (ndp->ni_rdir) 200 vrele(ndp->ni_rdir); 201 crfree(ndp->ni_cred); 202 } 203 204 /* 205 * Routines having to do with the management of the vnode table. 206 */ 207 struct vnode *vfreeh, **vfreet; 208 extern struct vnodeops dead_vnodeops, spec_vnodeops; 209 extern void vclean(); 210 long numvnodes; 211 struct vattr va_null; 212 213 /* 214 * Initialize the vnode structures and initialize each file system type. 215 */ 216 vfsinit() 217 { 218 struct vfsops **vfsp; 219 220 /* 221 * Initialize the vnode name cache 222 */ 223 nchinit(); 224 /* 225 * Initialize each file system type. 226 */ 227 vattr_null(&va_null); 228 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 229 if (*vfsp == NULL) 230 continue; 231 (*(*vfsp)->vfs_init)(); 232 } 233 } 234 235 /* 236 * Return the next vnode from the free list. 237 */ 238 getnewvnode(tag, mp, vops, vpp) 239 enum vtagtype tag; 240 struct mount *mp; 241 struct vnodeops *vops; 242 struct vnode **vpp; 243 { 244 register struct vnode *vp, *vq; 245 246 if (numvnodes < desiredvnodes) { 247 vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK); 248 bzero((char *)vp, sizeof *vp); 249 numvnodes++; 250 } else { 251 if ((vp = vfreeh) == NULL) { 252 tablefull("vnode"); 253 *vpp = 0; 254 return (ENFILE); 255 } 256 if (vp->v_usecount) 257 panic("free vnode isn't"); 258 if (vq = vp->v_freef) 259 vq->v_freeb = &vfreeh; 260 else 261 vfreet = &vfreeh; 262 vfreeh = vq; 263 vp->v_freef = NULL; 264 vp->v_freeb = NULL; 265 if (vp->v_type != VBAD) 266 vgone(vp); 267 vp->v_flag = 0; 268 vp->v_shlockc = 0; 269 vp->v_exlockc = 0; 270 vp->v_lastr = 0; 271 vp->v_socket = 0; 272 } 273 vp->v_type = VNON; 274 cache_purge(vp); 275 vp->v_tag = tag; 276 vp->v_op = vops; 277 insmntque(vp, mp); 278 VREF(vp); 279 *vpp = vp; 280 return (0); 281 } 282 283 /* 284 * Move a vnode from one mount queue to another. 285 */ 286 insmntque(vp, mp) 287 register struct vnode *vp; 288 register struct mount *mp; 289 { 290 struct vnode *vq; 291 292 /* 293 * Delete from old mount point vnode list, if on one. 294 */ 295 if (vp->v_mountb) { 296 if (vq = vp->v_mountf) 297 vq->v_mountb = vp->v_mountb; 298 *vp->v_mountb = vq; 299 } 300 /* 301 * Insert into list of vnodes for the new mount point, if available. 302 */ 303 vp->v_mount = mp; 304 if (mp == NULL) { 305 vp->v_mountf = NULL; 306 vp->v_mountb = NULL; 307 return; 308 } 309 if (mp->mnt_mounth) { 310 vp->v_mountf = mp->mnt_mounth; 311 vp->v_mountb = &mp->mnt_mounth; 312 mp->mnt_mounth->v_mountb = &vp->v_mountf; 313 mp->mnt_mounth = vp; 314 } else { 315 mp->mnt_mounth = vp; 316 vp->v_mountb = &mp->mnt_mounth; 317 vp->v_mountf = NULL; 318 } 319 } 320 321 /* 322 * Create a vnode for a block device. 323 * Used for root filesystem, argdev, and swap areas. 324 * Also used for memory file system special devices. 325 */ 326 bdevvp(dev, vpp) 327 dev_t dev; 328 struct vnode **vpp; 329 { 330 register struct vnode *vp; 331 struct vnode *nvp; 332 int error; 333 334 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 335 if (error) { 336 *vpp = 0; 337 return (error); 338 } 339 vp = nvp; 340 vp->v_type = VBLK; 341 if (nvp = checkalias(vp, dev, (struct mount *)0)) { 342 vput(vp); 343 vp = nvp; 344 } 345 *vpp = vp; 346 return (0); 347 } 348 349 /* 350 * Check to see if the new vnode represents a special device 351 * for which we already have a vnode (either because of 352 * bdevvp() or because of a different vnode representing 353 * the same block device). If such an alias exists, deallocate 354 * the existing contents and return the aliased vnode. The 355 * caller is responsible for filling it with its new contents. 356 */ 357 struct vnode * 358 checkalias(nvp, nvp_rdev, mp) 359 register struct vnode *nvp; 360 dev_t nvp_rdev; 361 struct mount *mp; 362 { 363 register struct vnode *vp; 364 struct vnode **vpp; 365 366 if (nvp->v_type != VBLK && nvp->v_type != VCHR) 367 return (NULLVP); 368 369 vpp = &speclisth[SPECHASH(nvp_rdev)]; 370 loop: 371 for (vp = *vpp; vp; vp = vp->v_specnext) { 372 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 373 continue; 374 /* 375 * Alias, but not in use, so flush it out. 376 */ 377 if (vp->v_usecount == 0) { 378 vgone(vp); 379 goto loop; 380 } 381 if (vget(vp)) 382 goto loop; 383 break; 384 } 385 if (vp == NULL || vp->v_tag != VT_NON) { 386 MALLOC(nvp->v_specinfo, struct specinfo *, 387 sizeof(struct specinfo), M_VNODE, M_WAITOK); 388 nvp->v_rdev = nvp_rdev; 389 nvp->v_hashchain = vpp; 390 nvp->v_specnext = *vpp; 391 *vpp = nvp; 392 if (vp != NULL) { 393 nvp->v_flag |= VALIASED; 394 vp->v_flag |= VALIASED; 395 vput(vp); 396 } 397 return (NULLVP); 398 } 399 VOP_UNLOCK(vp); 400 vclean(vp, 0); 401 vp->v_op = nvp->v_op; 402 vp->v_tag = nvp->v_tag; 403 nvp->v_type = VNON; 404 insmntque(vp, mp); 405 return (vp); 406 } 407 408 /* 409 * Grab a particular vnode from the free list, increment its 410 * reference count and lock it. The vnode lock bit is set the 411 * vnode is being eliminated in vgone. The process is awakened 412 * when the transition is completed, and an error returned to 413 * indicate that the vnode is no longer usable (possibly having 414 * been changed to a new file system type). 415 */ 416 vget(vp) 417 register struct vnode *vp; 418 { 419 register struct vnode *vq; 420 421 if (vp->v_flag & VXLOCK) { 422 vp->v_flag |= VXWANT; 423 sleep((caddr_t)vp, PINOD); 424 return (1); 425 } 426 if (vp->v_usecount == 0) { 427 if (vq = vp->v_freef) 428 vq->v_freeb = vp->v_freeb; 429 else 430 vfreet = vp->v_freeb; 431 *vp->v_freeb = vq; 432 vp->v_freef = NULL; 433 vp->v_freeb = NULL; 434 } 435 VREF(vp); 436 VOP_LOCK(vp); 437 return (0); 438 } 439 440 /* 441 * Vnode reference, just increment the count 442 */ 443 void vref(vp) 444 struct vnode *vp; 445 { 446 447 vp->v_usecount++; 448 } 449 450 /* 451 * vput(), just unlock and vrele() 452 */ 453 void vput(vp) 454 register struct vnode *vp; 455 { 456 VOP_UNLOCK(vp); 457 vrele(vp); 458 } 459 460 /* 461 * Vnode release. 462 * If count drops to zero, call inactive routine and return to freelist. 463 */ 464 void vrele(vp) 465 register struct vnode *vp; 466 { 467 468 if (vp == NULL) 469 panic("vrele: null vp"); 470 vp->v_usecount--; 471 if (vp->v_usecount < 0) 472 vprint("vrele: bad ref count", vp); 473 if (vp->v_usecount > 0) 474 return; 475 if (vfreeh == NULLVP) { 476 /* 477 * insert into empty list 478 */ 479 vfreeh = vp; 480 vp->v_freeb = &vfreeh; 481 } else { 482 /* 483 * insert at tail of list 484 */ 485 *vfreet = vp; 486 vp->v_freeb = vfreet; 487 } 488 vp->v_freef = NULL; 489 vfreet = &vp->v_freef; 490 VOP_INACTIVE(vp); 491 } 492 493 /* 494 * Page or buffer structure gets a reference. 495 */ 496 vhold(vp) 497 register struct vnode *vp; 498 { 499 500 vp->v_holdcnt++; 501 } 502 503 /* 504 * Page or buffer structure frees a reference. 505 */ 506 holdrele(vp) 507 register struct vnode *vp; 508 { 509 510 if (vp->v_holdcnt <= 0) 511 panic("holdrele: holdcnt"); 512 vp->v_holdcnt--; 513 } 514 515 /* 516 * Remove any vnodes in the vnode table belonging to mount point mp. 517 * 518 * If MNT_NOFORCE is specified, there should not be any active ones, 519 * return error if any are found (nb: this is a user error, not a 520 * system error). If MNT_FORCE is specified, detach any active vnodes 521 * that are found. 522 */ 523 int busyprt = 0; /* patch to print out busy vnodes */ 524 525 vflush(mp, skipvp, flags) 526 struct mount *mp; 527 struct vnode *skipvp; 528 int flags; 529 { 530 register struct vnode *vp, *nvp; 531 int busy = 0; 532 533 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 534 panic("vflush: not busy"); 535 for (vp = mp->mnt_mounth; vp; vp = nvp) { 536 nvp = vp->v_mountf; 537 /* 538 * Skip over a selected vnode. 539 */ 540 if (vp == skipvp) 541 continue; 542 /* 543 * Skip over a vnodes marked VSYSTEM. 544 */ 545 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 546 continue; 547 /* 548 * With v_usecount == 0, all we need to do is clear 549 * out the vnode data structures and we are done. 550 */ 551 if (vp->v_usecount == 0) { 552 vgone(vp); 553 continue; 554 } 555 /* 556 * For block or character devices, revert to an 557 * anonymous device. For all other files, just kill them. 558 */ 559 if (flags & FORCECLOSE) { 560 if (vp->v_type != VBLK && vp->v_type != VCHR) { 561 vgone(vp); 562 } else { 563 vclean(vp, 0); 564 vp->v_op = &spec_vnodeops; 565 insmntque(vp, (struct mount *)0); 566 } 567 continue; 568 } 569 if (busyprt) 570 vprint("vflush: busy vnode", vp); 571 busy++; 572 } 573 if (busy) 574 return (EBUSY); 575 return (0); 576 } 577 578 /* 579 * Disassociate the underlying file system from a vnode. 580 */ 581 void vclean(vp, flags) 582 register struct vnode *vp; 583 long flags; 584 { 585 struct vnodeops *origops; 586 int active; 587 588 /* 589 * Check to see if the vnode is in use. 590 * If so we have to reference it before we clean it out 591 * so that its count cannot fall to zero and generate a 592 * race against ourselves to recycle it. 593 */ 594 if (active = vp->v_usecount) 595 VREF(vp); 596 /* 597 * Prevent the vnode from being recycled or 598 * brought into use while we clean it out. 599 */ 600 if (vp->v_flag & VXLOCK) 601 panic("vclean: deadlock"); 602 vp->v_flag |= VXLOCK; 603 /* 604 * Even if the count is zero, the VOP_INACTIVE routine may still 605 * have the object locked while it cleans it out. The VOP_LOCK 606 * ensures that the VOP_INACTIVE routine is done with its work. 607 * For active vnodes, it ensures that no other activity can 608 * occur while the buffer list is being cleaned out. 609 */ 610 VOP_LOCK(vp); 611 if (flags & DOCLOSE) 612 vinvalbuf(vp, 1); 613 /* 614 * Prevent any further operations on the vnode from 615 * being passed through to the old file system. 616 */ 617 origops = vp->v_op; 618 vp->v_op = &dead_vnodeops; 619 vp->v_tag = VT_NON; 620 /* 621 * If purging an active vnode, it must be unlocked, closed, 622 * and deactivated before being reclaimed. 623 */ 624 (*(origops->vn_unlock))(vp); 625 if (active) { 626 if (flags & DOCLOSE) 627 (*(origops->vn_close))(vp, 0, NOCRED); 628 (*(origops->vn_inactive))(vp); 629 } 630 /* 631 * Reclaim the vnode. 632 */ 633 if ((*(origops->vn_reclaim))(vp)) 634 panic("vclean: cannot reclaim"); 635 if (active) 636 vrele(vp); 637 /* 638 * Done with purge, notify sleepers in vget of the grim news. 639 */ 640 vp->v_flag &= ~VXLOCK; 641 if (vp->v_flag & VXWANT) { 642 vp->v_flag &= ~VXWANT; 643 wakeup((caddr_t)vp); 644 } 645 } 646 647 /* 648 * Eliminate all activity associated with the requested vnode 649 * and with all vnodes aliased to the requested vnode. 650 */ 651 void vgoneall(vp) 652 register struct vnode *vp; 653 { 654 register struct vnode *vq; 655 656 if (vp->v_flag & VALIASED) { 657 /* 658 * If a vgone (or vclean) is already in progress, 659 * wait until it is done and return. 660 */ 661 if (vp->v_flag & VXLOCK) { 662 vp->v_flag |= VXWANT; 663 sleep((caddr_t)vp, PINOD); 664 return; 665 } 666 /* 667 * Ensure that vp will not be vgone'd while we 668 * are eliminating its aliases. 669 */ 670 vp->v_flag |= VXLOCK; 671 while (vp->v_flag & VALIASED) { 672 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 673 if (vq->v_rdev != vp->v_rdev || 674 vq->v_type != vp->v_type || vp == vq) 675 continue; 676 vgone(vq); 677 break; 678 } 679 } 680 /* 681 * Remove the lock so that vgone below will 682 * really eliminate the vnode after which time 683 * vgone will awaken any sleepers. 684 */ 685 vp->v_flag &= ~VXLOCK; 686 } 687 vgone(vp); 688 } 689 690 /* 691 * Eliminate all activity associated with a vnode 692 * in preparation for reuse. 693 */ 694 void vgone(vp) 695 register struct vnode *vp; 696 { 697 register struct vnode *vq; 698 struct vnode *vx; 699 long count; 700 701 /* 702 * If a vgone (or vclean) is already in progress, 703 * wait until it is done and return. 704 */ 705 if (vp->v_flag & VXLOCK) { 706 vp->v_flag |= VXWANT; 707 sleep((caddr_t)vp, PINOD); 708 return; 709 } 710 /* 711 * Clean out the filesystem specific data. 712 */ 713 vclean(vp, DOCLOSE); 714 /* 715 * Delete from old mount point vnode list, if on one. 716 */ 717 if (vp->v_mountb) { 718 if (vq = vp->v_mountf) 719 vq->v_mountb = vp->v_mountb; 720 *vp->v_mountb = vq; 721 vp->v_mountf = NULL; 722 vp->v_mountb = NULL; 723 } 724 /* 725 * If special device, remove it from special device alias list. 726 */ 727 if (vp->v_type == VBLK || vp->v_type == VCHR) { 728 if (*vp->v_hashchain == vp) { 729 *vp->v_hashchain = vp->v_specnext; 730 } else { 731 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 732 if (vq->v_specnext != vp) 733 continue; 734 vq->v_specnext = vp->v_specnext; 735 break; 736 } 737 if (vq == NULL) 738 panic("missing bdev"); 739 } 740 if (vp->v_flag & VALIASED) { 741 count = 0; 742 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 743 if (vq->v_rdev != vp->v_rdev || 744 vq->v_type != vp->v_type) 745 continue; 746 count++; 747 vx = vq; 748 } 749 if (count == 0) 750 panic("missing alias"); 751 if (count == 1) 752 vx->v_flag &= ~VALIASED; 753 vp->v_flag &= ~VALIASED; 754 } 755 FREE(vp->v_specinfo, M_VNODE); 756 vp->v_specinfo = NULL; 757 } 758 /* 759 * If it is on the freelist, move it to the head of the list. 760 */ 761 if (vp->v_freeb) { 762 if (vq = vp->v_freef) 763 vq->v_freeb = vp->v_freeb; 764 else 765 vfreet = vp->v_freeb; 766 *vp->v_freeb = vq; 767 vp->v_freef = vfreeh; 768 vp->v_freeb = &vfreeh; 769 vfreeh->v_freeb = &vp->v_freef; 770 vfreeh = vp; 771 } 772 vp->v_type = VBAD; 773 } 774 775 /* 776 * Lookup a vnode by device number. 777 */ 778 vfinddev(dev, type, vpp) 779 dev_t dev; 780 enum vtype type; 781 struct vnode **vpp; 782 { 783 register struct vnode *vp; 784 785 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 786 if (dev != vp->v_rdev || type != vp->v_type) 787 continue; 788 *vpp = vp; 789 return (0); 790 } 791 return (1); 792 } 793 794 /* 795 * Calculate the total number of references to a special device. 796 */ 797 vcount(vp) 798 register struct vnode *vp; 799 { 800 register struct vnode *vq; 801 int count; 802 803 if ((vp->v_flag & VALIASED) == 0) 804 return (vp->v_usecount); 805 loop: 806 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 807 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 808 continue; 809 /* 810 * Alias, but not in use, so flush it out. 811 */ 812 if (vq->v_usecount == 0) { 813 vgone(vq); 814 goto loop; 815 } 816 count += vq->v_usecount; 817 } 818 return (count); 819 } 820 821 /* 822 * Print out a description of a vnode. 823 */ 824 static char *typename[] = 825 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 826 827 vprint(label, vp) 828 char *label; 829 register struct vnode *vp; 830 { 831 char buf[64]; 832 833 if (label != NULL) 834 printf("%s: ", label); 835 printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 836 vp->v_usecount, vp->v_holdcnt); 837 buf[0] = '\0'; 838 if (vp->v_flag & VROOT) 839 strcat(buf, "|VROOT"); 840 if (vp->v_flag & VTEXT) 841 strcat(buf, "|VTEXT"); 842 if (vp->v_flag & VSYSTEM) 843 strcat(buf, "|VSYSTEM"); 844 if (vp->v_flag & VEXLOCK) 845 strcat(buf, "|VEXLOCK"); 846 if (vp->v_flag & VSHLOCK) 847 strcat(buf, "|VSHLOCK"); 848 if (vp->v_flag & VLWAIT) 849 strcat(buf, "|VLWAIT"); 850 if (vp->v_flag & VXLOCK) 851 strcat(buf, "|VXLOCK"); 852 if (vp->v_flag & VXWANT) 853 strcat(buf, "|VXWANT"); 854 if (vp->v_flag & VBWAIT) 855 strcat(buf, "|VBWAIT"); 856 if (vp->v_flag & VALIASED) 857 strcat(buf, "|VALIASED"); 858 if (buf[0] != '\0') 859 printf(" flags (%s)", &buf[1]); 860 printf("\n\t"); 861 VOP_PRINT(vp); 862 } 863 864 int kinfo_vdebug = 1; 865 int kinfo_vgetfailed; 866 #define KINFO_VNODESLOP 10 867 /* 868 * Dump vnode list (via kinfo). 869 * Copyout address of vnode followed by vnode. 870 */ 871 kinfo_vnode(op, where, acopysize, arg, aneeded) 872 char *where; 873 int *acopysize, *aneeded; 874 { 875 register struct mount *mp = rootfs; 876 register struct vnode *nextvp; 877 struct mount *omp; 878 struct vnode *vp; 879 register needed = 0; 880 register char *bp = where, *savebp; 881 char *ewhere = where + *acopysize; 882 int error; 883 884 #define VPTRSZ sizeof (struct vnode *) 885 #define VNODESZ sizeof (struct vnode) 886 if (where == NULL) { 887 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 888 return (0); 889 } 890 891 #define RETRY bp = savebp ; goto again 892 do { 893 if (vfs_busy(mp)) { 894 mp = mp->mnt_next; 895 continue; 896 } 897 /* 898 * A vget can fail if the vnode is being 899 * recycled. In this (rare) case, we have to start 900 * over with this filesystem. Also, have to 901 * check that nextvp is still associated 902 * with this filesystem. RACE: could have been 903 * recycled onto same filesystem. 904 */ 905 savebp = bp; 906 again: 907 nextvp = mp->mnt_mounth; 908 while (vp = nextvp) { 909 if (vget(vp)) { 910 if (kinfo_vdebug) 911 printf("kinfo: vget failed\n"); 912 kinfo_vgetfailed++; 913 RETRY; 914 } 915 if (vp->v_mount != mp) { 916 if (kinfo_vdebug) 917 printf("kinfo: vp changed\n"); 918 vput(vp); 919 RETRY; 920 } 921 if ((bp + VPTRSZ + VNODESZ <= ewhere) && 922 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 923 (error = copyout((caddr_t)vp, bp + VPTRSZ, 924 VNODESZ)))) { 925 vput(vp); 926 return (error); 927 } 928 bp += VPTRSZ + VNODESZ; 929 nextvp = vp->v_mountf; 930 vput(vp); 931 } 932 omp = mp; 933 mp = mp->mnt_next; 934 vfs_unbusy(omp); 935 } while (mp != rootfs); 936 937 *aneeded = bp - where; 938 if (bp > ewhere) 939 *acopysize = ewhere - where; 940 else 941 *acopysize = bp - where; 942 return (0); 943 } 944