137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*54442Smckusick * @(#)vfs_subr.c 7.81 (Berkeley) 06/25/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 */ 306*54442Smckusick int 307*54442Smckusick vinvalbuf(vp, save, cred, p) 30849232Smckusick register struct vnode *vp; 30949232Smckusick int save; 310*54442Smckusick struct ucred *cred; 311*54442Smckusick struct proc *p; 31249232Smckusick { 31353547Sheideman USES_VOP_BWRITE; 314*54442Smckusick USES_VOP_FSYNC; 31549232Smckusick register struct buf *bp; 31649232Smckusick struct buf *nbp, *blist; 317*54442Smckusick int s, error; 31849232Smckusick 319*54442Smckusick if (save) { 320*54442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 321*54442Smckusick return (error); 322*54442Smckusick if (vp->v_dirtyblkhd != NULL) 323*54442Smckusick panic("vinvalbuf: dirty bufs"); 324*54442Smckusick } 32549232Smckusick for (;;) { 326*54442Smckusick if (blist = vp->v_cleanblkhd) 32749232Smckusick /* void */; 328*54442Smckusick else if (blist = vp->v_dirtyblkhd) 32949232Smckusick /* void */; 33049232Smckusick else 33149232Smckusick break; 33249232Smckusick for (bp = blist; bp; bp = nbp) { 33349232Smckusick nbp = bp->b_blockf; 33449232Smckusick s = splbio(); 33549232Smckusick if (bp->b_flags & B_BUSY) { 33649232Smckusick bp->b_flags |= B_WANTED; 33749232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 33849232Smckusick splx(s); 33949232Smckusick break; 34049232Smckusick } 34149232Smckusick bremfree(bp); 34249232Smckusick bp->b_flags |= B_BUSY; 34349232Smckusick splx(s); 34449232Smckusick if (bp->b_vp != vp) 34549232Smckusick reassignbuf(bp, bp->b_vp); 34649232Smckusick else 34749232Smckusick bp->b_flags |= B_INVAL; 34849232Smckusick brelse(bp); 34949232Smckusick } 35049232Smckusick } 35149232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 35249232Smckusick panic("vinvalbuf: flush failed"); 353*54442Smckusick 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 { 49253547Sheideman USES_VOP_UNLOCK; 49339433Smckusick register struct vnode *vp; 49439615Smckusick struct vnode **vpp; 49539433Smckusick 49639433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 49741400Smckusick return (NULLVP); 49839615Smckusick 49939615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 50039433Smckusick loop: 50139615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 50239615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50339433Smckusick continue; 50439615Smckusick /* 50539615Smckusick * Alias, but not in use, so flush it out. 50639615Smckusick */ 50739809Smckusick if (vp->v_usecount == 0) { 50839615Smckusick vgone(vp); 50939615Smckusick goto loop; 51039615Smckusick } 51139633Smckusick if (vget(vp)) 51239633Smckusick goto loop; 51339433Smckusick break; 51439433Smckusick } 51539615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 51639615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 51739615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 51839615Smckusick nvp->v_rdev = nvp_rdev; 51939809Smckusick nvp->v_hashchain = vpp; 52039615Smckusick nvp->v_specnext = *vpp; 52142152Smckusick nvp->v_specflags = 0; 52239615Smckusick *vpp = nvp; 52340640Smckusick if (vp != NULL) { 52440640Smckusick nvp->v_flag |= VALIASED; 52540640Smckusick vp->v_flag |= VALIASED; 52640640Smckusick vput(vp); 52740640Smckusick } 52841400Smckusick return (NULLVP); 52939433Smckusick } 53039484Smckusick VOP_UNLOCK(vp); 53139484Smckusick vclean(vp, 0); 53239433Smckusick vp->v_op = nvp->v_op; 53339433Smckusick vp->v_tag = nvp->v_tag; 53439433Smckusick nvp->v_type = VNON; 53539433Smckusick insmntque(vp, mp); 53639433Smckusick return (vp); 53739433Smckusick } 53839433Smckusick 53939433Smckusick /* 54039433Smckusick * Grab a particular vnode from the free list, increment its 54139433Smckusick * reference count and lock it. The vnode lock bit is set the 54239433Smckusick * vnode is being eliminated in vgone. The process is awakened 54339433Smckusick * when the transition is completed, and an error returned to 54439433Smckusick * indicate that the vnode is no longer usable (possibly having 54539433Smckusick * been changed to a new file system type). 54639433Smckusick */ 54739397Smckusick vget(vp) 54839397Smckusick register struct vnode *vp; 54939397Smckusick { 55053547Sheideman USES_VOP_LOCK; 55139397Smckusick register struct vnode *vq; 55239397Smckusick 55339433Smckusick if (vp->v_flag & VXLOCK) { 55439433Smckusick vp->v_flag |= VXWANT; 55539433Smckusick sleep((caddr_t)vp, PINOD); 55639433Smckusick return (1); 55739433Smckusick } 55839809Smckusick if (vp->v_usecount == 0) { 55939433Smckusick if (vq = vp->v_freef) 56039433Smckusick vq->v_freeb = vp->v_freeb; 56139433Smckusick else 56239433Smckusick vfreet = vp->v_freeb; 56339433Smckusick *vp->v_freeb = vq; 56439433Smckusick vp->v_freef = NULL; 56539433Smckusick vp->v_freeb = NULL; 56639433Smckusick } 56739397Smckusick VREF(vp); 56839433Smckusick VOP_LOCK(vp); 56939433Smckusick return (0); 57039397Smckusick } 57139397Smckusick 57239397Smckusick /* 57339397Smckusick * Vnode reference, just increment the count 57439397Smckusick */ 57539397Smckusick void vref(vp) 57639397Smckusick struct vnode *vp; 57739397Smckusick { 57839397Smckusick 57939809Smckusick vp->v_usecount++; 58039397Smckusick } 58139397Smckusick 58239397Smckusick /* 58339397Smckusick * vput(), just unlock and vrele() 58439397Smckusick */ 58539397Smckusick void vput(vp) 58639397Smckusick register struct vnode *vp; 58739397Smckusick { 58853547Sheideman USES_VOP_UNLOCK; 58952416Storek 59039397Smckusick VOP_UNLOCK(vp); 59139397Smckusick vrele(vp); 59239397Smckusick } 59339397Smckusick 59439397Smckusick /* 59539397Smckusick * Vnode release. 59639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59739397Smckusick */ 59839397Smckusick void vrele(vp) 59939397Smckusick register struct vnode *vp; 60039397Smckusick { 60153547Sheideman USES_VOP_INACTIVE; 60239397Smckusick 60350109Smckusick #ifdef DIAGNOSTIC 60439397Smckusick if (vp == NULL) 60539433Smckusick panic("vrele: null vp"); 60650109Smckusick #endif 60739809Smckusick vp->v_usecount--; 60839809Smckusick if (vp->v_usecount > 0) 60939397Smckusick return; 61050109Smckusick #ifdef DIAGNOSTIC 61150109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 61250109Smckusick vprint("vrele: bad ref count", vp); 61350109Smckusick panic("vrele: ref cnt"); 61450109Smckusick } 61550109Smckusick #endif 61641400Smckusick if (vfreeh == NULLVP) { 61739397Smckusick /* 61839397Smckusick * insert into empty list 61939397Smckusick */ 62039397Smckusick vfreeh = vp; 62139397Smckusick vp->v_freeb = &vfreeh; 62239397Smckusick } else { 62339397Smckusick /* 62439397Smckusick * insert at tail of list 62539397Smckusick */ 62639397Smckusick *vfreet = vp; 62739397Smckusick vp->v_freeb = vfreet; 62839397Smckusick } 62939433Smckusick vp->v_freef = NULL; 63039433Smckusick vfreet = &vp->v_freef; 631*54442Smckusick VOP_INACTIVE(vp); 63239397Smckusick } 63339433Smckusick 63439433Smckusick /* 63539809Smckusick * Page or buffer structure gets a reference. 63639809Smckusick */ 63753312Smckusick void vhold(vp) 63839809Smckusick register struct vnode *vp; 63939809Smckusick { 64039809Smckusick 64139809Smckusick vp->v_holdcnt++; 64239809Smckusick } 64339809Smckusick 64439809Smckusick /* 64539809Smckusick * Page or buffer structure frees a reference. 64639809Smckusick */ 64753312Smckusick void holdrele(vp) 64839809Smckusick register struct vnode *vp; 64939809Smckusick { 65039809Smckusick 65139809Smckusick if (vp->v_holdcnt <= 0) 65239809Smckusick panic("holdrele: holdcnt"); 65339809Smckusick vp->v_holdcnt--; 65439809Smckusick } 65539809Smckusick 65639809Smckusick /* 65739509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 65839509Smckusick * 65939509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 66039509Smckusick * return error if any are found (nb: this is a user error, not a 66139509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 66239509Smckusick * that are found. 66339509Smckusick */ 66439509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 66539509Smckusick 66639509Smckusick vflush(mp, skipvp, flags) 66739509Smckusick struct mount *mp; 66839509Smckusick struct vnode *skipvp; 66939509Smckusick int flags; 67039509Smckusick { 67139509Smckusick register struct vnode *vp, *nvp; 67239509Smckusick int busy = 0; 67339509Smckusick 67441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 67541300Smckusick panic("vflush: not busy"); 67641421Smckusick loop: 67741400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 67841421Smckusick if (vp->v_mount != mp) 67941421Smckusick goto loop; 68039509Smckusick nvp = vp->v_mountf; 68139509Smckusick /* 68239509Smckusick * Skip over a selected vnode. 68339509Smckusick */ 68439509Smckusick if (vp == skipvp) 68539509Smckusick continue; 68639509Smckusick /* 68741300Smckusick * Skip over a vnodes marked VSYSTEM. 68841300Smckusick */ 68941300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 69041300Smckusick continue; 69141300Smckusick /* 69239809Smckusick * With v_usecount == 0, all we need to do is clear 69339509Smckusick * out the vnode data structures and we are done. 69439509Smckusick */ 69539809Smckusick if (vp->v_usecount == 0) { 69639509Smckusick vgone(vp); 69739509Smckusick continue; 69839509Smckusick } 69939509Smckusick /* 70039509Smckusick * For block or character devices, revert to an 70139509Smckusick * anonymous device. For all other files, just kill them. 70239509Smckusick */ 70341300Smckusick if (flags & FORCECLOSE) { 70439509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 70539509Smckusick vgone(vp); 70639509Smckusick } else { 70739509Smckusick vclean(vp, 0); 70853547Sheideman vp->v_op = spec_vnodeop_p; 70939509Smckusick insmntque(vp, (struct mount *)0); 71039509Smckusick } 71139509Smckusick continue; 71239509Smckusick } 71339509Smckusick if (busyprt) 71439667Smckusick vprint("vflush: busy vnode", vp); 71539509Smckusick busy++; 71639509Smckusick } 71739509Smckusick if (busy) 71839509Smckusick return (EBUSY); 71939509Smckusick return (0); 72039509Smckusick } 72139509Smckusick 72239509Smckusick /* 72339433Smckusick * Disassociate the underlying file system from a vnode. 72439433Smckusick */ 72554347Smckusick void 72654347Smckusick vclean(vp, flags) 72739433Smckusick register struct vnode *vp; 72845118Smckusick int flags; 72939433Smckusick { 73053580Sheideman USES_VOP_LOCK; 73153580Sheideman USES_VOP_UNLOCK; 73253580Sheideman USES_VOP_CLOSE; 73353547Sheideman USES_VOP_INACTIVE; 73453580Sheideman USES_VOP_RECLAIM; 73553580Sheideman int (**origops)(); 73639484Smckusick int active; 73739433Smckusick 73839484Smckusick /* 73939484Smckusick * Check to see if the vnode is in use. 74039667Smckusick * If so we have to reference it before we clean it out 74139667Smckusick * so that its count cannot fall to zero and generate a 74239667Smckusick * race against ourselves to recycle it. 74339484Smckusick */ 74439809Smckusick if (active = vp->v_usecount) 74539484Smckusick VREF(vp); 74639484Smckusick /* 74739484Smckusick * Prevent the vnode from being recycled or 74839484Smckusick * brought into use while we clean it out. 74939484Smckusick */ 75039667Smckusick if (vp->v_flag & VXLOCK) 75139667Smckusick panic("vclean: deadlock"); 75239433Smckusick vp->v_flag |= VXLOCK; 75339433Smckusick /* 75439667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 75539667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 75639667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 75739667Smckusick * For active vnodes, it ensures that no other activity can 75839667Smckusick * occur while the buffer list is being cleaned out. 75939667Smckusick */ 76039667Smckusick VOP_LOCK(vp); 76141300Smckusick if (flags & DOCLOSE) 762*54442Smckusick vinvalbuf(vp, 1, NOCRED, NULL); 76339667Smckusick /* 76439433Smckusick * Prevent any further operations on the vnode from 76539433Smckusick * being passed through to the old file system. 76639433Smckusick */ 76739433Smckusick origops = vp->v_op; 76853547Sheideman vp->v_op = dead_vnodeop_p; 76939433Smckusick vp->v_tag = VT_NON; 77039433Smckusick /* 77139484Smckusick * If purging an active vnode, it must be unlocked, closed, 77239484Smckusick * and deactivated before being reclaimed. 77339433Smckusick */ 77453580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 77553580Sheideman vop_unlock_a.a_vp = vp; 77653580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 77739484Smckusick if (active) { 77853580Sheideman /* 77953580Sheideman * Note: these next two calls imply 78053580Sheideman * that vop_close and vop_inactive implementations 78153580Sheideman * cannot count on the ops vector being correctly 78253580Sheideman * set. 78353580Sheideman */ 78453580Sheideman if (flags & DOCLOSE) { 78553580Sheideman vop_close_a.a_desc = VDESC(vop_close); 78653580Sheideman vop_close_a.a_vp = vp; 78753580Sheideman vop_close_a.a_fflag = IO_NDELAY; 788*54442Smckusick vop_close_a.a_p = NULL; 78953580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 79053580Sheideman }; 79153580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 79253580Sheideman vop_inactive_a.a_vp = vp; 79353580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 79439433Smckusick } 79539433Smckusick /* 79639433Smckusick * Reclaim the vnode. 79739433Smckusick */ 79853580Sheideman /* 79953580Sheideman * Emulate VOP_RECLAIM. 80053580Sheideman */ 80153580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 80253580Sheideman vop_reclaim_a.a_vp = vp; 80353580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 80439433Smckusick panic("vclean: cannot reclaim"); 80539484Smckusick if (active) 80639484Smckusick vrele(vp); 80753580Sheideman 80839433Smckusick /* 80939433Smckusick * Done with purge, notify sleepers in vget of the grim news. 81039433Smckusick */ 81139433Smckusick vp->v_flag &= ~VXLOCK; 81239433Smckusick if (vp->v_flag & VXWANT) { 81339433Smckusick vp->v_flag &= ~VXWANT; 81439433Smckusick wakeup((caddr_t)vp); 81539433Smckusick } 81639433Smckusick } 81739433Smckusick 81839433Smckusick /* 81939633Smckusick * Eliminate all activity associated with the requested vnode 82039633Smckusick * and with all vnodes aliased to the requested vnode. 82139633Smckusick */ 82239633Smckusick void vgoneall(vp) 82339633Smckusick register struct vnode *vp; 82439633Smckusick { 82539809Smckusick register struct vnode *vq; 82639633Smckusick 82740665Smckusick if (vp->v_flag & VALIASED) { 82840665Smckusick /* 82940665Smckusick * If a vgone (or vclean) is already in progress, 83040665Smckusick * wait until it is done and return. 83140665Smckusick */ 83240665Smckusick if (vp->v_flag & VXLOCK) { 83340665Smckusick vp->v_flag |= VXWANT; 83440665Smckusick sleep((caddr_t)vp, PINOD); 83540665Smckusick return; 83639633Smckusick } 83740665Smckusick /* 83840665Smckusick * Ensure that vp will not be vgone'd while we 83940665Smckusick * are eliminating its aliases. 84040665Smckusick */ 84140665Smckusick vp->v_flag |= VXLOCK; 84240665Smckusick while (vp->v_flag & VALIASED) { 84340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 84440665Smckusick if (vq->v_rdev != vp->v_rdev || 84540665Smckusick vq->v_type != vp->v_type || vp == vq) 84640665Smckusick continue; 84740665Smckusick vgone(vq); 84840665Smckusick break; 84940665Smckusick } 85040665Smckusick } 85140665Smckusick /* 85240665Smckusick * Remove the lock so that vgone below will 85340665Smckusick * really eliminate the vnode after which time 85440665Smckusick * vgone will awaken any sleepers. 85540665Smckusick */ 85640665Smckusick vp->v_flag &= ~VXLOCK; 85739633Smckusick } 85839633Smckusick vgone(vp); 85939633Smckusick } 86039633Smckusick 86139633Smckusick /* 86239433Smckusick * Eliminate all activity associated with a vnode 86339433Smckusick * in preparation for reuse. 86439433Smckusick */ 86539433Smckusick void vgone(vp) 86639433Smckusick register struct vnode *vp; 86739433Smckusick { 86839809Smckusick register struct vnode *vq; 86939615Smckusick struct vnode *vx; 87039433Smckusick 87139433Smckusick /* 87240548Smckusick * If a vgone (or vclean) is already in progress, 87340548Smckusick * wait until it is done and return. 87440548Smckusick */ 87540548Smckusick if (vp->v_flag & VXLOCK) { 87640548Smckusick vp->v_flag |= VXWANT; 87740548Smckusick sleep((caddr_t)vp, PINOD); 87840548Smckusick return; 87940548Smckusick } 88040548Smckusick /* 88139433Smckusick * Clean out the filesystem specific data. 88239433Smckusick */ 88341300Smckusick vclean(vp, DOCLOSE); 88439433Smckusick /* 88539433Smckusick * Delete from old mount point vnode list, if on one. 88639433Smckusick */ 88739433Smckusick if (vp->v_mountb) { 88839433Smckusick if (vq = vp->v_mountf) 88939433Smckusick vq->v_mountb = vp->v_mountb; 89039433Smckusick *vp->v_mountb = vq; 89139433Smckusick vp->v_mountf = NULL; 89239433Smckusick vp->v_mountb = NULL; 89352311Smckusick vp->v_mount = NULL; 89439433Smckusick } 89539433Smckusick /* 89639433Smckusick * If special device, remove it from special device alias list. 89739433Smckusick */ 89839433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 89939809Smckusick if (*vp->v_hashchain == vp) { 90039809Smckusick *vp->v_hashchain = vp->v_specnext; 90139433Smckusick } else { 90239809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90339615Smckusick if (vq->v_specnext != vp) 90439433Smckusick continue; 90539615Smckusick vq->v_specnext = vp->v_specnext; 90639433Smckusick break; 90739433Smckusick } 90839615Smckusick if (vq == NULL) 90939433Smckusick panic("missing bdev"); 91039433Smckusick } 91139615Smckusick if (vp->v_flag & VALIASED) { 91252416Storek vx = NULL; 91339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 91440108Smckusick if (vq->v_rdev != vp->v_rdev || 91540108Smckusick vq->v_type != vp->v_type) 91639615Smckusick continue; 91752416Storek if (vx) 91852416Storek break; 91939615Smckusick vx = vq; 92039615Smckusick } 92152416Storek if (vx == NULL) 92239615Smckusick panic("missing alias"); 92352416Storek if (vq == NULL) 92439615Smckusick vx->v_flag &= ~VALIASED; 92539615Smckusick vp->v_flag &= ~VALIASED; 92639615Smckusick } 92739615Smckusick FREE(vp->v_specinfo, M_VNODE); 92839615Smckusick vp->v_specinfo = NULL; 92939433Smckusick } 93039433Smckusick /* 93139433Smckusick * If it is on the freelist, move it to the head of the list. 93239433Smckusick */ 93339433Smckusick if (vp->v_freeb) { 93439433Smckusick if (vq = vp->v_freef) 93539433Smckusick vq->v_freeb = vp->v_freeb; 93639433Smckusick else 93739433Smckusick vfreet = vp->v_freeb; 93839433Smckusick *vp->v_freeb = vq; 93939433Smckusick vp->v_freef = vfreeh; 94039433Smckusick vp->v_freeb = &vfreeh; 94139433Smckusick vfreeh->v_freeb = &vp->v_freef; 94239433Smckusick vfreeh = vp; 94339433Smckusick } 94439484Smckusick vp->v_type = VBAD; 94539433Smckusick } 94639633Smckusick 94739633Smckusick /* 94839821Smckusick * Lookup a vnode by device number. 94939821Smckusick */ 95039821Smckusick vfinddev(dev, type, vpp) 95139821Smckusick dev_t dev; 95239821Smckusick enum vtype type; 95339821Smckusick struct vnode **vpp; 95439821Smckusick { 95539821Smckusick register struct vnode *vp; 95639821Smckusick 95739821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 95839821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 95939821Smckusick continue; 96039821Smckusick *vpp = vp; 96139821Smckusick return (0); 96239821Smckusick } 96339821Smckusick return (1); 96439821Smckusick } 96539821Smckusick 96639821Smckusick /* 96739633Smckusick * Calculate the total number of references to a special device. 96839633Smckusick */ 96939633Smckusick vcount(vp) 97039633Smckusick register struct vnode *vp; 97139633Smckusick { 97239809Smckusick register struct vnode *vq; 97339633Smckusick int count; 97439633Smckusick 97539633Smckusick if ((vp->v_flag & VALIASED) == 0) 97639809Smckusick return (vp->v_usecount); 97739633Smckusick loop: 97839809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97940108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 98039633Smckusick continue; 98139633Smckusick /* 98239633Smckusick * Alias, but not in use, so flush it out. 98339633Smckusick */ 98439809Smckusick if (vq->v_usecount == 0) { 98539633Smckusick vgone(vq); 98639633Smckusick goto loop; 98739633Smckusick } 98839809Smckusick count += vq->v_usecount; 98939633Smckusick } 99039633Smckusick return (count); 99139633Smckusick } 99239667Smckusick 99339667Smckusick /* 99439667Smckusick * Print out a description of a vnode. 99539667Smckusick */ 99639667Smckusick static char *typename[] = 99740286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 99839667Smckusick 99939667Smckusick vprint(label, vp) 100039667Smckusick char *label; 100139667Smckusick register struct vnode *vp; 100239667Smckusick { 100353547Sheideman USES_VOP_PRINT; 100439913Smckusick char buf[64]; 100539667Smckusick 100639667Smckusick if (label != NULL) 100739667Smckusick printf("%s: ", label); 100850109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 100950109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 101050109Smckusick vp->v_holdcnt); 101139913Smckusick buf[0] = '\0'; 101239913Smckusick if (vp->v_flag & VROOT) 101339913Smckusick strcat(buf, "|VROOT"); 101439913Smckusick if (vp->v_flag & VTEXT) 101539913Smckusick strcat(buf, "|VTEXT"); 101641300Smckusick if (vp->v_flag & VSYSTEM) 101741300Smckusick strcat(buf, "|VSYSTEM"); 101841300Smckusick if (vp->v_flag & VXLOCK) 101941300Smckusick strcat(buf, "|VXLOCK"); 102041300Smckusick if (vp->v_flag & VXWANT) 102141300Smckusick strcat(buf, "|VXWANT"); 102241300Smckusick if (vp->v_flag & VBWAIT) 102341300Smckusick strcat(buf, "|VBWAIT"); 102439913Smckusick if (vp->v_flag & VALIASED) 102539913Smckusick strcat(buf, "|VALIASED"); 102639913Smckusick if (buf[0] != '\0') 102739913Smckusick printf(" flags (%s)", &buf[1]); 102839913Smckusick printf("\n\t"); 102939667Smckusick VOP_PRINT(vp); 103039667Smckusick } 103141110Smarc 103249691Smckusick #ifdef DEBUG 103349691Smckusick /* 103449691Smckusick * List all of the locked vnodes in the system. 103549691Smckusick * Called when debugging the kernel. 103649691Smckusick */ 103749691Smckusick printlockedvnodes() 103849691Smckusick { 103953547Sheideman USES_VOP_ISLOCKED; 104049691Smckusick register struct mount *mp; 104149691Smckusick register struct vnode *vp; 104249691Smckusick 104349691Smckusick printf("Locked vnodes\n"); 104449691Smckusick mp = rootfs; 104549691Smckusick do { 104649691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 104749691Smckusick if (VOP_ISLOCKED(vp)) 104849691Smckusick vprint((char *)0, vp); 104949691Smckusick mp = mp->mnt_next; 105049691Smckusick } while (mp != rootfs); 105149691Smckusick } 105249691Smckusick #endif 105349691Smckusick 105441110Smarc int kinfo_vdebug = 1; 105541110Smarc int kinfo_vgetfailed; 105641110Smarc #define KINFO_VNODESLOP 10 105741110Smarc /* 105841110Smarc * Dump vnode list (via kinfo). 105941110Smarc * Copyout address of vnode followed by vnode. 106041110Smarc */ 106145118Smckusick /* ARGSUSED */ 106241110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 106345118Smckusick int op; 106441110Smarc char *where; 106545118Smckusick int *acopysize, arg, *aneeded; 106641110Smarc { 106741110Smarc register struct mount *mp = rootfs; 106841300Smckusick struct mount *omp; 106941110Smarc struct vnode *vp; 107041110Smarc register char *bp = where, *savebp; 107153818Smckusick char *ewhere; 107241110Smarc int error; 107341110Smarc 107441110Smarc #define VPTRSZ sizeof (struct vnode *) 107541110Smarc #define VNODESZ sizeof (struct vnode) 107641110Smarc if (where == NULL) { 107741110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 107841110Smarc return (0); 107941110Smarc } 108053818Smckusick ewhere = where + *acopysize; 108141110Smarc 108241110Smarc do { 108341300Smckusick if (vfs_busy(mp)) { 108441400Smckusick mp = mp->mnt_next; 108541300Smckusick continue; 108641300Smckusick } 108741110Smarc savebp = bp; 108841110Smarc again: 108941421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 109041422Smckusick /* 109141422Smckusick * Check that the vp is still associated with 109241422Smckusick * this filesystem. RACE: could have been 109341422Smckusick * recycled onto the same filesystem. 109441422Smckusick */ 109541421Smckusick if (vp->v_mount != mp) { 109641421Smckusick if (kinfo_vdebug) 109741421Smckusick printf("kinfo: vp changed\n"); 109841421Smckusick bp = savebp; 109941421Smckusick goto again; 110041421Smckusick } 110141110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 110241110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 110341110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 110441422Smckusick VNODESZ)))) 110541110Smarc return (error); 110641110Smarc bp += VPTRSZ + VNODESZ; 110741110Smarc } 110841300Smckusick omp = mp; 110941400Smckusick mp = mp->mnt_next; 111041300Smckusick vfs_unbusy(omp); 111141110Smarc } while (mp != rootfs); 111241110Smarc 111341110Smarc *aneeded = bp - where; 111441110Smarc if (bp > ewhere) 111541110Smarc *acopysize = ewhere - where; 111641110Smarc else 111741110Smarc *acopysize = bp - where; 111841110Smarc return (0); 111941110Smarc } 1120