137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*53829Spendry * @(#)vfs_subr.c 7.78 (Berkeley) 06/03/92 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 15*53829Spendry #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 /* 144*53829Spendry * Get a new unique fsid 145*53829Spendry */ 146*53829Spendry void 147*53829Spendry getnewfsid(mp, mtype) 148*53829Spendry struct mount *mp; 149*53829Spendry int mtype; 150*53829Spendry { 151*53829Spendry static u_short xxxfs_mntid; 152*53829Spendry 153*53829Spendry fsid_t tfsid; 154*53829Spendry 155*53829Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0); /* XXX */ 156*53829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 157*53829Spendry if (xxxfs_mntid == 0) 158*53829Spendry ++xxxfs_mntid; 159*53829Spendry tfsid.val[0] = makedev(nblkdev, xxxfs_mntid); 160*53829Spendry tfsid.val[1] = mtype; 161*53829Spendry while (getvfs(&tfsid)) { 162*53829Spendry tfsid.val[0]++; 163*53829Spendry xxxfs_mntid++; 164*53829Spendry } 165*53829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 166*53829Spendry } 167*53829Spendry 168*53829Spendry /* 16937488Smckusick * Set vnode attributes to VNOVAL 17037488Smckusick */ 17137488Smckusick void vattr_null(vap) 17237488Smckusick register struct vattr *vap; 17337488Smckusick { 17437488Smckusick 17537488Smckusick vap->va_type = VNON; 17652005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 17752005Smckusick #ifdef _NOQUAD 17852005Smckusick vap->va_size_rsv = vap->va_bytes_rsv = VNOVAL; 17952005Smckusick #endif 18037488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18152005Smckusick vap->va_fsid = vap->va_fileid = 18252005Smckusick vap->va_blocksize = vap->va_rdev = 18337488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 18437488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 18538258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 18638258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 18737488Smckusick } 18838265Smckusick 18938265Smckusick /* 19039397Smckusick * Routines having to do with the management of the vnode table. 19139397Smckusick */ 19253493Sheideman extern struct vnode *vfreeh, **vfreet; 19353547Sheideman extern int (**dead_vnodeop_p)(); 19453547Sheideman extern int (**spec_vnodeop_p)(); 19539635Smckusick extern void vclean(); 19640883Smckusick long numvnodes; 19753493Sheideman extern struct vattr va_null; 19839397Smckusick 19939397Smckusick /* 20039397Smckusick * Return the next vnode from the free list. 20139397Smckusick */ 20239397Smckusick getnewvnode(tag, mp, vops, vpp) 20339397Smckusick enum vtagtype tag; 20439397Smckusick struct mount *mp; 20553495Sheideman int (**vops)(); 20639397Smckusick struct vnode **vpp; 20739397Smckusick { 20839397Smckusick register struct vnode *vp, *vq; 20939397Smckusick 21040883Smckusick if (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 * Make sure all write-behind blocks associated 28449232Smckusick * with mount point are flushed out (from sync). 28549232Smckusick */ 28649232Smckusick mntflushbuf(mountp, flags) 28749232Smckusick struct mount *mountp; 28849232Smckusick int flags; 28949232Smckusick { 29053547Sheideman USES_VOP_ISLOCKED; 29149232Smckusick register struct vnode *vp; 29249232Smckusick 29349232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 29449232Smckusick panic("mntflushbuf: not busy"); 29549232Smckusick loop: 29649232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 29749232Smckusick if (VOP_ISLOCKED(vp)) 29849232Smckusick continue; 29949232Smckusick if (vget(vp)) 30049232Smckusick goto loop; 30149232Smckusick vflushbuf(vp, flags); 30249232Smckusick vput(vp); 30349232Smckusick if (vp->v_mount != mountp) 30449232Smckusick goto loop; 30549232Smckusick } 30649232Smckusick } 30749232Smckusick 30849232Smckusick /* 30949232Smckusick * Flush all dirty buffers associated with a vnode. 31049232Smckusick */ 31149232Smckusick vflushbuf(vp, flags) 31249232Smckusick register struct vnode *vp; 31349232Smckusick int flags; 31449232Smckusick { 31549232Smckusick register struct buf *bp; 31649232Smckusick struct buf *nbp; 31749232Smckusick int s; 31849232Smckusick 31949232Smckusick loop: 32049232Smckusick s = splbio(); 32149232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 32249232Smckusick nbp = bp->b_blockf; 32349232Smckusick if ((bp->b_flags & B_BUSY)) 32449232Smckusick continue; 32549232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 32649232Smckusick panic("vflushbuf: not dirty"); 32749232Smckusick bremfree(bp); 32849232Smckusick bp->b_flags |= B_BUSY; 32949232Smckusick splx(s); 33049232Smckusick /* 33149232Smckusick * Wait for I/O associated with indirect blocks to complete, 33249232Smckusick * since there is no way to quickly wait for them below. 33349232Smckusick * NB: This is really specific to ufs, but is done here 33449232Smckusick * as it is easier and quicker. 33549232Smckusick */ 33649460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 33749232Smckusick (void) bawrite(bp); 33849460Smckusick else 33949232Smckusick (void) bwrite(bp); 34049460Smckusick goto loop; 34149232Smckusick } 34249232Smckusick splx(s); 34349232Smckusick if ((flags & B_SYNC) == 0) 34449232Smckusick return; 34549232Smckusick s = splbio(); 34649232Smckusick while (vp->v_numoutput) { 34749232Smckusick vp->v_flag |= VBWAIT; 34849232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 34949232Smckusick } 35049232Smckusick splx(s); 35149232Smckusick if (vp->v_dirtyblkhd) { 35249232Smckusick vprint("vflushbuf: dirty", vp); 35349232Smckusick goto loop; 35449232Smckusick } 35549232Smckusick } 35649232Smckusick 35749232Smckusick /* 35849232Smckusick * Update outstanding I/O count and do wakeup if requested. 35949232Smckusick */ 36049232Smckusick vwakeup(bp) 36149232Smckusick register struct buf *bp; 36249232Smckusick { 36349232Smckusick register struct vnode *vp; 36449232Smckusick 36549232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 36649232Smckusick if (vp = bp->b_vp) { 36749232Smckusick vp->v_numoutput--; 36849232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 36949232Smckusick if (vp->v_numoutput < 0) 37049232Smckusick panic("vwakeup: neg numoutput"); 37149232Smckusick vp->v_flag &= ~VBWAIT; 37249232Smckusick wakeup((caddr_t)&vp->v_numoutput); 37349232Smckusick } 37449232Smckusick } 37549232Smckusick } 37649232Smckusick 37749232Smckusick /* 37849232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 37949232Smckusick * 38049232Smckusick * Go through the list of vnodes associated with the file system; 38149232Smckusick * for each vnode invalidate any buffers that it holds. Normally 38249232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 38349232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 38449232Smckusick * returns the count of dirty buffers when it is finished. 38549232Smckusick */ 38649232Smckusick mntinvalbuf(mountp) 38749232Smckusick struct mount *mountp; 38849232Smckusick { 38949232Smckusick register struct vnode *vp; 39049232Smckusick int dirty = 0; 39149232Smckusick 39249232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 39349232Smckusick panic("mntinvalbuf: not busy"); 39449232Smckusick loop: 39549232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 39649232Smckusick if (vget(vp)) 39749232Smckusick goto loop; 39849232Smckusick dirty += vinvalbuf(vp, 1); 39949232Smckusick vput(vp); 40049232Smckusick if (vp->v_mount != mountp) 40149232Smckusick goto loop; 40249232Smckusick } 40349232Smckusick return (dirty); 40449232Smckusick } 40549232Smckusick 40649232Smckusick /* 40749232Smckusick * Flush out and invalidate all buffers associated with a vnode. 40849232Smckusick * Called with the underlying object locked. 40949232Smckusick */ 41049232Smckusick vinvalbuf(vp, save) 41149232Smckusick register struct vnode *vp; 41249232Smckusick int save; 41349232Smckusick { 41453547Sheideman USES_VOP_BWRITE; 41549232Smckusick register struct buf *bp; 41649232Smckusick struct buf *nbp, *blist; 41749232Smckusick int s, dirty = 0; 41849232Smckusick 41949232Smckusick for (;;) { 42049232Smckusick if (blist = vp->v_dirtyblkhd) 42149232Smckusick /* void */; 42249232Smckusick else if (blist = vp->v_cleanblkhd) 42349232Smckusick /* void */; 42449232Smckusick else 42549232Smckusick break; 42649232Smckusick for (bp = blist; bp; bp = nbp) { 42749232Smckusick nbp = bp->b_blockf; 42849232Smckusick s = splbio(); 42949232Smckusick if (bp->b_flags & B_BUSY) { 43049232Smckusick bp->b_flags |= B_WANTED; 43149232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 43249232Smckusick splx(s); 43349232Smckusick break; 43449232Smckusick } 43549232Smckusick bremfree(bp); 43649232Smckusick bp->b_flags |= B_BUSY; 43749232Smckusick splx(s); 43849232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 43951568Smckusick dirty++; 44051568Smckusick (void) VOP_BWRITE(bp); 44149232Smckusick break; 44249232Smckusick } 44349232Smckusick if (bp->b_vp != vp) 44449232Smckusick reassignbuf(bp, bp->b_vp); 44549232Smckusick else 44649232Smckusick bp->b_flags |= B_INVAL; 44749232Smckusick brelse(bp); 44849232Smckusick } 44949232Smckusick } 45049232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 45149232Smckusick panic("vinvalbuf: flush failed"); 45249232Smckusick return (dirty); 45349232Smckusick } 45449232Smckusick 45549232Smckusick /* 45649232Smckusick * Associate a buffer with a vnode. 45749232Smckusick */ 45849232Smckusick bgetvp(vp, bp) 45949232Smckusick register struct vnode *vp; 46049232Smckusick register struct buf *bp; 46149232Smckusick { 46249973Smckusick register struct vnode *vq; 46349973Smckusick register struct buf *bq; 46449232Smckusick 46549232Smckusick if (bp->b_vp) 46649232Smckusick panic("bgetvp: not free"); 46749232Smckusick VHOLD(vp); 46849232Smckusick bp->b_vp = vp; 46949232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 47049232Smckusick bp->b_dev = vp->v_rdev; 47149232Smckusick else 47249232Smckusick bp->b_dev = NODEV; 47349232Smckusick /* 47449232Smckusick * Insert onto list for new vnode. 47549232Smckusick */ 47649973Smckusick if (bq = vp->v_cleanblkhd) 47749973Smckusick bq->b_blockb = &bp->b_blockf; 47849973Smckusick bp->b_blockf = bq; 47949973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 48049973Smckusick vp->v_cleanblkhd = bp; 48149232Smckusick } 48249232Smckusick 48349232Smckusick /* 48449232Smckusick * Disassociate a buffer from a vnode. 48549232Smckusick */ 48649232Smckusick brelvp(bp) 48749232Smckusick register struct buf *bp; 48849232Smckusick { 48949232Smckusick struct buf *bq; 49049232Smckusick struct vnode *vp; 49149232Smckusick 49249232Smckusick if (bp->b_vp == (struct vnode *) 0) 49349232Smckusick panic("brelvp: NULL"); 49449232Smckusick /* 49549232Smckusick * Delete from old vnode list, if on one. 49649232Smckusick */ 49749232Smckusick if (bp->b_blockb) { 49849232Smckusick if (bq = bp->b_blockf) 49949232Smckusick bq->b_blockb = bp->b_blockb; 50049232Smckusick *bp->b_blockb = bq; 50149232Smckusick bp->b_blockf = NULL; 50249232Smckusick bp->b_blockb = NULL; 50349232Smckusick } 50449232Smckusick vp = bp->b_vp; 50549232Smckusick bp->b_vp = (struct vnode *) 0; 50649232Smckusick HOLDRELE(vp); 50749232Smckusick } 50849232Smckusick 50949232Smckusick /* 51049232Smckusick * Reassign a buffer from one vnode to another. 51149232Smckusick * Used to assign file specific control information 51249232Smckusick * (indirect blocks) to the vnode to which they belong. 51349232Smckusick */ 51449232Smckusick reassignbuf(bp, newvp) 51549232Smckusick register struct buf *bp; 51649232Smckusick register struct vnode *newvp; 51749232Smckusick { 51849232Smckusick register struct buf *bq, **listheadp; 51949232Smckusick 52052655Smckusick if (newvp == NULL) { 52152655Smckusick printf("reassignbuf: NULL"); 52252655Smckusick return; 52352655Smckusick } 52449232Smckusick /* 52549232Smckusick * Delete from old vnode list, if on one. 52649232Smckusick */ 52749232Smckusick if (bp->b_blockb) { 52849232Smckusick if (bq = bp->b_blockf) 52949232Smckusick bq->b_blockb = bp->b_blockb; 53049232Smckusick *bp->b_blockb = bq; 53149232Smckusick } 53249232Smckusick /* 53349232Smckusick * If dirty, put on list of dirty buffers; 53449232Smckusick * otherwise insert onto list of clean buffers. 53549232Smckusick */ 53649232Smckusick if (bp->b_flags & B_DELWRI) 53749232Smckusick listheadp = &newvp->v_dirtyblkhd; 53849232Smckusick else 53949232Smckusick listheadp = &newvp->v_cleanblkhd; 54049973Smckusick if (bq = *listheadp) 54149973Smckusick bq->b_blockb = &bp->b_blockf; 54249973Smckusick bp->b_blockf = bq; 54349973Smckusick bp->b_blockb = listheadp; 54449973Smckusick *listheadp = bp; 54549232Smckusick } 54649232Smckusick 54749232Smckusick /* 54839433Smckusick * Create a vnode for a block device. 54939433Smckusick * Used for root filesystem, argdev, and swap areas. 55039433Smckusick * Also used for memory file system special devices. 55139397Smckusick */ 55239433Smckusick bdevvp(dev, vpp) 55339433Smckusick dev_t dev; 55439433Smckusick struct vnode **vpp; 55539433Smckusick { 55639433Smckusick register struct vnode *vp; 55739433Smckusick struct vnode *nvp; 55839433Smckusick int error; 55939433Smckusick 56046989Smckusick if (dev == NODEV) 56146989Smckusick return (0); 56253547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 56339433Smckusick if (error) { 56439433Smckusick *vpp = 0; 56539433Smckusick return (error); 56639433Smckusick } 56739433Smckusick vp = nvp; 56839433Smckusick vp->v_type = VBLK; 56939615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 57039433Smckusick vput(vp); 57139433Smckusick vp = nvp; 57239433Smckusick } 57339433Smckusick *vpp = vp; 57439433Smckusick return (0); 57539433Smckusick } 57639433Smckusick 57739433Smckusick /* 57839433Smckusick * Check to see if the new vnode represents a special device 57939433Smckusick * for which we already have a vnode (either because of 58039433Smckusick * bdevvp() or because of a different vnode representing 58139433Smckusick * the same block device). If such an alias exists, deallocate 58239509Smckusick * the existing contents and return the aliased vnode. The 58339433Smckusick * caller is responsible for filling it with its new contents. 58439433Smckusick */ 58539433Smckusick struct vnode * 58639615Smckusick checkalias(nvp, nvp_rdev, mp) 58739433Smckusick register struct vnode *nvp; 58839615Smckusick dev_t nvp_rdev; 58939433Smckusick struct mount *mp; 59039433Smckusick { 59153547Sheideman USES_VOP_UNLOCK; 59239433Smckusick register struct vnode *vp; 59339615Smckusick struct vnode **vpp; 59439433Smckusick 59539433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 59641400Smckusick return (NULLVP); 59739615Smckusick 59839615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 59939433Smckusick loop: 60039615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 60139615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 60239433Smckusick continue; 60339615Smckusick /* 60439615Smckusick * Alias, but not in use, so flush it out. 60539615Smckusick */ 60639809Smckusick if (vp->v_usecount == 0) { 60739615Smckusick vgone(vp); 60839615Smckusick goto loop; 60939615Smckusick } 61039633Smckusick if (vget(vp)) 61139633Smckusick goto loop; 61239433Smckusick break; 61339433Smckusick } 61439615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 61539615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 61639615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 61739615Smckusick nvp->v_rdev = nvp_rdev; 61839809Smckusick nvp->v_hashchain = vpp; 61939615Smckusick nvp->v_specnext = *vpp; 62042152Smckusick nvp->v_specflags = 0; 62139615Smckusick *vpp = nvp; 62240640Smckusick if (vp != NULL) { 62340640Smckusick nvp->v_flag |= VALIASED; 62440640Smckusick vp->v_flag |= VALIASED; 62540640Smckusick vput(vp); 62640640Smckusick } 62741400Smckusick return (NULLVP); 62839433Smckusick } 62939484Smckusick VOP_UNLOCK(vp); 63039484Smckusick vclean(vp, 0); 63139433Smckusick vp->v_op = nvp->v_op; 63239433Smckusick vp->v_tag = nvp->v_tag; 63339433Smckusick nvp->v_type = VNON; 63439433Smckusick insmntque(vp, mp); 63539433Smckusick return (vp); 63639433Smckusick } 63739433Smckusick 63839433Smckusick /* 63939433Smckusick * Grab a particular vnode from the free list, increment its 64039433Smckusick * reference count and lock it. The vnode lock bit is set the 64139433Smckusick * vnode is being eliminated in vgone. The process is awakened 64239433Smckusick * when the transition is completed, and an error returned to 64339433Smckusick * indicate that the vnode is no longer usable (possibly having 64439433Smckusick * been changed to a new file system type). 64539433Smckusick */ 64639397Smckusick vget(vp) 64739397Smckusick register struct vnode *vp; 64839397Smckusick { 64953547Sheideman USES_VOP_LOCK; 65039397Smckusick register struct vnode *vq; 65139397Smckusick 65239433Smckusick if (vp->v_flag & VXLOCK) { 65339433Smckusick vp->v_flag |= VXWANT; 65439433Smckusick sleep((caddr_t)vp, PINOD); 65539433Smckusick return (1); 65639433Smckusick } 65739809Smckusick if (vp->v_usecount == 0) { 65839433Smckusick if (vq = vp->v_freef) 65939433Smckusick vq->v_freeb = vp->v_freeb; 66039433Smckusick else 66139433Smckusick vfreet = vp->v_freeb; 66239433Smckusick *vp->v_freeb = vq; 66339433Smckusick vp->v_freef = NULL; 66439433Smckusick vp->v_freeb = NULL; 66539433Smckusick } 66639397Smckusick VREF(vp); 66739433Smckusick VOP_LOCK(vp); 66839433Smckusick return (0); 66939397Smckusick } 67039397Smckusick 67139397Smckusick /* 67239397Smckusick * Vnode reference, just increment the count 67339397Smckusick */ 67439397Smckusick void vref(vp) 67539397Smckusick struct vnode *vp; 67639397Smckusick { 67739397Smckusick 67839809Smckusick vp->v_usecount++; 67939397Smckusick } 68039397Smckusick 68139397Smckusick /* 68239397Smckusick * vput(), just unlock and vrele() 68339397Smckusick */ 68439397Smckusick void vput(vp) 68539397Smckusick register struct vnode *vp; 68639397Smckusick { 68753547Sheideman USES_VOP_UNLOCK; 68852416Storek 68939397Smckusick VOP_UNLOCK(vp); 69039397Smckusick vrele(vp); 69139397Smckusick } 69239397Smckusick 69339397Smckusick /* 69439397Smckusick * Vnode release. 69539397Smckusick * If count drops to zero, call inactive routine and return to freelist. 69639397Smckusick */ 69739397Smckusick void vrele(vp) 69839397Smckusick register struct vnode *vp; 69939397Smckusick { 70053547Sheideman USES_VOP_INACTIVE; 70148024Smckusick struct proc *p = curproc; /* XXX */ 70239397Smckusick 70350109Smckusick #ifdef DIAGNOSTIC 70439397Smckusick if (vp == NULL) 70539433Smckusick panic("vrele: null vp"); 70650109Smckusick #endif 70739809Smckusick vp->v_usecount--; 70839809Smckusick if (vp->v_usecount > 0) 70939397Smckusick return; 71050109Smckusick #ifdef DIAGNOSTIC 71150109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 71250109Smckusick vprint("vrele: bad ref count", vp); 71350109Smckusick panic("vrele: ref cnt"); 71450109Smckusick } 71550109Smckusick #endif 71641400Smckusick if (vfreeh == NULLVP) { 71739397Smckusick /* 71839397Smckusick * insert into empty list 71939397Smckusick */ 72039397Smckusick vfreeh = vp; 72139397Smckusick vp->v_freeb = &vfreeh; 72239397Smckusick } else { 72339397Smckusick /* 72439397Smckusick * insert at tail of list 72539397Smckusick */ 72639397Smckusick *vfreet = vp; 72739397Smckusick vp->v_freeb = vfreet; 72839397Smckusick } 72939433Smckusick vp->v_freef = NULL; 73039433Smckusick vfreet = &vp->v_freef; 73148024Smckusick VOP_INACTIVE(vp, p); 73239397Smckusick } 73339433Smckusick 73439433Smckusick /* 73539809Smckusick * Page or buffer structure gets a reference. 73639809Smckusick */ 73753312Smckusick void vhold(vp) 73839809Smckusick register struct vnode *vp; 73939809Smckusick { 74039809Smckusick 74139809Smckusick vp->v_holdcnt++; 74239809Smckusick } 74339809Smckusick 74439809Smckusick /* 74539809Smckusick * Page or buffer structure frees a reference. 74639809Smckusick */ 74753312Smckusick void holdrele(vp) 74839809Smckusick register struct vnode *vp; 74939809Smckusick { 75039809Smckusick 75139809Smckusick if (vp->v_holdcnt <= 0) 75239809Smckusick panic("holdrele: holdcnt"); 75339809Smckusick vp->v_holdcnt--; 75439809Smckusick } 75539809Smckusick 75639809Smckusick /* 75739509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 75839509Smckusick * 75939509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 76039509Smckusick * return error if any are found (nb: this is a user error, not a 76139509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 76239509Smckusick * that are found. 76339509Smckusick */ 76439509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 76539509Smckusick 76639509Smckusick vflush(mp, skipvp, flags) 76739509Smckusick struct mount *mp; 76839509Smckusick struct vnode *skipvp; 76939509Smckusick int flags; 77039509Smckusick { 77139509Smckusick register struct vnode *vp, *nvp; 77239509Smckusick int busy = 0; 77339509Smckusick 77441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 77541300Smckusick panic("vflush: not busy"); 77641421Smckusick loop: 77741400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 77841421Smckusick if (vp->v_mount != mp) 77941421Smckusick goto loop; 78039509Smckusick nvp = vp->v_mountf; 78139509Smckusick /* 78239509Smckusick * Skip over a selected vnode. 78339509Smckusick */ 78439509Smckusick if (vp == skipvp) 78539509Smckusick continue; 78639509Smckusick /* 78741300Smckusick * Skip over a vnodes marked VSYSTEM. 78841300Smckusick */ 78941300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 79041300Smckusick continue; 79141300Smckusick /* 79239809Smckusick * With v_usecount == 0, all we need to do is clear 79339509Smckusick * out the vnode data structures and we are done. 79439509Smckusick */ 79539809Smckusick if (vp->v_usecount == 0) { 79639509Smckusick vgone(vp); 79739509Smckusick continue; 79839509Smckusick } 79939509Smckusick /* 80039509Smckusick * For block or character devices, revert to an 80139509Smckusick * anonymous device. For all other files, just kill them. 80239509Smckusick */ 80341300Smckusick if (flags & FORCECLOSE) { 80439509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 80539509Smckusick vgone(vp); 80639509Smckusick } else { 80739509Smckusick vclean(vp, 0); 80853547Sheideman vp->v_op = spec_vnodeop_p; 80939509Smckusick insmntque(vp, (struct mount *)0); 81039509Smckusick } 81139509Smckusick continue; 81239509Smckusick } 81339509Smckusick if (busyprt) 81439667Smckusick vprint("vflush: busy vnode", vp); 81539509Smckusick busy++; 81639509Smckusick } 81739509Smckusick if (busy) 81839509Smckusick return (EBUSY); 81939509Smckusick return (0); 82039509Smckusick } 82139509Smckusick 82239509Smckusick /* 82339433Smckusick * Disassociate the underlying file system from a vnode. 82439433Smckusick */ 82541300Smckusick void vclean(vp, flags) 82639433Smckusick register struct vnode *vp; 82745118Smckusick int flags; 82839433Smckusick { 82953580Sheideman USES_VOP_LOCK; 83053580Sheideman USES_VOP_UNLOCK; 83153580Sheideman USES_VOP_CLOSE; 83253547Sheideman USES_VOP_INACTIVE; 83353580Sheideman USES_VOP_RECLAIM; 83453580Sheideman int (**origops)(); 83539484Smckusick int active; 83648024Smckusick struct proc *p = curproc; /* XXX */ 83739433Smckusick 83839484Smckusick /* 83939484Smckusick * Check to see if the vnode is in use. 84039667Smckusick * If so we have to reference it before we clean it out 84139667Smckusick * so that its count cannot fall to zero and generate a 84239667Smckusick * race against ourselves to recycle it. 84339484Smckusick */ 84439809Smckusick if (active = vp->v_usecount) 84539484Smckusick VREF(vp); 84639484Smckusick /* 84739484Smckusick * Prevent the vnode from being recycled or 84839484Smckusick * brought into use while we clean it out. 84939484Smckusick */ 85039667Smckusick if (vp->v_flag & VXLOCK) 85139667Smckusick panic("vclean: deadlock"); 85239433Smckusick vp->v_flag |= VXLOCK; 85339433Smckusick /* 85439667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 85539667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 85639667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 85739667Smckusick * For active vnodes, it ensures that no other activity can 85839667Smckusick * occur while the buffer list is being cleaned out. 85939667Smckusick */ 86039667Smckusick VOP_LOCK(vp); 86141300Smckusick if (flags & DOCLOSE) 86239667Smckusick vinvalbuf(vp, 1); 86339667Smckusick /* 86439433Smckusick * Prevent any further operations on the vnode from 86539433Smckusick * being passed through to the old file system. 86639433Smckusick */ 86739433Smckusick origops = vp->v_op; 86853547Sheideman vp->v_op = dead_vnodeop_p; 86939433Smckusick vp->v_tag = VT_NON; 87039433Smckusick /* 87139484Smckusick * If purging an active vnode, it must be unlocked, closed, 87239484Smckusick * and deactivated before being reclaimed. 87339433Smckusick */ 87453580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 87553580Sheideman vop_unlock_a.a_vp = vp; 87653580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 87739484Smckusick if (active) { 87853580Sheideman /* 87953580Sheideman * Note: these next two calls imply 88053580Sheideman * that vop_close and vop_inactive implementations 88153580Sheideman * cannot count on the ops vector being correctly 88253580Sheideman * set. 88353580Sheideman */ 88453580Sheideman if (flags & DOCLOSE) { 88553580Sheideman vop_close_a.a_desc = VDESC(vop_close); 88653580Sheideman vop_close_a.a_vp = vp; 88753580Sheideman vop_close_a.a_fflag = IO_NDELAY; 88853580Sheideman vop_close_a.a_p = p; 88953580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 89053580Sheideman }; 89153580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 89253580Sheideman vop_inactive_a.a_vp = vp; 89353580Sheideman vop_inactive_a.a_p = p; 89453580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 89539433Smckusick } 89639433Smckusick /* 89739433Smckusick * Reclaim the vnode. 89839433Smckusick */ 89953580Sheideman /* 90053580Sheideman * Emulate VOP_RECLAIM. 90153580Sheideman */ 90253580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 90353580Sheideman vop_reclaim_a.a_vp = vp; 90453580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 90539433Smckusick panic("vclean: cannot reclaim"); 90639484Smckusick if (active) 90739484Smckusick vrele(vp); 90853580Sheideman 90939433Smckusick /* 91039433Smckusick * Done with purge, notify sleepers in vget of the grim news. 91139433Smckusick */ 91239433Smckusick vp->v_flag &= ~VXLOCK; 91339433Smckusick if (vp->v_flag & VXWANT) { 91439433Smckusick vp->v_flag &= ~VXWANT; 91539433Smckusick wakeup((caddr_t)vp); 91639433Smckusick } 91739433Smckusick } 91839433Smckusick 91939433Smckusick /* 92039633Smckusick * Eliminate all activity associated with the requested vnode 92139633Smckusick * and with all vnodes aliased to the requested vnode. 92239633Smckusick */ 92339633Smckusick void vgoneall(vp) 92439633Smckusick register struct vnode *vp; 92539633Smckusick { 92639809Smckusick register struct vnode *vq; 92739633Smckusick 92840665Smckusick if (vp->v_flag & VALIASED) { 92940665Smckusick /* 93040665Smckusick * If a vgone (or vclean) is already in progress, 93140665Smckusick * wait until it is done and return. 93240665Smckusick */ 93340665Smckusick if (vp->v_flag & VXLOCK) { 93440665Smckusick vp->v_flag |= VXWANT; 93540665Smckusick sleep((caddr_t)vp, PINOD); 93640665Smckusick return; 93739633Smckusick } 93840665Smckusick /* 93940665Smckusick * Ensure that vp will not be vgone'd while we 94040665Smckusick * are eliminating its aliases. 94140665Smckusick */ 94240665Smckusick vp->v_flag |= VXLOCK; 94340665Smckusick while (vp->v_flag & VALIASED) { 94440665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 94540665Smckusick if (vq->v_rdev != vp->v_rdev || 94640665Smckusick vq->v_type != vp->v_type || vp == vq) 94740665Smckusick continue; 94840665Smckusick vgone(vq); 94940665Smckusick break; 95040665Smckusick } 95140665Smckusick } 95240665Smckusick /* 95340665Smckusick * Remove the lock so that vgone below will 95440665Smckusick * really eliminate the vnode after which time 95540665Smckusick * vgone will awaken any sleepers. 95640665Smckusick */ 95740665Smckusick vp->v_flag &= ~VXLOCK; 95839633Smckusick } 95939633Smckusick vgone(vp); 96039633Smckusick } 96139633Smckusick 96239633Smckusick /* 96339433Smckusick * Eliminate all activity associated with a vnode 96439433Smckusick * in preparation for reuse. 96539433Smckusick */ 96639433Smckusick void vgone(vp) 96739433Smckusick register struct vnode *vp; 96839433Smckusick { 96939809Smckusick register struct vnode *vq; 97039615Smckusick struct vnode *vx; 97139433Smckusick 97239433Smckusick /* 97340548Smckusick * If a vgone (or vclean) is already in progress, 97440548Smckusick * wait until it is done and return. 97540548Smckusick */ 97640548Smckusick if (vp->v_flag & VXLOCK) { 97740548Smckusick vp->v_flag |= VXWANT; 97840548Smckusick sleep((caddr_t)vp, PINOD); 97940548Smckusick return; 98040548Smckusick } 98140548Smckusick /* 98239433Smckusick * Clean out the filesystem specific data. 98339433Smckusick */ 98441300Smckusick vclean(vp, DOCLOSE); 98539433Smckusick /* 98639433Smckusick * Delete from old mount point vnode list, if on one. 98739433Smckusick */ 98839433Smckusick if (vp->v_mountb) { 98939433Smckusick if (vq = vp->v_mountf) 99039433Smckusick vq->v_mountb = vp->v_mountb; 99139433Smckusick *vp->v_mountb = vq; 99239433Smckusick vp->v_mountf = NULL; 99339433Smckusick vp->v_mountb = NULL; 99452311Smckusick vp->v_mount = NULL; 99539433Smckusick } 99639433Smckusick /* 99739433Smckusick * If special device, remove it from special device alias list. 99839433Smckusick */ 99939433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 100039809Smckusick if (*vp->v_hashchain == vp) { 100139809Smckusick *vp->v_hashchain = vp->v_specnext; 100239433Smckusick } else { 100339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 100439615Smckusick if (vq->v_specnext != vp) 100539433Smckusick continue; 100639615Smckusick vq->v_specnext = vp->v_specnext; 100739433Smckusick break; 100839433Smckusick } 100939615Smckusick if (vq == NULL) 101039433Smckusick panic("missing bdev"); 101139433Smckusick } 101239615Smckusick if (vp->v_flag & VALIASED) { 101352416Storek vx = NULL; 101439809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 101540108Smckusick if (vq->v_rdev != vp->v_rdev || 101640108Smckusick vq->v_type != vp->v_type) 101739615Smckusick continue; 101852416Storek if (vx) 101952416Storek break; 102039615Smckusick vx = vq; 102139615Smckusick } 102252416Storek if (vx == NULL) 102339615Smckusick panic("missing alias"); 102452416Storek if (vq == NULL) 102539615Smckusick vx->v_flag &= ~VALIASED; 102639615Smckusick vp->v_flag &= ~VALIASED; 102739615Smckusick } 102839615Smckusick FREE(vp->v_specinfo, M_VNODE); 102939615Smckusick vp->v_specinfo = NULL; 103039433Smckusick } 103139433Smckusick /* 103239433Smckusick * If it is on the freelist, move it to the head of the list. 103339433Smckusick */ 103439433Smckusick if (vp->v_freeb) { 103539433Smckusick if (vq = vp->v_freef) 103639433Smckusick vq->v_freeb = vp->v_freeb; 103739433Smckusick else 103839433Smckusick vfreet = vp->v_freeb; 103939433Smckusick *vp->v_freeb = vq; 104039433Smckusick vp->v_freef = vfreeh; 104139433Smckusick vp->v_freeb = &vfreeh; 104239433Smckusick vfreeh->v_freeb = &vp->v_freef; 104339433Smckusick vfreeh = vp; 104439433Smckusick } 104539484Smckusick vp->v_type = VBAD; 104639433Smckusick } 104739633Smckusick 104839633Smckusick /* 104939821Smckusick * Lookup a vnode by device number. 105039821Smckusick */ 105139821Smckusick vfinddev(dev, type, vpp) 105239821Smckusick dev_t dev; 105339821Smckusick enum vtype type; 105439821Smckusick struct vnode **vpp; 105539821Smckusick { 105639821Smckusick register struct vnode *vp; 105739821Smckusick 105839821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 105939821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 106039821Smckusick continue; 106139821Smckusick *vpp = vp; 106239821Smckusick return (0); 106339821Smckusick } 106439821Smckusick return (1); 106539821Smckusick } 106639821Smckusick 106739821Smckusick /* 106839633Smckusick * Calculate the total number of references to a special device. 106939633Smckusick */ 107039633Smckusick vcount(vp) 107139633Smckusick register struct vnode *vp; 107239633Smckusick { 107339809Smckusick register struct vnode *vq; 107439633Smckusick int count; 107539633Smckusick 107639633Smckusick if ((vp->v_flag & VALIASED) == 0) 107739809Smckusick return (vp->v_usecount); 107839633Smckusick loop: 107939809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 108040108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 108139633Smckusick continue; 108239633Smckusick /* 108339633Smckusick * Alias, but not in use, so flush it out. 108439633Smckusick */ 108539809Smckusick if (vq->v_usecount == 0) { 108639633Smckusick vgone(vq); 108739633Smckusick goto loop; 108839633Smckusick } 108939809Smckusick count += vq->v_usecount; 109039633Smckusick } 109139633Smckusick return (count); 109239633Smckusick } 109339667Smckusick 109439667Smckusick /* 109539667Smckusick * Print out a description of a vnode. 109639667Smckusick */ 109739667Smckusick static char *typename[] = 109840286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 109939667Smckusick 110039667Smckusick vprint(label, vp) 110139667Smckusick char *label; 110239667Smckusick register struct vnode *vp; 110339667Smckusick { 110453547Sheideman USES_VOP_PRINT; 110539913Smckusick char buf[64]; 110639667Smckusick 110739667Smckusick if (label != NULL) 110839667Smckusick printf("%s: ", label); 110950109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 111050109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 111150109Smckusick vp->v_holdcnt); 111239913Smckusick buf[0] = '\0'; 111339913Smckusick if (vp->v_flag & VROOT) 111439913Smckusick strcat(buf, "|VROOT"); 111539913Smckusick if (vp->v_flag & VTEXT) 111639913Smckusick strcat(buf, "|VTEXT"); 111741300Smckusick if (vp->v_flag & VSYSTEM) 111841300Smckusick strcat(buf, "|VSYSTEM"); 111941300Smckusick if (vp->v_flag & VXLOCK) 112041300Smckusick strcat(buf, "|VXLOCK"); 112141300Smckusick if (vp->v_flag & VXWANT) 112241300Smckusick strcat(buf, "|VXWANT"); 112341300Smckusick if (vp->v_flag & VBWAIT) 112441300Smckusick strcat(buf, "|VBWAIT"); 112539913Smckusick if (vp->v_flag & VALIASED) 112639913Smckusick strcat(buf, "|VALIASED"); 112739913Smckusick if (buf[0] != '\0') 112839913Smckusick printf(" flags (%s)", &buf[1]); 112939913Smckusick printf("\n\t"); 113039667Smckusick VOP_PRINT(vp); 113139667Smckusick } 113241110Smarc 113349691Smckusick #ifdef DEBUG 113449691Smckusick /* 113549691Smckusick * List all of the locked vnodes in the system. 113649691Smckusick * Called when debugging the kernel. 113749691Smckusick */ 113849691Smckusick printlockedvnodes() 113949691Smckusick { 114053547Sheideman USES_VOP_ISLOCKED; 114149691Smckusick register struct mount *mp; 114249691Smckusick register struct vnode *vp; 114349691Smckusick 114449691Smckusick printf("Locked vnodes\n"); 114549691Smckusick mp = rootfs; 114649691Smckusick do { 114749691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 114849691Smckusick if (VOP_ISLOCKED(vp)) 114949691Smckusick vprint((char *)0, vp); 115049691Smckusick mp = mp->mnt_next; 115149691Smckusick } while (mp != rootfs); 115249691Smckusick } 115349691Smckusick #endif 115449691Smckusick 115541110Smarc int kinfo_vdebug = 1; 115641110Smarc int kinfo_vgetfailed; 115741110Smarc #define KINFO_VNODESLOP 10 115841110Smarc /* 115941110Smarc * Dump vnode list (via kinfo). 116041110Smarc * Copyout address of vnode followed by vnode. 116141110Smarc */ 116245118Smckusick /* ARGSUSED */ 116341110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 116445118Smckusick int op; 116541110Smarc char *where; 116645118Smckusick int *acopysize, arg, *aneeded; 116741110Smarc { 116841110Smarc register struct mount *mp = rootfs; 116941300Smckusick struct mount *omp; 117041110Smarc struct vnode *vp; 117141110Smarc register char *bp = where, *savebp; 117253818Smckusick char *ewhere; 117341110Smarc int error; 117441110Smarc 117541110Smarc #define VPTRSZ sizeof (struct vnode *) 117641110Smarc #define VNODESZ sizeof (struct vnode) 117741110Smarc if (where == NULL) { 117841110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 117941110Smarc return (0); 118041110Smarc } 118153818Smckusick ewhere = where + *acopysize; 118241110Smarc 118341110Smarc do { 118441300Smckusick if (vfs_busy(mp)) { 118541400Smckusick mp = mp->mnt_next; 118641300Smckusick continue; 118741300Smckusick } 118841110Smarc savebp = bp; 118941110Smarc again: 119041421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 119141422Smckusick /* 119241422Smckusick * Check that the vp is still associated with 119341422Smckusick * this filesystem. RACE: could have been 119441422Smckusick * recycled onto the same filesystem. 119541422Smckusick */ 119641421Smckusick if (vp->v_mount != mp) { 119741421Smckusick if (kinfo_vdebug) 119841421Smckusick printf("kinfo: vp changed\n"); 119941421Smckusick bp = savebp; 120041421Smckusick goto again; 120141421Smckusick } 120241110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 120341110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 120441110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 120541422Smckusick VNODESZ)))) 120641110Smarc return (error); 120741110Smarc bp += VPTRSZ + VNODESZ; 120841110Smarc } 120941300Smckusick omp = mp; 121041400Smckusick mp = mp->mnt_next; 121141300Smckusick vfs_unbusy(omp); 121241110Smarc } while (mp != rootfs); 121341110Smarc 121441110Smarc *aneeded = bp - where; 121541110Smarc if (bp > ewhere) 121641110Smarc *acopysize = ewhere - where; 121741110Smarc else 121841110Smarc *acopysize = bp - where; 121941110Smarc return (0); 122041110Smarc } 1221