137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*52311Smckusick * @(#)vfs_subr.c 7.67 (Berkeley) 02/03/92 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 1551460Sbostic #include <sys/proc.h> 1651460Sbostic #include <sys/mount.h> 1751460Sbostic #include <sys/time.h> 1851460Sbostic #include <sys/vnode.h> 1951460Sbostic #include <sys/specdev.h> 2051460Sbostic #include <sys/namei.h> 2151460Sbostic #include <sys/ucred.h> 2251460Sbostic #include <sys/buf.h> 2351460Sbostic #include <sys/errno.h> 2451460Sbostic #include <sys/malloc.h> 2537488Smckusick 2637488Smckusick /* 2737488Smckusick * Remove a mount point from the list of mounted filesystems. 2837488Smckusick * Unmount of the root is illegal. 2937488Smckusick */ 3037488Smckusick void 3137488Smckusick vfs_remove(mp) 3237488Smckusick register struct mount *mp; 3337488Smckusick { 3437488Smckusick 3537488Smckusick if (mp == rootfs) 3637488Smckusick panic("vfs_remove: unmounting root"); 3741400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3841400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3941400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 4037488Smckusick vfs_unlock(mp); 4137488Smckusick } 4237488Smckusick 4337488Smckusick /* 4437488Smckusick * Lock a filesystem. 4537488Smckusick * Used to prevent access to it while mounting and unmounting. 4637488Smckusick */ 4737488Smckusick vfs_lock(mp) 4837488Smckusick register struct mount *mp; 4937488Smckusick { 5037488Smckusick 5141400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5241400Smckusick mp->mnt_flag |= MNT_MWAIT; 5339045Smckusick sleep((caddr_t)mp, PVFS); 5439045Smckusick } 5541400Smckusick mp->mnt_flag |= MNT_MLOCK; 5637488Smckusick return (0); 5737488Smckusick } 5837488Smckusick 5937488Smckusick /* 6037488Smckusick * Unlock a locked filesystem. 6137488Smckusick * Panic if filesystem is not locked. 6237488Smckusick */ 6337488Smckusick void 6437488Smckusick vfs_unlock(mp) 6537488Smckusick register struct mount *mp; 6637488Smckusick { 6737488Smckusick 6841400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6941300Smckusick panic("vfs_unlock: not locked"); 7041400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7141400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7241400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7337488Smckusick wakeup((caddr_t)mp); 7437488Smckusick } 7537488Smckusick } 7637488Smckusick 7737488Smckusick /* 7841300Smckusick * Mark a mount point as busy. 7941300Smckusick * Used to synchronize access and to delay unmounting. 8041300Smckusick */ 8141300Smckusick vfs_busy(mp) 8241300Smckusick register struct mount *mp; 8341300Smckusick { 8441300Smckusick 8541400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8641400Smckusick mp->mnt_flag |= MNT_MPWANT; 8741400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8841300Smckusick } 8941419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 9041419Smckusick return (1); 9141400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9241300Smckusick return (0); 9341300Smckusick } 9441300Smckusick 9541300Smckusick /* 9641300Smckusick * Free a busy filesystem. 9741300Smckusick * Panic if filesystem is not busy. 9841300Smckusick */ 9941300Smckusick vfs_unbusy(mp) 10041300Smckusick register struct mount *mp; 10141300Smckusick { 10241300Smckusick 10341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10441300Smckusick panic("vfs_unbusy: not busy"); 10541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10941300Smckusick } 11041300Smckusick } 11141300Smckusick 11241300Smckusick /* 11337488Smckusick * Lookup a mount point by filesystem identifier. 11437488Smckusick */ 11537488Smckusick struct mount * 11637488Smckusick getvfs(fsid) 11737488Smckusick fsid_t *fsid; 11837488Smckusick { 11937488Smckusick register struct mount *mp; 12037488Smckusick 12138288Smckusick mp = rootfs; 12238288Smckusick do { 12341400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12441400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12538288Smckusick return (mp); 12637488Smckusick } 12741400Smckusick mp = mp->mnt_next; 12838288Smckusick } while (mp != rootfs); 12938288Smckusick return ((struct mount *)0); 13037488Smckusick } 13137488Smckusick 13237488Smckusick /* 13337488Smckusick * Set vnode attributes to VNOVAL 13437488Smckusick */ 13537488Smckusick void vattr_null(vap) 13637488Smckusick register struct vattr *vap; 13737488Smckusick { 13837488Smckusick 13937488Smckusick vap->va_type = VNON; 14052005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 14152005Smckusick #ifdef _NOQUAD 14252005Smckusick vap->va_size_rsv = vap->va_bytes_rsv = VNOVAL; 14352005Smckusick #endif 14437488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14552005Smckusick vap->va_fsid = vap->va_fileid = 14652005Smckusick vap->va_blocksize = vap->va_rdev = 14737488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14837488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14938258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 15038258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 15137488Smckusick } 15238265Smckusick 15338265Smckusick /* 15439397Smckusick * Routines having to do with the management of the vnode table. 15539397Smckusick */ 15639397Smckusick struct vnode *vfreeh, **vfreet; 15739447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 15839635Smckusick extern void vclean(); 15940883Smckusick long numvnodes; 16041363Smckusick struct vattr va_null; 16139397Smckusick 16239397Smckusick /* 16339433Smckusick * Initialize the vnode structures and initialize each file system type. 16439397Smckusick */ 16539433Smckusick vfsinit() 16639397Smckusick { 16739433Smckusick struct vfsops **vfsp; 16839397Smckusick 16939433Smckusick /* 17039433Smckusick * Initialize the vnode name cache 17139433Smckusick */ 17239433Smckusick nchinit(); 17339433Smckusick /* 17439433Smckusick * Initialize each file system type. 17539433Smckusick */ 17641363Smckusick vattr_null(&va_null); 17739433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 17839433Smckusick if (*vfsp == NULL) 17939433Smckusick continue; 18039433Smckusick (*(*vfsp)->vfs_init)(); 18139433Smckusick } 18239397Smckusick } 18339397Smckusick 18439397Smckusick /* 18539397Smckusick * Return the next vnode from the free list. 18639397Smckusick */ 18739397Smckusick getnewvnode(tag, mp, vops, vpp) 18839397Smckusick enum vtagtype tag; 18939397Smckusick struct mount *mp; 19039397Smckusick struct vnodeops *vops; 19139397Smckusick struct vnode **vpp; 19239397Smckusick { 19339397Smckusick register struct vnode *vp, *vq; 19439397Smckusick 19540883Smckusick if (numvnodes < desiredvnodes) { 19645118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 19745118Smckusick M_VNODE, M_WAITOK); 19840883Smckusick bzero((char *)vp, sizeof *vp); 19940883Smckusick numvnodes++; 20040883Smckusick } else { 20140883Smckusick if ((vp = vfreeh) == NULL) { 20240883Smckusick tablefull("vnode"); 20340883Smckusick *vpp = 0; 20440883Smckusick return (ENFILE); 20540883Smckusick } 20640883Smckusick if (vp->v_usecount) 20740883Smckusick panic("free vnode isn't"); 20840883Smckusick if (vq = vp->v_freef) 20940883Smckusick vq->v_freeb = &vfreeh; 21040883Smckusick else 21140883Smckusick vfreet = &vfreeh; 21240883Smckusick vfreeh = vq; 21340883Smckusick vp->v_freef = NULL; 21440883Smckusick vp->v_freeb = NULL; 21552190Smckusick vp->v_lease = NULL; 21640883Smckusick if (vp->v_type != VBAD) 21740883Smckusick vgone(vp); 21852006Smckusick if (vp->v_data) 21952006Smckusick panic("cleaned vnode isn't"); 22040883Smckusick vp->v_flag = 0; 22140883Smckusick vp->v_lastr = 0; 22240883Smckusick vp->v_socket = 0; 22339397Smckusick } 22439512Smckusick vp->v_type = VNON; 22539397Smckusick cache_purge(vp); 22639397Smckusick vp->v_tag = tag; 22739433Smckusick vp->v_op = vops; 22839397Smckusick insmntque(vp, mp); 22939397Smckusick VREF(vp); 23039397Smckusick *vpp = vp; 23139397Smckusick return (0); 23239397Smckusick } 23339397Smckusick 23439397Smckusick /* 23539397Smckusick * Move a vnode from one mount queue to another. 23639397Smckusick */ 23739397Smckusick insmntque(vp, mp) 23839397Smckusick register struct vnode *vp; 23939397Smckusick register struct mount *mp; 24039397Smckusick { 24149973Smckusick register struct vnode *vq; 24239397Smckusick 24339397Smckusick /* 24439397Smckusick * Delete from old mount point vnode list, if on one. 24539397Smckusick */ 24639397Smckusick if (vp->v_mountb) { 24739397Smckusick if (vq = vp->v_mountf) 24839397Smckusick vq->v_mountb = vp->v_mountb; 24939397Smckusick *vp->v_mountb = vq; 25039397Smckusick } 25139397Smckusick /* 25239397Smckusick * Insert into list of vnodes for the new mount point, if available. 25339397Smckusick */ 25439621Smckusick vp->v_mount = mp; 25539397Smckusick if (mp == NULL) { 25639397Smckusick vp->v_mountf = NULL; 25739397Smckusick vp->v_mountb = NULL; 25839397Smckusick return; 25939397Smckusick } 26049973Smckusick if (vq = mp->mnt_mounth) 26149973Smckusick vq->v_mountb = &vp->v_mountf; 26249973Smckusick vp->v_mountf = vq; 26349973Smckusick vp->v_mountb = &mp->mnt_mounth; 26449973Smckusick mp->mnt_mounth = vp; 26539397Smckusick } 26639397Smckusick 26739397Smckusick /* 26849232Smckusick * Make sure all write-behind blocks associated 26949232Smckusick * with mount point are flushed out (from sync). 27049232Smckusick */ 27149232Smckusick mntflushbuf(mountp, flags) 27249232Smckusick struct mount *mountp; 27349232Smckusick int flags; 27449232Smckusick { 27549232Smckusick register struct vnode *vp; 27649232Smckusick 27749232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 27849232Smckusick panic("mntflushbuf: not busy"); 27949232Smckusick loop: 28049232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 28149232Smckusick if (VOP_ISLOCKED(vp)) 28249232Smckusick continue; 28349232Smckusick if (vget(vp)) 28449232Smckusick goto loop; 28549232Smckusick vflushbuf(vp, flags); 28649232Smckusick vput(vp); 28749232Smckusick if (vp->v_mount != mountp) 28849232Smckusick goto loop; 28949232Smckusick } 29049232Smckusick } 29149232Smckusick 29249232Smckusick /* 29349232Smckusick * Flush all dirty buffers associated with a vnode. 29449232Smckusick */ 29549232Smckusick vflushbuf(vp, flags) 29649232Smckusick register struct vnode *vp; 29749232Smckusick int flags; 29849232Smckusick { 29949232Smckusick register struct buf *bp; 30049232Smckusick struct buf *nbp; 30149232Smckusick int s; 30249232Smckusick 30349232Smckusick loop: 30449232Smckusick s = splbio(); 30549232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 30649232Smckusick nbp = bp->b_blockf; 30749232Smckusick if ((bp->b_flags & B_BUSY)) 30849232Smckusick continue; 30949232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 31049232Smckusick panic("vflushbuf: not dirty"); 31149232Smckusick bremfree(bp); 31249232Smckusick bp->b_flags |= B_BUSY; 31349232Smckusick splx(s); 31449232Smckusick /* 31549232Smckusick * Wait for I/O associated with indirect blocks to complete, 31649232Smckusick * since there is no way to quickly wait for them below. 31749232Smckusick * NB: This is really specific to ufs, but is done here 31849232Smckusick * as it is easier and quicker. 31949232Smckusick */ 32049460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 32149232Smckusick (void) bawrite(bp); 32249460Smckusick else 32349232Smckusick (void) bwrite(bp); 32449460Smckusick goto loop; 32549232Smckusick } 32649232Smckusick splx(s); 32749232Smckusick if ((flags & B_SYNC) == 0) 32849232Smckusick return; 32949232Smckusick s = splbio(); 33049232Smckusick while (vp->v_numoutput) { 33149232Smckusick vp->v_flag |= VBWAIT; 33249232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 33349232Smckusick } 33449232Smckusick splx(s); 33549232Smckusick if (vp->v_dirtyblkhd) { 33649232Smckusick vprint("vflushbuf: dirty", vp); 33749232Smckusick goto loop; 33849232Smckusick } 33949232Smckusick } 34049232Smckusick 34149232Smckusick /* 34249232Smckusick * Update outstanding I/O count and do wakeup if requested. 34349232Smckusick */ 34449232Smckusick vwakeup(bp) 34549232Smckusick register struct buf *bp; 34649232Smckusick { 34749232Smckusick register struct vnode *vp; 34849232Smckusick 34949232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 35049232Smckusick if (vp = bp->b_vp) { 35149232Smckusick vp->v_numoutput--; 35249232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 35349232Smckusick if (vp->v_numoutput < 0) 35449232Smckusick panic("vwakeup: neg numoutput"); 35549232Smckusick vp->v_flag &= ~VBWAIT; 35649232Smckusick wakeup((caddr_t)&vp->v_numoutput); 35749232Smckusick } 35849232Smckusick } 35949232Smckusick } 36049232Smckusick 36149232Smckusick /* 36249232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 36349232Smckusick * 36449232Smckusick * Go through the list of vnodes associated with the file system; 36549232Smckusick * for each vnode invalidate any buffers that it holds. Normally 36649232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 36749232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 36849232Smckusick * returns the count of dirty buffers when it is finished. 36949232Smckusick */ 37049232Smckusick mntinvalbuf(mountp) 37149232Smckusick struct mount *mountp; 37249232Smckusick { 37349232Smckusick register struct vnode *vp; 37449232Smckusick int dirty = 0; 37549232Smckusick 37649232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 37749232Smckusick panic("mntinvalbuf: not busy"); 37849232Smckusick loop: 37949232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 38049232Smckusick if (vget(vp)) 38149232Smckusick goto loop; 38249232Smckusick dirty += vinvalbuf(vp, 1); 38349232Smckusick vput(vp); 38449232Smckusick if (vp->v_mount != mountp) 38549232Smckusick goto loop; 38649232Smckusick } 38749232Smckusick return (dirty); 38849232Smckusick } 38949232Smckusick 39049232Smckusick /* 39149232Smckusick * Flush out and invalidate all buffers associated with a vnode. 39249232Smckusick * Called with the underlying object locked. 39349232Smckusick */ 39449232Smckusick vinvalbuf(vp, save) 39549232Smckusick register struct vnode *vp; 39649232Smckusick int save; 39749232Smckusick { 39849232Smckusick register struct buf *bp; 39949232Smckusick struct buf *nbp, *blist; 40049232Smckusick int s, dirty = 0; 40149232Smckusick 40249232Smckusick for (;;) { 40349232Smckusick if (blist = vp->v_dirtyblkhd) 40449232Smckusick /* void */; 40549232Smckusick else if (blist = vp->v_cleanblkhd) 40649232Smckusick /* void */; 40749232Smckusick else 40849232Smckusick break; 40949232Smckusick for (bp = blist; bp; bp = nbp) { 41049232Smckusick nbp = bp->b_blockf; 41149232Smckusick s = splbio(); 41249232Smckusick if (bp->b_flags & B_BUSY) { 41349232Smckusick bp->b_flags |= B_WANTED; 41449232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 41549232Smckusick splx(s); 41649232Smckusick break; 41749232Smckusick } 41849232Smckusick bremfree(bp); 41949232Smckusick bp->b_flags |= B_BUSY; 42049232Smckusick splx(s); 42149232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 42251568Smckusick dirty++; 42351568Smckusick (void) VOP_BWRITE(bp); 42449232Smckusick break; 42549232Smckusick } 42649232Smckusick if (bp->b_vp != vp) 42749232Smckusick reassignbuf(bp, bp->b_vp); 42849232Smckusick else 42949232Smckusick bp->b_flags |= B_INVAL; 43049232Smckusick brelse(bp); 43149232Smckusick } 43249232Smckusick } 43349232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 43449232Smckusick panic("vinvalbuf: flush failed"); 43549232Smckusick return (dirty); 43649232Smckusick } 43749232Smckusick 43849232Smckusick /* 43949232Smckusick * Associate a buffer with a vnode. 44049232Smckusick */ 44149232Smckusick bgetvp(vp, bp) 44249232Smckusick register struct vnode *vp; 44349232Smckusick register struct buf *bp; 44449232Smckusick { 44549973Smckusick register struct vnode *vq; 44649973Smckusick register struct buf *bq; 44749232Smckusick 44849232Smckusick if (bp->b_vp) 44949232Smckusick panic("bgetvp: not free"); 45049232Smckusick VHOLD(vp); 45149232Smckusick bp->b_vp = vp; 45249232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 45349232Smckusick bp->b_dev = vp->v_rdev; 45449232Smckusick else 45549232Smckusick bp->b_dev = NODEV; 45649232Smckusick /* 45749232Smckusick * Insert onto list for new vnode. 45849232Smckusick */ 45949973Smckusick if (bq = vp->v_cleanblkhd) 46049973Smckusick bq->b_blockb = &bp->b_blockf; 46149973Smckusick bp->b_blockf = bq; 46249973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 46349973Smckusick vp->v_cleanblkhd = bp; 46449232Smckusick } 46549232Smckusick 46649232Smckusick /* 46749232Smckusick * Disassociate a buffer from a vnode. 46849232Smckusick */ 46949232Smckusick brelvp(bp) 47049232Smckusick register struct buf *bp; 47149232Smckusick { 47249232Smckusick struct buf *bq; 47349232Smckusick struct vnode *vp; 47449232Smckusick 47549232Smckusick if (bp->b_vp == (struct vnode *) 0) 47649232Smckusick panic("brelvp: NULL"); 47749232Smckusick /* 47849232Smckusick * Delete from old vnode list, if on one. 47949232Smckusick */ 48049232Smckusick if (bp->b_blockb) { 48149232Smckusick if (bq = bp->b_blockf) 48249232Smckusick bq->b_blockb = bp->b_blockb; 48349232Smckusick *bp->b_blockb = bq; 48449232Smckusick bp->b_blockf = NULL; 48549232Smckusick bp->b_blockb = NULL; 48649232Smckusick } 48749232Smckusick vp = bp->b_vp; 48849232Smckusick bp->b_vp = (struct vnode *) 0; 48949232Smckusick HOLDRELE(vp); 49049232Smckusick } 49149232Smckusick 49249232Smckusick /* 49349232Smckusick * Reassign a buffer from one vnode to another. 49449232Smckusick * Used to assign file specific control information 49549232Smckusick * (indirect blocks) to the vnode to which they belong. 49649232Smckusick */ 49749232Smckusick reassignbuf(bp, newvp) 49849232Smckusick register struct buf *bp; 49949232Smckusick register struct vnode *newvp; 50049232Smckusick { 50149232Smckusick register struct buf *bq, **listheadp; 50249232Smckusick 50349232Smckusick if (newvp == NULL) 50449232Smckusick panic("reassignbuf: NULL"); 50549232Smckusick /* 50649232Smckusick * Delete from old vnode list, if on one. 50749232Smckusick */ 50849232Smckusick if (bp->b_blockb) { 50949232Smckusick if (bq = bp->b_blockf) 51049232Smckusick bq->b_blockb = bp->b_blockb; 51149232Smckusick *bp->b_blockb = bq; 51249232Smckusick } 51349232Smckusick /* 51449232Smckusick * If dirty, put on list of dirty buffers; 51549232Smckusick * otherwise insert onto list of clean buffers. 51649232Smckusick */ 51749232Smckusick if (bp->b_flags & B_DELWRI) 51849232Smckusick listheadp = &newvp->v_dirtyblkhd; 51949232Smckusick else 52049232Smckusick listheadp = &newvp->v_cleanblkhd; 52149973Smckusick if (bq = *listheadp) 52249973Smckusick bq->b_blockb = &bp->b_blockf; 52349973Smckusick bp->b_blockf = bq; 52449973Smckusick bp->b_blockb = listheadp; 52549973Smckusick *listheadp = bp; 52649232Smckusick } 52749232Smckusick 52849232Smckusick /* 52939433Smckusick * Create a vnode for a block device. 53039433Smckusick * Used for root filesystem, argdev, and swap areas. 53139433Smckusick * Also used for memory file system special devices. 53239397Smckusick */ 53339433Smckusick bdevvp(dev, vpp) 53439433Smckusick dev_t dev; 53539433Smckusick struct vnode **vpp; 53639433Smckusick { 53739433Smckusick register struct vnode *vp; 53839433Smckusick struct vnode *nvp; 53939433Smckusick int error; 54039433Smckusick 54146989Smckusick if (dev == NODEV) 54246989Smckusick return (0); 54339447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 54439433Smckusick if (error) { 54539433Smckusick *vpp = 0; 54639433Smckusick return (error); 54739433Smckusick } 54839433Smckusick vp = nvp; 54939433Smckusick vp->v_type = VBLK; 55039615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 55139433Smckusick vput(vp); 55239433Smckusick vp = nvp; 55339433Smckusick } 55439433Smckusick *vpp = vp; 55539433Smckusick return (0); 55639433Smckusick } 55739433Smckusick 55839433Smckusick /* 55939433Smckusick * Check to see if the new vnode represents a special device 56039433Smckusick * for which we already have a vnode (either because of 56139433Smckusick * bdevvp() or because of a different vnode representing 56239433Smckusick * the same block device). If such an alias exists, deallocate 56339509Smckusick * the existing contents and return the aliased vnode. The 56439433Smckusick * caller is responsible for filling it with its new contents. 56539433Smckusick */ 56639433Smckusick struct vnode * 56739615Smckusick checkalias(nvp, nvp_rdev, mp) 56839433Smckusick register struct vnode *nvp; 56939615Smckusick dev_t nvp_rdev; 57039433Smckusick struct mount *mp; 57139433Smckusick { 57239433Smckusick register struct vnode *vp; 57339615Smckusick struct vnode **vpp; 57439433Smckusick 57539433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 57641400Smckusick return (NULLVP); 57739615Smckusick 57839615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 57939433Smckusick loop: 58039615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 58139615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 58239433Smckusick continue; 58339615Smckusick /* 58439615Smckusick * Alias, but not in use, so flush it out. 58539615Smckusick */ 58639809Smckusick if (vp->v_usecount == 0) { 58739615Smckusick vgone(vp); 58839615Smckusick goto loop; 58939615Smckusick } 59039633Smckusick if (vget(vp)) 59139633Smckusick goto loop; 59239433Smckusick break; 59339433Smckusick } 59439615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 59539615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 59639615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 59739615Smckusick nvp->v_rdev = nvp_rdev; 59839809Smckusick nvp->v_hashchain = vpp; 59939615Smckusick nvp->v_specnext = *vpp; 60042152Smckusick nvp->v_specflags = 0; 60139615Smckusick *vpp = nvp; 60240640Smckusick if (vp != NULL) { 60340640Smckusick nvp->v_flag |= VALIASED; 60440640Smckusick vp->v_flag |= VALIASED; 60540640Smckusick vput(vp); 60640640Smckusick } 60741400Smckusick return (NULLVP); 60839433Smckusick } 60939484Smckusick VOP_UNLOCK(vp); 61039484Smckusick vclean(vp, 0); 61139433Smckusick vp->v_op = nvp->v_op; 61239433Smckusick vp->v_tag = nvp->v_tag; 61339433Smckusick nvp->v_type = VNON; 61439433Smckusick insmntque(vp, mp); 61539433Smckusick return (vp); 61639433Smckusick } 61739433Smckusick 61839433Smckusick /* 61939433Smckusick * Grab a particular vnode from the free list, increment its 62039433Smckusick * reference count and lock it. The vnode lock bit is set the 62139433Smckusick * vnode is being eliminated in vgone. The process is awakened 62239433Smckusick * when the transition is completed, and an error returned to 62339433Smckusick * indicate that the vnode is no longer usable (possibly having 62439433Smckusick * been changed to a new file system type). 62539433Smckusick */ 62639397Smckusick vget(vp) 62739397Smckusick register struct vnode *vp; 62839397Smckusick { 62939397Smckusick register struct vnode *vq; 63039397Smckusick 63139433Smckusick if (vp->v_flag & VXLOCK) { 63239433Smckusick vp->v_flag |= VXWANT; 63339433Smckusick sleep((caddr_t)vp, PINOD); 63439433Smckusick return (1); 63539433Smckusick } 63639809Smckusick if (vp->v_usecount == 0) { 63739433Smckusick if (vq = vp->v_freef) 63839433Smckusick vq->v_freeb = vp->v_freeb; 63939433Smckusick else 64039433Smckusick vfreet = vp->v_freeb; 64139433Smckusick *vp->v_freeb = vq; 64239433Smckusick vp->v_freef = NULL; 64339433Smckusick vp->v_freeb = NULL; 64439433Smckusick } 64539397Smckusick VREF(vp); 64639433Smckusick VOP_LOCK(vp); 64739433Smckusick return (0); 64839397Smckusick } 64939397Smckusick 65039397Smckusick /* 65139397Smckusick * Vnode reference, just increment the count 65239397Smckusick */ 65339397Smckusick void vref(vp) 65439397Smckusick struct vnode *vp; 65539397Smckusick { 65639397Smckusick 65739809Smckusick vp->v_usecount++; 65839397Smckusick } 65939397Smckusick 66039397Smckusick /* 66139397Smckusick * vput(), just unlock and vrele() 66239397Smckusick */ 66339397Smckusick void vput(vp) 66439397Smckusick register struct vnode *vp; 66539397Smckusick { 66639397Smckusick VOP_UNLOCK(vp); 66739397Smckusick vrele(vp); 66839397Smckusick } 66939397Smckusick 67039397Smckusick /* 67139397Smckusick * Vnode release. 67239397Smckusick * If count drops to zero, call inactive routine and return to freelist. 67339397Smckusick */ 67439397Smckusick void vrele(vp) 67539397Smckusick register struct vnode *vp; 67639397Smckusick { 67748024Smckusick struct proc *p = curproc; /* XXX */ 67839397Smckusick 67950109Smckusick #ifdef DIAGNOSTIC 68039397Smckusick if (vp == NULL) 68139433Smckusick panic("vrele: null vp"); 68250109Smckusick #endif 68339809Smckusick vp->v_usecount--; 68439809Smckusick if (vp->v_usecount > 0) 68539397Smckusick return; 68650109Smckusick #ifdef DIAGNOSTIC 68750109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 68850109Smckusick vprint("vrele: bad ref count", vp); 68950109Smckusick panic("vrele: ref cnt"); 69050109Smckusick } 69150109Smckusick #endif 69241400Smckusick if (vfreeh == NULLVP) { 69339397Smckusick /* 69439397Smckusick * insert into empty list 69539397Smckusick */ 69639397Smckusick vfreeh = vp; 69739397Smckusick vp->v_freeb = &vfreeh; 69839397Smckusick } else { 69939397Smckusick /* 70039397Smckusick * insert at tail of list 70139397Smckusick */ 70239397Smckusick *vfreet = vp; 70339397Smckusick vp->v_freeb = vfreet; 70439397Smckusick } 70539433Smckusick vp->v_freef = NULL; 70639433Smckusick vfreet = &vp->v_freef; 70748024Smckusick VOP_INACTIVE(vp, p); 70839397Smckusick } 70939433Smckusick 71039433Smckusick /* 71139809Smckusick * Page or buffer structure gets a reference. 71239809Smckusick */ 71339809Smckusick vhold(vp) 71439809Smckusick register struct vnode *vp; 71539809Smckusick { 71639809Smckusick 71739809Smckusick vp->v_holdcnt++; 71839809Smckusick } 71939809Smckusick 72039809Smckusick /* 72139809Smckusick * Page or buffer structure frees a reference. 72239809Smckusick */ 72339809Smckusick holdrele(vp) 72439809Smckusick register struct vnode *vp; 72539809Smckusick { 72639809Smckusick 72739809Smckusick if (vp->v_holdcnt <= 0) 72839809Smckusick panic("holdrele: holdcnt"); 72939809Smckusick vp->v_holdcnt--; 73039809Smckusick } 73139809Smckusick 73239809Smckusick /* 73339509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 73439509Smckusick * 73539509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 73639509Smckusick * return error if any are found (nb: this is a user error, not a 73739509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 73839509Smckusick * that are found. 73939509Smckusick */ 74039509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 74139509Smckusick 74239509Smckusick vflush(mp, skipvp, flags) 74339509Smckusick struct mount *mp; 74439509Smckusick struct vnode *skipvp; 74539509Smckusick int flags; 74639509Smckusick { 74739509Smckusick register struct vnode *vp, *nvp; 74839509Smckusick int busy = 0; 74939509Smckusick 75041400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 75141300Smckusick panic("vflush: not busy"); 75241421Smckusick loop: 75341400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 75441421Smckusick if (vp->v_mount != mp) 75541421Smckusick goto loop; 75639509Smckusick nvp = vp->v_mountf; 75739509Smckusick /* 75839509Smckusick * Skip over a selected vnode. 75939509Smckusick */ 76039509Smckusick if (vp == skipvp) 76139509Smckusick continue; 76239509Smckusick /* 76341300Smckusick * Skip over a vnodes marked VSYSTEM. 76441300Smckusick */ 76541300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 76641300Smckusick continue; 76741300Smckusick /* 76839809Smckusick * With v_usecount == 0, all we need to do is clear 76939509Smckusick * out the vnode data structures and we are done. 77039509Smckusick */ 77139809Smckusick if (vp->v_usecount == 0) { 77239509Smckusick vgone(vp); 77339509Smckusick continue; 77439509Smckusick } 77539509Smckusick /* 77639509Smckusick * For block or character devices, revert to an 77739509Smckusick * anonymous device. For all other files, just kill them. 77839509Smckusick */ 77941300Smckusick if (flags & FORCECLOSE) { 78039509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 78139509Smckusick vgone(vp); 78239509Smckusick } else { 78339509Smckusick vclean(vp, 0); 78439509Smckusick vp->v_op = &spec_vnodeops; 78539509Smckusick insmntque(vp, (struct mount *)0); 78639509Smckusick } 78739509Smckusick continue; 78839509Smckusick } 78939509Smckusick if (busyprt) 79039667Smckusick vprint("vflush: busy vnode", vp); 79139509Smckusick busy++; 79239509Smckusick } 79339509Smckusick if (busy) 79439509Smckusick return (EBUSY); 79539509Smckusick return (0); 79639509Smckusick } 79739509Smckusick 79839509Smckusick /* 79939433Smckusick * Disassociate the underlying file system from a vnode. 80039433Smckusick */ 80141300Smckusick void vclean(vp, flags) 80239433Smckusick register struct vnode *vp; 80345118Smckusick int flags; 80439433Smckusick { 80539433Smckusick struct vnodeops *origops; 80639484Smckusick int active; 80748024Smckusick struct proc *p = curproc; /* XXX */ 80839433Smckusick 80939484Smckusick /* 81039484Smckusick * Check to see if the vnode is in use. 81139667Smckusick * If so we have to reference it before we clean it out 81239667Smckusick * so that its count cannot fall to zero and generate a 81339667Smckusick * race against ourselves to recycle it. 81439484Smckusick */ 81539809Smckusick if (active = vp->v_usecount) 81639484Smckusick VREF(vp); 81739484Smckusick /* 81839484Smckusick * Prevent the vnode from being recycled or 81939484Smckusick * brought into use while we clean it out. 82039484Smckusick */ 82139667Smckusick if (vp->v_flag & VXLOCK) 82239667Smckusick panic("vclean: deadlock"); 82339433Smckusick vp->v_flag |= VXLOCK; 82439433Smckusick /* 82539667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 82639667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 82739667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 82839667Smckusick * For active vnodes, it ensures that no other activity can 82939667Smckusick * occur while the buffer list is being cleaned out. 83039667Smckusick */ 83139667Smckusick VOP_LOCK(vp); 83241300Smckusick if (flags & DOCLOSE) 83339667Smckusick vinvalbuf(vp, 1); 83439667Smckusick /* 83539433Smckusick * Prevent any further operations on the vnode from 83639433Smckusick * being passed through to the old file system. 83739433Smckusick */ 83839433Smckusick origops = vp->v_op; 83939433Smckusick vp->v_op = &dead_vnodeops; 84039433Smckusick vp->v_tag = VT_NON; 84139433Smckusick /* 84239484Smckusick * If purging an active vnode, it must be unlocked, closed, 84339484Smckusick * and deactivated before being reclaimed. 84439433Smckusick */ 84549761Smckusick (*(origops->vop_unlock))(vp); 84639484Smckusick if (active) { 84741300Smckusick if (flags & DOCLOSE) 84849761Smckusick (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 84949761Smckusick (*(origops->vop_inactive))(vp, p); 85039433Smckusick } 85139433Smckusick /* 85239433Smckusick * Reclaim the vnode. 85339433Smckusick */ 85449761Smckusick if ((*(origops->vop_reclaim))(vp)) 85539433Smckusick panic("vclean: cannot reclaim"); 85639484Smckusick if (active) 85739484Smckusick vrele(vp); 85839433Smckusick /* 85939433Smckusick * Done with purge, notify sleepers in vget of the grim news. 86039433Smckusick */ 86139433Smckusick vp->v_flag &= ~VXLOCK; 86239433Smckusick if (vp->v_flag & VXWANT) { 86339433Smckusick vp->v_flag &= ~VXWANT; 86439433Smckusick wakeup((caddr_t)vp); 86539433Smckusick } 86639433Smckusick } 86739433Smckusick 86839433Smckusick /* 86939633Smckusick * Eliminate all activity associated with the requested vnode 87039633Smckusick * and with all vnodes aliased to the requested vnode. 87139633Smckusick */ 87239633Smckusick void vgoneall(vp) 87339633Smckusick register struct vnode *vp; 87439633Smckusick { 87539809Smckusick register struct vnode *vq; 87639633Smckusick 87740665Smckusick if (vp->v_flag & VALIASED) { 87840665Smckusick /* 87940665Smckusick * If a vgone (or vclean) is already in progress, 88040665Smckusick * wait until it is done and return. 88140665Smckusick */ 88240665Smckusick if (vp->v_flag & VXLOCK) { 88340665Smckusick vp->v_flag |= VXWANT; 88440665Smckusick sleep((caddr_t)vp, PINOD); 88540665Smckusick return; 88639633Smckusick } 88740665Smckusick /* 88840665Smckusick * Ensure that vp will not be vgone'd while we 88940665Smckusick * are eliminating its aliases. 89040665Smckusick */ 89140665Smckusick vp->v_flag |= VXLOCK; 89240665Smckusick while (vp->v_flag & VALIASED) { 89340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 89440665Smckusick if (vq->v_rdev != vp->v_rdev || 89540665Smckusick vq->v_type != vp->v_type || vp == vq) 89640665Smckusick continue; 89740665Smckusick vgone(vq); 89840665Smckusick break; 89940665Smckusick } 90040665Smckusick } 90140665Smckusick /* 90240665Smckusick * Remove the lock so that vgone below will 90340665Smckusick * really eliminate the vnode after which time 90440665Smckusick * vgone will awaken any sleepers. 90540665Smckusick */ 90640665Smckusick vp->v_flag &= ~VXLOCK; 90739633Smckusick } 90839633Smckusick vgone(vp); 90939633Smckusick } 91039633Smckusick 91139633Smckusick /* 91239433Smckusick * Eliminate all activity associated with a vnode 91339433Smckusick * in preparation for reuse. 91439433Smckusick */ 91539433Smckusick void vgone(vp) 91639433Smckusick register struct vnode *vp; 91739433Smckusick { 91839809Smckusick register struct vnode *vq; 91939615Smckusick struct vnode *vx; 92039615Smckusick long count; 92139433Smckusick 92239433Smckusick /* 92340548Smckusick * If a vgone (or vclean) is already in progress, 92440548Smckusick * wait until it is done and return. 92540548Smckusick */ 92640548Smckusick if (vp->v_flag & VXLOCK) { 92740548Smckusick vp->v_flag |= VXWANT; 92840548Smckusick sleep((caddr_t)vp, PINOD); 92940548Smckusick return; 93040548Smckusick } 93140548Smckusick /* 93239433Smckusick * Clean out the filesystem specific data. 93339433Smckusick */ 93441300Smckusick vclean(vp, DOCLOSE); 93539433Smckusick /* 93639433Smckusick * Delete from old mount point vnode list, if on one. 93739433Smckusick */ 93839433Smckusick if (vp->v_mountb) { 93939433Smckusick if (vq = vp->v_mountf) 94039433Smckusick vq->v_mountb = vp->v_mountb; 94139433Smckusick *vp->v_mountb = vq; 94239433Smckusick vp->v_mountf = NULL; 94339433Smckusick vp->v_mountb = NULL; 944*52311Smckusick vp->v_mount = NULL; 94539433Smckusick } 94639433Smckusick /* 94739433Smckusick * If special device, remove it from special device alias list. 94839433Smckusick */ 94939433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 95039809Smckusick if (*vp->v_hashchain == vp) { 95139809Smckusick *vp->v_hashchain = vp->v_specnext; 95239433Smckusick } else { 95339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 95439615Smckusick if (vq->v_specnext != vp) 95539433Smckusick continue; 95639615Smckusick vq->v_specnext = vp->v_specnext; 95739433Smckusick break; 95839433Smckusick } 95939615Smckusick if (vq == NULL) 96039433Smckusick panic("missing bdev"); 96139433Smckusick } 96239615Smckusick if (vp->v_flag & VALIASED) { 96339809Smckusick count = 0; 96439809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 96540108Smckusick if (vq->v_rdev != vp->v_rdev || 96640108Smckusick vq->v_type != vp->v_type) 96739615Smckusick continue; 96839615Smckusick count++; 96939615Smckusick vx = vq; 97039615Smckusick } 97139615Smckusick if (count == 0) 97239615Smckusick panic("missing alias"); 97339615Smckusick if (count == 1) 97439615Smckusick vx->v_flag &= ~VALIASED; 97539615Smckusick vp->v_flag &= ~VALIASED; 97639615Smckusick } 97739615Smckusick FREE(vp->v_specinfo, M_VNODE); 97839615Smckusick vp->v_specinfo = NULL; 97939433Smckusick } 98039433Smckusick /* 98139433Smckusick * If it is on the freelist, move it to the head of the list. 98239433Smckusick */ 98339433Smckusick if (vp->v_freeb) { 98439433Smckusick if (vq = vp->v_freef) 98539433Smckusick vq->v_freeb = vp->v_freeb; 98639433Smckusick else 98739433Smckusick vfreet = vp->v_freeb; 98839433Smckusick *vp->v_freeb = vq; 98939433Smckusick vp->v_freef = vfreeh; 99039433Smckusick vp->v_freeb = &vfreeh; 99139433Smckusick vfreeh->v_freeb = &vp->v_freef; 99239433Smckusick vfreeh = vp; 99339433Smckusick } 99439484Smckusick vp->v_type = VBAD; 99539433Smckusick } 99639633Smckusick 99739633Smckusick /* 99839821Smckusick * Lookup a vnode by device number. 99939821Smckusick */ 100039821Smckusick vfinddev(dev, type, vpp) 100139821Smckusick dev_t dev; 100239821Smckusick enum vtype type; 100339821Smckusick struct vnode **vpp; 100439821Smckusick { 100539821Smckusick register struct vnode *vp; 100639821Smckusick 100739821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 100839821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 100939821Smckusick continue; 101039821Smckusick *vpp = vp; 101139821Smckusick return (0); 101239821Smckusick } 101339821Smckusick return (1); 101439821Smckusick } 101539821Smckusick 101639821Smckusick /* 101739633Smckusick * Calculate the total number of references to a special device. 101839633Smckusick */ 101939633Smckusick vcount(vp) 102039633Smckusick register struct vnode *vp; 102139633Smckusick { 102239809Smckusick register struct vnode *vq; 102339633Smckusick int count; 102439633Smckusick 102539633Smckusick if ((vp->v_flag & VALIASED) == 0) 102639809Smckusick return (vp->v_usecount); 102739633Smckusick loop: 102839809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 102940108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 103039633Smckusick continue; 103139633Smckusick /* 103239633Smckusick * Alias, but not in use, so flush it out. 103339633Smckusick */ 103439809Smckusick if (vq->v_usecount == 0) { 103539633Smckusick vgone(vq); 103639633Smckusick goto loop; 103739633Smckusick } 103839809Smckusick count += vq->v_usecount; 103939633Smckusick } 104039633Smckusick return (count); 104139633Smckusick } 104239667Smckusick 104339667Smckusick /* 104439667Smckusick * Print out a description of a vnode. 104539667Smckusick */ 104639667Smckusick static char *typename[] = 104740286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 104839667Smckusick 104939667Smckusick vprint(label, vp) 105039667Smckusick char *label; 105139667Smckusick register struct vnode *vp; 105239667Smckusick { 105339913Smckusick char buf[64]; 105439667Smckusick 105539667Smckusick if (label != NULL) 105639667Smckusick printf("%s: ", label); 105750109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 105850109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 105950109Smckusick vp->v_holdcnt); 106039913Smckusick buf[0] = '\0'; 106139913Smckusick if (vp->v_flag & VROOT) 106239913Smckusick strcat(buf, "|VROOT"); 106339913Smckusick if (vp->v_flag & VTEXT) 106439913Smckusick strcat(buf, "|VTEXT"); 106541300Smckusick if (vp->v_flag & VSYSTEM) 106641300Smckusick strcat(buf, "|VSYSTEM"); 106741300Smckusick if (vp->v_flag & VXLOCK) 106841300Smckusick strcat(buf, "|VXLOCK"); 106941300Smckusick if (vp->v_flag & VXWANT) 107041300Smckusick strcat(buf, "|VXWANT"); 107141300Smckusick if (vp->v_flag & VBWAIT) 107241300Smckusick strcat(buf, "|VBWAIT"); 107339913Smckusick if (vp->v_flag & VALIASED) 107439913Smckusick strcat(buf, "|VALIASED"); 107539913Smckusick if (buf[0] != '\0') 107639913Smckusick printf(" flags (%s)", &buf[1]); 107739913Smckusick printf("\n\t"); 107839667Smckusick VOP_PRINT(vp); 107939667Smckusick } 108041110Smarc 108149691Smckusick #ifdef DEBUG 108249691Smckusick /* 108349691Smckusick * List all of the locked vnodes in the system. 108449691Smckusick * Called when debugging the kernel. 108549691Smckusick */ 108649691Smckusick printlockedvnodes() 108749691Smckusick { 108849691Smckusick register struct mount *mp; 108949691Smckusick register struct vnode *vp; 109049691Smckusick 109149691Smckusick printf("Locked vnodes\n"); 109249691Smckusick mp = rootfs; 109349691Smckusick do { 109449691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 109549691Smckusick if (VOP_ISLOCKED(vp)) 109649691Smckusick vprint((char *)0, vp); 109749691Smckusick mp = mp->mnt_next; 109849691Smckusick } while (mp != rootfs); 109949691Smckusick } 110049691Smckusick #endif 110149691Smckusick 110241110Smarc int kinfo_vdebug = 1; 110341110Smarc int kinfo_vgetfailed; 110441110Smarc #define KINFO_VNODESLOP 10 110541110Smarc /* 110641110Smarc * Dump vnode list (via kinfo). 110741110Smarc * Copyout address of vnode followed by vnode. 110841110Smarc */ 110945118Smckusick /* ARGSUSED */ 111041110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 111145118Smckusick int op; 111241110Smarc char *where; 111345118Smckusick int *acopysize, arg, *aneeded; 111441110Smarc { 111541110Smarc register struct mount *mp = rootfs; 111641300Smckusick struct mount *omp; 111741110Smarc struct vnode *vp; 111841110Smarc register char *bp = where, *savebp; 111941110Smarc char *ewhere = where + *acopysize; 112041110Smarc int error; 112141110Smarc 112241110Smarc #define VPTRSZ sizeof (struct vnode *) 112341110Smarc #define VNODESZ sizeof (struct vnode) 112441110Smarc if (where == NULL) { 112541110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 112641110Smarc return (0); 112741110Smarc } 112841110Smarc 112941110Smarc do { 113041300Smckusick if (vfs_busy(mp)) { 113141400Smckusick mp = mp->mnt_next; 113241300Smckusick continue; 113341300Smckusick } 113441110Smarc savebp = bp; 113541110Smarc again: 113641421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 113741422Smckusick /* 113841422Smckusick * Check that the vp is still associated with 113941422Smckusick * this filesystem. RACE: could have been 114041422Smckusick * recycled onto the same filesystem. 114141422Smckusick */ 114241421Smckusick if (vp->v_mount != mp) { 114341421Smckusick if (kinfo_vdebug) 114441421Smckusick printf("kinfo: vp changed\n"); 114541421Smckusick bp = savebp; 114641421Smckusick goto again; 114741421Smckusick } 114841110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 114941110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 115041110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 115141422Smckusick VNODESZ)))) 115241110Smarc return (error); 115341110Smarc bp += VPTRSZ + VNODESZ; 115441110Smarc } 115541300Smckusick omp = mp; 115641400Smckusick mp = mp->mnt_next; 115741300Smckusick vfs_unbusy(omp); 115841110Smarc } while (mp != rootfs); 115941110Smarc 116041110Smarc *aneeded = bp - where; 116141110Smarc if (bp > ewhere) 116241110Smarc *acopysize = ewhere - where; 116341110Smarc else 116441110Smarc *acopysize = bp - where; 116541110Smarc return (0); 116641110Smarc } 1167