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