137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*54641Smckusick * @(#)vfs_subr.c 7.82 (Berkeley) 07/03/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/specdev.h> 2251460Sbostic #include <sys/namei.h> 2351460Sbostic #include <sys/ucred.h> 2451460Sbostic #include <sys/buf.h> 2551460Sbostic #include <sys/errno.h> 2651460Sbostic #include <sys/malloc.h> 2737488Smckusick 2852415Smckusick enum vtype iftovt_tab[16] = { 2952415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 3052415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3152415Smckusick }; 3252415Smckusick int vttoif_tab[9] = { 3352415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 3452415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 3552415Smckusick }; 3652415Smckusick 3737488Smckusick /* 3837488Smckusick * Remove a mount point from the list of mounted filesystems. 3937488Smckusick * Unmount of the root is illegal. 4037488Smckusick */ 4137488Smckusick void 4237488Smckusick vfs_remove(mp) 4337488Smckusick register struct mount *mp; 4437488Smckusick { 4537488Smckusick 4637488Smckusick if (mp == rootfs) 4737488Smckusick panic("vfs_remove: unmounting root"); 4841400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 4941400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 5041400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 5137488Smckusick vfs_unlock(mp); 5237488Smckusick } 5337488Smckusick 5437488Smckusick /* 5537488Smckusick * Lock a filesystem. 5637488Smckusick * Used to prevent access to it while mounting and unmounting. 5737488Smckusick */ 5837488Smckusick vfs_lock(mp) 5937488Smckusick register struct mount *mp; 6037488Smckusick { 6137488Smckusick 6241400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 6341400Smckusick mp->mnt_flag |= MNT_MWAIT; 6439045Smckusick sleep((caddr_t)mp, PVFS); 6539045Smckusick } 6641400Smckusick mp->mnt_flag |= MNT_MLOCK; 6737488Smckusick return (0); 6837488Smckusick } 6937488Smckusick 7037488Smckusick /* 7137488Smckusick * Unlock a locked filesystem. 7237488Smckusick * Panic if filesystem is not locked. 7337488Smckusick */ 7437488Smckusick void 7537488Smckusick vfs_unlock(mp) 7637488Smckusick register struct mount *mp; 7737488Smckusick { 7837488Smckusick 7941400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 8041300Smckusick panic("vfs_unlock: not locked"); 8141400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 8241400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 8341400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 8437488Smckusick wakeup((caddr_t)mp); 8537488Smckusick } 8637488Smckusick } 8737488Smckusick 8837488Smckusick /* 8941300Smckusick * Mark a mount point as busy. 9041300Smckusick * Used to synchronize access and to delay unmounting. 9141300Smckusick */ 9241300Smckusick vfs_busy(mp) 9341300Smckusick register struct mount *mp; 9441300Smckusick { 9541300Smckusick 9641400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 9741400Smckusick mp->mnt_flag |= MNT_MPWANT; 9841400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 9941300Smckusick } 10041419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 10141419Smckusick return (1); 10241400Smckusick mp->mnt_flag |= MNT_MPBUSY; 10341300Smckusick return (0); 10441300Smckusick } 10541300Smckusick 10641300Smckusick /* 10741300Smckusick * Free a busy filesystem. 10841300Smckusick * Panic if filesystem is not busy. 10941300Smckusick */ 11041300Smckusick vfs_unbusy(mp) 11141300Smckusick register struct mount *mp; 11241300Smckusick { 11341300Smckusick 11441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 11541300Smckusick panic("vfs_unbusy: not busy"); 11641400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 11741400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 11841400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 11941400Smckusick wakeup((caddr_t)&mp->mnt_flag); 12041300Smckusick } 12141300Smckusick } 12241300Smckusick 12341300Smckusick /* 12437488Smckusick * Lookup a mount point by filesystem identifier. 12537488Smckusick */ 12637488Smckusick struct mount * 12737488Smckusick getvfs(fsid) 12837488Smckusick fsid_t *fsid; 12937488Smckusick { 13037488Smckusick register struct mount *mp; 13137488Smckusick 13238288Smckusick mp = rootfs; 13338288Smckusick do { 13441400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 13541400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 13638288Smckusick return (mp); 13737488Smckusick } 13841400Smckusick mp = mp->mnt_next; 13938288Smckusick } while (mp != rootfs); 14038288Smckusick return ((struct mount *)0); 14137488Smckusick } 14237488Smckusick 14337488Smckusick /* 14453829Spendry * Get a new unique fsid 14553829Spendry */ 14653829Spendry void 14753829Spendry getnewfsid(mp, mtype) 14853829Spendry struct mount *mp; 14953829Spendry int mtype; 15053829Spendry { 15153829Spendry static u_short xxxfs_mntid; 15253829Spendry 15353829Spendry fsid_t tfsid; 15453829Spendry 15553829Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0); /* XXX */ 15653829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 15753829Spendry if (xxxfs_mntid == 0) 15853829Spendry ++xxxfs_mntid; 15953829Spendry tfsid.val[0] = makedev(nblkdev, xxxfs_mntid); 16053829Spendry tfsid.val[1] = mtype; 16153936Spendry if (rootfs) { 16253936Spendry while (getvfs(&tfsid)) { 16353936Spendry tfsid.val[0]++; 16453936Spendry xxxfs_mntid++; 16553936Spendry } 16653829Spendry } 16753829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 16853829Spendry } 16953829Spendry 17053829Spendry /* 17137488Smckusick * Set vnode attributes to VNOVAL 17237488Smckusick */ 17337488Smckusick void vattr_null(vap) 17437488Smckusick register struct vattr *vap; 17537488Smckusick { 17637488Smckusick 17737488Smckusick vap->va_type = VNON; 17852005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 17937488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18052005Smckusick vap->va_fsid = vap->va_fileid = 18152005Smckusick vap->va_blocksize = vap->va_rdev = 18254347Smckusick vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 18354347Smckusick vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 18454347Smckusick vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 18538258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 18637488Smckusick } 18738265Smckusick 18838265Smckusick /* 18939397Smckusick * Routines having to do with the management of the vnode table. 19039397Smckusick */ 19153493Sheideman extern struct vnode *vfreeh, **vfreet; 19253547Sheideman extern int (**dead_vnodeop_p)(); 19353547Sheideman extern int (**spec_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 30754442Smckusick vinvalbuf(vp, save, cred, p) 30849232Smckusick register struct vnode *vp; 30949232Smckusick int save; 31054442Smckusick struct ucred *cred; 31154442Smckusick struct proc *p; 31249232Smckusick { 31349232Smckusick register struct buf *bp; 31449232Smckusick struct buf *nbp, *blist; 31554442Smckusick int s, error; 31649232Smckusick 31754442Smckusick if (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 (;;) { 32454442Smckusick if (blist = vp->v_cleanblkhd) 32549232Smckusick /* void */; 32654442Smckusick else if (blist = vp->v_dirtyblkhd) 32749232Smckusick /* void */; 32849232Smckusick else 32949232Smckusick break; 33049232Smckusick for (bp = blist; bp; bp = nbp) { 33149232Smckusick nbp = bp->b_blockf; 33249232Smckusick s = splbio(); 33349232Smckusick if (bp->b_flags & B_BUSY) { 33449232Smckusick bp->b_flags |= B_WANTED; 33549232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 33649232Smckusick splx(s); 33749232Smckusick break; 33849232Smckusick } 33949232Smckusick bremfree(bp); 34049232Smckusick bp->b_flags |= B_BUSY; 34149232Smckusick splx(s); 34249232Smckusick if (bp->b_vp != vp) 34349232Smckusick reassignbuf(bp, bp->b_vp); 34449232Smckusick else 34549232Smckusick bp->b_flags |= B_INVAL; 34649232Smckusick brelse(bp); 34749232Smckusick } 34849232Smckusick } 34949232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 35049232Smckusick panic("vinvalbuf: flush failed"); 35154442Smckusick return (0); 35249232Smckusick } 35349232Smckusick 35449232Smckusick /* 35549232Smckusick * Associate a buffer with a vnode. 35649232Smckusick */ 35749232Smckusick bgetvp(vp, bp) 35849232Smckusick register struct vnode *vp; 35949232Smckusick register struct buf *bp; 36049232Smckusick { 36149973Smckusick register struct vnode *vq; 36249973Smckusick register struct buf *bq; 36349232Smckusick 36449232Smckusick if (bp->b_vp) 36549232Smckusick panic("bgetvp: not free"); 36649232Smckusick VHOLD(vp); 36749232Smckusick bp->b_vp = vp; 36849232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 36949232Smckusick bp->b_dev = vp->v_rdev; 37049232Smckusick else 37149232Smckusick bp->b_dev = NODEV; 37249232Smckusick /* 37349232Smckusick * Insert onto list for new vnode. 37449232Smckusick */ 37549973Smckusick if (bq = vp->v_cleanblkhd) 37649973Smckusick bq->b_blockb = &bp->b_blockf; 37749973Smckusick bp->b_blockf = bq; 37849973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 37949973Smckusick vp->v_cleanblkhd = bp; 38049232Smckusick } 38149232Smckusick 38249232Smckusick /* 38349232Smckusick * Disassociate a buffer from a vnode. 38449232Smckusick */ 38549232Smckusick brelvp(bp) 38649232Smckusick register struct buf *bp; 38749232Smckusick { 38849232Smckusick struct buf *bq; 38949232Smckusick struct vnode *vp; 39049232Smckusick 39149232Smckusick if (bp->b_vp == (struct vnode *) 0) 39249232Smckusick panic("brelvp: NULL"); 39349232Smckusick /* 39449232Smckusick * Delete from old vnode list, if on one. 39549232Smckusick */ 39649232Smckusick if (bp->b_blockb) { 39749232Smckusick if (bq = bp->b_blockf) 39849232Smckusick bq->b_blockb = bp->b_blockb; 39949232Smckusick *bp->b_blockb = bq; 40049232Smckusick bp->b_blockf = NULL; 40149232Smckusick bp->b_blockb = NULL; 40249232Smckusick } 40349232Smckusick vp = bp->b_vp; 40449232Smckusick bp->b_vp = (struct vnode *) 0; 40549232Smckusick HOLDRELE(vp); 40649232Smckusick } 40749232Smckusick 40849232Smckusick /* 40949232Smckusick * Reassign a buffer from one vnode to another. 41049232Smckusick * Used to assign file specific control information 41149232Smckusick * (indirect blocks) to the vnode to which they belong. 41249232Smckusick */ 41349232Smckusick reassignbuf(bp, newvp) 41449232Smckusick register struct buf *bp; 41549232Smckusick register struct vnode *newvp; 41649232Smckusick { 41749232Smckusick register struct buf *bq, **listheadp; 41849232Smckusick 41952655Smckusick if (newvp == NULL) { 42052655Smckusick printf("reassignbuf: NULL"); 42152655Smckusick return; 42252655Smckusick } 42349232Smckusick /* 42449232Smckusick * Delete from old vnode list, if on one. 42549232Smckusick */ 42649232Smckusick if (bp->b_blockb) { 42749232Smckusick if (bq = bp->b_blockf) 42849232Smckusick bq->b_blockb = bp->b_blockb; 42949232Smckusick *bp->b_blockb = bq; 43049232Smckusick } 43149232Smckusick /* 43249232Smckusick * If dirty, put on list of dirty buffers; 43349232Smckusick * otherwise insert onto list of clean buffers. 43449232Smckusick */ 43549232Smckusick if (bp->b_flags & B_DELWRI) 43649232Smckusick listheadp = &newvp->v_dirtyblkhd; 43749232Smckusick else 43849232Smckusick listheadp = &newvp->v_cleanblkhd; 43949973Smckusick if (bq = *listheadp) 44049973Smckusick bq->b_blockb = &bp->b_blockf; 44149973Smckusick bp->b_blockf = bq; 44249973Smckusick bp->b_blockb = listheadp; 44349973Smckusick *listheadp = bp; 44449232Smckusick } 44549232Smckusick 44649232Smckusick /* 44739433Smckusick * Create a vnode for a block device. 44839433Smckusick * Used for root filesystem, argdev, and swap areas. 44939433Smckusick * Also used for memory file system special devices. 45039397Smckusick */ 45139433Smckusick bdevvp(dev, vpp) 45239433Smckusick dev_t dev; 45339433Smckusick struct vnode **vpp; 45439433Smckusick { 45539433Smckusick register struct vnode *vp; 45639433Smckusick struct vnode *nvp; 45739433Smckusick int error; 45839433Smckusick 45946989Smckusick if (dev == NODEV) 46046989Smckusick return (0); 46153547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 46239433Smckusick if (error) { 46339433Smckusick *vpp = 0; 46439433Smckusick return (error); 46539433Smckusick } 46639433Smckusick vp = nvp; 46739433Smckusick vp->v_type = VBLK; 46839615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 46939433Smckusick vput(vp); 47039433Smckusick vp = nvp; 47139433Smckusick } 47239433Smckusick *vpp = vp; 47339433Smckusick return (0); 47439433Smckusick } 47539433Smckusick 47639433Smckusick /* 47739433Smckusick * Check to see if the new vnode represents a special device 47839433Smckusick * for which we already have a vnode (either because of 47939433Smckusick * bdevvp() or because of a different vnode representing 48039433Smckusick * the same block device). If such an alias exists, deallocate 48139509Smckusick * the existing contents and return the aliased vnode. The 48239433Smckusick * caller is responsible for filling it with its new contents. 48339433Smckusick */ 48439433Smckusick struct vnode * 48539615Smckusick checkalias(nvp, nvp_rdev, mp) 48639433Smckusick register struct vnode *nvp; 48739615Smckusick dev_t nvp_rdev; 48839433Smckusick struct mount *mp; 48939433Smckusick { 49039433Smckusick register struct vnode *vp; 49139615Smckusick struct vnode **vpp; 49239433Smckusick 49339433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 49441400Smckusick return (NULLVP); 49539615Smckusick 49639615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 49739433Smckusick loop: 49839615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 49939615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50039433Smckusick continue; 50139615Smckusick /* 50239615Smckusick * Alias, but not in use, so flush it out. 50339615Smckusick */ 50439809Smckusick if (vp->v_usecount == 0) { 50539615Smckusick vgone(vp); 50639615Smckusick goto loop; 50739615Smckusick } 50839633Smckusick if (vget(vp)) 50939633Smckusick goto loop; 51039433Smckusick break; 51139433Smckusick } 51239615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 51339615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 51439615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 51539615Smckusick nvp->v_rdev = nvp_rdev; 51639809Smckusick nvp->v_hashchain = vpp; 51739615Smckusick nvp->v_specnext = *vpp; 51842152Smckusick nvp->v_specflags = 0; 51939615Smckusick *vpp = nvp; 52040640Smckusick if (vp != NULL) { 52140640Smckusick nvp->v_flag |= VALIASED; 52240640Smckusick vp->v_flag |= VALIASED; 52340640Smckusick vput(vp); 52440640Smckusick } 52541400Smckusick return (NULLVP); 52639433Smckusick } 52739484Smckusick VOP_UNLOCK(vp); 52839484Smckusick vclean(vp, 0); 52939433Smckusick vp->v_op = nvp->v_op; 53039433Smckusick vp->v_tag = nvp->v_tag; 53139433Smckusick nvp->v_type = VNON; 53239433Smckusick insmntque(vp, mp); 53339433Smckusick return (vp); 53439433Smckusick } 53539433Smckusick 53639433Smckusick /* 53739433Smckusick * Grab a particular vnode from the free list, increment its 53839433Smckusick * reference count and lock it. The vnode lock bit is set the 53939433Smckusick * vnode is being eliminated in vgone. The process is awakened 54039433Smckusick * when the transition is completed, and an error returned to 54139433Smckusick * indicate that the vnode is no longer usable (possibly having 54239433Smckusick * been changed to a new file system type). 54339433Smckusick */ 54439397Smckusick vget(vp) 54539397Smckusick register struct vnode *vp; 54639397Smckusick { 54739397Smckusick register struct vnode *vq; 54839397Smckusick 54939433Smckusick if (vp->v_flag & VXLOCK) { 55039433Smckusick vp->v_flag |= VXWANT; 55139433Smckusick sleep((caddr_t)vp, PINOD); 55239433Smckusick return (1); 55339433Smckusick } 55439809Smckusick if (vp->v_usecount == 0) { 55539433Smckusick if (vq = vp->v_freef) 55639433Smckusick vq->v_freeb = vp->v_freeb; 55739433Smckusick else 55839433Smckusick vfreet = vp->v_freeb; 55939433Smckusick *vp->v_freeb = vq; 56039433Smckusick vp->v_freef = NULL; 56139433Smckusick vp->v_freeb = NULL; 56239433Smckusick } 56339397Smckusick VREF(vp); 56439433Smckusick VOP_LOCK(vp); 56539433Smckusick return (0); 56639397Smckusick } 56739397Smckusick 56839397Smckusick /* 56939397Smckusick * Vnode reference, just increment the count 57039397Smckusick */ 57139397Smckusick void vref(vp) 57239397Smckusick struct vnode *vp; 57339397Smckusick { 57439397Smckusick 57539809Smckusick vp->v_usecount++; 57639397Smckusick } 57739397Smckusick 57839397Smckusick /* 57939397Smckusick * vput(), just unlock and vrele() 58039397Smckusick */ 58139397Smckusick void vput(vp) 58239397Smckusick register struct vnode *vp; 58339397Smckusick { 58452416Storek 58539397Smckusick VOP_UNLOCK(vp); 58639397Smckusick vrele(vp); 58739397Smckusick } 58839397Smckusick 58939397Smckusick /* 59039397Smckusick * Vnode release. 59139397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59239397Smckusick */ 59339397Smckusick void vrele(vp) 59439397Smckusick register struct vnode *vp; 59539397Smckusick { 59639397Smckusick 59750109Smckusick #ifdef DIAGNOSTIC 59839397Smckusick if (vp == NULL) 59939433Smckusick panic("vrele: null vp"); 60050109Smckusick #endif 60139809Smckusick vp->v_usecount--; 60239809Smckusick if (vp->v_usecount > 0) 60339397Smckusick return; 60450109Smckusick #ifdef DIAGNOSTIC 60550109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 60650109Smckusick vprint("vrele: bad ref count", vp); 60750109Smckusick panic("vrele: ref cnt"); 60850109Smckusick } 60950109Smckusick #endif 61041400Smckusick if (vfreeh == NULLVP) { 61139397Smckusick /* 61239397Smckusick * insert into empty list 61339397Smckusick */ 61439397Smckusick vfreeh = vp; 61539397Smckusick vp->v_freeb = &vfreeh; 61639397Smckusick } else { 61739397Smckusick /* 61839397Smckusick * insert at tail of list 61939397Smckusick */ 62039397Smckusick *vfreet = vp; 62139397Smckusick vp->v_freeb = vfreet; 62239397Smckusick } 62339433Smckusick vp->v_freef = NULL; 62439433Smckusick vfreet = &vp->v_freef; 62554442Smckusick VOP_INACTIVE(vp); 62639397Smckusick } 62739433Smckusick 62839433Smckusick /* 62939809Smckusick * Page or buffer structure gets a reference. 63039809Smckusick */ 63153312Smckusick void vhold(vp) 63239809Smckusick register struct vnode *vp; 63339809Smckusick { 63439809Smckusick 63539809Smckusick vp->v_holdcnt++; 63639809Smckusick } 63739809Smckusick 63839809Smckusick /* 63939809Smckusick * Page or buffer structure frees a reference. 64039809Smckusick */ 64153312Smckusick void holdrele(vp) 64239809Smckusick register struct vnode *vp; 64339809Smckusick { 64439809Smckusick 64539809Smckusick if (vp->v_holdcnt <= 0) 64639809Smckusick panic("holdrele: holdcnt"); 64739809Smckusick vp->v_holdcnt--; 64839809Smckusick } 64939809Smckusick 65039809Smckusick /* 65139509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 65239509Smckusick * 65339509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 65439509Smckusick * return error if any are found (nb: this is a user error, not a 65539509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 65639509Smckusick * that are found. 65739509Smckusick */ 65839509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 65939509Smckusick 66039509Smckusick vflush(mp, skipvp, flags) 66139509Smckusick struct mount *mp; 66239509Smckusick struct vnode *skipvp; 66339509Smckusick int flags; 66439509Smckusick { 66539509Smckusick register struct vnode *vp, *nvp; 66639509Smckusick int busy = 0; 66739509Smckusick 66841400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 66941300Smckusick panic("vflush: not busy"); 67041421Smckusick loop: 67141400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 67241421Smckusick if (vp->v_mount != mp) 67341421Smckusick goto loop; 67439509Smckusick nvp = vp->v_mountf; 67539509Smckusick /* 67639509Smckusick * Skip over a selected vnode. 67739509Smckusick */ 67839509Smckusick if (vp == skipvp) 67939509Smckusick continue; 68039509Smckusick /* 68141300Smckusick * Skip over a vnodes marked VSYSTEM. 68241300Smckusick */ 68341300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 68441300Smckusick continue; 68541300Smckusick /* 68639809Smckusick * With v_usecount == 0, all we need to do is clear 68739509Smckusick * out the vnode data structures and we are done. 68839509Smckusick */ 68939809Smckusick if (vp->v_usecount == 0) { 69039509Smckusick vgone(vp); 69139509Smckusick continue; 69239509Smckusick } 69339509Smckusick /* 69439509Smckusick * For block or character devices, revert to an 69539509Smckusick * anonymous device. For all other files, just kill them. 69639509Smckusick */ 69741300Smckusick if (flags & FORCECLOSE) { 69839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 69939509Smckusick vgone(vp); 70039509Smckusick } else { 70139509Smckusick vclean(vp, 0); 70253547Sheideman vp->v_op = spec_vnodeop_p; 70339509Smckusick insmntque(vp, (struct mount *)0); 70439509Smckusick } 70539509Smckusick continue; 70639509Smckusick } 70739509Smckusick if (busyprt) 70839667Smckusick vprint("vflush: busy vnode", vp); 70939509Smckusick busy++; 71039509Smckusick } 71139509Smckusick if (busy) 71239509Smckusick return (EBUSY); 71339509Smckusick return (0); 71439509Smckusick } 71539509Smckusick 71639509Smckusick /* 71739433Smckusick * Disassociate the underlying file system from a vnode. 71839433Smckusick */ 71954347Smckusick void 72054347Smckusick vclean(vp, flags) 72139433Smckusick register struct vnode *vp; 72245118Smckusick int flags; 72339433Smckusick { 724*54641Smckusick struct vop_inactive_args vop_inactive_a; 725*54641Smckusick struct vop_reclaim_args vop_reclaim_a; 726*54641Smckusick struct vop_unlock_args vop_unlock_a; 727*54641Smckusick struct vop_close_args vop_close_a; 72853580Sheideman int (**origops)(); 72939484Smckusick int active; 73039433Smckusick 73139484Smckusick /* 73239484Smckusick * Check to see if the vnode is in use. 73339667Smckusick * If so we have to reference it before we clean it out 73439667Smckusick * so that its count cannot fall to zero and generate a 73539667Smckusick * race against ourselves to recycle it. 73639484Smckusick */ 73739809Smckusick if (active = vp->v_usecount) 73839484Smckusick VREF(vp); 73939484Smckusick /* 74039484Smckusick * Prevent the vnode from being recycled or 74139484Smckusick * brought into use while we clean it out. 74239484Smckusick */ 74339667Smckusick if (vp->v_flag & VXLOCK) 74439667Smckusick panic("vclean: deadlock"); 74539433Smckusick vp->v_flag |= VXLOCK; 74639433Smckusick /* 74739667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 74839667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 74939667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 75039667Smckusick * For active vnodes, it ensures that no other activity can 75139667Smckusick * occur while the buffer list is being cleaned out. 75239667Smckusick */ 75339667Smckusick VOP_LOCK(vp); 75441300Smckusick if (flags & DOCLOSE) 75554442Smckusick vinvalbuf(vp, 1, NOCRED, NULL); 75639667Smckusick /* 75739433Smckusick * Prevent any further operations on the vnode from 75839433Smckusick * being passed through to the old file system. 75939433Smckusick */ 76039433Smckusick origops = vp->v_op; 76153547Sheideman vp->v_op = dead_vnodeop_p; 76239433Smckusick vp->v_tag = VT_NON; 76339433Smckusick /* 76439484Smckusick * If purging an active vnode, it must be unlocked, closed, 76539484Smckusick * and deactivated before being reclaimed. 76639433Smckusick */ 76753580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 76853580Sheideman vop_unlock_a.a_vp = vp; 76953580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 77039484Smckusick if (active) { 77153580Sheideman /* 77253580Sheideman * Note: these next two calls imply 77353580Sheideman * that vop_close and vop_inactive implementations 77453580Sheideman * cannot count on the ops vector being correctly 77553580Sheideman * set. 77653580Sheideman */ 77753580Sheideman if (flags & DOCLOSE) { 77853580Sheideman vop_close_a.a_desc = VDESC(vop_close); 77953580Sheideman vop_close_a.a_vp = vp; 78053580Sheideman vop_close_a.a_fflag = IO_NDELAY; 78154442Smckusick vop_close_a.a_p = NULL; 78253580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 78353580Sheideman }; 78453580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 78553580Sheideman vop_inactive_a.a_vp = vp; 78653580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 78739433Smckusick } 78839433Smckusick /* 78939433Smckusick * Reclaim the vnode. 79039433Smckusick */ 79153580Sheideman /* 79253580Sheideman * Emulate VOP_RECLAIM. 79353580Sheideman */ 79453580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 79553580Sheideman vop_reclaim_a.a_vp = vp; 79653580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 79739433Smckusick panic("vclean: cannot reclaim"); 79839484Smckusick if (active) 79939484Smckusick vrele(vp); 80053580Sheideman 80139433Smckusick /* 80239433Smckusick * Done with purge, notify sleepers in vget of the grim news. 80339433Smckusick */ 80439433Smckusick vp->v_flag &= ~VXLOCK; 80539433Smckusick if (vp->v_flag & VXWANT) { 80639433Smckusick vp->v_flag &= ~VXWANT; 80739433Smckusick wakeup((caddr_t)vp); 80839433Smckusick } 80939433Smckusick } 81039433Smckusick 81139433Smckusick /* 81239633Smckusick * Eliminate all activity associated with the requested vnode 81339633Smckusick * and with all vnodes aliased to the requested vnode. 81439633Smckusick */ 81539633Smckusick void vgoneall(vp) 81639633Smckusick register struct vnode *vp; 81739633Smckusick { 81839809Smckusick register struct vnode *vq; 81939633Smckusick 82040665Smckusick if (vp->v_flag & VALIASED) { 82140665Smckusick /* 82240665Smckusick * If a vgone (or vclean) is already in progress, 82340665Smckusick * wait until it is done and return. 82440665Smckusick */ 82540665Smckusick if (vp->v_flag & VXLOCK) { 82640665Smckusick vp->v_flag |= VXWANT; 82740665Smckusick sleep((caddr_t)vp, PINOD); 82840665Smckusick return; 82939633Smckusick } 83040665Smckusick /* 83140665Smckusick * Ensure that vp will not be vgone'd while we 83240665Smckusick * are eliminating its aliases. 83340665Smckusick */ 83440665Smckusick vp->v_flag |= VXLOCK; 83540665Smckusick while (vp->v_flag & VALIASED) { 83640665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 83740665Smckusick if (vq->v_rdev != vp->v_rdev || 83840665Smckusick vq->v_type != vp->v_type || vp == vq) 83940665Smckusick continue; 84040665Smckusick vgone(vq); 84140665Smckusick break; 84240665Smckusick } 84340665Smckusick } 84440665Smckusick /* 84540665Smckusick * Remove the lock so that vgone below will 84640665Smckusick * really eliminate the vnode after which time 84740665Smckusick * vgone will awaken any sleepers. 84840665Smckusick */ 84940665Smckusick vp->v_flag &= ~VXLOCK; 85039633Smckusick } 85139633Smckusick vgone(vp); 85239633Smckusick } 85339633Smckusick 85439633Smckusick /* 85539433Smckusick * Eliminate all activity associated with a vnode 85639433Smckusick * in preparation for reuse. 85739433Smckusick */ 85839433Smckusick void vgone(vp) 85939433Smckusick register struct vnode *vp; 86039433Smckusick { 86139809Smckusick register struct vnode *vq; 86239615Smckusick struct vnode *vx; 86339433Smckusick 86439433Smckusick /* 86540548Smckusick * If a vgone (or vclean) is already in progress, 86640548Smckusick * wait until it is done and return. 86740548Smckusick */ 86840548Smckusick if (vp->v_flag & VXLOCK) { 86940548Smckusick vp->v_flag |= VXWANT; 87040548Smckusick sleep((caddr_t)vp, PINOD); 87140548Smckusick return; 87240548Smckusick } 87340548Smckusick /* 87439433Smckusick * Clean out the filesystem specific data. 87539433Smckusick */ 87641300Smckusick vclean(vp, DOCLOSE); 87739433Smckusick /* 87839433Smckusick * Delete from old mount point vnode list, if on one. 87939433Smckusick */ 88039433Smckusick if (vp->v_mountb) { 88139433Smckusick if (vq = vp->v_mountf) 88239433Smckusick vq->v_mountb = vp->v_mountb; 88339433Smckusick *vp->v_mountb = vq; 88439433Smckusick vp->v_mountf = NULL; 88539433Smckusick vp->v_mountb = NULL; 88652311Smckusick vp->v_mount = NULL; 88739433Smckusick } 88839433Smckusick /* 88939433Smckusick * If special device, remove it from special device alias list. 89039433Smckusick */ 89139433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 89239809Smckusick if (*vp->v_hashchain == vp) { 89339809Smckusick *vp->v_hashchain = vp->v_specnext; 89439433Smckusick } else { 89539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 89639615Smckusick if (vq->v_specnext != vp) 89739433Smckusick continue; 89839615Smckusick vq->v_specnext = vp->v_specnext; 89939433Smckusick break; 90039433Smckusick } 90139615Smckusick if (vq == NULL) 90239433Smckusick panic("missing bdev"); 90339433Smckusick } 90439615Smckusick if (vp->v_flag & VALIASED) { 90552416Storek vx = NULL; 90639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90740108Smckusick if (vq->v_rdev != vp->v_rdev || 90840108Smckusick vq->v_type != vp->v_type) 90939615Smckusick continue; 91052416Storek if (vx) 91152416Storek break; 91239615Smckusick vx = vq; 91339615Smckusick } 91452416Storek if (vx == NULL) 91539615Smckusick panic("missing alias"); 91652416Storek if (vq == NULL) 91739615Smckusick vx->v_flag &= ~VALIASED; 91839615Smckusick vp->v_flag &= ~VALIASED; 91939615Smckusick } 92039615Smckusick FREE(vp->v_specinfo, M_VNODE); 92139615Smckusick vp->v_specinfo = NULL; 92239433Smckusick } 92339433Smckusick /* 92439433Smckusick * If it is on the freelist, move it to the head of the list. 92539433Smckusick */ 92639433Smckusick if (vp->v_freeb) { 92739433Smckusick if (vq = vp->v_freef) 92839433Smckusick vq->v_freeb = vp->v_freeb; 92939433Smckusick else 93039433Smckusick vfreet = vp->v_freeb; 93139433Smckusick *vp->v_freeb = vq; 93239433Smckusick vp->v_freef = vfreeh; 93339433Smckusick vp->v_freeb = &vfreeh; 93439433Smckusick vfreeh->v_freeb = &vp->v_freef; 93539433Smckusick vfreeh = vp; 93639433Smckusick } 93739484Smckusick vp->v_type = VBAD; 93839433Smckusick } 93939633Smckusick 94039633Smckusick /* 94139821Smckusick * Lookup a vnode by device number. 94239821Smckusick */ 94339821Smckusick vfinddev(dev, type, vpp) 94439821Smckusick dev_t dev; 94539821Smckusick enum vtype type; 94639821Smckusick struct vnode **vpp; 94739821Smckusick { 94839821Smckusick register struct vnode *vp; 94939821Smckusick 95039821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 95139821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 95239821Smckusick continue; 95339821Smckusick *vpp = vp; 95439821Smckusick return (0); 95539821Smckusick } 95639821Smckusick return (1); 95739821Smckusick } 95839821Smckusick 95939821Smckusick /* 96039633Smckusick * Calculate the total number of references to a special device. 96139633Smckusick */ 96239633Smckusick vcount(vp) 96339633Smckusick register struct vnode *vp; 96439633Smckusick { 96539809Smckusick register struct vnode *vq; 96639633Smckusick int count; 96739633Smckusick 96839633Smckusick if ((vp->v_flag & VALIASED) == 0) 96939809Smckusick return (vp->v_usecount); 97039633Smckusick loop: 97139809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97240108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 97339633Smckusick continue; 97439633Smckusick /* 97539633Smckusick * Alias, but not in use, so flush it out. 97639633Smckusick */ 97739809Smckusick if (vq->v_usecount == 0) { 97839633Smckusick vgone(vq); 97939633Smckusick goto loop; 98039633Smckusick } 98139809Smckusick count += vq->v_usecount; 98239633Smckusick } 98339633Smckusick return (count); 98439633Smckusick } 98539667Smckusick 98639667Smckusick /* 98739667Smckusick * Print out a description of a vnode. 98839667Smckusick */ 98939667Smckusick static char *typename[] = 99040286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 99139667Smckusick 99239667Smckusick vprint(label, vp) 99339667Smckusick char *label; 99439667Smckusick register struct vnode *vp; 99539667Smckusick { 99639913Smckusick char buf[64]; 99739667Smckusick 99839667Smckusick if (label != NULL) 99939667Smckusick printf("%s: ", label); 100050109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 100150109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 100250109Smckusick vp->v_holdcnt); 100339913Smckusick buf[0] = '\0'; 100439913Smckusick if (vp->v_flag & VROOT) 100539913Smckusick strcat(buf, "|VROOT"); 100639913Smckusick if (vp->v_flag & VTEXT) 100739913Smckusick strcat(buf, "|VTEXT"); 100841300Smckusick if (vp->v_flag & VSYSTEM) 100941300Smckusick strcat(buf, "|VSYSTEM"); 101041300Smckusick if (vp->v_flag & VXLOCK) 101141300Smckusick strcat(buf, "|VXLOCK"); 101241300Smckusick if (vp->v_flag & VXWANT) 101341300Smckusick strcat(buf, "|VXWANT"); 101441300Smckusick if (vp->v_flag & VBWAIT) 101541300Smckusick strcat(buf, "|VBWAIT"); 101639913Smckusick if (vp->v_flag & VALIASED) 101739913Smckusick strcat(buf, "|VALIASED"); 101839913Smckusick if (buf[0] != '\0') 101939913Smckusick printf(" flags (%s)", &buf[1]); 102039913Smckusick printf("\n\t"); 102139667Smckusick VOP_PRINT(vp); 102239667Smckusick } 102341110Smarc 102449691Smckusick #ifdef DEBUG 102549691Smckusick /* 102649691Smckusick * List all of the locked vnodes in the system. 102749691Smckusick * Called when debugging the kernel. 102849691Smckusick */ 102949691Smckusick printlockedvnodes() 103049691Smckusick { 103149691Smckusick register struct mount *mp; 103249691Smckusick register struct vnode *vp; 103349691Smckusick 103449691Smckusick printf("Locked vnodes\n"); 103549691Smckusick mp = rootfs; 103649691Smckusick do { 103749691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 103849691Smckusick if (VOP_ISLOCKED(vp)) 103949691Smckusick vprint((char *)0, vp); 104049691Smckusick mp = mp->mnt_next; 104149691Smckusick } while (mp != rootfs); 104249691Smckusick } 104349691Smckusick #endif 104449691Smckusick 104541110Smarc int kinfo_vdebug = 1; 104641110Smarc int kinfo_vgetfailed; 104741110Smarc #define KINFO_VNODESLOP 10 104841110Smarc /* 104941110Smarc * Dump vnode list (via kinfo). 105041110Smarc * Copyout address of vnode followed by vnode. 105141110Smarc */ 105245118Smckusick /* ARGSUSED */ 105341110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 105445118Smckusick int op; 105541110Smarc char *where; 105645118Smckusick int *acopysize, arg, *aneeded; 105741110Smarc { 105841110Smarc register struct mount *mp = rootfs; 105941300Smckusick struct mount *omp; 106041110Smarc struct vnode *vp; 106141110Smarc register char *bp = where, *savebp; 106253818Smckusick char *ewhere; 106341110Smarc int error; 106441110Smarc 106541110Smarc #define VPTRSZ sizeof (struct vnode *) 106641110Smarc #define VNODESZ sizeof (struct vnode) 106741110Smarc if (where == NULL) { 106841110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 106941110Smarc return (0); 107041110Smarc } 107153818Smckusick ewhere = where + *acopysize; 107241110Smarc 107341110Smarc do { 107441300Smckusick if (vfs_busy(mp)) { 107541400Smckusick mp = mp->mnt_next; 107641300Smckusick continue; 107741300Smckusick } 107841110Smarc savebp = bp; 107941110Smarc again: 108041421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 108141422Smckusick /* 108241422Smckusick * Check that the vp is still associated with 108341422Smckusick * this filesystem. RACE: could have been 108441422Smckusick * recycled onto the same filesystem. 108541422Smckusick */ 108641421Smckusick if (vp->v_mount != mp) { 108741421Smckusick if (kinfo_vdebug) 108841421Smckusick printf("kinfo: vp changed\n"); 108941421Smckusick bp = savebp; 109041421Smckusick goto again; 109141421Smckusick } 109241110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 109341110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 109441110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 109541422Smckusick VNODESZ)))) 109641110Smarc return (error); 109741110Smarc bp += VPTRSZ + VNODESZ; 109841110Smarc } 109941300Smckusick omp = mp; 110041400Smckusick mp = mp->mnt_next; 110141300Smckusick vfs_unbusy(omp); 110241110Smarc } while (mp != rootfs); 110341110Smarc 110441110Smarc *aneeded = bp - where; 110541110Smarc if (bp > ewhere) 110641110Smarc *acopysize = ewhere - where; 110741110Smarc else 110841110Smarc *acopysize = bp - where; 110941110Smarc return (0); 111041110Smarc } 1111