137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*55050Spendry * @(#)vfs_subr.c 7.83 (Berkeley) 07/12/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 27*55050Spendry #include <miscfs/specfs/specdev.h> 28*55050Spendry 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 */ 19253493Sheideman extern struct vnode *vfreeh, **vfreet; 19353547Sheideman extern int (**dead_vnodeop_p)(); 19453547Sheideman extern int (**spec_vnodeop_p)(); 19539635Smckusick extern void vclean(); 19640883Smckusick long numvnodes; 19753493Sheideman extern struct vattr va_null; 19839397Smckusick 19939397Smckusick /* 20039397Smckusick * Return the next vnode from the free list. 20139397Smckusick */ 20239397Smckusick getnewvnode(tag, mp, vops, vpp) 20339397Smckusick enum vtagtype tag; 20439397Smckusick struct mount *mp; 20553495Sheideman int (**vops)(); 20639397Smckusick struct vnode **vpp; 20739397Smckusick { 20839397Smckusick register struct vnode *vp, *vq; 20939397Smckusick 21054347Smckusick if ((vfreeh == NULL && numvnodes < 2 * desiredvnodes) || 21154347Smckusick numvnodes < desiredvnodes) { 21245118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 21345118Smckusick M_VNODE, M_WAITOK); 21440883Smckusick bzero((char *)vp, sizeof *vp); 21540883Smckusick numvnodes++; 21640883Smckusick } else { 21740883Smckusick if ((vp = vfreeh) == NULL) { 21840883Smckusick tablefull("vnode"); 21940883Smckusick *vpp = 0; 22040883Smckusick return (ENFILE); 22140883Smckusick } 22240883Smckusick if (vp->v_usecount) 22340883Smckusick panic("free vnode isn't"); 22440883Smckusick if (vq = vp->v_freef) 22540883Smckusick vq->v_freeb = &vfreeh; 22640883Smckusick else 22740883Smckusick vfreet = &vfreeh; 22840883Smckusick vfreeh = vq; 22940883Smckusick vp->v_freef = NULL; 23040883Smckusick vp->v_freeb = NULL; 23152190Smckusick vp->v_lease = NULL; 23240883Smckusick if (vp->v_type != VBAD) 23340883Smckusick vgone(vp); 23452006Smckusick if (vp->v_data) 23552006Smckusick panic("cleaned vnode isn't"); 23640883Smckusick vp->v_flag = 0; 23740883Smckusick vp->v_lastr = 0; 23840883Smckusick vp->v_socket = 0; 23939397Smckusick } 24039512Smckusick vp->v_type = VNON; 24139397Smckusick cache_purge(vp); 24239397Smckusick vp->v_tag = tag; 24339433Smckusick vp->v_op = vops; 24439397Smckusick insmntque(vp, mp); 24539397Smckusick VREF(vp); 24639397Smckusick *vpp = vp; 24739397Smckusick return (0); 24839397Smckusick } 24939397Smckusick 25039397Smckusick /* 25139397Smckusick * Move a vnode from one mount queue to another. 25239397Smckusick */ 25339397Smckusick insmntque(vp, mp) 25439397Smckusick register struct vnode *vp; 25539397Smckusick register struct mount *mp; 25639397Smckusick { 25749973Smckusick register struct vnode *vq; 25839397Smckusick 25939397Smckusick /* 26039397Smckusick * Delete from old mount point vnode list, if on one. 26139397Smckusick */ 26239397Smckusick if (vp->v_mountb) { 26339397Smckusick if (vq = vp->v_mountf) 26439397Smckusick vq->v_mountb = vp->v_mountb; 26539397Smckusick *vp->v_mountb = vq; 26639397Smckusick } 26739397Smckusick /* 26839397Smckusick * Insert into list of vnodes for the new mount point, if available. 26939397Smckusick */ 27039621Smckusick vp->v_mount = mp; 27139397Smckusick if (mp == NULL) { 27239397Smckusick vp->v_mountf = NULL; 27339397Smckusick vp->v_mountb = NULL; 27439397Smckusick return; 27539397Smckusick } 27649973Smckusick if (vq = mp->mnt_mounth) 27749973Smckusick vq->v_mountb = &vp->v_mountf; 27849973Smckusick vp->v_mountf = vq; 27949973Smckusick vp->v_mountb = &mp->mnt_mounth; 28049973Smckusick mp->mnt_mounth = vp; 28139397Smckusick } 28239397Smckusick 28339397Smckusick /* 28449232Smckusick * Update outstanding I/O count and do wakeup if requested. 28549232Smckusick */ 28649232Smckusick vwakeup(bp) 28749232Smckusick register struct buf *bp; 28849232Smckusick { 28949232Smckusick register struct vnode *vp; 29049232Smckusick 29149232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 29249232Smckusick if (vp = bp->b_vp) { 29349232Smckusick vp->v_numoutput--; 29449232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 29549232Smckusick if (vp->v_numoutput < 0) 29649232Smckusick panic("vwakeup: neg numoutput"); 29749232Smckusick vp->v_flag &= ~VBWAIT; 29849232Smckusick wakeup((caddr_t)&vp->v_numoutput); 29949232Smckusick } 30049232Smckusick } 30149232Smckusick } 30249232Smckusick 30349232Smckusick /* 30449232Smckusick * Flush out and invalidate all buffers associated with a vnode. 30549232Smckusick * Called with the underlying object locked. 30649232Smckusick */ 30754442Smckusick int 30854442Smckusick vinvalbuf(vp, save, cred, p) 30949232Smckusick register struct vnode *vp; 31049232Smckusick int save; 31154442Smckusick struct ucred *cred; 31254442Smckusick struct proc *p; 31349232Smckusick { 31449232Smckusick register struct buf *bp; 31549232Smckusick struct buf *nbp, *blist; 31654442Smckusick int s, error; 31749232Smckusick 31854442Smckusick if (save) { 31954442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 32054442Smckusick return (error); 32154442Smckusick if (vp->v_dirtyblkhd != NULL) 32254442Smckusick panic("vinvalbuf: dirty bufs"); 32354442Smckusick } 32449232Smckusick for (;;) { 32554442Smckusick if (blist = vp->v_cleanblkhd) 32649232Smckusick /* void */; 32754442Smckusick else if (blist = vp->v_dirtyblkhd) 32849232Smckusick /* void */; 32949232Smckusick else 33049232Smckusick break; 33149232Smckusick for (bp = blist; bp; bp = nbp) { 33249232Smckusick nbp = bp->b_blockf; 33349232Smckusick s = splbio(); 33449232Smckusick if (bp->b_flags & B_BUSY) { 33549232Smckusick bp->b_flags |= B_WANTED; 33649232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 33749232Smckusick splx(s); 33849232Smckusick break; 33949232Smckusick } 34049232Smckusick bremfree(bp); 34149232Smckusick bp->b_flags |= B_BUSY; 34249232Smckusick splx(s); 34349232Smckusick if (bp->b_vp != vp) 34449232Smckusick reassignbuf(bp, bp->b_vp); 34549232Smckusick else 34649232Smckusick bp->b_flags |= B_INVAL; 34749232Smckusick brelse(bp); 34849232Smckusick } 34949232Smckusick } 35049232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 35149232Smckusick panic("vinvalbuf: flush failed"); 35254442Smckusick return (0); 35349232Smckusick } 35449232Smckusick 35549232Smckusick /* 35649232Smckusick * Associate a buffer with a vnode. 35749232Smckusick */ 35849232Smckusick bgetvp(vp, bp) 35949232Smckusick register struct vnode *vp; 36049232Smckusick register struct buf *bp; 36149232Smckusick { 36249973Smckusick register struct vnode *vq; 36349973Smckusick register struct buf *bq; 36449232Smckusick 36549232Smckusick if (bp->b_vp) 36649232Smckusick panic("bgetvp: not free"); 36749232Smckusick VHOLD(vp); 36849232Smckusick bp->b_vp = vp; 36949232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 37049232Smckusick bp->b_dev = vp->v_rdev; 37149232Smckusick else 37249232Smckusick bp->b_dev = NODEV; 37349232Smckusick /* 37449232Smckusick * Insert onto list for new vnode. 37549232Smckusick */ 37649973Smckusick if (bq = vp->v_cleanblkhd) 37749973Smckusick bq->b_blockb = &bp->b_blockf; 37849973Smckusick bp->b_blockf = bq; 37949973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 38049973Smckusick vp->v_cleanblkhd = bp; 38149232Smckusick } 38249232Smckusick 38349232Smckusick /* 38449232Smckusick * Disassociate a buffer from a vnode. 38549232Smckusick */ 38649232Smckusick brelvp(bp) 38749232Smckusick register struct buf *bp; 38849232Smckusick { 38949232Smckusick struct buf *bq; 39049232Smckusick struct vnode *vp; 39149232Smckusick 39249232Smckusick if (bp->b_vp == (struct vnode *) 0) 39349232Smckusick panic("brelvp: NULL"); 39449232Smckusick /* 39549232Smckusick * Delete from old vnode list, if on one. 39649232Smckusick */ 39749232Smckusick if (bp->b_blockb) { 39849232Smckusick if (bq = bp->b_blockf) 39949232Smckusick bq->b_blockb = bp->b_blockb; 40049232Smckusick *bp->b_blockb = bq; 40149232Smckusick bp->b_blockf = NULL; 40249232Smckusick bp->b_blockb = NULL; 40349232Smckusick } 40449232Smckusick vp = bp->b_vp; 40549232Smckusick bp->b_vp = (struct vnode *) 0; 40649232Smckusick HOLDRELE(vp); 40749232Smckusick } 40849232Smckusick 40949232Smckusick /* 41049232Smckusick * Reassign a buffer from one vnode to another. 41149232Smckusick * Used to assign file specific control information 41249232Smckusick * (indirect blocks) to the vnode to which they belong. 41349232Smckusick */ 41449232Smckusick reassignbuf(bp, newvp) 41549232Smckusick register struct buf *bp; 41649232Smckusick register struct vnode *newvp; 41749232Smckusick { 41849232Smckusick register struct buf *bq, **listheadp; 41949232Smckusick 42052655Smckusick if (newvp == NULL) { 42152655Smckusick printf("reassignbuf: NULL"); 42252655Smckusick return; 42352655Smckusick } 42449232Smckusick /* 42549232Smckusick * Delete from old vnode list, if on one. 42649232Smckusick */ 42749232Smckusick if (bp->b_blockb) { 42849232Smckusick if (bq = bp->b_blockf) 42949232Smckusick bq->b_blockb = bp->b_blockb; 43049232Smckusick *bp->b_blockb = bq; 43149232Smckusick } 43249232Smckusick /* 43349232Smckusick * If dirty, put on list of dirty buffers; 43449232Smckusick * otherwise insert onto list of clean buffers. 43549232Smckusick */ 43649232Smckusick if (bp->b_flags & B_DELWRI) 43749232Smckusick listheadp = &newvp->v_dirtyblkhd; 43849232Smckusick else 43949232Smckusick listheadp = &newvp->v_cleanblkhd; 44049973Smckusick if (bq = *listheadp) 44149973Smckusick bq->b_blockb = &bp->b_blockf; 44249973Smckusick bp->b_blockf = bq; 44349973Smckusick bp->b_blockb = listheadp; 44449973Smckusick *listheadp = bp; 44549232Smckusick } 44649232Smckusick 44749232Smckusick /* 44839433Smckusick * Create a vnode for a block device. 44939433Smckusick * Used for root filesystem, argdev, and swap areas. 45039433Smckusick * Also used for memory file system special devices. 45139397Smckusick */ 45239433Smckusick bdevvp(dev, vpp) 45339433Smckusick dev_t dev; 45439433Smckusick struct vnode **vpp; 45539433Smckusick { 45639433Smckusick register struct vnode *vp; 45739433Smckusick struct vnode *nvp; 45839433Smckusick int error; 45939433Smckusick 46046989Smckusick if (dev == NODEV) 46146989Smckusick return (0); 46253547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 46339433Smckusick if (error) { 46439433Smckusick *vpp = 0; 46539433Smckusick return (error); 46639433Smckusick } 46739433Smckusick vp = nvp; 46839433Smckusick vp->v_type = VBLK; 46939615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 47039433Smckusick vput(vp); 47139433Smckusick vp = nvp; 47239433Smckusick } 47339433Smckusick *vpp = vp; 47439433Smckusick return (0); 47539433Smckusick } 47639433Smckusick 47739433Smckusick /* 47839433Smckusick * Check to see if the new vnode represents a special device 47939433Smckusick * for which we already have a vnode (either because of 48039433Smckusick * bdevvp() or because of a different vnode representing 48139433Smckusick * the same block device). If such an alias exists, deallocate 48239509Smckusick * the existing contents and return the aliased vnode. The 48339433Smckusick * caller is responsible for filling it with its new contents. 48439433Smckusick */ 48539433Smckusick struct vnode * 48639615Smckusick checkalias(nvp, nvp_rdev, mp) 48739433Smckusick register struct vnode *nvp; 48839615Smckusick dev_t nvp_rdev; 48939433Smckusick struct mount *mp; 49039433Smckusick { 49139433Smckusick register struct vnode *vp; 49239615Smckusick struct vnode **vpp; 49339433Smckusick 49439433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 49541400Smckusick return (NULLVP); 49639615Smckusick 49739615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 49839433Smckusick loop: 49939615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 50039615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50139433Smckusick continue; 50239615Smckusick /* 50339615Smckusick * Alias, but not in use, so flush it out. 50439615Smckusick */ 50539809Smckusick if (vp->v_usecount == 0) { 50639615Smckusick vgone(vp); 50739615Smckusick goto loop; 50839615Smckusick } 50939633Smckusick if (vget(vp)) 51039633Smckusick goto loop; 51139433Smckusick break; 51239433Smckusick } 51339615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 51439615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 51539615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 51639615Smckusick nvp->v_rdev = nvp_rdev; 51739809Smckusick nvp->v_hashchain = vpp; 51839615Smckusick nvp->v_specnext = *vpp; 51942152Smckusick nvp->v_specflags = 0; 52039615Smckusick *vpp = nvp; 52140640Smckusick if (vp != NULL) { 52240640Smckusick nvp->v_flag |= VALIASED; 52340640Smckusick vp->v_flag |= VALIASED; 52440640Smckusick vput(vp); 52540640Smckusick } 52641400Smckusick return (NULLVP); 52739433Smckusick } 52839484Smckusick VOP_UNLOCK(vp); 52939484Smckusick vclean(vp, 0); 53039433Smckusick vp->v_op = nvp->v_op; 53139433Smckusick vp->v_tag = nvp->v_tag; 53239433Smckusick nvp->v_type = VNON; 53339433Smckusick insmntque(vp, mp); 53439433Smckusick return (vp); 53539433Smckusick } 53639433Smckusick 53739433Smckusick /* 53839433Smckusick * Grab a particular vnode from the free list, increment its 53939433Smckusick * reference count and lock it. The vnode lock bit is set the 54039433Smckusick * vnode is being eliminated in vgone. The process is awakened 54139433Smckusick * when the transition is completed, and an error returned to 54239433Smckusick * indicate that the vnode is no longer usable (possibly having 54339433Smckusick * been changed to a new file system type). 54439433Smckusick */ 54539397Smckusick vget(vp) 54639397Smckusick register struct vnode *vp; 54739397Smckusick { 54839397Smckusick register struct vnode *vq; 54939397Smckusick 55039433Smckusick if (vp->v_flag & VXLOCK) { 55139433Smckusick vp->v_flag |= VXWANT; 55239433Smckusick sleep((caddr_t)vp, PINOD); 55339433Smckusick return (1); 55439433Smckusick } 55539809Smckusick if (vp->v_usecount == 0) { 55639433Smckusick if (vq = vp->v_freef) 55739433Smckusick vq->v_freeb = vp->v_freeb; 55839433Smckusick else 55939433Smckusick vfreet = vp->v_freeb; 56039433Smckusick *vp->v_freeb = vq; 56139433Smckusick vp->v_freef = NULL; 56239433Smckusick vp->v_freeb = NULL; 56339433Smckusick } 56439397Smckusick VREF(vp); 56539433Smckusick VOP_LOCK(vp); 56639433Smckusick return (0); 56739397Smckusick } 56839397Smckusick 56939397Smckusick /* 57039397Smckusick * Vnode reference, just increment the count 57139397Smckusick */ 57239397Smckusick void vref(vp) 57339397Smckusick struct vnode *vp; 57439397Smckusick { 57539397Smckusick 57639809Smckusick vp->v_usecount++; 57739397Smckusick } 57839397Smckusick 57939397Smckusick /* 58039397Smckusick * vput(), just unlock and vrele() 58139397Smckusick */ 58239397Smckusick void vput(vp) 58339397Smckusick register struct vnode *vp; 58439397Smckusick { 58552416Storek 58639397Smckusick VOP_UNLOCK(vp); 58739397Smckusick vrele(vp); 58839397Smckusick } 58939397Smckusick 59039397Smckusick /* 59139397Smckusick * Vnode release. 59239397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59339397Smckusick */ 59439397Smckusick void vrele(vp) 59539397Smckusick register struct vnode *vp; 59639397Smckusick { 59739397Smckusick 59850109Smckusick #ifdef DIAGNOSTIC 59939397Smckusick if (vp == NULL) 60039433Smckusick panic("vrele: null vp"); 60150109Smckusick #endif 60239809Smckusick vp->v_usecount--; 60339809Smckusick if (vp->v_usecount > 0) 60439397Smckusick return; 60550109Smckusick #ifdef DIAGNOSTIC 60650109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 60750109Smckusick vprint("vrele: bad ref count", vp); 60850109Smckusick panic("vrele: ref cnt"); 60950109Smckusick } 61050109Smckusick #endif 61141400Smckusick if (vfreeh == NULLVP) { 61239397Smckusick /* 61339397Smckusick * insert into empty list 61439397Smckusick */ 61539397Smckusick vfreeh = vp; 61639397Smckusick vp->v_freeb = &vfreeh; 61739397Smckusick } else { 61839397Smckusick /* 61939397Smckusick * insert at tail of list 62039397Smckusick */ 62139397Smckusick *vfreet = vp; 62239397Smckusick vp->v_freeb = vfreet; 62339397Smckusick } 62439433Smckusick vp->v_freef = NULL; 62539433Smckusick vfreet = &vp->v_freef; 62654442Smckusick VOP_INACTIVE(vp); 62739397Smckusick } 62839433Smckusick 62939433Smckusick /* 63039809Smckusick * Page or buffer structure gets a reference. 63139809Smckusick */ 63253312Smckusick void vhold(vp) 63339809Smckusick register struct vnode *vp; 63439809Smckusick { 63539809Smckusick 63639809Smckusick vp->v_holdcnt++; 63739809Smckusick } 63839809Smckusick 63939809Smckusick /* 64039809Smckusick * Page or buffer structure frees a reference. 64139809Smckusick */ 64253312Smckusick void holdrele(vp) 64339809Smckusick register struct vnode *vp; 64439809Smckusick { 64539809Smckusick 64639809Smckusick if (vp->v_holdcnt <= 0) 64739809Smckusick panic("holdrele: holdcnt"); 64839809Smckusick vp->v_holdcnt--; 64939809Smckusick } 65039809Smckusick 65139809Smckusick /* 65239509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 65339509Smckusick * 65439509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 65539509Smckusick * return error if any are found (nb: this is a user error, not a 65639509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 65739509Smckusick * that are found. 65839509Smckusick */ 65939509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 66039509Smckusick 66139509Smckusick vflush(mp, skipvp, flags) 66239509Smckusick struct mount *mp; 66339509Smckusick struct vnode *skipvp; 66439509Smckusick int flags; 66539509Smckusick { 66639509Smckusick register struct vnode *vp, *nvp; 66739509Smckusick int busy = 0; 66839509Smckusick 66941400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 67041300Smckusick panic("vflush: not busy"); 67141421Smckusick loop: 67241400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 67341421Smckusick if (vp->v_mount != mp) 67441421Smckusick goto loop; 67539509Smckusick nvp = vp->v_mountf; 67639509Smckusick /* 67739509Smckusick * Skip over a selected vnode. 67839509Smckusick */ 67939509Smckusick if (vp == skipvp) 68039509Smckusick continue; 68139509Smckusick /* 68241300Smckusick * Skip over a vnodes marked VSYSTEM. 68341300Smckusick */ 68441300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 68541300Smckusick continue; 68641300Smckusick /* 68739809Smckusick * With v_usecount == 0, all we need to do is clear 68839509Smckusick * out the vnode data structures and we are done. 68939509Smckusick */ 69039809Smckusick if (vp->v_usecount == 0) { 69139509Smckusick vgone(vp); 69239509Smckusick continue; 69339509Smckusick } 69439509Smckusick /* 69539509Smckusick * For block or character devices, revert to an 69639509Smckusick * anonymous device. For all other files, just kill them. 69739509Smckusick */ 69841300Smckusick if (flags & FORCECLOSE) { 69939509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 70039509Smckusick vgone(vp); 70139509Smckusick } else { 70239509Smckusick vclean(vp, 0); 70353547Sheideman vp->v_op = spec_vnodeop_p; 70439509Smckusick insmntque(vp, (struct mount *)0); 70539509Smckusick } 70639509Smckusick continue; 70739509Smckusick } 70839509Smckusick if (busyprt) 70939667Smckusick vprint("vflush: busy vnode", vp); 71039509Smckusick busy++; 71139509Smckusick } 71239509Smckusick if (busy) 71339509Smckusick return (EBUSY); 71439509Smckusick return (0); 71539509Smckusick } 71639509Smckusick 71739509Smckusick /* 71839433Smckusick * Disassociate the underlying file system from a vnode. 71939433Smckusick */ 72054347Smckusick void 72154347Smckusick vclean(vp, flags) 72239433Smckusick register struct vnode *vp; 72345118Smckusick int flags; 72439433Smckusick { 72554641Smckusick struct vop_inactive_args vop_inactive_a; 72654641Smckusick struct vop_reclaim_args vop_reclaim_a; 72754641Smckusick struct vop_unlock_args vop_unlock_a; 72854641Smckusick struct vop_close_args vop_close_a; 72953580Sheideman int (**origops)(); 73039484Smckusick int active; 73139433Smckusick 73239484Smckusick /* 73339484Smckusick * Check to see if the vnode is in use. 73439667Smckusick * If so we have to reference it before we clean it out 73539667Smckusick * so that its count cannot fall to zero and generate a 73639667Smckusick * race against ourselves to recycle it. 73739484Smckusick */ 73839809Smckusick if (active = vp->v_usecount) 73939484Smckusick VREF(vp); 74039484Smckusick /* 74139484Smckusick * Prevent the vnode from being recycled or 74239484Smckusick * brought into use while we clean it out. 74339484Smckusick */ 74439667Smckusick if (vp->v_flag & VXLOCK) 74539667Smckusick panic("vclean: deadlock"); 74639433Smckusick vp->v_flag |= VXLOCK; 74739433Smckusick /* 74839667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 74939667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 75039667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 75139667Smckusick * For active vnodes, it ensures that no other activity can 75239667Smckusick * occur while the buffer list is being cleaned out. 75339667Smckusick */ 75439667Smckusick VOP_LOCK(vp); 75541300Smckusick if (flags & DOCLOSE) 75654442Smckusick vinvalbuf(vp, 1, NOCRED, NULL); 75739667Smckusick /* 75839433Smckusick * Prevent any further operations on the vnode from 75939433Smckusick * being passed through to the old file system. 76039433Smckusick */ 76139433Smckusick origops = vp->v_op; 76253547Sheideman vp->v_op = dead_vnodeop_p; 76339433Smckusick vp->v_tag = VT_NON; 76439433Smckusick /* 76539484Smckusick * If purging an active vnode, it must be unlocked, closed, 76639484Smckusick * and deactivated before being reclaimed. 76739433Smckusick */ 76853580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 76953580Sheideman vop_unlock_a.a_vp = vp; 77053580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 77139484Smckusick if (active) { 77253580Sheideman /* 77353580Sheideman * Note: these next two calls imply 77453580Sheideman * that vop_close and vop_inactive implementations 77553580Sheideman * cannot count on the ops vector being correctly 77653580Sheideman * set. 77753580Sheideman */ 77853580Sheideman if (flags & DOCLOSE) { 77953580Sheideman vop_close_a.a_desc = VDESC(vop_close); 78053580Sheideman vop_close_a.a_vp = vp; 78153580Sheideman vop_close_a.a_fflag = IO_NDELAY; 78254442Smckusick vop_close_a.a_p = NULL; 78353580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 78453580Sheideman }; 78553580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 78653580Sheideman vop_inactive_a.a_vp = vp; 78753580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 78839433Smckusick } 78939433Smckusick /* 79039433Smckusick * Reclaim the vnode. 79139433Smckusick */ 79253580Sheideman /* 79353580Sheideman * Emulate VOP_RECLAIM. 79453580Sheideman */ 79553580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 79653580Sheideman vop_reclaim_a.a_vp = vp; 79753580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 79839433Smckusick panic("vclean: cannot reclaim"); 79939484Smckusick if (active) 80039484Smckusick vrele(vp); 80153580Sheideman 80239433Smckusick /* 80339433Smckusick * Done with purge, notify sleepers in vget of the grim news. 80439433Smckusick */ 80539433Smckusick vp->v_flag &= ~VXLOCK; 80639433Smckusick if (vp->v_flag & VXWANT) { 80739433Smckusick vp->v_flag &= ~VXWANT; 80839433Smckusick wakeup((caddr_t)vp); 80939433Smckusick } 81039433Smckusick } 81139433Smckusick 81239433Smckusick /* 81339633Smckusick * Eliminate all activity associated with the requested vnode 81439633Smckusick * and with all vnodes aliased to the requested vnode. 81539633Smckusick */ 81639633Smckusick void vgoneall(vp) 81739633Smckusick register struct vnode *vp; 81839633Smckusick { 81939809Smckusick register struct vnode *vq; 82039633Smckusick 82140665Smckusick if (vp->v_flag & VALIASED) { 82240665Smckusick /* 82340665Smckusick * If a vgone (or vclean) is already in progress, 82440665Smckusick * wait until it is done and return. 82540665Smckusick */ 82640665Smckusick if (vp->v_flag & VXLOCK) { 82740665Smckusick vp->v_flag |= VXWANT; 82840665Smckusick sleep((caddr_t)vp, PINOD); 82940665Smckusick return; 83039633Smckusick } 83140665Smckusick /* 83240665Smckusick * Ensure that vp will not be vgone'd while we 83340665Smckusick * are eliminating its aliases. 83440665Smckusick */ 83540665Smckusick vp->v_flag |= VXLOCK; 83640665Smckusick while (vp->v_flag & VALIASED) { 83740665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 83840665Smckusick if (vq->v_rdev != vp->v_rdev || 83940665Smckusick vq->v_type != vp->v_type || vp == vq) 84040665Smckusick continue; 84140665Smckusick vgone(vq); 84240665Smckusick break; 84340665Smckusick } 84440665Smckusick } 84540665Smckusick /* 84640665Smckusick * Remove the lock so that vgone below will 84740665Smckusick * really eliminate the vnode after which time 84840665Smckusick * vgone will awaken any sleepers. 84940665Smckusick */ 85040665Smckusick vp->v_flag &= ~VXLOCK; 85139633Smckusick } 85239633Smckusick vgone(vp); 85339633Smckusick } 85439633Smckusick 85539633Smckusick /* 85639433Smckusick * Eliminate all activity associated with a vnode 85739433Smckusick * in preparation for reuse. 85839433Smckusick */ 85939433Smckusick void vgone(vp) 86039433Smckusick register struct vnode *vp; 86139433Smckusick { 86239809Smckusick register struct vnode *vq; 86339615Smckusick struct vnode *vx; 86439433Smckusick 86539433Smckusick /* 86640548Smckusick * If a vgone (or vclean) is already in progress, 86740548Smckusick * wait until it is done and return. 86840548Smckusick */ 86940548Smckusick if (vp->v_flag & VXLOCK) { 87040548Smckusick vp->v_flag |= VXWANT; 87140548Smckusick sleep((caddr_t)vp, PINOD); 87240548Smckusick return; 87340548Smckusick } 87440548Smckusick /* 87539433Smckusick * Clean out the filesystem specific data. 87639433Smckusick */ 87741300Smckusick vclean(vp, DOCLOSE); 87839433Smckusick /* 87939433Smckusick * Delete from old mount point vnode list, if on one. 88039433Smckusick */ 88139433Smckusick if (vp->v_mountb) { 88239433Smckusick if (vq = vp->v_mountf) 88339433Smckusick vq->v_mountb = vp->v_mountb; 88439433Smckusick *vp->v_mountb = vq; 88539433Smckusick vp->v_mountf = NULL; 88639433Smckusick vp->v_mountb = NULL; 88752311Smckusick vp->v_mount = NULL; 88839433Smckusick } 88939433Smckusick /* 89039433Smckusick * If special device, remove it from special device alias list. 89139433Smckusick */ 89239433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 89339809Smckusick if (*vp->v_hashchain == vp) { 89439809Smckusick *vp->v_hashchain = vp->v_specnext; 89539433Smckusick } else { 89639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 89739615Smckusick if (vq->v_specnext != vp) 89839433Smckusick continue; 89939615Smckusick vq->v_specnext = vp->v_specnext; 90039433Smckusick break; 90139433Smckusick } 90239615Smckusick if (vq == NULL) 90339433Smckusick panic("missing bdev"); 90439433Smckusick } 90539615Smckusick if (vp->v_flag & VALIASED) { 90652416Storek vx = NULL; 90739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90840108Smckusick if (vq->v_rdev != vp->v_rdev || 90940108Smckusick vq->v_type != vp->v_type) 91039615Smckusick continue; 91152416Storek if (vx) 91252416Storek break; 91339615Smckusick vx = vq; 91439615Smckusick } 91552416Storek if (vx == NULL) 91639615Smckusick panic("missing alias"); 91752416Storek if (vq == NULL) 91839615Smckusick vx->v_flag &= ~VALIASED; 91939615Smckusick vp->v_flag &= ~VALIASED; 92039615Smckusick } 92139615Smckusick FREE(vp->v_specinfo, M_VNODE); 92239615Smckusick vp->v_specinfo = NULL; 92339433Smckusick } 92439433Smckusick /* 92539433Smckusick * If it is on the freelist, move it to the head of the list. 92639433Smckusick */ 92739433Smckusick if (vp->v_freeb) { 92839433Smckusick if (vq = vp->v_freef) 92939433Smckusick vq->v_freeb = vp->v_freeb; 93039433Smckusick else 93139433Smckusick vfreet = vp->v_freeb; 93239433Smckusick *vp->v_freeb = vq; 93339433Smckusick vp->v_freef = vfreeh; 93439433Smckusick vp->v_freeb = &vfreeh; 93539433Smckusick vfreeh->v_freeb = &vp->v_freef; 93639433Smckusick vfreeh = vp; 93739433Smckusick } 93839484Smckusick vp->v_type = VBAD; 93939433Smckusick } 94039633Smckusick 94139633Smckusick /* 94239821Smckusick * Lookup a vnode by device number. 94339821Smckusick */ 94439821Smckusick vfinddev(dev, type, vpp) 94539821Smckusick dev_t dev; 94639821Smckusick enum vtype type; 94739821Smckusick struct vnode **vpp; 94839821Smckusick { 94939821Smckusick register struct vnode *vp; 95039821Smckusick 95139821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 95239821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 95339821Smckusick continue; 95439821Smckusick *vpp = vp; 95539821Smckusick return (0); 95639821Smckusick } 95739821Smckusick return (1); 95839821Smckusick } 95939821Smckusick 96039821Smckusick /* 96139633Smckusick * Calculate the total number of references to a special device. 96239633Smckusick */ 96339633Smckusick vcount(vp) 96439633Smckusick register struct vnode *vp; 96539633Smckusick { 96639809Smckusick register struct vnode *vq; 96739633Smckusick int count; 96839633Smckusick 96939633Smckusick if ((vp->v_flag & VALIASED) == 0) 97039809Smckusick return (vp->v_usecount); 97139633Smckusick loop: 97239809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97340108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 97439633Smckusick continue; 97539633Smckusick /* 97639633Smckusick * Alias, but not in use, so flush it out. 97739633Smckusick */ 97839809Smckusick if (vq->v_usecount == 0) { 97939633Smckusick vgone(vq); 98039633Smckusick goto loop; 98139633Smckusick } 98239809Smckusick count += vq->v_usecount; 98339633Smckusick } 98439633Smckusick return (count); 98539633Smckusick } 98639667Smckusick 98739667Smckusick /* 98839667Smckusick * Print out a description of a vnode. 98939667Smckusick */ 99039667Smckusick static char *typename[] = 99140286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 99239667Smckusick 99339667Smckusick vprint(label, vp) 99439667Smckusick char *label; 99539667Smckusick register struct vnode *vp; 99639667Smckusick { 99739913Smckusick char buf[64]; 99839667Smckusick 99939667Smckusick if (label != NULL) 100039667Smckusick printf("%s: ", label); 100150109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 100250109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 100350109Smckusick vp->v_holdcnt); 100439913Smckusick buf[0] = '\0'; 100539913Smckusick if (vp->v_flag & VROOT) 100639913Smckusick strcat(buf, "|VROOT"); 100739913Smckusick if (vp->v_flag & VTEXT) 100839913Smckusick strcat(buf, "|VTEXT"); 100941300Smckusick if (vp->v_flag & VSYSTEM) 101041300Smckusick strcat(buf, "|VSYSTEM"); 101141300Smckusick if (vp->v_flag & VXLOCK) 101241300Smckusick strcat(buf, "|VXLOCK"); 101341300Smckusick if (vp->v_flag & VXWANT) 101441300Smckusick strcat(buf, "|VXWANT"); 101541300Smckusick if (vp->v_flag & VBWAIT) 101641300Smckusick strcat(buf, "|VBWAIT"); 101739913Smckusick if (vp->v_flag & VALIASED) 101839913Smckusick strcat(buf, "|VALIASED"); 101939913Smckusick if (buf[0] != '\0') 102039913Smckusick printf(" flags (%s)", &buf[1]); 102139913Smckusick printf("\n\t"); 102239667Smckusick VOP_PRINT(vp); 102339667Smckusick } 102441110Smarc 102549691Smckusick #ifdef DEBUG 102649691Smckusick /* 102749691Smckusick * List all of the locked vnodes in the system. 102849691Smckusick * Called when debugging the kernel. 102949691Smckusick */ 103049691Smckusick printlockedvnodes() 103149691Smckusick { 103249691Smckusick register struct mount *mp; 103349691Smckusick register struct vnode *vp; 103449691Smckusick 103549691Smckusick printf("Locked vnodes\n"); 103649691Smckusick mp = rootfs; 103749691Smckusick do { 103849691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 103949691Smckusick if (VOP_ISLOCKED(vp)) 104049691Smckusick vprint((char *)0, vp); 104149691Smckusick mp = mp->mnt_next; 104249691Smckusick } while (mp != rootfs); 104349691Smckusick } 104449691Smckusick #endif 104549691Smckusick 104641110Smarc int kinfo_vdebug = 1; 104741110Smarc int kinfo_vgetfailed; 104841110Smarc #define KINFO_VNODESLOP 10 104941110Smarc /* 105041110Smarc * Dump vnode list (via kinfo). 105141110Smarc * Copyout address of vnode followed by vnode. 105241110Smarc */ 105345118Smckusick /* ARGSUSED */ 105441110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 105545118Smckusick int op; 105641110Smarc char *where; 105745118Smckusick int *acopysize, arg, *aneeded; 105841110Smarc { 105941110Smarc register struct mount *mp = rootfs; 106041300Smckusick struct mount *omp; 106141110Smarc struct vnode *vp; 106241110Smarc register char *bp = where, *savebp; 106353818Smckusick char *ewhere; 106441110Smarc int error; 106541110Smarc 106641110Smarc #define VPTRSZ sizeof (struct vnode *) 106741110Smarc #define VNODESZ sizeof (struct vnode) 106841110Smarc if (where == NULL) { 106941110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 107041110Smarc return (0); 107141110Smarc } 107253818Smckusick ewhere = where + *acopysize; 107341110Smarc 107441110Smarc do { 107541300Smckusick if (vfs_busy(mp)) { 107641400Smckusick mp = mp->mnt_next; 107741300Smckusick continue; 107841300Smckusick } 107941110Smarc savebp = bp; 108041110Smarc again: 108141421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 108241422Smckusick /* 108341422Smckusick * Check that the vp is still associated with 108441422Smckusick * this filesystem. RACE: could have been 108541422Smckusick * recycled onto the same filesystem. 108641422Smckusick */ 108741421Smckusick if (vp->v_mount != mp) { 108841421Smckusick if (kinfo_vdebug) 108941421Smckusick printf("kinfo: vp changed\n"); 109041421Smckusick bp = savebp; 109141421Smckusick goto again; 109241421Smckusick } 109341110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 109441110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 109541110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 109641422Smckusick VNODESZ)))) 109741110Smarc return (error); 109841110Smarc bp += VPTRSZ + VNODESZ; 109941110Smarc } 110041300Smckusick omp = mp; 110141400Smckusick mp = mp->mnt_next; 110241300Smckusick vfs_unbusy(omp); 110341110Smarc } while (mp != rootfs); 110441110Smarc 110541110Smarc *aneeded = bp - where; 110641110Smarc if (bp > ewhere) 110741110Smarc *acopysize = ewhere - where; 110841110Smarc else 110941110Smarc *acopysize = bp - where; 111041110Smarc return (0); 111141110Smarc } 1112