137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*57810Smckusick * @(#)vfs_subr.c 7.93 (Berkeley) 02/03/93 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 1553829Spendry #include <sys/systm.h> 1651460Sbostic #include <sys/proc.h> 1751460Sbostic #include <sys/mount.h> 1851460Sbostic #include <sys/time.h> 1951460Sbostic #include <sys/vnode.h> 2052415Smckusick #include <sys/stat.h> 2151460Sbostic #include <sys/namei.h> 2251460Sbostic #include <sys/ucred.h> 2351460Sbostic #include <sys/buf.h> 2451460Sbostic #include <sys/errno.h> 2551460Sbostic #include <sys/malloc.h> 2637488Smckusick 2755050Spendry #include <miscfs/specfs/specdev.h> 2855050Spendry 2952415Smckusick enum vtype iftovt_tab[16] = { 3052415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 3152415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3252415Smckusick }; 3352415Smckusick int vttoif_tab[9] = { 3452415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 3552415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 3652415Smckusick }; 3752415Smckusick 3837488Smckusick /* 3956608Smckusick * Insq/Remq for the vnode usage lists. 4056608Smckusick */ 4156608Smckusick #define bufinsvn(bp, dp) list_enter_head(dp, bp, struct buf *, b_vnbufs) 4256608Smckusick #define bufremvn(bp) list_remove(bp, struct buf *, b_vnbufs) 4356608Smckusick 4456608Smckusick /* 4537488Smckusick * Remove a mount point from the list of mounted filesystems. 4637488Smckusick * Unmount of the root is illegal. 4737488Smckusick */ 4837488Smckusick void 4937488Smckusick vfs_remove(mp) 5037488Smckusick register struct mount *mp; 5137488Smckusick { 5237488Smckusick 5337488Smckusick if (mp == rootfs) 5437488Smckusick panic("vfs_remove: unmounting root"); 5541400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 5641400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 5741400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 5837488Smckusick vfs_unlock(mp); 5937488Smckusick } 6037488Smckusick 6137488Smckusick /* 6237488Smckusick * Lock a filesystem. 6337488Smckusick * Used to prevent access to it while mounting and unmounting. 6437488Smckusick */ 6537488Smckusick vfs_lock(mp) 6637488Smckusick register struct mount *mp; 6737488Smckusick { 6837488Smckusick 6941400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 7041400Smckusick mp->mnt_flag |= MNT_MWAIT; 7139045Smckusick sleep((caddr_t)mp, PVFS); 7239045Smckusick } 7341400Smckusick mp->mnt_flag |= MNT_MLOCK; 7437488Smckusick return (0); 7537488Smckusick } 7637488Smckusick 7737488Smckusick /* 7837488Smckusick * Unlock a locked filesystem. 7937488Smckusick * Panic if filesystem is not locked. 8037488Smckusick */ 8137488Smckusick void 8237488Smckusick vfs_unlock(mp) 8337488Smckusick register struct mount *mp; 8437488Smckusick { 8537488Smckusick 8641400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 8741300Smckusick panic("vfs_unlock: not locked"); 8841400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 8941400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 9041400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 9137488Smckusick wakeup((caddr_t)mp); 9237488Smckusick } 9337488Smckusick } 9437488Smckusick 9537488Smckusick /* 9641300Smckusick * Mark a mount point as busy. 9741300Smckusick * Used to synchronize access and to delay unmounting. 9841300Smckusick */ 9941300Smckusick vfs_busy(mp) 10041300Smckusick register struct mount *mp; 10141300Smckusick { 10241300Smckusick 10341400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 10441400Smckusick mp->mnt_flag |= MNT_MPWANT; 10541400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 10641300Smckusick } 10741419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 10841419Smckusick return (1); 10941400Smckusick mp->mnt_flag |= MNT_MPBUSY; 11041300Smckusick return (0); 11141300Smckusick } 11241300Smckusick 11341300Smckusick /* 11441300Smckusick * Free a busy filesystem. 11541300Smckusick * Panic if filesystem is not busy. 11641300Smckusick */ 11741300Smckusick vfs_unbusy(mp) 11841300Smckusick register struct mount *mp; 11941300Smckusick { 12041300Smckusick 12141400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 12241300Smckusick panic("vfs_unbusy: not busy"); 12341400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 12441400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 12541400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 12641400Smckusick wakeup((caddr_t)&mp->mnt_flag); 12741300Smckusick } 12841300Smckusick } 12941300Smckusick 13041300Smckusick /* 13137488Smckusick * Lookup a mount point by filesystem identifier. 13237488Smckusick */ 13337488Smckusick struct mount * 13437488Smckusick getvfs(fsid) 13537488Smckusick fsid_t *fsid; 13637488Smckusick { 13737488Smckusick register struct mount *mp; 13837488Smckusick 13938288Smckusick mp = rootfs; 14038288Smckusick do { 14141400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 14241400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 14338288Smckusick return (mp); 14437488Smckusick } 14541400Smckusick mp = mp->mnt_next; 14638288Smckusick } while (mp != rootfs); 14738288Smckusick return ((struct mount *)0); 14837488Smckusick } 14937488Smckusick 15037488Smckusick /* 15153829Spendry * Get a new unique fsid 15253829Spendry */ 15353829Spendry void 15453829Spendry getnewfsid(mp, mtype) 15553829Spendry struct mount *mp; 15653829Spendry int mtype; 15753829Spendry { 15853829Spendry static u_short xxxfs_mntid; 15953829Spendry 16053829Spendry fsid_t tfsid; 16153829Spendry 16253829Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0); /* XXX */ 16353829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 16453829Spendry if (xxxfs_mntid == 0) 16553829Spendry ++xxxfs_mntid; 16653829Spendry tfsid.val[0] = makedev(nblkdev, xxxfs_mntid); 16753829Spendry tfsid.val[1] = mtype; 16853936Spendry if (rootfs) { 16953936Spendry while (getvfs(&tfsid)) { 17053936Spendry tfsid.val[0]++; 17153936Spendry xxxfs_mntid++; 17253936Spendry } 17353829Spendry } 17453829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 17553829Spendry } 17653829Spendry 17753829Spendry /* 17837488Smckusick * Set vnode attributes to VNOVAL 17937488Smckusick */ 18037488Smckusick void vattr_null(vap) 18137488Smckusick register struct vattr *vap; 18237488Smckusick { 18337488Smckusick 18437488Smckusick vap->va_type = VNON; 18552005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 18637488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18752005Smckusick vap->va_fsid = vap->va_fileid = 18852005Smckusick vap->va_blocksize = vap->va_rdev = 18954347Smckusick vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 19054347Smckusick vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 19154347Smckusick vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 19238258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 19337488Smckusick } 19438265Smckusick 19538265Smckusick /* 19639397Smckusick * Routines having to do with the management of the vnode table. 19739397Smckusick */ 19855468Smckusick struct vnode *vfreeh, **vfreet = &vfreeh; 19953547Sheideman extern int (**dead_vnodeop_p)(); 20039635Smckusick extern void vclean(); 20140883Smckusick long numvnodes; 20253493Sheideman extern struct vattr va_null; 20339397Smckusick 20457042Smargo 20539397Smckusick /* 20639397Smckusick * Return the next vnode from the free list. 20739397Smckusick */ 20839397Smckusick getnewvnode(tag, mp, vops, vpp) 20939397Smckusick enum vtagtype tag; 21039397Smckusick struct mount *mp; 21153495Sheideman int (**vops)(); 21239397Smckusick struct vnode **vpp; 21339397Smckusick { 21439397Smckusick register struct vnode *vp, *vq; 21557042Smargo int s; 21639397Smckusick 21754347Smckusick if ((vfreeh == NULL && numvnodes < 2 * desiredvnodes) || 21854347Smckusick numvnodes < desiredvnodes) { 21945118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 22045118Smckusick M_VNODE, M_WAITOK); 22140883Smckusick bzero((char *)vp, sizeof *vp); 22240883Smckusick numvnodes++; 22340883Smckusick } else { 22440883Smckusick if ((vp = vfreeh) == NULL) { 22540883Smckusick tablefull("vnode"); 22640883Smckusick *vpp = 0; 22740883Smckusick return (ENFILE); 22840883Smckusick } 22940883Smckusick if (vp->v_usecount) 23040883Smckusick panic("free vnode isn't"); 23140883Smckusick if (vq = vp->v_freef) 23240883Smckusick vq->v_freeb = &vfreeh; 23340883Smckusick else 23440883Smckusick vfreet = &vfreeh; 23540883Smckusick vfreeh = vq; 23640883Smckusick vp->v_freef = NULL; 23740883Smckusick vp->v_freeb = NULL; 23852190Smckusick vp->v_lease = NULL; 23940883Smckusick if (vp->v_type != VBAD) 24040883Smckusick vgone(vp); 24157042Smargo #ifdef DIAGNOSTIC 24252006Smckusick if (vp->v_data) 24352006Smckusick panic("cleaned vnode isn't"); 24457042Smargo s = splbio(); 24557042Smargo if (vp->v_numoutput) 24657042Smargo panic("Clean vnode has pending I/O's"); 24757042Smargo splx(s); 24857042Smargo #endif 24940883Smckusick vp->v_flag = 0; 25040883Smckusick vp->v_lastr = 0; 25157042Smargo vp->v_lastw = 0; 25257042Smargo vp->v_lasta = 0; 25357042Smargo vp->v_cstart = 0; 25457042Smargo vp->v_clen = 0; 25540883Smckusick vp->v_socket = 0; 25639397Smckusick } 25757042Smargo vp->v_ralen = 1; 25839512Smckusick vp->v_type = VNON; 25939397Smckusick cache_purge(vp); 26039397Smckusick vp->v_tag = tag; 26139433Smckusick vp->v_op = vops; 26239397Smckusick insmntque(vp, mp); 26339397Smckusick VREF(vp); 26439397Smckusick *vpp = vp; 26539397Smckusick return (0); 26639397Smckusick } 26739397Smckusick /* 26839397Smckusick * Move a vnode from one mount queue to another. 26939397Smckusick */ 27039397Smckusick insmntque(vp, mp) 27139397Smckusick register struct vnode *vp; 27239397Smckusick register struct mount *mp; 27339397Smckusick { 27449973Smckusick register struct vnode *vq; 27539397Smckusick 27639397Smckusick /* 27739397Smckusick * Delete from old mount point vnode list, if on one. 27839397Smckusick */ 27939397Smckusick if (vp->v_mountb) { 28039397Smckusick if (vq = vp->v_mountf) 28139397Smckusick vq->v_mountb = vp->v_mountb; 28239397Smckusick *vp->v_mountb = vq; 28339397Smckusick } 28439397Smckusick /* 28539397Smckusick * Insert into list of vnodes for the new mount point, if available. 28639397Smckusick */ 28739621Smckusick vp->v_mount = mp; 28839397Smckusick if (mp == NULL) { 28939397Smckusick vp->v_mountf = NULL; 29039397Smckusick vp->v_mountb = NULL; 29139397Smckusick return; 29239397Smckusick } 29349973Smckusick if (vq = mp->mnt_mounth) 29449973Smckusick vq->v_mountb = &vp->v_mountf; 29549973Smckusick vp->v_mountf = vq; 29649973Smckusick vp->v_mountb = &mp->mnt_mounth; 29749973Smckusick mp->mnt_mounth = vp; 29839397Smckusick } 29939397Smckusick 30039397Smckusick /* 30149232Smckusick * Update outstanding I/O count and do wakeup if requested. 30249232Smckusick */ 30349232Smckusick vwakeup(bp) 30449232Smckusick register struct buf *bp; 30549232Smckusick { 30649232Smckusick register struct vnode *vp; 30749232Smckusick 308*57810Smckusick bp->b_flags &= ~B_WRITEINPROG; 30949232Smckusick if (vp = bp->b_vp) { 31049232Smckusick vp->v_numoutput--; 31157042Smargo if (vp->v_numoutput < 0) 31257042Smargo panic("vwakeup: neg numoutput"); 31349232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 31449232Smckusick if (vp->v_numoutput < 0) 31549232Smckusick panic("vwakeup: neg numoutput"); 31649232Smckusick vp->v_flag &= ~VBWAIT; 31749232Smckusick wakeup((caddr_t)&vp->v_numoutput); 31849232Smckusick } 31949232Smckusick } 32049232Smckusick } 32149232Smckusick 32249232Smckusick /* 32349232Smckusick * Flush out and invalidate all buffers associated with a vnode. 32449232Smckusick * Called with the underlying object locked. 32549232Smckusick */ 32654442Smckusick int 32757792Smckusick vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 32849232Smckusick register struct vnode *vp; 32956459Smargo int flags; 33054442Smckusick struct ucred *cred; 33154442Smckusick struct proc *p; 33257792Smckusick int slpflag, slptimeo; 33349232Smckusick { 33449232Smckusick register struct buf *bp; 33549232Smckusick struct buf *nbp, *blist; 33654442Smckusick int s, error; 33749232Smckusick 33856459Smargo if (flags & V_SAVE) { 33954442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 34054442Smckusick return (error); 34156608Smckusick if (vp->v_dirtyblkhd.le_next != NULL) 34254442Smckusick panic("vinvalbuf: dirty bufs"); 34354442Smckusick } 34449232Smckusick for (;;) { 34556608Smckusick if ((blist = vp->v_cleanblkhd.le_next) && flags & V_SAVEMETA) 34656459Smargo while (blist && blist->b_lblkno < 0) 34756608Smckusick blist = blist->b_vnbufs.qe_next; 34856608Smckusick if (!blist && (blist = vp->v_dirtyblkhd.le_next) && 34956608Smckusick (flags & V_SAVEMETA)) 35056459Smargo while (blist && blist->b_lblkno < 0) 35156608Smckusick blist = blist->b_vnbufs.qe_next; 35256459Smargo if (!blist) 35349232Smckusick break; 35456459Smargo 35549232Smckusick for (bp = blist; bp; bp = nbp) { 35656608Smckusick nbp = bp->b_vnbufs.qe_next; 35756459Smargo if (flags & V_SAVEMETA && bp->b_lblkno < 0) 35856459Smargo continue; 35949232Smckusick s = splbio(); 36049232Smckusick if (bp->b_flags & B_BUSY) { 36149232Smckusick bp->b_flags |= B_WANTED; 36257792Smckusick error = tsleep((caddr_t)bp, 36357792Smckusick slpflag | (PRIBIO + 1), "vinvalbuf", 36457792Smckusick slptimeo); 36549232Smckusick splx(s); 36657792Smckusick if (error) 36757792Smckusick return (error); 36849232Smckusick break; 36949232Smckusick } 37049232Smckusick bremfree(bp); 37149232Smckusick bp->b_flags |= B_BUSY; 37249232Smckusick splx(s); 37357792Smckusick /* 37457792Smckusick * XXX Since there are no node locks for NFS, I believe 37557792Smckusick * there is a slight chance that a delayed write will 37657792Smckusick * occur while sleeping just above, so check for it. 37757792Smckusick */ 37857792Smckusick if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 37957792Smckusick (void) VOP_BWRITE(bp); 38057792Smckusick break; 38157792Smckusick } 38256459Smargo bp->b_flags |= B_INVAL; 38349232Smckusick brelse(bp); 38449232Smckusick } 38549232Smckusick } 38656608Smckusick if (!(flags & V_SAVEMETA) && 38756608Smckusick (vp->v_dirtyblkhd.le_next || vp->v_cleanblkhd.le_next)) 38849232Smckusick panic("vinvalbuf: flush failed"); 38954442Smckusick return (0); 39049232Smckusick } 39149232Smckusick 39249232Smckusick /* 39349232Smckusick * Associate a buffer with a vnode. 39449232Smckusick */ 39549232Smckusick bgetvp(vp, bp) 39649232Smckusick register struct vnode *vp; 39749232Smckusick register struct buf *bp; 39849232Smckusick { 39949973Smckusick register struct vnode *vq; 40049232Smckusick 40149232Smckusick if (bp->b_vp) 40249232Smckusick panic("bgetvp: not free"); 40349232Smckusick VHOLD(vp); 40449232Smckusick bp->b_vp = vp; 40549232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 40649232Smckusick bp->b_dev = vp->v_rdev; 40749232Smckusick else 40849232Smckusick bp->b_dev = NODEV; 40949232Smckusick /* 41049232Smckusick * Insert onto list for new vnode. 41149232Smckusick */ 41256608Smckusick bufinsvn(bp, &vp->v_cleanblkhd); 41349232Smckusick } 41449232Smckusick 41549232Smckusick /* 41649232Smckusick * Disassociate a buffer from a vnode. 41749232Smckusick */ 41849232Smckusick brelvp(bp) 41949232Smckusick register struct buf *bp; 42049232Smckusick { 42149232Smckusick struct vnode *vp; 42249232Smckusick 42349232Smckusick if (bp->b_vp == (struct vnode *) 0) 42449232Smckusick panic("brelvp: NULL"); 42549232Smckusick /* 42649232Smckusick * Delete from old vnode list, if on one. 42749232Smckusick */ 42856608Smckusick if (bp->b_vnbufs.qe_next != NOLIST) 42956608Smckusick bufremvn(bp); 43049232Smckusick vp = bp->b_vp; 43149232Smckusick bp->b_vp = (struct vnode *) 0; 43249232Smckusick HOLDRELE(vp); 43349232Smckusick } 43449232Smckusick 43549232Smckusick /* 43649232Smckusick * Reassign a buffer from one vnode to another. 43749232Smckusick * Used to assign file specific control information 43849232Smckusick * (indirect blocks) to the vnode to which they belong. 43949232Smckusick */ 44049232Smckusick reassignbuf(bp, newvp) 44149232Smckusick register struct buf *bp; 44249232Smckusick register struct vnode *newvp; 44349232Smckusick { 44456608Smckusick register struct list_entry *listheadp; 44549232Smckusick 44652655Smckusick if (newvp == NULL) { 44752655Smckusick printf("reassignbuf: NULL"); 44852655Smckusick return; 44952655Smckusick } 45049232Smckusick /* 45149232Smckusick * Delete from old vnode list, if on one. 45249232Smckusick */ 45356608Smckusick if (bp->b_vnbufs.qe_next != NOLIST) 45456608Smckusick bufremvn(bp); 45549232Smckusick /* 45649232Smckusick * If dirty, put on list of dirty buffers; 45749232Smckusick * otherwise insert onto list of clean buffers. 45849232Smckusick */ 45949232Smckusick if (bp->b_flags & B_DELWRI) 46049232Smckusick listheadp = &newvp->v_dirtyblkhd; 46149232Smckusick else 46249232Smckusick listheadp = &newvp->v_cleanblkhd; 46356608Smckusick bufinsvn(bp, listheadp); 46449232Smckusick } 46549232Smckusick 46649232Smckusick /* 46739433Smckusick * Create a vnode for a block device. 46839433Smckusick * Used for root filesystem, argdev, and swap areas. 46939433Smckusick * Also used for memory file system special devices. 47039397Smckusick */ 47139433Smckusick bdevvp(dev, vpp) 47239433Smckusick dev_t dev; 47339433Smckusick struct vnode **vpp; 47439433Smckusick { 47539433Smckusick register struct vnode *vp; 47639433Smckusick struct vnode *nvp; 47739433Smckusick int error; 47839433Smckusick 47946989Smckusick if (dev == NODEV) 48046989Smckusick return (0); 48153547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 48239433Smckusick if (error) { 48339433Smckusick *vpp = 0; 48439433Smckusick return (error); 48539433Smckusick } 48639433Smckusick vp = nvp; 48739433Smckusick vp->v_type = VBLK; 48839615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 48939433Smckusick vput(vp); 49039433Smckusick vp = nvp; 49139433Smckusick } 49239433Smckusick *vpp = vp; 49339433Smckusick return (0); 49439433Smckusick } 49539433Smckusick 49639433Smckusick /* 49739433Smckusick * Check to see if the new vnode represents a special device 49839433Smckusick * for which we already have a vnode (either because of 49939433Smckusick * bdevvp() or because of a different vnode representing 50039433Smckusick * the same block device). If such an alias exists, deallocate 50139509Smckusick * the existing contents and return the aliased vnode. The 50239433Smckusick * caller is responsible for filling it with its new contents. 50339433Smckusick */ 50439433Smckusick struct vnode * 50539615Smckusick checkalias(nvp, nvp_rdev, mp) 50639433Smckusick register struct vnode *nvp; 50739615Smckusick dev_t nvp_rdev; 50839433Smckusick struct mount *mp; 50939433Smckusick { 51039433Smckusick register struct vnode *vp; 51139615Smckusick struct vnode **vpp; 51239433Smckusick 51339433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 51441400Smckusick return (NULLVP); 51539615Smckusick 51639615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 51739433Smckusick loop: 51839615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 51939615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 52039433Smckusick continue; 52139615Smckusick /* 52239615Smckusick * Alias, but not in use, so flush it out. 52339615Smckusick */ 52439809Smckusick if (vp->v_usecount == 0) { 52539615Smckusick vgone(vp); 52639615Smckusick goto loop; 52739615Smckusick } 52839633Smckusick if (vget(vp)) 52939633Smckusick goto loop; 53039433Smckusick break; 53139433Smckusick } 53239615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 53339615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 53439615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 53539615Smckusick nvp->v_rdev = nvp_rdev; 53639809Smckusick nvp->v_hashchain = vpp; 53739615Smckusick nvp->v_specnext = *vpp; 53842152Smckusick nvp->v_specflags = 0; 53939615Smckusick *vpp = nvp; 54040640Smckusick if (vp != NULL) { 54140640Smckusick nvp->v_flag |= VALIASED; 54240640Smckusick vp->v_flag |= VALIASED; 54340640Smckusick vput(vp); 54440640Smckusick } 54541400Smckusick return (NULLVP); 54639433Smckusick } 54739484Smckusick VOP_UNLOCK(vp); 54839484Smckusick vclean(vp, 0); 54939433Smckusick vp->v_op = nvp->v_op; 55039433Smckusick vp->v_tag = nvp->v_tag; 55139433Smckusick nvp->v_type = VNON; 55239433Smckusick insmntque(vp, mp); 55339433Smckusick return (vp); 55439433Smckusick } 55539433Smckusick 55639433Smckusick /* 55739433Smckusick * Grab a particular vnode from the free list, increment its 55839433Smckusick * reference count and lock it. The vnode lock bit is set the 55939433Smckusick * vnode is being eliminated in vgone. The process is awakened 56039433Smckusick * when the transition is completed, and an error returned to 56139433Smckusick * indicate that the vnode is no longer usable (possibly having 56239433Smckusick * been changed to a new file system type). 56339433Smckusick */ 56439397Smckusick vget(vp) 56539397Smckusick register struct vnode *vp; 56639397Smckusick { 56739397Smckusick register struct vnode *vq; 56839397Smckusick 56939433Smckusick if (vp->v_flag & VXLOCK) { 57039433Smckusick vp->v_flag |= VXWANT; 57139433Smckusick sleep((caddr_t)vp, PINOD); 57239433Smckusick return (1); 57339433Smckusick } 57439809Smckusick if (vp->v_usecount == 0) { 57539433Smckusick if (vq = vp->v_freef) 57639433Smckusick vq->v_freeb = vp->v_freeb; 57739433Smckusick else 57839433Smckusick vfreet = vp->v_freeb; 57939433Smckusick *vp->v_freeb = vq; 58039433Smckusick vp->v_freef = NULL; 58139433Smckusick vp->v_freeb = NULL; 58239433Smckusick } 58339397Smckusick VREF(vp); 58439433Smckusick VOP_LOCK(vp); 58539433Smckusick return (0); 58639397Smckusick } 58739397Smckusick 58839397Smckusick /* 58939397Smckusick * Vnode reference, just increment the count 59039397Smckusick */ 59139397Smckusick void vref(vp) 59239397Smckusick struct vnode *vp; 59339397Smckusick { 59439397Smckusick 59539809Smckusick vp->v_usecount++; 59639397Smckusick } 59739397Smckusick 59839397Smckusick /* 59939397Smckusick * vput(), just unlock and vrele() 60039397Smckusick */ 60139397Smckusick void vput(vp) 60239397Smckusick register struct vnode *vp; 60339397Smckusick { 60452416Storek 60539397Smckusick VOP_UNLOCK(vp); 60639397Smckusick vrele(vp); 60739397Smckusick } 60839397Smckusick 60939397Smckusick /* 61039397Smckusick * Vnode release. 61139397Smckusick * If count drops to zero, call inactive routine and return to freelist. 61239397Smckusick */ 61339397Smckusick void vrele(vp) 61439397Smckusick register struct vnode *vp; 61539397Smckusick { 61639397Smckusick 61750109Smckusick #ifdef DIAGNOSTIC 61839397Smckusick if (vp == NULL) 61939433Smckusick panic("vrele: null vp"); 62050109Smckusick #endif 62139809Smckusick vp->v_usecount--; 62239809Smckusick if (vp->v_usecount > 0) 62339397Smckusick return; 62450109Smckusick #ifdef DIAGNOSTIC 62550109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 62650109Smckusick vprint("vrele: bad ref count", vp); 62750109Smckusick panic("vrele: ref cnt"); 62850109Smckusick } 62950109Smckusick #endif 63055468Smckusick /* 63155468Smckusick * insert at tail of LRU list 63255468Smckusick */ 63355468Smckusick *vfreet = vp; 63455468Smckusick vp->v_freeb = vfreet; 63539433Smckusick vp->v_freef = NULL; 63639433Smckusick vfreet = &vp->v_freef; 63754442Smckusick VOP_INACTIVE(vp); 63839397Smckusick } 63939433Smckusick 64039433Smckusick /* 64139809Smckusick * Page or buffer structure gets a reference. 64239809Smckusick */ 64353312Smckusick void vhold(vp) 64439809Smckusick register struct vnode *vp; 64539809Smckusick { 64639809Smckusick 64739809Smckusick vp->v_holdcnt++; 64839809Smckusick } 64939809Smckusick 65039809Smckusick /* 65139809Smckusick * Page or buffer structure frees a reference. 65239809Smckusick */ 65353312Smckusick void holdrele(vp) 65439809Smckusick register struct vnode *vp; 65539809Smckusick { 65639809Smckusick 65739809Smckusick if (vp->v_holdcnt <= 0) 65839809Smckusick panic("holdrele: holdcnt"); 65939809Smckusick vp->v_holdcnt--; 66039809Smckusick } 66139809Smckusick 66239809Smckusick /* 66339509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 66439509Smckusick * 66539509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 66639509Smckusick * return error if any are found (nb: this is a user error, not a 66739509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 66839509Smckusick * that are found. 66939509Smckusick */ 67039509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 67139509Smckusick 67239509Smckusick vflush(mp, skipvp, flags) 67339509Smckusick struct mount *mp; 67439509Smckusick struct vnode *skipvp; 67539509Smckusick int flags; 67639509Smckusick { 67739509Smckusick register struct vnode *vp, *nvp; 67839509Smckusick int busy = 0; 67939509Smckusick 68041400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 68141300Smckusick panic("vflush: not busy"); 68241421Smckusick loop: 68341400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 68441421Smckusick if (vp->v_mount != mp) 68541421Smckusick goto loop; 68639509Smckusick nvp = vp->v_mountf; 68739509Smckusick /* 68839509Smckusick * Skip over a selected vnode. 68939509Smckusick */ 69039509Smckusick if (vp == skipvp) 69139509Smckusick continue; 69239509Smckusick /* 69341300Smckusick * Skip over a vnodes marked VSYSTEM. 69441300Smckusick */ 69541300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 69641300Smckusick continue; 69741300Smckusick /* 69857040Smckusick * If WRITECLOSE is set, only flush out regular file 69957040Smckusick * vnodes open for writing. 70057040Smckusick */ 70157040Smckusick if ((flags & WRITECLOSE) && 70257040Smckusick (vp->v_writecount == 0 || vp->v_type != VREG)) 70357040Smckusick continue; 70457040Smckusick /* 70539809Smckusick * With v_usecount == 0, all we need to do is clear 70639509Smckusick * out the vnode data structures and we are done. 70739509Smckusick */ 70839809Smckusick if (vp->v_usecount == 0) { 70939509Smckusick vgone(vp); 71039509Smckusick continue; 71139509Smckusick } 71239509Smckusick /* 71357040Smckusick * If FORCECLOSE is set, forcibly close the vnode. 71439509Smckusick * For block or character devices, revert to an 71539509Smckusick * anonymous device. For all other files, just kill them. 71639509Smckusick */ 71741300Smckusick if (flags & FORCECLOSE) { 71839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 71939509Smckusick vgone(vp); 72039509Smckusick } else { 72139509Smckusick vclean(vp, 0); 72253547Sheideman vp->v_op = spec_vnodeop_p; 72339509Smckusick insmntque(vp, (struct mount *)0); 72439509Smckusick } 72539509Smckusick continue; 72639509Smckusick } 72739509Smckusick if (busyprt) 72839667Smckusick vprint("vflush: busy vnode", vp); 72939509Smckusick busy++; 73039509Smckusick } 73139509Smckusick if (busy) 73239509Smckusick return (EBUSY); 73339509Smckusick return (0); 73439509Smckusick } 73539509Smckusick 73639509Smckusick /* 73739433Smckusick * Disassociate the underlying file system from a vnode. 73839433Smckusick */ 73954347Smckusick void 74054347Smckusick vclean(vp, flags) 74139433Smckusick register struct vnode *vp; 74245118Smckusick int flags; 74339433Smckusick { 74439484Smckusick int active; 74539433Smckusick 74639484Smckusick /* 74739484Smckusick * Check to see if the vnode is in use. 74839667Smckusick * If so we have to reference it before we clean it out 74939667Smckusick * so that its count cannot fall to zero and generate a 75039667Smckusick * race against ourselves to recycle it. 75139484Smckusick */ 75239809Smckusick if (active = vp->v_usecount) 75339484Smckusick VREF(vp); 75439484Smckusick /* 75556805Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 75656805Smckusick * have the object locked while it cleans it out. The VOP_LOCK 75756805Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 75856805Smckusick * For active vnodes, it ensures that no other activity can 75956805Smckusick * occur while the underlying object is being cleaned out. 76056805Smckusick */ 76156805Smckusick VOP_LOCK(vp); 76256805Smckusick /* 76339484Smckusick * Prevent the vnode from being recycled or 76439484Smckusick * brought into use while we clean it out. 76539484Smckusick */ 76639667Smckusick if (vp->v_flag & VXLOCK) 76739667Smckusick panic("vclean: deadlock"); 76839433Smckusick vp->v_flag |= VXLOCK; 76939433Smckusick /* 77056805Smckusick * Clean out any buffers associated with the vnode. 77139667Smckusick */ 77241300Smckusick if (flags & DOCLOSE) 77357792Smckusick vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); 77439667Smckusick /* 77556805Smckusick * Any other processes trying to obtain this lock must first 77656805Smckusick * wait for VXLOCK to clear, then call the new lock operation. 77739433Smckusick */ 77856805Smckusick VOP_UNLOCK(vp); 77939433Smckusick /* 78056805Smckusick * If purging an active vnode, it must be closed and 78156805Smckusick * deactivated before being reclaimed. 78239433Smckusick */ 78339484Smckusick if (active) { 78456805Smckusick if (flags & DOCLOSE) 78556805Smckusick VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL); 78656805Smckusick VOP_INACTIVE(vp); 78739433Smckusick } 78839433Smckusick /* 78939433Smckusick * Reclaim the vnode. 79039433Smckusick */ 79156805Smckusick if (VOP_RECLAIM(vp)) 79239433Smckusick panic("vclean: cannot reclaim"); 79339484Smckusick if (active) 79439484Smckusick vrele(vp); 79553580Sheideman 79639433Smckusick /* 79756805Smckusick * Done with purge, notify sleepers of the grim news. 79839433Smckusick */ 79956805Smckusick vp->v_op = dead_vnodeop_p; 80056805Smckusick vp->v_tag = VT_NON; 80139433Smckusick vp->v_flag &= ~VXLOCK; 80239433Smckusick if (vp->v_flag & VXWANT) { 80339433Smckusick vp->v_flag &= ~VXWANT; 80439433Smckusick wakeup((caddr_t)vp); 80539433Smckusick } 80639433Smckusick } 80739433Smckusick 80839433Smckusick /* 80939633Smckusick * Eliminate all activity associated with the requested vnode 81039633Smckusick * and with all vnodes aliased to the requested vnode. 81139633Smckusick */ 81239633Smckusick void vgoneall(vp) 81339633Smckusick register struct vnode *vp; 81439633Smckusick { 81539809Smckusick register struct vnode *vq; 81639633Smckusick 81740665Smckusick if (vp->v_flag & VALIASED) { 81840665Smckusick /* 81940665Smckusick * If a vgone (or vclean) is already in progress, 82040665Smckusick * wait until it is done and return. 82140665Smckusick */ 82240665Smckusick if (vp->v_flag & VXLOCK) { 82340665Smckusick vp->v_flag |= VXWANT; 82440665Smckusick sleep((caddr_t)vp, PINOD); 82540665Smckusick return; 82639633Smckusick } 82740665Smckusick /* 82840665Smckusick * Ensure that vp will not be vgone'd while we 82940665Smckusick * are eliminating its aliases. 83040665Smckusick */ 83140665Smckusick vp->v_flag |= VXLOCK; 83240665Smckusick while (vp->v_flag & VALIASED) { 83340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 83440665Smckusick if (vq->v_rdev != vp->v_rdev || 83540665Smckusick vq->v_type != vp->v_type || vp == vq) 83640665Smckusick continue; 83740665Smckusick vgone(vq); 83840665Smckusick break; 83940665Smckusick } 84040665Smckusick } 84140665Smckusick /* 84240665Smckusick * Remove the lock so that vgone below will 84340665Smckusick * really eliminate the vnode after which time 84440665Smckusick * vgone will awaken any sleepers. 84540665Smckusick */ 84640665Smckusick vp->v_flag &= ~VXLOCK; 84739633Smckusick } 84839633Smckusick vgone(vp); 84939633Smckusick } 85039633Smckusick 85139633Smckusick /* 85239433Smckusick * Eliminate all activity associated with a vnode 85339433Smckusick * in preparation for reuse. 85439433Smckusick */ 85539433Smckusick void vgone(vp) 85639433Smckusick register struct vnode *vp; 85739433Smckusick { 85839809Smckusick register struct vnode *vq; 85939615Smckusick struct vnode *vx; 86039433Smckusick 86139433Smckusick /* 86240548Smckusick * If a vgone (or vclean) is already in progress, 86340548Smckusick * wait until it is done and return. 86440548Smckusick */ 86540548Smckusick if (vp->v_flag & VXLOCK) { 86640548Smckusick vp->v_flag |= VXWANT; 86740548Smckusick sleep((caddr_t)vp, PINOD); 86840548Smckusick return; 86940548Smckusick } 87040548Smckusick /* 87139433Smckusick * Clean out the filesystem specific data. 87239433Smckusick */ 87341300Smckusick vclean(vp, DOCLOSE); 87439433Smckusick /* 87539433Smckusick * Delete from old mount point vnode list, if on one. 87639433Smckusick */ 87739433Smckusick if (vp->v_mountb) { 87839433Smckusick if (vq = vp->v_mountf) 87939433Smckusick vq->v_mountb = vp->v_mountb; 88039433Smckusick *vp->v_mountb = vq; 88139433Smckusick vp->v_mountf = NULL; 88239433Smckusick vp->v_mountb = NULL; 88352311Smckusick vp->v_mount = NULL; 88439433Smckusick } 88539433Smckusick /* 88639433Smckusick * If special device, remove it from special device alias list. 88739433Smckusick */ 88839433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 88939809Smckusick if (*vp->v_hashchain == vp) { 89039809Smckusick *vp->v_hashchain = vp->v_specnext; 89139433Smckusick } else { 89239809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 89339615Smckusick if (vq->v_specnext != vp) 89439433Smckusick continue; 89539615Smckusick vq->v_specnext = vp->v_specnext; 89639433Smckusick break; 89739433Smckusick } 89839615Smckusick if (vq == NULL) 89939433Smckusick panic("missing bdev"); 90039433Smckusick } 90139615Smckusick if (vp->v_flag & VALIASED) { 90252416Storek vx = NULL; 90339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90440108Smckusick if (vq->v_rdev != vp->v_rdev || 90540108Smckusick vq->v_type != vp->v_type) 90639615Smckusick continue; 90752416Storek if (vx) 90852416Storek break; 90939615Smckusick vx = vq; 91039615Smckusick } 91152416Storek if (vx == NULL) 91239615Smckusick panic("missing alias"); 91352416Storek if (vq == NULL) 91439615Smckusick vx->v_flag &= ~VALIASED; 91539615Smckusick vp->v_flag &= ~VALIASED; 91639615Smckusick } 91739615Smckusick FREE(vp->v_specinfo, M_VNODE); 91839615Smckusick vp->v_specinfo = NULL; 91939433Smckusick } 92039433Smckusick /* 92156932Smckusick * If it is on the freelist and not already at the head, 92256932Smckusick * move it to the head of the list. 92339433Smckusick */ 92456932Smckusick if (vp->v_freeb && vfreeh != vp) { 92539433Smckusick if (vq = vp->v_freef) 92639433Smckusick vq->v_freeb = vp->v_freeb; 92739433Smckusick else 92839433Smckusick vfreet = vp->v_freeb; 92939433Smckusick *vp->v_freeb = vq; 93039433Smckusick vp->v_freef = vfreeh; 93139433Smckusick vp->v_freeb = &vfreeh; 93239433Smckusick vfreeh->v_freeb = &vp->v_freef; 93339433Smckusick vfreeh = vp; 93439433Smckusick } 93539484Smckusick vp->v_type = VBAD; 93639433Smckusick } 93739633Smckusick 93839633Smckusick /* 93939821Smckusick * Lookup a vnode by device number. 94039821Smckusick */ 94139821Smckusick vfinddev(dev, type, vpp) 94239821Smckusick dev_t dev; 94339821Smckusick enum vtype type; 94439821Smckusick struct vnode **vpp; 94539821Smckusick { 94639821Smckusick register struct vnode *vp; 94739821Smckusick 94839821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 94939821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 95039821Smckusick continue; 95139821Smckusick *vpp = vp; 95239821Smckusick return (0); 95339821Smckusick } 95439821Smckusick return (1); 95539821Smckusick } 95639821Smckusick 95739821Smckusick /* 95839633Smckusick * Calculate the total number of references to a special device. 95939633Smckusick */ 96039633Smckusick vcount(vp) 96139633Smckusick register struct vnode *vp; 96239633Smckusick { 96339809Smckusick register struct vnode *vq; 96439633Smckusick int count; 96539633Smckusick 96639633Smckusick if ((vp->v_flag & VALIASED) == 0) 96739809Smckusick return (vp->v_usecount); 96839633Smckusick loop: 96939809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97040108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 97139633Smckusick continue; 97239633Smckusick /* 97339633Smckusick * Alias, but not in use, so flush it out. 97439633Smckusick */ 97539809Smckusick if (vq->v_usecount == 0) { 97639633Smckusick vgone(vq); 97739633Smckusick goto loop; 97839633Smckusick } 97939809Smckusick count += vq->v_usecount; 98039633Smckusick } 98139633Smckusick return (count); 98239633Smckusick } 98339667Smckusick 98439667Smckusick /* 98539667Smckusick * Print out a description of a vnode. 98639667Smckusick */ 98739667Smckusick static char *typename[] = 98840286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 98939667Smckusick 99039667Smckusick vprint(label, vp) 99139667Smckusick char *label; 99239667Smckusick register struct vnode *vp; 99339667Smckusick { 99439913Smckusick char buf[64]; 99539667Smckusick 99639667Smckusick if (label != NULL) 99739667Smckusick printf("%s: ", label); 99850109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 99950109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 100050109Smckusick vp->v_holdcnt); 100139913Smckusick buf[0] = '\0'; 100239913Smckusick if (vp->v_flag & VROOT) 100339913Smckusick strcat(buf, "|VROOT"); 100439913Smckusick if (vp->v_flag & VTEXT) 100539913Smckusick strcat(buf, "|VTEXT"); 100641300Smckusick if (vp->v_flag & VSYSTEM) 100741300Smckusick strcat(buf, "|VSYSTEM"); 100841300Smckusick if (vp->v_flag & VXLOCK) 100941300Smckusick strcat(buf, "|VXLOCK"); 101041300Smckusick if (vp->v_flag & VXWANT) 101141300Smckusick strcat(buf, "|VXWANT"); 101241300Smckusick if (vp->v_flag & VBWAIT) 101341300Smckusick strcat(buf, "|VBWAIT"); 101439913Smckusick if (vp->v_flag & VALIASED) 101539913Smckusick strcat(buf, "|VALIASED"); 101639913Smckusick if (buf[0] != '\0') 101739913Smckusick printf(" flags (%s)", &buf[1]); 101839913Smckusick printf("\n\t"); 101939667Smckusick VOP_PRINT(vp); 102039667Smckusick } 102141110Smarc 102249691Smckusick #ifdef DEBUG 102349691Smckusick /* 102449691Smckusick * List all of the locked vnodes in the system. 102549691Smckusick * Called when debugging the kernel. 102649691Smckusick */ 102749691Smckusick printlockedvnodes() 102849691Smckusick { 102949691Smckusick register struct mount *mp; 103049691Smckusick register struct vnode *vp; 103149691Smckusick 103249691Smckusick printf("Locked vnodes\n"); 103349691Smckusick mp = rootfs; 103449691Smckusick do { 103549691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 103649691Smckusick if (VOP_ISLOCKED(vp)) 103749691Smckusick vprint((char *)0, vp); 103849691Smckusick mp = mp->mnt_next; 103949691Smckusick } while (mp != rootfs); 104049691Smckusick } 104149691Smckusick #endif 104249691Smckusick 104341110Smarc int kinfo_vdebug = 1; 104441110Smarc int kinfo_vgetfailed; 104541110Smarc #define KINFO_VNODESLOP 10 104641110Smarc /* 104741110Smarc * Dump vnode list (via kinfo). 104841110Smarc * Copyout address of vnode followed by vnode. 104941110Smarc */ 105045118Smckusick /* ARGSUSED */ 105141110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 105245118Smckusick int op; 105341110Smarc char *where; 105445118Smckusick int *acopysize, arg, *aneeded; 105541110Smarc { 105641110Smarc register struct mount *mp = rootfs; 105741300Smckusick struct mount *omp; 105841110Smarc struct vnode *vp; 105941110Smarc register char *bp = where, *savebp; 106053818Smckusick char *ewhere; 106141110Smarc int error; 106241110Smarc 106341110Smarc #define VPTRSZ sizeof (struct vnode *) 106441110Smarc #define VNODESZ sizeof (struct vnode) 106541110Smarc if (where == NULL) { 106641110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 106741110Smarc return (0); 106841110Smarc } 106953818Smckusick ewhere = where + *acopysize; 107041110Smarc 107141110Smarc do { 107241300Smckusick if (vfs_busy(mp)) { 107341400Smckusick mp = mp->mnt_next; 107441300Smckusick continue; 107541300Smckusick } 107641110Smarc savebp = bp; 107741110Smarc again: 107841421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 107941422Smckusick /* 108041422Smckusick * Check that the vp is still associated with 108141422Smckusick * this filesystem. RACE: could have been 108241422Smckusick * recycled onto the same filesystem. 108341422Smckusick */ 108441421Smckusick if (vp->v_mount != mp) { 108541421Smckusick if (kinfo_vdebug) 108641421Smckusick printf("kinfo: vp changed\n"); 108741421Smckusick bp = savebp; 108841421Smckusick goto again; 108941421Smckusick } 109041110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 109141110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 109241110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 109341422Smckusick VNODESZ)))) 109441110Smarc return (error); 109541110Smarc bp += VPTRSZ + VNODESZ; 109641110Smarc } 109741300Smckusick omp = mp; 109841400Smckusick mp = mp->mnt_next; 109941300Smckusick vfs_unbusy(omp); 110041110Smarc } while (mp != rootfs); 110141110Smarc 110241110Smarc *aneeded = bp - where; 110341110Smarc if (bp > ewhere) 110441110Smarc *acopysize = ewhere - where; 110541110Smarc else 110641110Smarc *acopysize = bp - where; 110741110Smarc return (0); 110841110Smarc } 1109