137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*56459Smargo * @(#)vfs_subr.c 7.86 (Berkeley) 10/07/92 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 1553829Spendry #include <sys/systm.h> 1651460Sbostic #include <sys/proc.h> 1751460Sbostic #include <sys/mount.h> 1851460Sbostic #include <sys/time.h> 1951460Sbostic #include <sys/vnode.h> 2052415Smckusick #include <sys/stat.h> 2151460Sbostic #include <sys/namei.h> 2251460Sbostic #include <sys/ucred.h> 2351460Sbostic #include <sys/buf.h> 2451460Sbostic #include <sys/errno.h> 2551460Sbostic #include <sys/malloc.h> 2637488Smckusick 2755050Spendry #include <miscfs/specfs/specdev.h> 2855050Spendry 2952415Smckusick enum vtype iftovt_tab[16] = { 3052415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 3152415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3252415Smckusick }; 3352415Smckusick int vttoif_tab[9] = { 3452415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 3552415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 3652415Smckusick }; 3752415Smckusick 3837488Smckusick /* 3937488Smckusick * Remove a mount point from the list of mounted filesystems. 4037488Smckusick * Unmount of the root is illegal. 4137488Smckusick */ 4237488Smckusick void 4337488Smckusick vfs_remove(mp) 4437488Smckusick register struct mount *mp; 4537488Smckusick { 4637488Smckusick 4737488Smckusick if (mp == rootfs) 4837488Smckusick panic("vfs_remove: unmounting root"); 4941400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 5041400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 5141400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 5237488Smckusick vfs_unlock(mp); 5337488Smckusick } 5437488Smckusick 5537488Smckusick /* 5637488Smckusick * Lock a filesystem. 5737488Smckusick * Used to prevent access to it while mounting and unmounting. 5837488Smckusick */ 5937488Smckusick vfs_lock(mp) 6037488Smckusick register struct mount *mp; 6137488Smckusick { 6237488Smckusick 6341400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 6441400Smckusick mp->mnt_flag |= MNT_MWAIT; 6539045Smckusick sleep((caddr_t)mp, PVFS); 6639045Smckusick } 6741400Smckusick mp->mnt_flag |= MNT_MLOCK; 6837488Smckusick return (0); 6937488Smckusick } 7037488Smckusick 7137488Smckusick /* 7237488Smckusick * Unlock a locked filesystem. 7337488Smckusick * Panic if filesystem is not locked. 7437488Smckusick */ 7537488Smckusick void 7637488Smckusick vfs_unlock(mp) 7737488Smckusick register struct mount *mp; 7837488Smckusick { 7937488Smckusick 8041400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 8141300Smckusick panic("vfs_unlock: not locked"); 8241400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 8341400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 8441400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 8537488Smckusick wakeup((caddr_t)mp); 8637488Smckusick } 8737488Smckusick } 8837488Smckusick 8937488Smckusick /* 9041300Smckusick * Mark a mount point as busy. 9141300Smckusick * Used to synchronize access and to delay unmounting. 9241300Smckusick */ 9341300Smckusick vfs_busy(mp) 9441300Smckusick register struct mount *mp; 9541300Smckusick { 9641300Smckusick 9741400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 9841400Smckusick mp->mnt_flag |= MNT_MPWANT; 9941400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 10041300Smckusick } 10141419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 10241419Smckusick return (1); 10341400Smckusick mp->mnt_flag |= MNT_MPBUSY; 10441300Smckusick return (0); 10541300Smckusick } 10641300Smckusick 10741300Smckusick /* 10841300Smckusick * Free a busy filesystem. 10941300Smckusick * Panic if filesystem is not busy. 11041300Smckusick */ 11141300Smckusick vfs_unbusy(mp) 11241300Smckusick register struct mount *mp; 11341300Smckusick { 11441300Smckusick 11541400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 11641300Smckusick panic("vfs_unbusy: not busy"); 11741400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 11841400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 11941400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 12041400Smckusick wakeup((caddr_t)&mp->mnt_flag); 12141300Smckusick } 12241300Smckusick } 12341300Smckusick 12441300Smckusick /* 12537488Smckusick * Lookup a mount point by filesystem identifier. 12637488Smckusick */ 12737488Smckusick struct mount * 12837488Smckusick getvfs(fsid) 12937488Smckusick fsid_t *fsid; 13037488Smckusick { 13137488Smckusick register struct mount *mp; 13237488Smckusick 13338288Smckusick mp = rootfs; 13438288Smckusick do { 13541400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 13641400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 13738288Smckusick return (mp); 13837488Smckusick } 13941400Smckusick mp = mp->mnt_next; 14038288Smckusick } while (mp != rootfs); 14138288Smckusick return ((struct mount *)0); 14237488Smckusick } 14337488Smckusick 14437488Smckusick /* 14553829Spendry * Get a new unique fsid 14653829Spendry */ 14753829Spendry void 14853829Spendry getnewfsid(mp, mtype) 14953829Spendry struct mount *mp; 15053829Spendry int mtype; 15153829Spendry { 15253829Spendry static u_short xxxfs_mntid; 15353829Spendry 15453829Spendry fsid_t tfsid; 15553829Spendry 15653829Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0); /* XXX */ 15753829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 15853829Spendry if (xxxfs_mntid == 0) 15953829Spendry ++xxxfs_mntid; 16053829Spendry tfsid.val[0] = makedev(nblkdev, xxxfs_mntid); 16153829Spendry tfsid.val[1] = mtype; 16253936Spendry if (rootfs) { 16353936Spendry while (getvfs(&tfsid)) { 16453936Spendry tfsid.val[0]++; 16553936Spendry xxxfs_mntid++; 16653936Spendry } 16753829Spendry } 16853829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 16953829Spendry } 17053829Spendry 17153829Spendry /* 17237488Smckusick * Set vnode attributes to VNOVAL 17337488Smckusick */ 17437488Smckusick void vattr_null(vap) 17537488Smckusick register struct vattr *vap; 17637488Smckusick { 17737488Smckusick 17837488Smckusick vap->va_type = VNON; 17952005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 18037488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18152005Smckusick vap->va_fsid = vap->va_fileid = 18252005Smckusick vap->va_blocksize = vap->va_rdev = 18354347Smckusick vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 18454347Smckusick vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 18554347Smckusick vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 18638258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 18737488Smckusick } 18838265Smckusick 18938265Smckusick /* 19039397Smckusick * Routines having to do with the management of the vnode table. 19139397Smckusick */ 19255468Smckusick struct vnode *vfreeh, **vfreet = &vfreeh; 19353547Sheideman extern int (**dead_vnodeop_p)(); 19439635Smckusick extern void vclean(); 19540883Smckusick long numvnodes; 19653493Sheideman extern struct vattr va_null; 19739397Smckusick 19839397Smckusick /* 19939397Smckusick * Return the next vnode from the free list. 20039397Smckusick */ 20139397Smckusick getnewvnode(tag, mp, vops, vpp) 20239397Smckusick enum vtagtype tag; 20339397Smckusick struct mount *mp; 20453495Sheideman int (**vops)(); 20539397Smckusick struct vnode **vpp; 20639397Smckusick { 20739397Smckusick register struct vnode *vp, *vq; 20839397Smckusick 20954347Smckusick if ((vfreeh == NULL && numvnodes < 2 * desiredvnodes) || 21054347Smckusick numvnodes < desiredvnodes) { 21145118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 21245118Smckusick M_VNODE, M_WAITOK); 21340883Smckusick bzero((char *)vp, sizeof *vp); 21440883Smckusick numvnodes++; 21540883Smckusick } else { 21640883Smckusick if ((vp = vfreeh) == NULL) { 21740883Smckusick tablefull("vnode"); 21840883Smckusick *vpp = 0; 21940883Smckusick return (ENFILE); 22040883Smckusick } 22140883Smckusick if (vp->v_usecount) 22240883Smckusick panic("free vnode isn't"); 22340883Smckusick if (vq = vp->v_freef) 22440883Smckusick vq->v_freeb = &vfreeh; 22540883Smckusick else 22640883Smckusick vfreet = &vfreeh; 22740883Smckusick vfreeh = vq; 22840883Smckusick vp->v_freef = NULL; 22940883Smckusick vp->v_freeb = NULL; 23052190Smckusick vp->v_lease = NULL; 23140883Smckusick if (vp->v_type != VBAD) 23240883Smckusick vgone(vp); 23352006Smckusick if (vp->v_data) 23452006Smckusick panic("cleaned vnode isn't"); 23540883Smckusick vp->v_flag = 0; 23640883Smckusick vp->v_lastr = 0; 23740883Smckusick vp->v_socket = 0; 23839397Smckusick } 23939512Smckusick vp->v_type = VNON; 24039397Smckusick cache_purge(vp); 24139397Smckusick vp->v_tag = tag; 24239433Smckusick vp->v_op = vops; 24339397Smckusick insmntque(vp, mp); 24439397Smckusick VREF(vp); 24539397Smckusick *vpp = vp; 24639397Smckusick return (0); 24739397Smckusick } 24839397Smckusick 24939397Smckusick /* 25039397Smckusick * Move a vnode from one mount queue to another. 25139397Smckusick */ 25239397Smckusick insmntque(vp, mp) 25339397Smckusick register struct vnode *vp; 25439397Smckusick register struct mount *mp; 25539397Smckusick { 25649973Smckusick register struct vnode *vq; 25739397Smckusick 25839397Smckusick /* 25939397Smckusick * Delete from old mount point vnode list, if on one. 26039397Smckusick */ 26139397Smckusick if (vp->v_mountb) { 26239397Smckusick if (vq = vp->v_mountf) 26339397Smckusick vq->v_mountb = vp->v_mountb; 26439397Smckusick *vp->v_mountb = vq; 26539397Smckusick } 26639397Smckusick /* 26739397Smckusick * Insert into list of vnodes for the new mount point, if available. 26839397Smckusick */ 26939621Smckusick vp->v_mount = mp; 27039397Smckusick if (mp == NULL) { 27139397Smckusick vp->v_mountf = NULL; 27239397Smckusick vp->v_mountb = NULL; 27339397Smckusick return; 27439397Smckusick } 27549973Smckusick if (vq = mp->mnt_mounth) 27649973Smckusick vq->v_mountb = &vp->v_mountf; 27749973Smckusick vp->v_mountf = vq; 27849973Smckusick vp->v_mountb = &mp->mnt_mounth; 27949973Smckusick mp->mnt_mounth = vp; 28039397Smckusick } 28139397Smckusick 28239397Smckusick /* 28349232Smckusick * Update outstanding I/O count and do wakeup if requested. 28449232Smckusick */ 28549232Smckusick vwakeup(bp) 28649232Smckusick register struct buf *bp; 28749232Smckusick { 28849232Smckusick register struct vnode *vp; 28949232Smckusick 29049232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 29149232Smckusick if (vp = bp->b_vp) { 29249232Smckusick vp->v_numoutput--; 29349232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 29449232Smckusick if (vp->v_numoutput < 0) 29549232Smckusick panic("vwakeup: neg numoutput"); 29649232Smckusick vp->v_flag &= ~VBWAIT; 29749232Smckusick wakeup((caddr_t)&vp->v_numoutput); 29849232Smckusick } 29949232Smckusick } 30049232Smckusick } 30149232Smckusick 30249232Smckusick /* 30349232Smckusick * Flush out and invalidate all buffers associated with a vnode. 30449232Smckusick * Called with the underlying object locked. 30549232Smckusick */ 30654442Smckusick int 307*56459Smargo vinvalbuf(vp, flags, cred, p) 30849232Smckusick register struct vnode *vp; 309*56459Smargo int flags; 31054442Smckusick struct ucred *cred; 31154442Smckusick struct proc *p; 31249232Smckusick { 31349232Smckusick register struct buf *bp; 31449232Smckusick struct buf *nbp, *blist; 31554442Smckusick int s, error; 31649232Smckusick 317*56459Smargo if (flags & V_SAVE) { 31854442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 31954442Smckusick return (error); 32054442Smckusick if (vp->v_dirtyblkhd != NULL) 32154442Smckusick panic("vinvalbuf: dirty bufs"); 32254442Smckusick } 32349232Smckusick for (;;) { 324*56459Smargo if ((blist = vp->v_cleanblkhd) && flags & V_SAVEMETA) 325*56459Smargo while (blist && blist->b_lblkno < 0) 326*56459Smargo blist = blist->b_blockf; 327*56459Smargo if (!blist && (blist = vp->v_dirtyblkhd) && flags & V_SAVEMETA) 328*56459Smargo while (blist && blist->b_lblkno < 0) 329*56459Smargo blist = blist->b_blockf; 330*56459Smargo if (!blist) 33149232Smckusick break; 332*56459Smargo 33349232Smckusick for (bp = blist; bp; bp = nbp) { 33449232Smckusick nbp = bp->b_blockf; 335*56459Smargo if (flags & V_SAVEMETA && bp->b_lblkno < 0) 336*56459Smargo continue; 33749232Smckusick s = splbio(); 33849232Smckusick if (bp->b_flags & B_BUSY) { 33949232Smckusick bp->b_flags |= B_WANTED; 34049232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 34149232Smckusick splx(s); 34249232Smckusick break; 34349232Smckusick } 34449232Smckusick bremfree(bp); 34549232Smckusick bp->b_flags |= B_BUSY; 34649232Smckusick splx(s); 347*56459Smargo bp->b_flags |= B_INVAL; 34849232Smckusick brelse(bp); 34949232Smckusick } 35049232Smckusick } 351*56459Smargo if (!(flags & V_SAVEMETA) && (vp->v_dirtyblkhd || vp->v_cleanblkhd)) 35249232Smckusick panic("vinvalbuf: flush failed"); 35354442Smckusick return (0); 35449232Smckusick } 35549232Smckusick 35649232Smckusick /* 35749232Smckusick * Associate a buffer with a vnode. 35849232Smckusick */ 35949232Smckusick bgetvp(vp, bp) 36049232Smckusick register struct vnode *vp; 36149232Smckusick register struct buf *bp; 36249232Smckusick { 36349973Smckusick register struct vnode *vq; 36449973Smckusick register struct buf *bq; 36549232Smckusick 36649232Smckusick if (bp->b_vp) 36749232Smckusick panic("bgetvp: not free"); 36849232Smckusick VHOLD(vp); 36949232Smckusick bp->b_vp = vp; 37049232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 37149232Smckusick bp->b_dev = vp->v_rdev; 37249232Smckusick else 37349232Smckusick bp->b_dev = NODEV; 37449232Smckusick /* 37549232Smckusick * Insert onto list for new vnode. 37649232Smckusick */ 37749973Smckusick if (bq = vp->v_cleanblkhd) 37849973Smckusick bq->b_blockb = &bp->b_blockf; 37949973Smckusick bp->b_blockf = bq; 38049973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 38149973Smckusick vp->v_cleanblkhd = bp; 38249232Smckusick } 38349232Smckusick 38449232Smckusick /* 38549232Smckusick * Disassociate a buffer from a vnode. 38649232Smckusick */ 38749232Smckusick brelvp(bp) 38849232Smckusick register struct buf *bp; 38949232Smckusick { 39049232Smckusick struct buf *bq; 39149232Smckusick struct vnode *vp; 39249232Smckusick 39349232Smckusick if (bp->b_vp == (struct vnode *) 0) 39449232Smckusick panic("brelvp: NULL"); 39549232Smckusick /* 39649232Smckusick * Delete from old vnode list, if on one. 39749232Smckusick */ 39849232Smckusick if (bp->b_blockb) { 39949232Smckusick if (bq = bp->b_blockf) 40049232Smckusick bq->b_blockb = bp->b_blockb; 40149232Smckusick *bp->b_blockb = bq; 40249232Smckusick bp->b_blockf = NULL; 40349232Smckusick bp->b_blockb = NULL; 40449232Smckusick } 40549232Smckusick vp = bp->b_vp; 40649232Smckusick bp->b_vp = (struct vnode *) 0; 40749232Smckusick HOLDRELE(vp); 40849232Smckusick } 40949232Smckusick 41049232Smckusick /* 41149232Smckusick * Reassign a buffer from one vnode to another. 41249232Smckusick * Used to assign file specific control information 41349232Smckusick * (indirect blocks) to the vnode to which they belong. 41449232Smckusick */ 41549232Smckusick reassignbuf(bp, newvp) 41649232Smckusick register struct buf *bp; 41749232Smckusick register struct vnode *newvp; 41849232Smckusick { 41949232Smckusick register struct buf *bq, **listheadp; 42049232Smckusick 42152655Smckusick if (newvp == NULL) { 42252655Smckusick printf("reassignbuf: NULL"); 42352655Smckusick return; 42452655Smckusick } 42549232Smckusick /* 42649232Smckusick * Delete from old vnode list, if on one. 42749232Smckusick */ 42849232Smckusick if (bp->b_blockb) { 42949232Smckusick if (bq = bp->b_blockf) 43049232Smckusick bq->b_blockb = bp->b_blockb; 43149232Smckusick *bp->b_blockb = bq; 43249232Smckusick } 43349232Smckusick /* 43449232Smckusick * If dirty, put on list of dirty buffers; 43549232Smckusick * otherwise insert onto list of clean buffers. 43649232Smckusick */ 43749232Smckusick if (bp->b_flags & B_DELWRI) 43849232Smckusick listheadp = &newvp->v_dirtyblkhd; 43949232Smckusick else 44049232Smckusick listheadp = &newvp->v_cleanblkhd; 44149973Smckusick if (bq = *listheadp) 44249973Smckusick bq->b_blockb = &bp->b_blockf; 44349973Smckusick bp->b_blockf = bq; 44449973Smckusick bp->b_blockb = listheadp; 44549973Smckusick *listheadp = bp; 44649232Smckusick } 44749232Smckusick 44849232Smckusick /* 44939433Smckusick * Create a vnode for a block device. 45039433Smckusick * Used for root filesystem, argdev, and swap areas. 45139433Smckusick * Also used for memory file system special devices. 45239397Smckusick */ 45339433Smckusick bdevvp(dev, vpp) 45439433Smckusick dev_t dev; 45539433Smckusick struct vnode **vpp; 45639433Smckusick { 45739433Smckusick register struct vnode *vp; 45839433Smckusick struct vnode *nvp; 45939433Smckusick int error; 46039433Smckusick 46146989Smckusick if (dev == NODEV) 46246989Smckusick return (0); 46353547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 46439433Smckusick if (error) { 46539433Smckusick *vpp = 0; 46639433Smckusick return (error); 46739433Smckusick } 46839433Smckusick vp = nvp; 46939433Smckusick vp->v_type = VBLK; 47039615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 47139433Smckusick vput(vp); 47239433Smckusick vp = nvp; 47339433Smckusick } 47439433Smckusick *vpp = vp; 47539433Smckusick return (0); 47639433Smckusick } 47739433Smckusick 47839433Smckusick /* 47939433Smckusick * Check to see if the new vnode represents a special device 48039433Smckusick * for which we already have a vnode (either because of 48139433Smckusick * bdevvp() or because of a different vnode representing 48239433Smckusick * the same block device). If such an alias exists, deallocate 48339509Smckusick * the existing contents and return the aliased vnode. The 48439433Smckusick * caller is responsible for filling it with its new contents. 48539433Smckusick */ 48639433Smckusick struct vnode * 48739615Smckusick checkalias(nvp, nvp_rdev, mp) 48839433Smckusick register struct vnode *nvp; 48939615Smckusick dev_t nvp_rdev; 49039433Smckusick struct mount *mp; 49139433Smckusick { 49239433Smckusick register struct vnode *vp; 49339615Smckusick struct vnode **vpp; 49439433Smckusick 49539433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 49641400Smckusick return (NULLVP); 49739615Smckusick 49839615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 49939433Smckusick loop: 50039615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 50139615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50239433Smckusick continue; 50339615Smckusick /* 50439615Smckusick * Alias, but not in use, so flush it out. 50539615Smckusick */ 50639809Smckusick if (vp->v_usecount == 0) { 50739615Smckusick vgone(vp); 50839615Smckusick goto loop; 50939615Smckusick } 51039633Smckusick if (vget(vp)) 51139633Smckusick goto loop; 51239433Smckusick break; 51339433Smckusick } 51439615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 51539615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 51639615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 51739615Smckusick nvp->v_rdev = nvp_rdev; 51839809Smckusick nvp->v_hashchain = vpp; 51939615Smckusick nvp->v_specnext = *vpp; 52042152Smckusick nvp->v_specflags = 0; 52139615Smckusick *vpp = nvp; 52240640Smckusick if (vp != NULL) { 52340640Smckusick nvp->v_flag |= VALIASED; 52440640Smckusick vp->v_flag |= VALIASED; 52540640Smckusick vput(vp); 52640640Smckusick } 52741400Smckusick return (NULLVP); 52839433Smckusick } 52939484Smckusick VOP_UNLOCK(vp); 53039484Smckusick vclean(vp, 0); 53139433Smckusick vp->v_op = nvp->v_op; 53239433Smckusick vp->v_tag = nvp->v_tag; 53339433Smckusick nvp->v_type = VNON; 53439433Smckusick insmntque(vp, mp); 53539433Smckusick return (vp); 53639433Smckusick } 53739433Smckusick 53839433Smckusick /* 53939433Smckusick * Grab a particular vnode from the free list, increment its 54039433Smckusick * reference count and lock it. The vnode lock bit is set the 54139433Smckusick * vnode is being eliminated in vgone. The process is awakened 54239433Smckusick * when the transition is completed, and an error returned to 54339433Smckusick * indicate that the vnode is no longer usable (possibly having 54439433Smckusick * been changed to a new file system type). 54539433Smckusick */ 54639397Smckusick vget(vp) 54739397Smckusick register struct vnode *vp; 54839397Smckusick { 54939397Smckusick register struct vnode *vq; 55039397Smckusick 55139433Smckusick if (vp->v_flag & VXLOCK) { 55239433Smckusick vp->v_flag |= VXWANT; 55339433Smckusick sleep((caddr_t)vp, PINOD); 55439433Smckusick return (1); 55539433Smckusick } 55639809Smckusick if (vp->v_usecount == 0) { 55739433Smckusick if (vq = vp->v_freef) 55839433Smckusick vq->v_freeb = vp->v_freeb; 55939433Smckusick else 56039433Smckusick vfreet = vp->v_freeb; 56139433Smckusick *vp->v_freeb = vq; 56239433Smckusick vp->v_freef = NULL; 56339433Smckusick vp->v_freeb = NULL; 56439433Smckusick } 56539397Smckusick VREF(vp); 56639433Smckusick VOP_LOCK(vp); 56739433Smckusick return (0); 56839397Smckusick } 56939397Smckusick 57039397Smckusick /* 57139397Smckusick * Vnode reference, just increment the count 57239397Smckusick */ 57339397Smckusick void vref(vp) 57439397Smckusick struct vnode *vp; 57539397Smckusick { 57639397Smckusick 57739809Smckusick vp->v_usecount++; 57839397Smckusick } 57939397Smckusick 58039397Smckusick /* 58139397Smckusick * vput(), just unlock and vrele() 58239397Smckusick */ 58339397Smckusick void vput(vp) 58439397Smckusick register struct vnode *vp; 58539397Smckusick { 58652416Storek 58739397Smckusick VOP_UNLOCK(vp); 58839397Smckusick vrele(vp); 58939397Smckusick } 59039397Smckusick 59139397Smckusick /* 59239397Smckusick * Vnode release. 59339397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59439397Smckusick */ 59539397Smckusick void vrele(vp) 59639397Smckusick register struct vnode *vp; 59739397Smckusick { 59839397Smckusick 59950109Smckusick #ifdef DIAGNOSTIC 60039397Smckusick if (vp == NULL) 60139433Smckusick panic("vrele: null vp"); 60250109Smckusick #endif 60339809Smckusick vp->v_usecount--; 60439809Smckusick if (vp->v_usecount > 0) 60539397Smckusick return; 60650109Smckusick #ifdef DIAGNOSTIC 60750109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 60850109Smckusick vprint("vrele: bad ref count", vp); 60950109Smckusick panic("vrele: ref cnt"); 61050109Smckusick } 61150109Smckusick #endif 61255468Smckusick /* 61355468Smckusick * insert at tail of LRU list 61455468Smckusick */ 61555468Smckusick *vfreet = vp; 61655468Smckusick vp->v_freeb = vfreet; 61739433Smckusick vp->v_freef = NULL; 61839433Smckusick vfreet = &vp->v_freef; 61954442Smckusick VOP_INACTIVE(vp); 62039397Smckusick } 62139433Smckusick 62239433Smckusick /* 62339809Smckusick * Page or buffer structure gets a reference. 62439809Smckusick */ 62553312Smckusick void vhold(vp) 62639809Smckusick register struct vnode *vp; 62739809Smckusick { 62839809Smckusick 62939809Smckusick vp->v_holdcnt++; 63039809Smckusick } 63139809Smckusick 63239809Smckusick /* 63339809Smckusick * Page or buffer structure frees a reference. 63439809Smckusick */ 63553312Smckusick void holdrele(vp) 63639809Smckusick register struct vnode *vp; 63739809Smckusick { 63839809Smckusick 63939809Smckusick if (vp->v_holdcnt <= 0) 64039809Smckusick panic("holdrele: holdcnt"); 64139809Smckusick vp->v_holdcnt--; 64239809Smckusick } 64339809Smckusick 64439809Smckusick /* 64539509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 64639509Smckusick * 64739509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 64839509Smckusick * return error if any are found (nb: this is a user error, not a 64939509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 65039509Smckusick * that are found. 65139509Smckusick */ 65239509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 65339509Smckusick 65439509Smckusick vflush(mp, skipvp, flags) 65539509Smckusick struct mount *mp; 65639509Smckusick struct vnode *skipvp; 65739509Smckusick int flags; 65839509Smckusick { 65939509Smckusick register struct vnode *vp, *nvp; 66039509Smckusick int busy = 0; 66139509Smckusick 66241400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 66341300Smckusick panic("vflush: not busy"); 66441421Smckusick loop: 66541400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 66641421Smckusick if (vp->v_mount != mp) 66741421Smckusick goto loop; 66839509Smckusick nvp = vp->v_mountf; 66939509Smckusick /* 67039509Smckusick * Skip over a selected vnode. 67139509Smckusick */ 67239509Smckusick if (vp == skipvp) 67339509Smckusick continue; 67439509Smckusick /* 67541300Smckusick * Skip over a vnodes marked VSYSTEM. 67641300Smckusick */ 67741300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 67841300Smckusick continue; 67941300Smckusick /* 68039809Smckusick * With v_usecount == 0, all we need to do is clear 68139509Smckusick * out the vnode data structures and we are done. 68239509Smckusick */ 68339809Smckusick if (vp->v_usecount == 0) { 68439509Smckusick vgone(vp); 68539509Smckusick continue; 68639509Smckusick } 68739509Smckusick /* 68839509Smckusick * For block or character devices, revert to an 68939509Smckusick * anonymous device. For all other files, just kill them. 69039509Smckusick */ 69141300Smckusick if (flags & FORCECLOSE) { 69239509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 69339509Smckusick vgone(vp); 69439509Smckusick } else { 69539509Smckusick vclean(vp, 0); 69653547Sheideman vp->v_op = spec_vnodeop_p; 69739509Smckusick insmntque(vp, (struct mount *)0); 69839509Smckusick } 69939509Smckusick continue; 70039509Smckusick } 70139509Smckusick if (busyprt) 70239667Smckusick vprint("vflush: busy vnode", vp); 70339509Smckusick busy++; 70439509Smckusick } 70539509Smckusick if (busy) 70639509Smckusick return (EBUSY); 70739509Smckusick return (0); 70839509Smckusick } 70939509Smckusick 71039509Smckusick /* 71139433Smckusick * Disassociate the underlying file system from a vnode. 71239433Smckusick */ 71354347Smckusick void 71454347Smckusick vclean(vp, flags) 71539433Smckusick register struct vnode *vp; 71645118Smckusick int flags; 71739433Smckusick { 71854641Smckusick struct vop_inactive_args vop_inactive_a; 71954641Smckusick struct vop_reclaim_args vop_reclaim_a; 72054641Smckusick struct vop_unlock_args vop_unlock_a; 72154641Smckusick struct vop_close_args vop_close_a; 72253580Sheideman int (**origops)(); 72339484Smckusick int active; 72439433Smckusick 72539484Smckusick /* 72639484Smckusick * Check to see if the vnode is in use. 72739667Smckusick * If so we have to reference it before we clean it out 72839667Smckusick * so that its count cannot fall to zero and generate a 72939667Smckusick * race against ourselves to recycle it. 73039484Smckusick */ 73139809Smckusick if (active = vp->v_usecount) 73239484Smckusick VREF(vp); 73339484Smckusick /* 73439484Smckusick * Prevent the vnode from being recycled or 73539484Smckusick * brought into use while we clean it out. 73639484Smckusick */ 73739667Smckusick if (vp->v_flag & VXLOCK) 73839667Smckusick panic("vclean: deadlock"); 73939433Smckusick vp->v_flag |= VXLOCK; 74039433Smckusick /* 74139667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 74239667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 74339667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 74439667Smckusick * For active vnodes, it ensures that no other activity can 74539667Smckusick * occur while the buffer list is being cleaned out. 74639667Smckusick */ 74739667Smckusick VOP_LOCK(vp); 74841300Smckusick if (flags & DOCLOSE) 74954442Smckusick vinvalbuf(vp, 1, NOCRED, NULL); 75039667Smckusick /* 75139433Smckusick * Prevent any further operations on the vnode from 75239433Smckusick * being passed through to the old file system. 75339433Smckusick */ 75439433Smckusick origops = vp->v_op; 75553547Sheideman vp->v_op = dead_vnodeop_p; 75639433Smckusick vp->v_tag = VT_NON; 75739433Smckusick /* 75839484Smckusick * If purging an active vnode, it must be unlocked, closed, 75939484Smckusick * and deactivated before being reclaimed. 76039433Smckusick */ 76153580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 76253580Sheideman vop_unlock_a.a_vp = vp; 76353580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 76439484Smckusick if (active) { 76553580Sheideman /* 76653580Sheideman * Note: these next two calls imply 76753580Sheideman * that vop_close and vop_inactive implementations 76853580Sheideman * cannot count on the ops vector being correctly 76953580Sheideman * set. 77053580Sheideman */ 77153580Sheideman if (flags & DOCLOSE) { 77253580Sheideman vop_close_a.a_desc = VDESC(vop_close); 77353580Sheideman vop_close_a.a_vp = vp; 77453580Sheideman vop_close_a.a_fflag = IO_NDELAY; 77554442Smckusick vop_close_a.a_p = NULL; 77653580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 77753580Sheideman }; 77853580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 77953580Sheideman vop_inactive_a.a_vp = vp; 78053580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 78139433Smckusick } 78239433Smckusick /* 78339433Smckusick * Reclaim the vnode. 78439433Smckusick */ 78553580Sheideman /* 78653580Sheideman * Emulate VOP_RECLAIM. 78753580Sheideman */ 78853580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 78953580Sheideman vop_reclaim_a.a_vp = vp; 79053580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 79139433Smckusick panic("vclean: cannot reclaim"); 79239484Smckusick if (active) 79339484Smckusick vrele(vp); 79453580Sheideman 79539433Smckusick /* 79639433Smckusick * Done with purge, notify sleepers in vget of the grim news. 79739433Smckusick */ 79839433Smckusick vp->v_flag &= ~VXLOCK; 79939433Smckusick if (vp->v_flag & VXWANT) { 80039433Smckusick vp->v_flag &= ~VXWANT; 80139433Smckusick wakeup((caddr_t)vp); 80239433Smckusick } 80339433Smckusick } 80439433Smckusick 80539433Smckusick /* 80639633Smckusick * Eliminate all activity associated with the requested vnode 80739633Smckusick * and with all vnodes aliased to the requested vnode. 80839633Smckusick */ 80939633Smckusick void vgoneall(vp) 81039633Smckusick register struct vnode *vp; 81139633Smckusick { 81239809Smckusick register struct vnode *vq; 81339633Smckusick 81440665Smckusick if (vp->v_flag & VALIASED) { 81540665Smckusick /* 81640665Smckusick * If a vgone (or vclean) is already in progress, 81740665Smckusick * wait until it is done and return. 81840665Smckusick */ 81940665Smckusick if (vp->v_flag & VXLOCK) { 82040665Smckusick vp->v_flag |= VXWANT; 82140665Smckusick sleep((caddr_t)vp, PINOD); 82240665Smckusick return; 82339633Smckusick } 82440665Smckusick /* 82540665Smckusick * Ensure that vp will not be vgone'd while we 82640665Smckusick * are eliminating its aliases. 82740665Smckusick */ 82840665Smckusick vp->v_flag |= VXLOCK; 82940665Smckusick while (vp->v_flag & VALIASED) { 83040665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 83140665Smckusick if (vq->v_rdev != vp->v_rdev || 83240665Smckusick vq->v_type != vp->v_type || vp == vq) 83340665Smckusick continue; 83440665Smckusick vgone(vq); 83540665Smckusick break; 83640665Smckusick } 83740665Smckusick } 83840665Smckusick /* 83940665Smckusick * Remove the lock so that vgone below will 84040665Smckusick * really eliminate the vnode after which time 84140665Smckusick * vgone will awaken any sleepers. 84240665Smckusick */ 84340665Smckusick vp->v_flag &= ~VXLOCK; 84439633Smckusick } 84539633Smckusick vgone(vp); 84639633Smckusick } 84739633Smckusick 84839633Smckusick /* 84939433Smckusick * Eliminate all activity associated with a vnode 85039433Smckusick * in preparation for reuse. 85139433Smckusick */ 85239433Smckusick void vgone(vp) 85339433Smckusick register struct vnode *vp; 85439433Smckusick { 85539809Smckusick register struct vnode *vq; 85639615Smckusick struct vnode *vx; 85739433Smckusick 85839433Smckusick /* 85940548Smckusick * If a vgone (or vclean) is already in progress, 86040548Smckusick * wait until it is done and return. 86140548Smckusick */ 86240548Smckusick if (vp->v_flag & VXLOCK) { 86340548Smckusick vp->v_flag |= VXWANT; 86440548Smckusick sleep((caddr_t)vp, PINOD); 86540548Smckusick return; 86640548Smckusick } 86740548Smckusick /* 86839433Smckusick * Clean out the filesystem specific data. 86939433Smckusick */ 87041300Smckusick vclean(vp, DOCLOSE); 87139433Smckusick /* 87239433Smckusick * Delete from old mount point vnode list, if on one. 87339433Smckusick */ 87439433Smckusick if (vp->v_mountb) { 87539433Smckusick if (vq = vp->v_mountf) 87639433Smckusick vq->v_mountb = vp->v_mountb; 87739433Smckusick *vp->v_mountb = vq; 87839433Smckusick vp->v_mountf = NULL; 87939433Smckusick vp->v_mountb = NULL; 88052311Smckusick vp->v_mount = NULL; 88139433Smckusick } 88239433Smckusick /* 88339433Smckusick * If special device, remove it from special device alias list. 88439433Smckusick */ 88539433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 88639809Smckusick if (*vp->v_hashchain == vp) { 88739809Smckusick *vp->v_hashchain = vp->v_specnext; 88839433Smckusick } else { 88939809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 89039615Smckusick if (vq->v_specnext != vp) 89139433Smckusick continue; 89239615Smckusick vq->v_specnext = vp->v_specnext; 89339433Smckusick break; 89439433Smckusick } 89539615Smckusick if (vq == NULL) 89639433Smckusick panic("missing bdev"); 89739433Smckusick } 89839615Smckusick if (vp->v_flag & VALIASED) { 89952416Storek vx = NULL; 90039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90140108Smckusick if (vq->v_rdev != vp->v_rdev || 90240108Smckusick vq->v_type != vp->v_type) 90339615Smckusick continue; 90452416Storek if (vx) 90552416Storek break; 90639615Smckusick vx = vq; 90739615Smckusick } 90852416Storek if (vx == NULL) 90939615Smckusick panic("missing alias"); 91052416Storek if (vq == NULL) 91139615Smckusick vx->v_flag &= ~VALIASED; 91239615Smckusick vp->v_flag &= ~VALIASED; 91339615Smckusick } 91439615Smckusick FREE(vp->v_specinfo, M_VNODE); 91539615Smckusick vp->v_specinfo = NULL; 91639433Smckusick } 91739433Smckusick /* 91839433Smckusick * If it is on the freelist, move it to the head of the list. 91939433Smckusick */ 92039433Smckusick if (vp->v_freeb) { 92139433Smckusick if (vq = vp->v_freef) 92239433Smckusick vq->v_freeb = vp->v_freeb; 92339433Smckusick else 92439433Smckusick vfreet = vp->v_freeb; 92539433Smckusick *vp->v_freeb = vq; 92639433Smckusick vp->v_freef = vfreeh; 92739433Smckusick vp->v_freeb = &vfreeh; 92839433Smckusick vfreeh->v_freeb = &vp->v_freef; 92939433Smckusick vfreeh = vp; 93039433Smckusick } 93139484Smckusick vp->v_type = VBAD; 93239433Smckusick } 93339633Smckusick 93439633Smckusick /* 93539821Smckusick * Lookup a vnode by device number. 93639821Smckusick */ 93739821Smckusick vfinddev(dev, type, vpp) 93839821Smckusick dev_t dev; 93939821Smckusick enum vtype type; 94039821Smckusick struct vnode **vpp; 94139821Smckusick { 94239821Smckusick register struct vnode *vp; 94339821Smckusick 94439821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 94539821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 94639821Smckusick continue; 94739821Smckusick *vpp = vp; 94839821Smckusick return (0); 94939821Smckusick } 95039821Smckusick return (1); 95139821Smckusick } 95239821Smckusick 95339821Smckusick /* 95439633Smckusick * Calculate the total number of references to a special device. 95539633Smckusick */ 95639633Smckusick vcount(vp) 95739633Smckusick register struct vnode *vp; 95839633Smckusick { 95939809Smckusick register struct vnode *vq; 96039633Smckusick int count; 96139633Smckusick 96239633Smckusick if ((vp->v_flag & VALIASED) == 0) 96339809Smckusick return (vp->v_usecount); 96439633Smckusick loop: 96539809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 96640108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 96739633Smckusick continue; 96839633Smckusick /* 96939633Smckusick * Alias, but not in use, so flush it out. 97039633Smckusick */ 97139809Smckusick if (vq->v_usecount == 0) { 97239633Smckusick vgone(vq); 97339633Smckusick goto loop; 97439633Smckusick } 97539809Smckusick count += vq->v_usecount; 97639633Smckusick } 97739633Smckusick return (count); 97839633Smckusick } 97939667Smckusick 98039667Smckusick /* 98139667Smckusick * Print out a description of a vnode. 98239667Smckusick */ 98339667Smckusick static char *typename[] = 98440286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 98539667Smckusick 98639667Smckusick vprint(label, vp) 98739667Smckusick char *label; 98839667Smckusick register struct vnode *vp; 98939667Smckusick { 99039913Smckusick char buf[64]; 99139667Smckusick 99239667Smckusick if (label != NULL) 99339667Smckusick printf("%s: ", label); 99450109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 99550109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 99650109Smckusick vp->v_holdcnt); 99739913Smckusick buf[0] = '\0'; 99839913Smckusick if (vp->v_flag & VROOT) 99939913Smckusick strcat(buf, "|VROOT"); 100039913Smckusick if (vp->v_flag & VTEXT) 100139913Smckusick strcat(buf, "|VTEXT"); 100241300Smckusick if (vp->v_flag & VSYSTEM) 100341300Smckusick strcat(buf, "|VSYSTEM"); 100441300Smckusick if (vp->v_flag & VXLOCK) 100541300Smckusick strcat(buf, "|VXLOCK"); 100641300Smckusick if (vp->v_flag & VXWANT) 100741300Smckusick strcat(buf, "|VXWANT"); 100841300Smckusick if (vp->v_flag & VBWAIT) 100941300Smckusick strcat(buf, "|VBWAIT"); 101039913Smckusick if (vp->v_flag & VALIASED) 101139913Smckusick strcat(buf, "|VALIASED"); 101239913Smckusick if (buf[0] != '\0') 101339913Smckusick printf(" flags (%s)", &buf[1]); 101439913Smckusick printf("\n\t"); 101539667Smckusick VOP_PRINT(vp); 101639667Smckusick } 101741110Smarc 101849691Smckusick #ifdef DEBUG 101949691Smckusick /* 102049691Smckusick * List all of the locked vnodes in the system. 102149691Smckusick * Called when debugging the kernel. 102249691Smckusick */ 102349691Smckusick printlockedvnodes() 102449691Smckusick { 102549691Smckusick register struct mount *mp; 102649691Smckusick register struct vnode *vp; 102749691Smckusick 102849691Smckusick printf("Locked vnodes\n"); 102949691Smckusick mp = rootfs; 103049691Smckusick do { 103149691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 103249691Smckusick if (VOP_ISLOCKED(vp)) 103349691Smckusick vprint((char *)0, vp); 103449691Smckusick mp = mp->mnt_next; 103549691Smckusick } while (mp != rootfs); 103649691Smckusick } 103749691Smckusick #endif 103849691Smckusick 103941110Smarc int kinfo_vdebug = 1; 104041110Smarc int kinfo_vgetfailed; 104141110Smarc #define KINFO_VNODESLOP 10 104241110Smarc /* 104341110Smarc * Dump vnode list (via kinfo). 104441110Smarc * Copyout address of vnode followed by vnode. 104541110Smarc */ 104645118Smckusick /* ARGSUSED */ 104741110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 104845118Smckusick int op; 104941110Smarc char *where; 105045118Smckusick int *acopysize, arg, *aneeded; 105141110Smarc { 105241110Smarc register struct mount *mp = rootfs; 105341300Smckusick struct mount *omp; 105441110Smarc struct vnode *vp; 105541110Smarc register char *bp = where, *savebp; 105653818Smckusick char *ewhere; 105741110Smarc int error; 105841110Smarc 105941110Smarc #define VPTRSZ sizeof (struct vnode *) 106041110Smarc #define VNODESZ sizeof (struct vnode) 106141110Smarc if (where == NULL) { 106241110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 106341110Smarc return (0); 106441110Smarc } 106553818Smckusick ewhere = where + *acopysize; 106641110Smarc 106741110Smarc do { 106841300Smckusick if (vfs_busy(mp)) { 106941400Smckusick mp = mp->mnt_next; 107041300Smckusick continue; 107141300Smckusick } 107241110Smarc savebp = bp; 107341110Smarc again: 107441421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 107541422Smckusick /* 107641422Smckusick * Check that the vp is still associated with 107741422Smckusick * this filesystem. RACE: could have been 107841422Smckusick * recycled onto the same filesystem. 107941422Smckusick */ 108041421Smckusick if (vp->v_mount != mp) { 108141421Smckusick if (kinfo_vdebug) 108241421Smckusick printf("kinfo: vp changed\n"); 108341421Smckusick bp = savebp; 108441421Smckusick goto again; 108541421Smckusick } 108641110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 108741110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 108841110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 108941422Smckusick VNODESZ)))) 109041110Smarc return (error); 109141110Smarc bp += VPTRSZ + VNODESZ; 109241110Smarc } 109341300Smckusick omp = mp; 109441400Smckusick mp = mp->mnt_next; 109541300Smckusick vfs_unbusy(omp); 109641110Smarc } while (mp != rootfs); 109741110Smarc 109841110Smarc *aneeded = bp - where; 109941110Smarc if (bp > ewhere) 110041110Smarc *acopysize = ewhere - where; 110141110Smarc else 110241110Smarc *acopysize = bp - where; 110341110Smarc return (0); 110441110Smarc } 1105