137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*49973Smckusick * @(#)vfs_subr.c 7.59 (Berkeley) 06/03/91 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1548024Smckusick #include "proc.h" 1637488Smckusick #include "mount.h" 1737488Smckusick #include "time.h" 1837488Smckusick #include "vnode.h" 1940652Smckusick #include "specdev.h" 2038265Smckusick #include "namei.h" 2138265Smckusick #include "ucred.h" 2249232Smckusick #include "buf.h" 2337488Smckusick #include "errno.h" 2439433Smckusick #include "malloc.h" 2537488Smckusick 2637488Smckusick /* 2737488Smckusick * Remove a mount point from the list of mounted filesystems. 2837488Smckusick * Unmount of the root is illegal. 2937488Smckusick */ 3037488Smckusick void 3137488Smckusick vfs_remove(mp) 3237488Smckusick register struct mount *mp; 3337488Smckusick { 3437488Smckusick 3537488Smckusick if (mp == rootfs) 3637488Smckusick panic("vfs_remove: unmounting root"); 3741400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3841400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3941400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 4037488Smckusick vfs_unlock(mp); 4137488Smckusick } 4237488Smckusick 4337488Smckusick /* 4437488Smckusick * Lock a filesystem. 4537488Smckusick * Used to prevent access to it while mounting and unmounting. 4637488Smckusick */ 4737488Smckusick vfs_lock(mp) 4837488Smckusick register struct mount *mp; 4937488Smckusick { 5037488Smckusick 5141400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5241400Smckusick mp->mnt_flag |= MNT_MWAIT; 5339045Smckusick sleep((caddr_t)mp, PVFS); 5439045Smckusick } 5541400Smckusick mp->mnt_flag |= MNT_MLOCK; 5637488Smckusick return (0); 5737488Smckusick } 5837488Smckusick 5937488Smckusick /* 6037488Smckusick * Unlock a locked filesystem. 6137488Smckusick * Panic if filesystem is not locked. 6237488Smckusick */ 6337488Smckusick void 6437488Smckusick vfs_unlock(mp) 6537488Smckusick register struct mount *mp; 6637488Smckusick { 6737488Smckusick 6841400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6941300Smckusick panic("vfs_unlock: not locked"); 7041400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7141400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7241400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7337488Smckusick wakeup((caddr_t)mp); 7437488Smckusick } 7537488Smckusick } 7637488Smckusick 7737488Smckusick /* 7841300Smckusick * Mark a mount point as busy. 7941300Smckusick * Used to synchronize access and to delay unmounting. 8041300Smckusick */ 8141300Smckusick vfs_busy(mp) 8241300Smckusick register struct mount *mp; 8341300Smckusick { 8441300Smckusick 8541400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8641400Smckusick mp->mnt_flag |= MNT_MPWANT; 8741400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8841300Smckusick } 8941419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 9041419Smckusick return (1); 9141400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9241300Smckusick return (0); 9341300Smckusick } 9441300Smckusick 9541300Smckusick /* 9641300Smckusick * Free a busy filesystem. 9741300Smckusick * Panic if filesystem is not busy. 9841300Smckusick */ 9941300Smckusick vfs_unbusy(mp) 10041300Smckusick register struct mount *mp; 10141300Smckusick { 10241300Smckusick 10341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10441300Smckusick panic("vfs_unbusy: not busy"); 10541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10941300Smckusick } 11041300Smckusick } 11141300Smckusick 11241300Smckusick /* 11337488Smckusick * Lookup a mount point by filesystem identifier. 11437488Smckusick */ 11537488Smckusick struct mount * 11637488Smckusick getvfs(fsid) 11737488Smckusick fsid_t *fsid; 11837488Smckusick { 11937488Smckusick register struct mount *mp; 12037488Smckusick 12138288Smckusick mp = rootfs; 12238288Smckusick do { 12341400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12441400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12538288Smckusick return (mp); 12637488Smckusick } 12741400Smckusick mp = mp->mnt_next; 12838288Smckusick } while (mp != rootfs); 12938288Smckusick return ((struct mount *)0); 13037488Smckusick } 13137488Smckusick 13237488Smckusick /* 13337488Smckusick * Set vnode attributes to VNOVAL 13437488Smckusick */ 13537488Smckusick void vattr_null(vap) 13637488Smckusick register struct vattr *vap; 13737488Smckusick { 13837488Smckusick 13937488Smckusick vap->va_type = VNON; 14037488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14137488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14240643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14340643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14437488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14537488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14638258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14738258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14837488Smckusick } 14938265Smckusick 15038265Smckusick /* 15139397Smckusick * Routines having to do with the management of the vnode table. 15239397Smckusick */ 15339397Smckusick struct vnode *vfreeh, **vfreet; 15439447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 15539635Smckusick extern void vclean(); 15640883Smckusick long numvnodes; 15741363Smckusick struct vattr va_null; 15839397Smckusick 15939397Smckusick /* 16039433Smckusick * Initialize the vnode structures and initialize each file system type. 16139397Smckusick */ 16239433Smckusick vfsinit() 16339397Smckusick { 16439433Smckusick struct vfsops **vfsp; 16539397Smckusick 16639433Smckusick /* 16739433Smckusick * Initialize the vnode name cache 16839433Smckusick */ 16939433Smckusick nchinit(); 17039433Smckusick /* 17139433Smckusick * Initialize each file system type. 17239433Smckusick */ 17341363Smckusick vattr_null(&va_null); 17439433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 17539433Smckusick if (*vfsp == NULL) 17639433Smckusick continue; 17739433Smckusick (*(*vfsp)->vfs_init)(); 17839433Smckusick } 17939397Smckusick } 18039397Smckusick 18139397Smckusick /* 18239397Smckusick * Return the next vnode from the free list. 18339397Smckusick */ 18439397Smckusick getnewvnode(tag, mp, vops, vpp) 18539397Smckusick enum vtagtype tag; 18639397Smckusick struct mount *mp; 18739397Smckusick struct vnodeops *vops; 18839397Smckusick struct vnode **vpp; 18939397Smckusick { 19039397Smckusick register struct vnode *vp, *vq; 19139397Smckusick 19240883Smckusick if (numvnodes < desiredvnodes) { 19345118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 19445118Smckusick M_VNODE, M_WAITOK); 19540883Smckusick bzero((char *)vp, sizeof *vp); 19640883Smckusick numvnodes++; 19740883Smckusick } else { 19840883Smckusick if ((vp = vfreeh) == NULL) { 19940883Smckusick tablefull("vnode"); 20040883Smckusick *vpp = 0; 20140883Smckusick return (ENFILE); 20240883Smckusick } 20340883Smckusick if (vp->v_usecount) 20440883Smckusick panic("free vnode isn't"); 20540883Smckusick if (vq = vp->v_freef) 20640883Smckusick vq->v_freeb = &vfreeh; 20740883Smckusick else 20840883Smckusick vfreet = &vfreeh; 20940883Smckusick vfreeh = vq; 21040883Smckusick vp->v_freef = NULL; 21140883Smckusick vp->v_freeb = NULL; 21240883Smckusick if (vp->v_type != VBAD) 21340883Smckusick vgone(vp); 21440883Smckusick vp->v_flag = 0; 21540883Smckusick vp->v_lastr = 0; 21640883Smckusick vp->v_socket = 0; 21739397Smckusick } 21839512Smckusick vp->v_type = VNON; 21939397Smckusick cache_purge(vp); 22039397Smckusick vp->v_tag = tag; 22139433Smckusick vp->v_op = vops; 22239397Smckusick insmntque(vp, mp); 22339397Smckusick VREF(vp); 22439397Smckusick *vpp = vp; 22539397Smckusick return (0); 22639397Smckusick } 22739397Smckusick 22839397Smckusick /* 22939397Smckusick * Move a vnode from one mount queue to another. 23039397Smckusick */ 23139397Smckusick insmntque(vp, mp) 23239397Smckusick register struct vnode *vp; 23339397Smckusick register struct mount *mp; 23439397Smckusick { 235*49973Smckusick register struct vnode *vq; 23639397Smckusick 23739397Smckusick /* 23839397Smckusick * Delete from old mount point vnode list, if on one. 23939397Smckusick */ 24039397Smckusick if (vp->v_mountb) { 24139397Smckusick if (vq = vp->v_mountf) 24239397Smckusick vq->v_mountb = vp->v_mountb; 24339397Smckusick *vp->v_mountb = vq; 24439397Smckusick } 24539397Smckusick /* 24639397Smckusick * Insert into list of vnodes for the new mount point, if available. 24739397Smckusick */ 24839621Smckusick vp->v_mount = mp; 24939397Smckusick if (mp == NULL) { 25039397Smckusick vp->v_mountf = NULL; 25139397Smckusick vp->v_mountb = NULL; 25239397Smckusick return; 25339397Smckusick } 254*49973Smckusick if (vq = mp->mnt_mounth) 255*49973Smckusick vq->v_mountb = &vp->v_mountf; 256*49973Smckusick vp->v_mountf = vq; 257*49973Smckusick vp->v_mountb = &mp->mnt_mounth; 258*49973Smckusick mp->mnt_mounth = vp; 25939397Smckusick } 26039397Smckusick 26139397Smckusick /* 26249232Smckusick * Make sure all write-behind blocks associated 26349232Smckusick * with mount point are flushed out (from sync). 26449232Smckusick */ 26549232Smckusick mntflushbuf(mountp, flags) 26649232Smckusick struct mount *mountp; 26749232Smckusick int flags; 26849232Smckusick { 26949232Smckusick register struct vnode *vp; 27049232Smckusick 27149232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 27249232Smckusick panic("mntflushbuf: not busy"); 27349232Smckusick loop: 27449232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 27549232Smckusick if (VOP_ISLOCKED(vp)) 27649232Smckusick continue; 27749232Smckusick if (vget(vp)) 27849232Smckusick goto loop; 27949232Smckusick vflushbuf(vp, flags); 28049232Smckusick vput(vp); 28149232Smckusick if (vp->v_mount != mountp) 28249232Smckusick goto loop; 28349232Smckusick } 28449232Smckusick } 28549232Smckusick 28649232Smckusick /* 28749232Smckusick * Flush all dirty buffers associated with a vnode. 28849232Smckusick */ 28949232Smckusick vflushbuf(vp, flags) 29049232Smckusick register struct vnode *vp; 29149232Smckusick int flags; 29249232Smckusick { 29349232Smckusick register struct buf *bp; 29449232Smckusick struct buf *nbp; 29549232Smckusick int s; 29649232Smckusick 29749232Smckusick loop: 29849232Smckusick s = splbio(); 29949232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 30049232Smckusick nbp = bp->b_blockf; 30149232Smckusick if ((bp->b_flags & B_BUSY)) 30249232Smckusick continue; 30349232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 30449232Smckusick panic("vflushbuf: not dirty"); 30549232Smckusick bremfree(bp); 30649232Smckusick bp->b_flags |= B_BUSY; 30749232Smckusick splx(s); 30849232Smckusick /* 30949232Smckusick * Wait for I/O associated with indirect blocks to complete, 31049232Smckusick * since there is no way to quickly wait for them below. 31149232Smckusick * NB: This is really specific to ufs, but is done here 31249232Smckusick * as it is easier and quicker. 31349232Smckusick */ 31449460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 31549232Smckusick (void) bawrite(bp); 31649460Smckusick else 31749232Smckusick (void) bwrite(bp); 31849460Smckusick goto loop; 31949232Smckusick } 32049232Smckusick splx(s); 32149232Smckusick if ((flags & B_SYNC) == 0) 32249232Smckusick return; 32349232Smckusick s = splbio(); 32449232Smckusick while (vp->v_numoutput) { 32549232Smckusick vp->v_flag |= VBWAIT; 32649232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 32749232Smckusick } 32849232Smckusick splx(s); 32949232Smckusick if (vp->v_dirtyblkhd) { 33049232Smckusick vprint("vflushbuf: dirty", vp); 33149232Smckusick goto loop; 33249232Smckusick } 33349232Smckusick } 33449232Smckusick 33549232Smckusick /* 33649232Smckusick * Update outstanding I/O count and do wakeup if requested. 33749232Smckusick */ 33849232Smckusick vwakeup(bp) 33949232Smckusick register struct buf *bp; 34049232Smckusick { 34149232Smckusick register struct vnode *vp; 34249232Smckusick 34349232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 34449232Smckusick if (vp = bp->b_vp) { 34549232Smckusick vp->v_numoutput--; 34649232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 34749232Smckusick if (vp->v_numoutput < 0) 34849232Smckusick panic("vwakeup: neg numoutput"); 34949232Smckusick vp->v_flag &= ~VBWAIT; 35049232Smckusick wakeup((caddr_t)&vp->v_numoutput); 35149232Smckusick } 35249232Smckusick } 35349232Smckusick } 35449232Smckusick 35549232Smckusick /* 35649232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 35749232Smckusick * 35849232Smckusick * Go through the list of vnodes associated with the file system; 35949232Smckusick * for each vnode invalidate any buffers that it holds. Normally 36049232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 36149232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 36249232Smckusick * returns the count of dirty buffers when it is finished. 36349232Smckusick */ 36449232Smckusick mntinvalbuf(mountp) 36549232Smckusick struct mount *mountp; 36649232Smckusick { 36749232Smckusick register struct vnode *vp; 36849232Smckusick int dirty = 0; 36949232Smckusick 37049232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 37149232Smckusick panic("mntinvalbuf: not busy"); 37249232Smckusick loop: 37349232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 37449232Smckusick if (vget(vp)) 37549232Smckusick goto loop; 37649232Smckusick dirty += vinvalbuf(vp, 1); 37749232Smckusick vput(vp); 37849232Smckusick if (vp->v_mount != mountp) 37949232Smckusick goto loop; 38049232Smckusick } 38149232Smckusick return (dirty); 38249232Smckusick } 38349232Smckusick 38449232Smckusick /* 38549232Smckusick * Flush out and invalidate all buffers associated with a vnode. 38649232Smckusick * Called with the underlying object locked. 38749232Smckusick */ 38849232Smckusick vinvalbuf(vp, save) 38949232Smckusick register struct vnode *vp; 39049232Smckusick int save; 39149232Smckusick { 39249232Smckusick register struct buf *bp; 39349232Smckusick struct buf *nbp, *blist; 39449232Smckusick int s, dirty = 0; 39549232Smckusick 39649232Smckusick for (;;) { 39749232Smckusick if (blist = vp->v_dirtyblkhd) 39849232Smckusick /* void */; 39949232Smckusick else if (blist = vp->v_cleanblkhd) 40049232Smckusick /* void */; 40149232Smckusick else 40249232Smckusick break; 40349232Smckusick for (bp = blist; bp; bp = nbp) { 40449232Smckusick nbp = bp->b_blockf; 40549232Smckusick s = splbio(); 40649232Smckusick if (bp->b_flags & B_BUSY) { 40749232Smckusick bp->b_flags |= B_WANTED; 40849232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 40949232Smckusick splx(s); 41049232Smckusick break; 41149232Smckusick } 41249232Smckusick bremfree(bp); 41349232Smckusick bp->b_flags |= B_BUSY; 41449232Smckusick splx(s); 41549232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 41649232Smckusick dirty++; 41749232Smckusick (void) bwrite(bp); 41849232Smckusick break; 41949232Smckusick } 42049232Smckusick if (bp->b_vp != vp) 42149232Smckusick reassignbuf(bp, bp->b_vp); 42249232Smckusick else 42349232Smckusick bp->b_flags |= B_INVAL; 42449232Smckusick brelse(bp); 42549232Smckusick } 42649232Smckusick } 42749232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 42849232Smckusick panic("vinvalbuf: flush failed"); 42949232Smckusick return (dirty); 43049232Smckusick } 43149232Smckusick 43249232Smckusick /* 43349232Smckusick * Associate a buffer with a vnode. 43449232Smckusick */ 43549232Smckusick bgetvp(vp, bp) 43649232Smckusick register struct vnode *vp; 43749232Smckusick register struct buf *bp; 43849232Smckusick { 439*49973Smckusick register struct vnode *vq; 440*49973Smckusick register struct buf *bq; 44149232Smckusick 44249232Smckusick if (bp->b_vp) 44349232Smckusick panic("bgetvp: not free"); 44449232Smckusick VHOLD(vp); 44549232Smckusick bp->b_vp = vp; 44649232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 44749232Smckusick bp->b_dev = vp->v_rdev; 44849232Smckusick else 44949232Smckusick bp->b_dev = NODEV; 45049232Smckusick /* 45149232Smckusick * Insert onto list for new vnode. 45249232Smckusick */ 453*49973Smckusick if (bq = vp->v_cleanblkhd) 454*49973Smckusick bq->b_blockb = &bp->b_blockf; 455*49973Smckusick bp->b_blockf = bq; 456*49973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 457*49973Smckusick vp->v_cleanblkhd = bp; 45849232Smckusick } 45949232Smckusick 46049232Smckusick /* 46149232Smckusick * Disassociate a buffer from a vnode. 46249232Smckusick */ 46349232Smckusick brelvp(bp) 46449232Smckusick register struct buf *bp; 46549232Smckusick { 46649232Smckusick struct buf *bq; 46749232Smckusick struct vnode *vp; 46849232Smckusick 46949232Smckusick if (bp->b_vp == (struct vnode *) 0) 47049232Smckusick panic("brelvp: NULL"); 47149232Smckusick /* 47249232Smckusick * Delete from old vnode list, if on one. 47349232Smckusick */ 47449232Smckusick if (bp->b_blockb) { 47549232Smckusick if (bq = bp->b_blockf) 47649232Smckusick bq->b_blockb = bp->b_blockb; 47749232Smckusick *bp->b_blockb = bq; 47849232Smckusick bp->b_blockf = NULL; 47949232Smckusick bp->b_blockb = NULL; 48049232Smckusick } 48149232Smckusick vp = bp->b_vp; 48249232Smckusick bp->b_vp = (struct vnode *) 0; 48349232Smckusick HOLDRELE(vp); 48449232Smckusick } 48549232Smckusick 48649232Smckusick /* 48749232Smckusick * Reassign a buffer from one vnode to another. 48849232Smckusick * Used to assign file specific control information 48949232Smckusick * (indirect blocks) to the vnode to which they belong. 49049232Smckusick */ 49149232Smckusick reassignbuf(bp, newvp) 49249232Smckusick register struct buf *bp; 49349232Smckusick register struct vnode *newvp; 49449232Smckusick { 49549232Smckusick register struct buf *bq, **listheadp; 49649232Smckusick 49749232Smckusick if (newvp == NULL) 49849232Smckusick panic("reassignbuf: NULL"); 49949232Smckusick /* 50049232Smckusick * Delete from old vnode list, if on one. 50149232Smckusick */ 50249232Smckusick if (bp->b_blockb) { 50349232Smckusick if (bq = bp->b_blockf) 50449232Smckusick bq->b_blockb = bp->b_blockb; 50549232Smckusick *bp->b_blockb = bq; 50649232Smckusick } 50749232Smckusick /* 50849232Smckusick * If dirty, put on list of dirty buffers; 50949232Smckusick * otherwise insert onto list of clean buffers. 51049232Smckusick */ 51149232Smckusick if (bp->b_flags & B_DELWRI) 51249232Smckusick listheadp = &newvp->v_dirtyblkhd; 51349232Smckusick else 51449232Smckusick listheadp = &newvp->v_cleanblkhd; 515*49973Smckusick if (bq = *listheadp) 516*49973Smckusick bq->b_blockb = &bp->b_blockf; 517*49973Smckusick bp->b_blockf = bq; 518*49973Smckusick bp->b_blockb = listheadp; 519*49973Smckusick *listheadp = bp; 52049232Smckusick } 52149232Smckusick 52249232Smckusick /* 52339433Smckusick * Create a vnode for a block device. 52439433Smckusick * Used for root filesystem, argdev, and swap areas. 52539433Smckusick * Also used for memory file system special devices. 52639397Smckusick */ 52739433Smckusick bdevvp(dev, vpp) 52839433Smckusick dev_t dev; 52939433Smckusick struct vnode **vpp; 53039433Smckusick { 53139433Smckusick register struct vnode *vp; 53239433Smckusick struct vnode *nvp; 53339433Smckusick int error; 53439433Smckusick 53546989Smckusick if (dev == NODEV) 53646989Smckusick return (0); 53739447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 53839433Smckusick if (error) { 53939433Smckusick *vpp = 0; 54039433Smckusick return (error); 54139433Smckusick } 54239433Smckusick vp = nvp; 54339433Smckusick vp->v_type = VBLK; 54439615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 54539433Smckusick vput(vp); 54639433Smckusick vp = nvp; 54739433Smckusick } 54839433Smckusick *vpp = vp; 54939433Smckusick return (0); 55039433Smckusick } 55139433Smckusick 55239433Smckusick /* 55339433Smckusick * Check to see if the new vnode represents a special device 55439433Smckusick * for which we already have a vnode (either because of 55539433Smckusick * bdevvp() or because of a different vnode representing 55639433Smckusick * the same block device). If such an alias exists, deallocate 55739509Smckusick * the existing contents and return the aliased vnode. The 55839433Smckusick * caller is responsible for filling it with its new contents. 55939433Smckusick */ 56039433Smckusick struct vnode * 56139615Smckusick checkalias(nvp, nvp_rdev, mp) 56239433Smckusick register struct vnode *nvp; 56339615Smckusick dev_t nvp_rdev; 56439433Smckusick struct mount *mp; 56539433Smckusick { 56639433Smckusick register struct vnode *vp; 56739615Smckusick struct vnode **vpp; 56839433Smckusick 56939433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 57041400Smckusick return (NULLVP); 57139615Smckusick 57239615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 57339433Smckusick loop: 57439615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 57539615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 57639433Smckusick continue; 57739615Smckusick /* 57839615Smckusick * Alias, but not in use, so flush it out. 57939615Smckusick */ 58039809Smckusick if (vp->v_usecount == 0) { 58139615Smckusick vgone(vp); 58239615Smckusick goto loop; 58339615Smckusick } 58439633Smckusick if (vget(vp)) 58539633Smckusick goto loop; 58639433Smckusick break; 58739433Smckusick } 58839615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 58939615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 59039615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 59139615Smckusick nvp->v_rdev = nvp_rdev; 59239809Smckusick nvp->v_hashchain = vpp; 59339615Smckusick nvp->v_specnext = *vpp; 59442152Smckusick nvp->v_specflags = 0; 59539615Smckusick *vpp = nvp; 59640640Smckusick if (vp != NULL) { 59740640Smckusick nvp->v_flag |= VALIASED; 59840640Smckusick vp->v_flag |= VALIASED; 59940640Smckusick vput(vp); 60040640Smckusick } 60141400Smckusick return (NULLVP); 60239433Smckusick } 60339484Smckusick VOP_UNLOCK(vp); 60439484Smckusick vclean(vp, 0); 60539433Smckusick vp->v_op = nvp->v_op; 60639433Smckusick vp->v_tag = nvp->v_tag; 60739433Smckusick nvp->v_type = VNON; 60839433Smckusick insmntque(vp, mp); 60939433Smckusick return (vp); 61039433Smckusick } 61139433Smckusick 61239433Smckusick /* 61339433Smckusick * Grab a particular vnode from the free list, increment its 61439433Smckusick * reference count and lock it. The vnode lock bit is set the 61539433Smckusick * vnode is being eliminated in vgone. The process is awakened 61639433Smckusick * when the transition is completed, and an error returned to 61739433Smckusick * indicate that the vnode is no longer usable (possibly having 61839433Smckusick * been changed to a new file system type). 61939433Smckusick */ 62039397Smckusick vget(vp) 62139397Smckusick register struct vnode *vp; 62239397Smckusick { 62339397Smckusick register struct vnode *vq; 62439397Smckusick 62539433Smckusick if (vp->v_flag & VXLOCK) { 62639433Smckusick vp->v_flag |= VXWANT; 62739433Smckusick sleep((caddr_t)vp, PINOD); 62839433Smckusick return (1); 62939433Smckusick } 63039809Smckusick if (vp->v_usecount == 0) { 63139433Smckusick if (vq = vp->v_freef) 63239433Smckusick vq->v_freeb = vp->v_freeb; 63339433Smckusick else 63439433Smckusick vfreet = vp->v_freeb; 63539433Smckusick *vp->v_freeb = vq; 63639433Smckusick vp->v_freef = NULL; 63739433Smckusick vp->v_freeb = NULL; 63839433Smckusick } 63939397Smckusick VREF(vp); 64039433Smckusick VOP_LOCK(vp); 64139433Smckusick return (0); 64239397Smckusick } 64339397Smckusick 64439397Smckusick /* 64539397Smckusick * Vnode reference, just increment the count 64639397Smckusick */ 64739397Smckusick void vref(vp) 64839397Smckusick struct vnode *vp; 64939397Smckusick { 65039397Smckusick 65139809Smckusick vp->v_usecount++; 65239397Smckusick } 65339397Smckusick 65439397Smckusick /* 65539397Smckusick * vput(), just unlock and vrele() 65639397Smckusick */ 65739397Smckusick void vput(vp) 65839397Smckusick register struct vnode *vp; 65939397Smckusick { 66039397Smckusick VOP_UNLOCK(vp); 66139397Smckusick vrele(vp); 66239397Smckusick } 66339397Smckusick 66439397Smckusick /* 66539397Smckusick * Vnode release. 66639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 66739397Smckusick */ 66839397Smckusick void vrele(vp) 66939397Smckusick register struct vnode *vp; 67039397Smckusick { 67148024Smckusick struct proc *p = curproc; /* XXX */ 67239397Smckusick 67339397Smckusick if (vp == NULL) 67439433Smckusick panic("vrele: null vp"); 67539809Smckusick vp->v_usecount--; 67639809Smckusick if (vp->v_usecount < 0) 67739667Smckusick vprint("vrele: bad ref count", vp); 67839809Smckusick if (vp->v_usecount > 0) 67939397Smckusick return; 68041400Smckusick if (vfreeh == NULLVP) { 68139397Smckusick /* 68239397Smckusick * insert into empty list 68339397Smckusick */ 68439397Smckusick vfreeh = vp; 68539397Smckusick vp->v_freeb = &vfreeh; 68639397Smckusick } else { 68739397Smckusick /* 68839397Smckusick * insert at tail of list 68939397Smckusick */ 69039397Smckusick *vfreet = vp; 69139397Smckusick vp->v_freeb = vfreet; 69239397Smckusick } 69339433Smckusick vp->v_freef = NULL; 69439433Smckusick vfreet = &vp->v_freef; 69548024Smckusick VOP_INACTIVE(vp, p); 69639397Smckusick } 69739433Smckusick 69839433Smckusick /* 69939809Smckusick * Page or buffer structure gets a reference. 70039809Smckusick */ 70139809Smckusick vhold(vp) 70239809Smckusick register struct vnode *vp; 70339809Smckusick { 70439809Smckusick 70539809Smckusick vp->v_holdcnt++; 70639809Smckusick } 70739809Smckusick 70839809Smckusick /* 70939809Smckusick * Page or buffer structure frees a reference. 71039809Smckusick */ 71139809Smckusick holdrele(vp) 71239809Smckusick register struct vnode *vp; 71339809Smckusick { 71439809Smckusick 71539809Smckusick if (vp->v_holdcnt <= 0) 71639809Smckusick panic("holdrele: holdcnt"); 71739809Smckusick vp->v_holdcnt--; 71839809Smckusick } 71939809Smckusick 72039809Smckusick /* 72139509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 72239509Smckusick * 72339509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 72439509Smckusick * return error if any are found (nb: this is a user error, not a 72539509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 72639509Smckusick * that are found. 72739509Smckusick */ 72839509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 72939509Smckusick 73039509Smckusick vflush(mp, skipvp, flags) 73139509Smckusick struct mount *mp; 73239509Smckusick struct vnode *skipvp; 73339509Smckusick int flags; 73439509Smckusick { 73539509Smckusick register struct vnode *vp, *nvp; 73639509Smckusick int busy = 0; 73739509Smckusick 73841400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 73941300Smckusick panic("vflush: not busy"); 74041421Smckusick loop: 74141400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 74241421Smckusick if (vp->v_mount != mp) 74341421Smckusick goto loop; 74439509Smckusick nvp = vp->v_mountf; 74539509Smckusick /* 74639509Smckusick * Skip over a selected vnode. 74739509Smckusick */ 74839509Smckusick if (vp == skipvp) 74939509Smckusick continue; 75039509Smckusick /* 75141300Smckusick * Skip over a vnodes marked VSYSTEM. 75241300Smckusick */ 75341300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 75441300Smckusick continue; 75541300Smckusick /* 75639809Smckusick * With v_usecount == 0, all we need to do is clear 75739509Smckusick * out the vnode data structures and we are done. 75839509Smckusick */ 75939809Smckusick if (vp->v_usecount == 0) { 76039509Smckusick vgone(vp); 76139509Smckusick continue; 76239509Smckusick } 76339509Smckusick /* 76439509Smckusick * For block or character devices, revert to an 76539509Smckusick * anonymous device. For all other files, just kill them. 76639509Smckusick */ 76741300Smckusick if (flags & FORCECLOSE) { 76839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 76939509Smckusick vgone(vp); 77039509Smckusick } else { 77139509Smckusick vclean(vp, 0); 77239509Smckusick vp->v_op = &spec_vnodeops; 77339509Smckusick insmntque(vp, (struct mount *)0); 77439509Smckusick } 77539509Smckusick continue; 77639509Smckusick } 77739509Smckusick if (busyprt) 77839667Smckusick vprint("vflush: busy vnode", vp); 77939509Smckusick busy++; 78039509Smckusick } 78139509Smckusick if (busy) 78239509Smckusick return (EBUSY); 78339509Smckusick return (0); 78439509Smckusick } 78539509Smckusick 78639509Smckusick /* 78739433Smckusick * Disassociate the underlying file system from a vnode. 78839433Smckusick */ 78941300Smckusick void vclean(vp, flags) 79039433Smckusick register struct vnode *vp; 79145118Smckusick int flags; 79239433Smckusick { 79339433Smckusick struct vnodeops *origops; 79439484Smckusick int active; 79548024Smckusick struct proc *p = curproc; /* XXX */ 79639433Smckusick 79739484Smckusick /* 79839484Smckusick * Check to see if the vnode is in use. 79939667Smckusick * If so we have to reference it before we clean it out 80039667Smckusick * so that its count cannot fall to zero and generate a 80139667Smckusick * race against ourselves to recycle it. 80239484Smckusick */ 80339809Smckusick if (active = vp->v_usecount) 80439484Smckusick VREF(vp); 80539484Smckusick /* 80639484Smckusick * Prevent the vnode from being recycled or 80739484Smckusick * brought into use while we clean it out. 80839484Smckusick */ 80939667Smckusick if (vp->v_flag & VXLOCK) 81039667Smckusick panic("vclean: deadlock"); 81139433Smckusick vp->v_flag |= VXLOCK; 81239433Smckusick /* 81339667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 81439667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 81539667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 81639667Smckusick * For active vnodes, it ensures that no other activity can 81739667Smckusick * occur while the buffer list is being cleaned out. 81839667Smckusick */ 81939667Smckusick VOP_LOCK(vp); 82041300Smckusick if (flags & DOCLOSE) 82139667Smckusick vinvalbuf(vp, 1); 82239667Smckusick /* 82339433Smckusick * Prevent any further operations on the vnode from 82439433Smckusick * being passed through to the old file system. 82539433Smckusick */ 82639433Smckusick origops = vp->v_op; 82739433Smckusick vp->v_op = &dead_vnodeops; 82839433Smckusick vp->v_tag = VT_NON; 82939433Smckusick /* 83039484Smckusick * If purging an active vnode, it must be unlocked, closed, 83139484Smckusick * and deactivated before being reclaimed. 83239433Smckusick */ 83349761Smckusick (*(origops->vop_unlock))(vp); 83439484Smckusick if (active) { 83541300Smckusick if (flags & DOCLOSE) 83649761Smckusick (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 83749761Smckusick (*(origops->vop_inactive))(vp, p); 83839433Smckusick } 83939433Smckusick /* 84039433Smckusick * Reclaim the vnode. 84139433Smckusick */ 84249761Smckusick if ((*(origops->vop_reclaim))(vp)) 84339433Smckusick panic("vclean: cannot reclaim"); 84439484Smckusick if (active) 84539484Smckusick vrele(vp); 84639433Smckusick /* 84739433Smckusick * Done with purge, notify sleepers in vget of the grim news. 84839433Smckusick */ 84939433Smckusick vp->v_flag &= ~VXLOCK; 85039433Smckusick if (vp->v_flag & VXWANT) { 85139433Smckusick vp->v_flag &= ~VXWANT; 85239433Smckusick wakeup((caddr_t)vp); 85339433Smckusick } 85439433Smckusick } 85539433Smckusick 85639433Smckusick /* 85739633Smckusick * Eliminate all activity associated with the requested vnode 85839633Smckusick * and with all vnodes aliased to the requested vnode. 85939633Smckusick */ 86039633Smckusick void vgoneall(vp) 86139633Smckusick register struct vnode *vp; 86239633Smckusick { 86339809Smckusick register struct vnode *vq; 86439633Smckusick 86540665Smckusick if (vp->v_flag & VALIASED) { 86640665Smckusick /* 86740665Smckusick * If a vgone (or vclean) is already in progress, 86840665Smckusick * wait until it is done and return. 86940665Smckusick */ 87040665Smckusick if (vp->v_flag & VXLOCK) { 87140665Smckusick vp->v_flag |= VXWANT; 87240665Smckusick sleep((caddr_t)vp, PINOD); 87340665Smckusick return; 87439633Smckusick } 87540665Smckusick /* 87640665Smckusick * Ensure that vp will not be vgone'd while we 87740665Smckusick * are eliminating its aliases. 87840665Smckusick */ 87940665Smckusick vp->v_flag |= VXLOCK; 88040665Smckusick while (vp->v_flag & VALIASED) { 88140665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 88240665Smckusick if (vq->v_rdev != vp->v_rdev || 88340665Smckusick vq->v_type != vp->v_type || vp == vq) 88440665Smckusick continue; 88540665Smckusick vgone(vq); 88640665Smckusick break; 88740665Smckusick } 88840665Smckusick } 88940665Smckusick /* 89040665Smckusick * Remove the lock so that vgone below will 89140665Smckusick * really eliminate the vnode after which time 89240665Smckusick * vgone will awaken any sleepers. 89340665Smckusick */ 89440665Smckusick vp->v_flag &= ~VXLOCK; 89539633Smckusick } 89639633Smckusick vgone(vp); 89739633Smckusick } 89839633Smckusick 89939633Smckusick /* 90039433Smckusick * Eliminate all activity associated with a vnode 90139433Smckusick * in preparation for reuse. 90239433Smckusick */ 90339433Smckusick void vgone(vp) 90439433Smckusick register struct vnode *vp; 90539433Smckusick { 90639809Smckusick register struct vnode *vq; 90739615Smckusick struct vnode *vx; 90839615Smckusick long count; 90939433Smckusick 91039433Smckusick /* 91140548Smckusick * If a vgone (or vclean) is already in progress, 91240548Smckusick * wait until it is done and return. 91340548Smckusick */ 91440548Smckusick if (vp->v_flag & VXLOCK) { 91540548Smckusick vp->v_flag |= VXWANT; 91640548Smckusick sleep((caddr_t)vp, PINOD); 91740548Smckusick return; 91840548Smckusick } 91940548Smckusick /* 92039433Smckusick * Clean out the filesystem specific data. 92139433Smckusick */ 92241300Smckusick vclean(vp, DOCLOSE); 92339433Smckusick /* 92439433Smckusick * Delete from old mount point vnode list, if on one. 92539433Smckusick */ 92639433Smckusick if (vp->v_mountb) { 92739433Smckusick if (vq = vp->v_mountf) 92839433Smckusick vq->v_mountb = vp->v_mountb; 92939433Smckusick *vp->v_mountb = vq; 93039433Smckusick vp->v_mountf = NULL; 93139433Smckusick vp->v_mountb = NULL; 93239433Smckusick } 93339433Smckusick /* 93439433Smckusick * If special device, remove it from special device alias list. 93539433Smckusick */ 93639433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 93739809Smckusick if (*vp->v_hashchain == vp) { 93839809Smckusick *vp->v_hashchain = vp->v_specnext; 93939433Smckusick } else { 94039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 94139615Smckusick if (vq->v_specnext != vp) 94239433Smckusick continue; 94339615Smckusick vq->v_specnext = vp->v_specnext; 94439433Smckusick break; 94539433Smckusick } 94639615Smckusick if (vq == NULL) 94739433Smckusick panic("missing bdev"); 94839433Smckusick } 94939615Smckusick if (vp->v_flag & VALIASED) { 95039809Smckusick count = 0; 95139809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 95240108Smckusick if (vq->v_rdev != vp->v_rdev || 95340108Smckusick vq->v_type != vp->v_type) 95439615Smckusick continue; 95539615Smckusick count++; 95639615Smckusick vx = vq; 95739615Smckusick } 95839615Smckusick if (count == 0) 95939615Smckusick panic("missing alias"); 96039615Smckusick if (count == 1) 96139615Smckusick vx->v_flag &= ~VALIASED; 96239615Smckusick vp->v_flag &= ~VALIASED; 96339615Smckusick } 96439615Smckusick FREE(vp->v_specinfo, M_VNODE); 96539615Smckusick vp->v_specinfo = NULL; 96639433Smckusick } 96739433Smckusick /* 96839433Smckusick * If it is on the freelist, move it to the head of the list. 96939433Smckusick */ 97039433Smckusick if (vp->v_freeb) { 97139433Smckusick if (vq = vp->v_freef) 97239433Smckusick vq->v_freeb = vp->v_freeb; 97339433Smckusick else 97439433Smckusick vfreet = vp->v_freeb; 97539433Smckusick *vp->v_freeb = vq; 97639433Smckusick vp->v_freef = vfreeh; 97739433Smckusick vp->v_freeb = &vfreeh; 97839433Smckusick vfreeh->v_freeb = &vp->v_freef; 97939433Smckusick vfreeh = vp; 98039433Smckusick } 98139484Smckusick vp->v_type = VBAD; 98239433Smckusick } 98339633Smckusick 98439633Smckusick /* 98539821Smckusick * Lookup a vnode by device number. 98639821Smckusick */ 98739821Smckusick vfinddev(dev, type, vpp) 98839821Smckusick dev_t dev; 98939821Smckusick enum vtype type; 99039821Smckusick struct vnode **vpp; 99139821Smckusick { 99239821Smckusick register struct vnode *vp; 99339821Smckusick 99439821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 99539821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 99639821Smckusick continue; 99739821Smckusick *vpp = vp; 99839821Smckusick return (0); 99939821Smckusick } 100039821Smckusick return (1); 100139821Smckusick } 100239821Smckusick 100339821Smckusick /* 100439633Smckusick * Calculate the total number of references to a special device. 100539633Smckusick */ 100639633Smckusick vcount(vp) 100739633Smckusick register struct vnode *vp; 100839633Smckusick { 100939809Smckusick register struct vnode *vq; 101039633Smckusick int count; 101139633Smckusick 101239633Smckusick if ((vp->v_flag & VALIASED) == 0) 101339809Smckusick return (vp->v_usecount); 101439633Smckusick loop: 101539809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 101640108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 101739633Smckusick continue; 101839633Smckusick /* 101939633Smckusick * Alias, but not in use, so flush it out. 102039633Smckusick */ 102139809Smckusick if (vq->v_usecount == 0) { 102239633Smckusick vgone(vq); 102339633Smckusick goto loop; 102439633Smckusick } 102539809Smckusick count += vq->v_usecount; 102639633Smckusick } 102739633Smckusick return (count); 102839633Smckusick } 102939667Smckusick 103039667Smckusick /* 103139667Smckusick * Print out a description of a vnode. 103239667Smckusick */ 103339667Smckusick static char *typename[] = 103440286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 103539667Smckusick 103639667Smckusick vprint(label, vp) 103739667Smckusick char *label; 103839667Smckusick register struct vnode *vp; 103939667Smckusick { 104039913Smckusick char buf[64]; 104139667Smckusick 104239667Smckusick if (label != NULL) 104339667Smckusick printf("%s: ", label); 104439913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 104539809Smckusick vp->v_usecount, vp->v_holdcnt); 104639913Smckusick buf[0] = '\0'; 104739913Smckusick if (vp->v_flag & VROOT) 104839913Smckusick strcat(buf, "|VROOT"); 104939913Smckusick if (vp->v_flag & VTEXT) 105039913Smckusick strcat(buf, "|VTEXT"); 105141300Smckusick if (vp->v_flag & VSYSTEM) 105241300Smckusick strcat(buf, "|VSYSTEM"); 105341300Smckusick if (vp->v_flag & VXLOCK) 105441300Smckusick strcat(buf, "|VXLOCK"); 105541300Smckusick if (vp->v_flag & VXWANT) 105641300Smckusick strcat(buf, "|VXWANT"); 105741300Smckusick if (vp->v_flag & VBWAIT) 105841300Smckusick strcat(buf, "|VBWAIT"); 105939913Smckusick if (vp->v_flag & VALIASED) 106039913Smckusick strcat(buf, "|VALIASED"); 106139913Smckusick if (buf[0] != '\0') 106239913Smckusick printf(" flags (%s)", &buf[1]); 106339913Smckusick printf("\n\t"); 106439667Smckusick VOP_PRINT(vp); 106539667Smckusick } 106641110Smarc 106749691Smckusick #ifdef DEBUG 106849691Smckusick /* 106949691Smckusick * List all of the locked vnodes in the system. 107049691Smckusick * Called when debugging the kernel. 107149691Smckusick */ 107249691Smckusick printlockedvnodes() 107349691Smckusick { 107449691Smckusick register struct mount *mp; 107549691Smckusick register struct vnode *vp; 107649691Smckusick 107749691Smckusick printf("Locked vnodes\n"); 107849691Smckusick mp = rootfs; 107949691Smckusick do { 108049691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 108149691Smckusick if (VOP_ISLOCKED(vp)) 108249691Smckusick vprint((char *)0, vp); 108349691Smckusick mp = mp->mnt_next; 108449691Smckusick } while (mp != rootfs); 108549691Smckusick } 108649691Smckusick #endif 108749691Smckusick 108841110Smarc int kinfo_vdebug = 1; 108941110Smarc int kinfo_vgetfailed; 109041110Smarc #define KINFO_VNODESLOP 10 109141110Smarc /* 109241110Smarc * Dump vnode list (via kinfo). 109341110Smarc * Copyout address of vnode followed by vnode. 109441110Smarc */ 109545118Smckusick /* ARGSUSED */ 109641110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 109745118Smckusick int op; 109841110Smarc char *where; 109945118Smckusick int *acopysize, arg, *aneeded; 110041110Smarc { 110141110Smarc register struct mount *mp = rootfs; 110241300Smckusick struct mount *omp; 110341110Smarc struct vnode *vp; 110441110Smarc register char *bp = where, *savebp; 110541110Smarc char *ewhere = where + *acopysize; 110641110Smarc int error; 110741110Smarc 110841110Smarc #define VPTRSZ sizeof (struct vnode *) 110941110Smarc #define VNODESZ sizeof (struct vnode) 111041110Smarc if (where == NULL) { 111141110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 111241110Smarc return (0); 111341110Smarc } 111441110Smarc 111541110Smarc do { 111641300Smckusick if (vfs_busy(mp)) { 111741400Smckusick mp = mp->mnt_next; 111841300Smckusick continue; 111941300Smckusick } 112041110Smarc savebp = bp; 112141110Smarc again: 112241421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 112341422Smckusick /* 112441422Smckusick * Check that the vp is still associated with 112541422Smckusick * this filesystem. RACE: could have been 112641422Smckusick * recycled onto the same filesystem. 112741422Smckusick */ 112841421Smckusick if (vp->v_mount != mp) { 112941421Smckusick if (kinfo_vdebug) 113041421Smckusick printf("kinfo: vp changed\n"); 113141421Smckusick bp = savebp; 113241421Smckusick goto again; 113341421Smckusick } 113441110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 113541110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 113641110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 113741422Smckusick VNODESZ)))) 113841110Smarc return (error); 113941110Smarc bp += VPTRSZ + VNODESZ; 114041110Smarc } 114141300Smckusick omp = mp; 114241400Smckusick mp = mp->mnt_next; 114341300Smckusick vfs_unbusy(omp); 114441110Smarc } while (mp != rootfs); 114541110Smarc 114641110Smarc *aneeded = bp - where; 114741110Smarc if (bp > ewhere) 114841110Smarc *acopysize = ewhere - where; 114941110Smarc else 115041110Smarc *acopysize = bp - where; 115141110Smarc return (0); 115241110Smarc } 1153