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