137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*53936Spendry * @(#)vfs_subr.c 7.79 (Berkeley) 06/05/92 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 1553829Spendry #include <sys/systm.h> 1651460Sbostic #include <sys/proc.h> 1751460Sbostic #include <sys/mount.h> 1851460Sbostic #include <sys/time.h> 1951460Sbostic #include <sys/vnode.h> 2052415Smckusick #include <sys/stat.h> 2151460Sbostic #include <sys/specdev.h> 2251460Sbostic #include <sys/namei.h> 2351460Sbostic #include <sys/ucred.h> 2451460Sbostic #include <sys/buf.h> 2551460Sbostic #include <sys/errno.h> 2651460Sbostic #include <sys/malloc.h> 2737488Smckusick 2852415Smckusick enum vtype iftovt_tab[16] = { 2952415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 3052415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3152415Smckusick }; 3252415Smckusick int vttoif_tab[9] = { 3352415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 3452415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 3552415Smckusick }; 3652415Smckusick 3737488Smckusick /* 3837488Smckusick * Remove a mount point from the list of mounted filesystems. 3937488Smckusick * Unmount of the root is illegal. 4037488Smckusick */ 4137488Smckusick void 4237488Smckusick vfs_remove(mp) 4337488Smckusick register struct mount *mp; 4437488Smckusick { 4537488Smckusick 4637488Smckusick if (mp == rootfs) 4737488Smckusick panic("vfs_remove: unmounting root"); 4841400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 4941400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 5041400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 5137488Smckusick vfs_unlock(mp); 5237488Smckusick } 5337488Smckusick 5437488Smckusick /* 5537488Smckusick * Lock a filesystem. 5637488Smckusick * Used to prevent access to it while mounting and unmounting. 5737488Smckusick */ 5837488Smckusick vfs_lock(mp) 5937488Smckusick register struct mount *mp; 6037488Smckusick { 6137488Smckusick 6241400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 6341400Smckusick mp->mnt_flag |= MNT_MWAIT; 6439045Smckusick sleep((caddr_t)mp, PVFS); 6539045Smckusick } 6641400Smckusick mp->mnt_flag |= MNT_MLOCK; 6737488Smckusick return (0); 6837488Smckusick } 6937488Smckusick 7037488Smckusick /* 7137488Smckusick * Unlock a locked filesystem. 7237488Smckusick * Panic if filesystem is not locked. 7337488Smckusick */ 7437488Smckusick void 7537488Smckusick vfs_unlock(mp) 7637488Smckusick register struct mount *mp; 7737488Smckusick { 7837488Smckusick 7941400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 8041300Smckusick panic("vfs_unlock: not locked"); 8141400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 8241400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 8341400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 8437488Smckusick wakeup((caddr_t)mp); 8537488Smckusick } 8637488Smckusick } 8737488Smckusick 8837488Smckusick /* 8941300Smckusick * Mark a mount point as busy. 9041300Smckusick * Used to synchronize access and to delay unmounting. 9141300Smckusick */ 9241300Smckusick vfs_busy(mp) 9341300Smckusick register struct mount *mp; 9441300Smckusick { 9541300Smckusick 9641400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 9741400Smckusick mp->mnt_flag |= MNT_MPWANT; 9841400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 9941300Smckusick } 10041419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 10141419Smckusick return (1); 10241400Smckusick mp->mnt_flag |= MNT_MPBUSY; 10341300Smckusick return (0); 10441300Smckusick } 10541300Smckusick 10641300Smckusick /* 10741300Smckusick * Free a busy filesystem. 10841300Smckusick * Panic if filesystem is not busy. 10941300Smckusick */ 11041300Smckusick vfs_unbusy(mp) 11141300Smckusick register struct mount *mp; 11241300Smckusick { 11341300Smckusick 11441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 11541300Smckusick panic("vfs_unbusy: not busy"); 11641400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 11741400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 11841400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 11941400Smckusick wakeup((caddr_t)&mp->mnt_flag); 12041300Smckusick } 12141300Smckusick } 12241300Smckusick 12341300Smckusick /* 12437488Smckusick * Lookup a mount point by filesystem identifier. 12537488Smckusick */ 12637488Smckusick struct mount * 12737488Smckusick getvfs(fsid) 12837488Smckusick fsid_t *fsid; 12937488Smckusick { 13037488Smckusick register struct mount *mp; 13137488Smckusick 13238288Smckusick mp = rootfs; 13338288Smckusick do { 13441400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 13541400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 13638288Smckusick return (mp); 13737488Smckusick } 13841400Smckusick mp = mp->mnt_next; 13938288Smckusick } while (mp != rootfs); 14038288Smckusick return ((struct mount *)0); 14137488Smckusick } 14237488Smckusick 14337488Smckusick /* 14453829Spendry * Get a new unique fsid 14553829Spendry */ 14653829Spendry void 14753829Spendry getnewfsid(mp, mtype) 14853829Spendry struct mount *mp; 14953829Spendry int mtype; 15053829Spendry { 15153829Spendry static u_short xxxfs_mntid; 15253829Spendry 15353829Spendry fsid_t tfsid; 15453829Spendry 15553829Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0); /* XXX */ 15653829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 15753829Spendry if (xxxfs_mntid == 0) 15853829Spendry ++xxxfs_mntid; 15953829Spendry tfsid.val[0] = makedev(nblkdev, xxxfs_mntid); 16053829Spendry tfsid.val[1] = mtype; 161*53936Spendry if (rootfs) { 162*53936Spendry while (getvfs(&tfsid)) { 163*53936Spendry tfsid.val[0]++; 164*53936Spendry xxxfs_mntid++; 165*53936Spendry } 16653829Spendry } 16753829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 16853829Spendry } 16953829Spendry 17053829Spendry /* 17137488Smckusick * Set vnode attributes to VNOVAL 17237488Smckusick */ 17337488Smckusick void vattr_null(vap) 17437488Smckusick register struct vattr *vap; 17537488Smckusick { 17637488Smckusick 17737488Smckusick vap->va_type = VNON; 17852005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 17952005Smckusick #ifdef _NOQUAD 18052005Smckusick vap->va_size_rsv = vap->va_bytes_rsv = VNOVAL; 18152005Smckusick #endif 18237488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18352005Smckusick vap->va_fsid = vap->va_fileid = 18452005Smckusick vap->va_blocksize = vap->va_rdev = 18537488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 18637488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 18738258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 18838258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 18937488Smckusick } 19038265Smckusick 19138265Smckusick /* 19239397Smckusick * Routines having to do with the management of the vnode table. 19339397Smckusick */ 19453493Sheideman extern struct vnode *vfreeh, **vfreet; 19553547Sheideman extern int (**dead_vnodeop_p)(); 19653547Sheideman extern int (**spec_vnodeop_p)(); 19739635Smckusick extern void vclean(); 19840883Smckusick long numvnodes; 19953493Sheideman extern struct vattr va_null; 20039397Smckusick 20139397Smckusick /* 20239397Smckusick * Return the next vnode from the free list. 20339397Smckusick */ 20439397Smckusick getnewvnode(tag, mp, vops, vpp) 20539397Smckusick enum vtagtype tag; 20639397Smckusick struct mount *mp; 20753495Sheideman int (**vops)(); 20839397Smckusick struct vnode **vpp; 20939397Smckusick { 21039397Smckusick register struct vnode *vp, *vq; 21139397Smckusick 21240883Smckusick if (numvnodes < desiredvnodes) { 21345118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 21445118Smckusick M_VNODE, M_WAITOK); 21540883Smckusick bzero((char *)vp, sizeof *vp); 21640883Smckusick numvnodes++; 21740883Smckusick } else { 21840883Smckusick if ((vp = vfreeh) == NULL) { 21940883Smckusick tablefull("vnode"); 22040883Smckusick *vpp = 0; 22140883Smckusick return (ENFILE); 22240883Smckusick } 22340883Smckusick if (vp->v_usecount) 22440883Smckusick panic("free vnode isn't"); 22540883Smckusick if (vq = vp->v_freef) 22640883Smckusick vq->v_freeb = &vfreeh; 22740883Smckusick else 22840883Smckusick vfreet = &vfreeh; 22940883Smckusick vfreeh = vq; 23040883Smckusick vp->v_freef = NULL; 23140883Smckusick vp->v_freeb = NULL; 23252190Smckusick vp->v_lease = NULL; 23340883Smckusick if (vp->v_type != VBAD) 23440883Smckusick vgone(vp); 23552006Smckusick if (vp->v_data) 23652006Smckusick panic("cleaned vnode isn't"); 23740883Smckusick vp->v_flag = 0; 23840883Smckusick vp->v_lastr = 0; 23940883Smckusick vp->v_socket = 0; 24039397Smckusick } 24139512Smckusick vp->v_type = VNON; 24239397Smckusick cache_purge(vp); 24339397Smckusick vp->v_tag = tag; 24439433Smckusick vp->v_op = vops; 24539397Smckusick insmntque(vp, mp); 24639397Smckusick VREF(vp); 24739397Smckusick *vpp = vp; 24839397Smckusick return (0); 24939397Smckusick } 25039397Smckusick 25139397Smckusick /* 25239397Smckusick * Move a vnode from one mount queue to another. 25339397Smckusick */ 25439397Smckusick insmntque(vp, mp) 25539397Smckusick register struct vnode *vp; 25639397Smckusick register struct mount *mp; 25739397Smckusick { 25849973Smckusick register struct vnode *vq; 25939397Smckusick 26039397Smckusick /* 26139397Smckusick * Delete from old mount point vnode list, if on one. 26239397Smckusick */ 26339397Smckusick if (vp->v_mountb) { 26439397Smckusick if (vq = vp->v_mountf) 26539397Smckusick vq->v_mountb = vp->v_mountb; 26639397Smckusick *vp->v_mountb = vq; 26739397Smckusick } 26839397Smckusick /* 26939397Smckusick * Insert into list of vnodes for the new mount point, if available. 27039397Smckusick */ 27139621Smckusick vp->v_mount = mp; 27239397Smckusick if (mp == NULL) { 27339397Smckusick vp->v_mountf = NULL; 27439397Smckusick vp->v_mountb = NULL; 27539397Smckusick return; 27639397Smckusick } 27749973Smckusick if (vq = mp->mnt_mounth) 27849973Smckusick vq->v_mountb = &vp->v_mountf; 27949973Smckusick vp->v_mountf = vq; 28049973Smckusick vp->v_mountb = &mp->mnt_mounth; 28149973Smckusick mp->mnt_mounth = vp; 28239397Smckusick } 28339397Smckusick 28439397Smckusick /* 28549232Smckusick * Make sure all write-behind blocks associated 28649232Smckusick * with mount point are flushed out (from sync). 28749232Smckusick */ 28849232Smckusick mntflushbuf(mountp, flags) 28949232Smckusick struct mount *mountp; 29049232Smckusick int flags; 29149232Smckusick { 29253547Sheideman USES_VOP_ISLOCKED; 29349232Smckusick register struct vnode *vp; 29449232Smckusick 29549232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 29649232Smckusick panic("mntflushbuf: not busy"); 29749232Smckusick loop: 29849232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 29949232Smckusick if (VOP_ISLOCKED(vp)) 30049232Smckusick continue; 30149232Smckusick if (vget(vp)) 30249232Smckusick goto loop; 30349232Smckusick vflushbuf(vp, flags); 30449232Smckusick vput(vp); 30549232Smckusick if (vp->v_mount != mountp) 30649232Smckusick goto loop; 30749232Smckusick } 30849232Smckusick } 30949232Smckusick 31049232Smckusick /* 31149232Smckusick * Flush all dirty buffers associated with a vnode. 31249232Smckusick */ 31349232Smckusick vflushbuf(vp, flags) 31449232Smckusick register struct vnode *vp; 31549232Smckusick int flags; 31649232Smckusick { 31749232Smckusick register struct buf *bp; 31849232Smckusick struct buf *nbp; 31949232Smckusick int s; 32049232Smckusick 32149232Smckusick loop: 32249232Smckusick s = splbio(); 32349232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 32449232Smckusick nbp = bp->b_blockf; 32549232Smckusick if ((bp->b_flags & B_BUSY)) 32649232Smckusick continue; 32749232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 32849232Smckusick panic("vflushbuf: not dirty"); 32949232Smckusick bremfree(bp); 33049232Smckusick bp->b_flags |= B_BUSY; 33149232Smckusick splx(s); 33249232Smckusick /* 33349232Smckusick * Wait for I/O associated with indirect blocks to complete, 33449232Smckusick * since there is no way to quickly wait for them below. 33549232Smckusick * NB: This is really specific to ufs, but is done here 33649232Smckusick * as it is easier and quicker. 33749232Smckusick */ 33849460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 33949232Smckusick (void) bawrite(bp); 34049460Smckusick else 34149232Smckusick (void) bwrite(bp); 34249460Smckusick goto loop; 34349232Smckusick } 34449232Smckusick splx(s); 34549232Smckusick if ((flags & B_SYNC) == 0) 34649232Smckusick return; 34749232Smckusick s = splbio(); 34849232Smckusick while (vp->v_numoutput) { 34949232Smckusick vp->v_flag |= VBWAIT; 35049232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 35149232Smckusick } 35249232Smckusick splx(s); 35349232Smckusick if (vp->v_dirtyblkhd) { 35449232Smckusick vprint("vflushbuf: dirty", vp); 35549232Smckusick goto loop; 35649232Smckusick } 35749232Smckusick } 35849232Smckusick 35949232Smckusick /* 36049232Smckusick * Update outstanding I/O count and do wakeup if requested. 36149232Smckusick */ 36249232Smckusick vwakeup(bp) 36349232Smckusick register struct buf *bp; 36449232Smckusick { 36549232Smckusick register struct vnode *vp; 36649232Smckusick 36749232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 36849232Smckusick if (vp = bp->b_vp) { 36949232Smckusick vp->v_numoutput--; 37049232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 37149232Smckusick if (vp->v_numoutput < 0) 37249232Smckusick panic("vwakeup: neg numoutput"); 37349232Smckusick vp->v_flag &= ~VBWAIT; 37449232Smckusick wakeup((caddr_t)&vp->v_numoutput); 37549232Smckusick } 37649232Smckusick } 37749232Smckusick } 37849232Smckusick 37949232Smckusick /* 38049232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 38149232Smckusick * 38249232Smckusick * Go through the list of vnodes associated with the file system; 38349232Smckusick * for each vnode invalidate any buffers that it holds. Normally 38449232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 38549232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 38649232Smckusick * returns the count of dirty buffers when it is finished. 38749232Smckusick */ 38849232Smckusick mntinvalbuf(mountp) 38949232Smckusick struct mount *mountp; 39049232Smckusick { 39149232Smckusick register struct vnode *vp; 39249232Smckusick int dirty = 0; 39349232Smckusick 39449232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 39549232Smckusick panic("mntinvalbuf: not busy"); 39649232Smckusick loop: 39749232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 39849232Smckusick if (vget(vp)) 39949232Smckusick goto loop; 40049232Smckusick dirty += vinvalbuf(vp, 1); 40149232Smckusick vput(vp); 40249232Smckusick if (vp->v_mount != mountp) 40349232Smckusick goto loop; 40449232Smckusick } 40549232Smckusick return (dirty); 40649232Smckusick } 40749232Smckusick 40849232Smckusick /* 40949232Smckusick * Flush out and invalidate all buffers associated with a vnode. 41049232Smckusick * Called with the underlying object locked. 41149232Smckusick */ 41249232Smckusick vinvalbuf(vp, save) 41349232Smckusick register struct vnode *vp; 41449232Smckusick int save; 41549232Smckusick { 41653547Sheideman USES_VOP_BWRITE; 41749232Smckusick register struct buf *bp; 41849232Smckusick struct buf *nbp, *blist; 41949232Smckusick int s, dirty = 0; 42049232Smckusick 42149232Smckusick for (;;) { 42249232Smckusick if (blist = vp->v_dirtyblkhd) 42349232Smckusick /* void */; 42449232Smckusick else if (blist = vp->v_cleanblkhd) 42549232Smckusick /* void */; 42649232Smckusick else 42749232Smckusick break; 42849232Smckusick for (bp = blist; bp; bp = nbp) { 42949232Smckusick nbp = bp->b_blockf; 43049232Smckusick s = splbio(); 43149232Smckusick if (bp->b_flags & B_BUSY) { 43249232Smckusick bp->b_flags |= B_WANTED; 43349232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 43449232Smckusick splx(s); 43549232Smckusick break; 43649232Smckusick } 43749232Smckusick bremfree(bp); 43849232Smckusick bp->b_flags |= B_BUSY; 43949232Smckusick splx(s); 44049232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 44151568Smckusick dirty++; 44251568Smckusick (void) VOP_BWRITE(bp); 44349232Smckusick break; 44449232Smckusick } 44549232Smckusick if (bp->b_vp != vp) 44649232Smckusick reassignbuf(bp, bp->b_vp); 44749232Smckusick else 44849232Smckusick bp->b_flags |= B_INVAL; 44949232Smckusick brelse(bp); 45049232Smckusick } 45149232Smckusick } 45249232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 45349232Smckusick panic("vinvalbuf: flush failed"); 45449232Smckusick return (dirty); 45549232Smckusick } 45649232Smckusick 45749232Smckusick /* 45849232Smckusick * Associate a buffer with a vnode. 45949232Smckusick */ 46049232Smckusick bgetvp(vp, bp) 46149232Smckusick register struct vnode *vp; 46249232Smckusick register struct buf *bp; 46349232Smckusick { 46449973Smckusick register struct vnode *vq; 46549973Smckusick register struct buf *bq; 46649232Smckusick 46749232Smckusick if (bp->b_vp) 46849232Smckusick panic("bgetvp: not free"); 46949232Smckusick VHOLD(vp); 47049232Smckusick bp->b_vp = vp; 47149232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 47249232Smckusick bp->b_dev = vp->v_rdev; 47349232Smckusick else 47449232Smckusick bp->b_dev = NODEV; 47549232Smckusick /* 47649232Smckusick * Insert onto list for new vnode. 47749232Smckusick */ 47849973Smckusick if (bq = vp->v_cleanblkhd) 47949973Smckusick bq->b_blockb = &bp->b_blockf; 48049973Smckusick bp->b_blockf = bq; 48149973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 48249973Smckusick vp->v_cleanblkhd = bp; 48349232Smckusick } 48449232Smckusick 48549232Smckusick /* 48649232Smckusick * Disassociate a buffer from a vnode. 48749232Smckusick */ 48849232Smckusick brelvp(bp) 48949232Smckusick register struct buf *bp; 49049232Smckusick { 49149232Smckusick struct buf *bq; 49249232Smckusick struct vnode *vp; 49349232Smckusick 49449232Smckusick if (bp->b_vp == (struct vnode *) 0) 49549232Smckusick panic("brelvp: NULL"); 49649232Smckusick /* 49749232Smckusick * Delete from old vnode list, if on one. 49849232Smckusick */ 49949232Smckusick if (bp->b_blockb) { 50049232Smckusick if (bq = bp->b_blockf) 50149232Smckusick bq->b_blockb = bp->b_blockb; 50249232Smckusick *bp->b_blockb = bq; 50349232Smckusick bp->b_blockf = NULL; 50449232Smckusick bp->b_blockb = NULL; 50549232Smckusick } 50649232Smckusick vp = bp->b_vp; 50749232Smckusick bp->b_vp = (struct vnode *) 0; 50849232Smckusick HOLDRELE(vp); 50949232Smckusick } 51049232Smckusick 51149232Smckusick /* 51249232Smckusick * Reassign a buffer from one vnode to another. 51349232Smckusick * Used to assign file specific control information 51449232Smckusick * (indirect blocks) to the vnode to which they belong. 51549232Smckusick */ 51649232Smckusick reassignbuf(bp, newvp) 51749232Smckusick register struct buf *bp; 51849232Smckusick register struct vnode *newvp; 51949232Smckusick { 52049232Smckusick register struct buf *bq, **listheadp; 52149232Smckusick 52252655Smckusick if (newvp == NULL) { 52352655Smckusick printf("reassignbuf: NULL"); 52452655Smckusick return; 52552655Smckusick } 52649232Smckusick /* 52749232Smckusick * Delete from old vnode list, if on one. 52849232Smckusick */ 52949232Smckusick if (bp->b_blockb) { 53049232Smckusick if (bq = bp->b_blockf) 53149232Smckusick bq->b_blockb = bp->b_blockb; 53249232Smckusick *bp->b_blockb = bq; 53349232Smckusick } 53449232Smckusick /* 53549232Smckusick * If dirty, put on list of dirty buffers; 53649232Smckusick * otherwise insert onto list of clean buffers. 53749232Smckusick */ 53849232Smckusick if (bp->b_flags & B_DELWRI) 53949232Smckusick listheadp = &newvp->v_dirtyblkhd; 54049232Smckusick else 54149232Smckusick listheadp = &newvp->v_cleanblkhd; 54249973Smckusick if (bq = *listheadp) 54349973Smckusick bq->b_blockb = &bp->b_blockf; 54449973Smckusick bp->b_blockf = bq; 54549973Smckusick bp->b_blockb = listheadp; 54649973Smckusick *listheadp = bp; 54749232Smckusick } 54849232Smckusick 54949232Smckusick /* 55039433Smckusick * Create a vnode for a block device. 55139433Smckusick * Used for root filesystem, argdev, and swap areas. 55239433Smckusick * Also used for memory file system special devices. 55339397Smckusick */ 55439433Smckusick bdevvp(dev, vpp) 55539433Smckusick dev_t dev; 55639433Smckusick struct vnode **vpp; 55739433Smckusick { 55839433Smckusick register struct vnode *vp; 55939433Smckusick struct vnode *nvp; 56039433Smckusick int error; 56139433Smckusick 56246989Smckusick if (dev == NODEV) 56346989Smckusick return (0); 56453547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 56539433Smckusick if (error) { 56639433Smckusick *vpp = 0; 56739433Smckusick return (error); 56839433Smckusick } 56939433Smckusick vp = nvp; 57039433Smckusick vp->v_type = VBLK; 57139615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 57239433Smckusick vput(vp); 57339433Smckusick vp = nvp; 57439433Smckusick } 57539433Smckusick *vpp = vp; 57639433Smckusick return (0); 57739433Smckusick } 57839433Smckusick 57939433Smckusick /* 58039433Smckusick * Check to see if the new vnode represents a special device 58139433Smckusick * for which we already have a vnode (either because of 58239433Smckusick * bdevvp() or because of a different vnode representing 58339433Smckusick * the same block device). If such an alias exists, deallocate 58439509Smckusick * the existing contents and return the aliased vnode. The 58539433Smckusick * caller is responsible for filling it with its new contents. 58639433Smckusick */ 58739433Smckusick struct vnode * 58839615Smckusick checkalias(nvp, nvp_rdev, mp) 58939433Smckusick register struct vnode *nvp; 59039615Smckusick dev_t nvp_rdev; 59139433Smckusick struct mount *mp; 59239433Smckusick { 59353547Sheideman USES_VOP_UNLOCK; 59439433Smckusick register struct vnode *vp; 59539615Smckusick struct vnode **vpp; 59639433Smckusick 59739433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 59841400Smckusick return (NULLVP); 59939615Smckusick 60039615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 60139433Smckusick loop: 60239615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 60339615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 60439433Smckusick continue; 60539615Smckusick /* 60639615Smckusick * Alias, but not in use, so flush it out. 60739615Smckusick */ 60839809Smckusick if (vp->v_usecount == 0) { 60939615Smckusick vgone(vp); 61039615Smckusick goto loop; 61139615Smckusick } 61239633Smckusick if (vget(vp)) 61339633Smckusick goto loop; 61439433Smckusick break; 61539433Smckusick } 61639615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 61739615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 61839615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 61939615Smckusick nvp->v_rdev = nvp_rdev; 62039809Smckusick nvp->v_hashchain = vpp; 62139615Smckusick nvp->v_specnext = *vpp; 62242152Smckusick nvp->v_specflags = 0; 62339615Smckusick *vpp = nvp; 62440640Smckusick if (vp != NULL) { 62540640Smckusick nvp->v_flag |= VALIASED; 62640640Smckusick vp->v_flag |= VALIASED; 62740640Smckusick vput(vp); 62840640Smckusick } 62941400Smckusick return (NULLVP); 63039433Smckusick } 63139484Smckusick VOP_UNLOCK(vp); 63239484Smckusick vclean(vp, 0); 63339433Smckusick vp->v_op = nvp->v_op; 63439433Smckusick vp->v_tag = nvp->v_tag; 63539433Smckusick nvp->v_type = VNON; 63639433Smckusick insmntque(vp, mp); 63739433Smckusick return (vp); 63839433Smckusick } 63939433Smckusick 64039433Smckusick /* 64139433Smckusick * Grab a particular vnode from the free list, increment its 64239433Smckusick * reference count and lock it. The vnode lock bit is set the 64339433Smckusick * vnode is being eliminated in vgone. The process is awakened 64439433Smckusick * when the transition is completed, and an error returned to 64539433Smckusick * indicate that the vnode is no longer usable (possibly having 64639433Smckusick * been changed to a new file system type). 64739433Smckusick */ 64839397Smckusick vget(vp) 64939397Smckusick register struct vnode *vp; 65039397Smckusick { 65153547Sheideman USES_VOP_LOCK; 65239397Smckusick register struct vnode *vq; 65339397Smckusick 65439433Smckusick if (vp->v_flag & VXLOCK) { 65539433Smckusick vp->v_flag |= VXWANT; 65639433Smckusick sleep((caddr_t)vp, PINOD); 65739433Smckusick return (1); 65839433Smckusick } 65939809Smckusick if (vp->v_usecount == 0) { 66039433Smckusick if (vq = vp->v_freef) 66139433Smckusick vq->v_freeb = vp->v_freeb; 66239433Smckusick else 66339433Smckusick vfreet = vp->v_freeb; 66439433Smckusick *vp->v_freeb = vq; 66539433Smckusick vp->v_freef = NULL; 66639433Smckusick vp->v_freeb = NULL; 66739433Smckusick } 66839397Smckusick VREF(vp); 66939433Smckusick VOP_LOCK(vp); 67039433Smckusick return (0); 67139397Smckusick } 67239397Smckusick 67339397Smckusick /* 67439397Smckusick * Vnode reference, just increment the count 67539397Smckusick */ 67639397Smckusick void vref(vp) 67739397Smckusick struct vnode *vp; 67839397Smckusick { 67939397Smckusick 68039809Smckusick vp->v_usecount++; 68139397Smckusick } 68239397Smckusick 68339397Smckusick /* 68439397Smckusick * vput(), just unlock and vrele() 68539397Smckusick */ 68639397Smckusick void vput(vp) 68739397Smckusick register struct vnode *vp; 68839397Smckusick { 68953547Sheideman USES_VOP_UNLOCK; 69052416Storek 69139397Smckusick VOP_UNLOCK(vp); 69239397Smckusick vrele(vp); 69339397Smckusick } 69439397Smckusick 69539397Smckusick /* 69639397Smckusick * Vnode release. 69739397Smckusick * If count drops to zero, call inactive routine and return to freelist. 69839397Smckusick */ 69939397Smckusick void vrele(vp) 70039397Smckusick register struct vnode *vp; 70139397Smckusick { 70253547Sheideman USES_VOP_INACTIVE; 70348024Smckusick struct proc *p = curproc; /* XXX */ 70439397Smckusick 70550109Smckusick #ifdef DIAGNOSTIC 70639397Smckusick if (vp == NULL) 70739433Smckusick panic("vrele: null vp"); 70850109Smckusick #endif 70939809Smckusick vp->v_usecount--; 71039809Smckusick if (vp->v_usecount > 0) 71139397Smckusick return; 71250109Smckusick #ifdef DIAGNOSTIC 71350109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 71450109Smckusick vprint("vrele: bad ref count", vp); 71550109Smckusick panic("vrele: ref cnt"); 71650109Smckusick } 71750109Smckusick #endif 71841400Smckusick if (vfreeh == NULLVP) { 71939397Smckusick /* 72039397Smckusick * insert into empty list 72139397Smckusick */ 72239397Smckusick vfreeh = vp; 72339397Smckusick vp->v_freeb = &vfreeh; 72439397Smckusick } else { 72539397Smckusick /* 72639397Smckusick * insert at tail of list 72739397Smckusick */ 72839397Smckusick *vfreet = vp; 72939397Smckusick vp->v_freeb = vfreet; 73039397Smckusick } 73139433Smckusick vp->v_freef = NULL; 73239433Smckusick vfreet = &vp->v_freef; 73348024Smckusick VOP_INACTIVE(vp, p); 73439397Smckusick } 73539433Smckusick 73639433Smckusick /* 73739809Smckusick * Page or buffer structure gets a reference. 73839809Smckusick */ 73953312Smckusick void vhold(vp) 74039809Smckusick register struct vnode *vp; 74139809Smckusick { 74239809Smckusick 74339809Smckusick vp->v_holdcnt++; 74439809Smckusick } 74539809Smckusick 74639809Smckusick /* 74739809Smckusick * Page or buffer structure frees a reference. 74839809Smckusick */ 74953312Smckusick void holdrele(vp) 75039809Smckusick register struct vnode *vp; 75139809Smckusick { 75239809Smckusick 75339809Smckusick if (vp->v_holdcnt <= 0) 75439809Smckusick panic("holdrele: holdcnt"); 75539809Smckusick vp->v_holdcnt--; 75639809Smckusick } 75739809Smckusick 75839809Smckusick /* 75939509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 76039509Smckusick * 76139509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 76239509Smckusick * return error if any are found (nb: this is a user error, not a 76339509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 76439509Smckusick * that are found. 76539509Smckusick */ 76639509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 76739509Smckusick 76839509Smckusick vflush(mp, skipvp, flags) 76939509Smckusick struct mount *mp; 77039509Smckusick struct vnode *skipvp; 77139509Smckusick int flags; 77239509Smckusick { 77339509Smckusick register struct vnode *vp, *nvp; 77439509Smckusick int busy = 0; 77539509Smckusick 77641400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 77741300Smckusick panic("vflush: not busy"); 77841421Smckusick loop: 77941400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 78041421Smckusick if (vp->v_mount != mp) 78141421Smckusick goto loop; 78239509Smckusick nvp = vp->v_mountf; 78339509Smckusick /* 78439509Smckusick * Skip over a selected vnode. 78539509Smckusick */ 78639509Smckusick if (vp == skipvp) 78739509Smckusick continue; 78839509Smckusick /* 78941300Smckusick * Skip over a vnodes marked VSYSTEM. 79041300Smckusick */ 79141300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 79241300Smckusick continue; 79341300Smckusick /* 79439809Smckusick * With v_usecount == 0, all we need to do is clear 79539509Smckusick * out the vnode data structures and we are done. 79639509Smckusick */ 79739809Smckusick if (vp->v_usecount == 0) { 79839509Smckusick vgone(vp); 79939509Smckusick continue; 80039509Smckusick } 80139509Smckusick /* 80239509Smckusick * For block or character devices, revert to an 80339509Smckusick * anonymous device. For all other files, just kill them. 80439509Smckusick */ 80541300Smckusick if (flags & FORCECLOSE) { 80639509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 80739509Smckusick vgone(vp); 80839509Smckusick } else { 80939509Smckusick vclean(vp, 0); 81053547Sheideman vp->v_op = spec_vnodeop_p; 81139509Smckusick insmntque(vp, (struct mount *)0); 81239509Smckusick } 81339509Smckusick continue; 81439509Smckusick } 81539509Smckusick if (busyprt) 81639667Smckusick vprint("vflush: busy vnode", vp); 81739509Smckusick busy++; 81839509Smckusick } 81939509Smckusick if (busy) 82039509Smckusick return (EBUSY); 82139509Smckusick return (0); 82239509Smckusick } 82339509Smckusick 82439509Smckusick /* 82539433Smckusick * Disassociate the underlying file system from a vnode. 82639433Smckusick */ 82741300Smckusick void vclean(vp, flags) 82839433Smckusick register struct vnode *vp; 82945118Smckusick int flags; 83039433Smckusick { 83153580Sheideman USES_VOP_LOCK; 83253580Sheideman USES_VOP_UNLOCK; 83353580Sheideman USES_VOP_CLOSE; 83453547Sheideman USES_VOP_INACTIVE; 83553580Sheideman USES_VOP_RECLAIM; 83653580Sheideman int (**origops)(); 83739484Smckusick int active; 83848024Smckusick struct proc *p = curproc; /* XXX */ 83939433Smckusick 84039484Smckusick /* 84139484Smckusick * Check to see if the vnode is in use. 84239667Smckusick * If so we have to reference it before we clean it out 84339667Smckusick * so that its count cannot fall to zero and generate a 84439667Smckusick * race against ourselves to recycle it. 84539484Smckusick */ 84639809Smckusick if (active = vp->v_usecount) 84739484Smckusick VREF(vp); 84839484Smckusick /* 84939484Smckusick * Prevent the vnode from being recycled or 85039484Smckusick * brought into use while we clean it out. 85139484Smckusick */ 85239667Smckusick if (vp->v_flag & VXLOCK) 85339667Smckusick panic("vclean: deadlock"); 85439433Smckusick vp->v_flag |= VXLOCK; 85539433Smckusick /* 85639667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 85739667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 85839667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 85939667Smckusick * For active vnodes, it ensures that no other activity can 86039667Smckusick * occur while the buffer list is being cleaned out. 86139667Smckusick */ 86239667Smckusick VOP_LOCK(vp); 86341300Smckusick if (flags & DOCLOSE) 86439667Smckusick vinvalbuf(vp, 1); 86539667Smckusick /* 86639433Smckusick * Prevent any further operations on the vnode from 86739433Smckusick * being passed through to the old file system. 86839433Smckusick */ 86939433Smckusick origops = vp->v_op; 87053547Sheideman vp->v_op = dead_vnodeop_p; 87139433Smckusick vp->v_tag = VT_NON; 87239433Smckusick /* 87339484Smckusick * If purging an active vnode, it must be unlocked, closed, 87439484Smckusick * and deactivated before being reclaimed. 87539433Smckusick */ 87653580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 87753580Sheideman vop_unlock_a.a_vp = vp; 87853580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 87939484Smckusick if (active) { 88053580Sheideman /* 88153580Sheideman * Note: these next two calls imply 88253580Sheideman * that vop_close and vop_inactive implementations 88353580Sheideman * cannot count on the ops vector being correctly 88453580Sheideman * set. 88553580Sheideman */ 88653580Sheideman if (flags & DOCLOSE) { 88753580Sheideman vop_close_a.a_desc = VDESC(vop_close); 88853580Sheideman vop_close_a.a_vp = vp; 88953580Sheideman vop_close_a.a_fflag = IO_NDELAY; 89053580Sheideman vop_close_a.a_p = p; 89153580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 89253580Sheideman }; 89353580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 89453580Sheideman vop_inactive_a.a_vp = vp; 89553580Sheideman vop_inactive_a.a_p = p; 89653580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 89739433Smckusick } 89839433Smckusick /* 89939433Smckusick * Reclaim the vnode. 90039433Smckusick */ 90153580Sheideman /* 90253580Sheideman * Emulate VOP_RECLAIM. 90353580Sheideman */ 90453580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 90553580Sheideman vop_reclaim_a.a_vp = vp; 90653580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 90739433Smckusick panic("vclean: cannot reclaim"); 90839484Smckusick if (active) 90939484Smckusick vrele(vp); 91053580Sheideman 91139433Smckusick /* 91239433Smckusick * Done with purge, notify sleepers in vget of the grim news. 91339433Smckusick */ 91439433Smckusick vp->v_flag &= ~VXLOCK; 91539433Smckusick if (vp->v_flag & VXWANT) { 91639433Smckusick vp->v_flag &= ~VXWANT; 91739433Smckusick wakeup((caddr_t)vp); 91839433Smckusick } 91939433Smckusick } 92039433Smckusick 92139433Smckusick /* 92239633Smckusick * Eliminate all activity associated with the requested vnode 92339633Smckusick * and with all vnodes aliased to the requested vnode. 92439633Smckusick */ 92539633Smckusick void vgoneall(vp) 92639633Smckusick register struct vnode *vp; 92739633Smckusick { 92839809Smckusick register struct vnode *vq; 92939633Smckusick 93040665Smckusick if (vp->v_flag & VALIASED) { 93140665Smckusick /* 93240665Smckusick * If a vgone (or vclean) is already in progress, 93340665Smckusick * wait until it is done and return. 93440665Smckusick */ 93540665Smckusick if (vp->v_flag & VXLOCK) { 93640665Smckusick vp->v_flag |= VXWANT; 93740665Smckusick sleep((caddr_t)vp, PINOD); 93840665Smckusick return; 93939633Smckusick } 94040665Smckusick /* 94140665Smckusick * Ensure that vp will not be vgone'd while we 94240665Smckusick * are eliminating its aliases. 94340665Smckusick */ 94440665Smckusick vp->v_flag |= VXLOCK; 94540665Smckusick while (vp->v_flag & VALIASED) { 94640665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 94740665Smckusick if (vq->v_rdev != vp->v_rdev || 94840665Smckusick vq->v_type != vp->v_type || vp == vq) 94940665Smckusick continue; 95040665Smckusick vgone(vq); 95140665Smckusick break; 95240665Smckusick } 95340665Smckusick } 95440665Smckusick /* 95540665Smckusick * Remove the lock so that vgone below will 95640665Smckusick * really eliminate the vnode after which time 95740665Smckusick * vgone will awaken any sleepers. 95840665Smckusick */ 95940665Smckusick vp->v_flag &= ~VXLOCK; 96039633Smckusick } 96139633Smckusick vgone(vp); 96239633Smckusick } 96339633Smckusick 96439633Smckusick /* 96539433Smckusick * Eliminate all activity associated with a vnode 96639433Smckusick * in preparation for reuse. 96739433Smckusick */ 96839433Smckusick void vgone(vp) 96939433Smckusick register struct vnode *vp; 97039433Smckusick { 97139809Smckusick register struct vnode *vq; 97239615Smckusick struct vnode *vx; 97339433Smckusick 97439433Smckusick /* 97540548Smckusick * If a vgone (or vclean) is already in progress, 97640548Smckusick * wait until it is done and return. 97740548Smckusick */ 97840548Smckusick if (vp->v_flag & VXLOCK) { 97940548Smckusick vp->v_flag |= VXWANT; 98040548Smckusick sleep((caddr_t)vp, PINOD); 98140548Smckusick return; 98240548Smckusick } 98340548Smckusick /* 98439433Smckusick * Clean out the filesystem specific data. 98539433Smckusick */ 98641300Smckusick vclean(vp, DOCLOSE); 98739433Smckusick /* 98839433Smckusick * Delete from old mount point vnode list, if on one. 98939433Smckusick */ 99039433Smckusick if (vp->v_mountb) { 99139433Smckusick if (vq = vp->v_mountf) 99239433Smckusick vq->v_mountb = vp->v_mountb; 99339433Smckusick *vp->v_mountb = vq; 99439433Smckusick vp->v_mountf = NULL; 99539433Smckusick vp->v_mountb = NULL; 99652311Smckusick vp->v_mount = NULL; 99739433Smckusick } 99839433Smckusick /* 99939433Smckusick * If special device, remove it from special device alias list. 100039433Smckusick */ 100139433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 100239809Smckusick if (*vp->v_hashchain == vp) { 100339809Smckusick *vp->v_hashchain = vp->v_specnext; 100439433Smckusick } else { 100539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 100639615Smckusick if (vq->v_specnext != vp) 100739433Smckusick continue; 100839615Smckusick vq->v_specnext = vp->v_specnext; 100939433Smckusick break; 101039433Smckusick } 101139615Smckusick if (vq == NULL) 101239433Smckusick panic("missing bdev"); 101339433Smckusick } 101439615Smckusick if (vp->v_flag & VALIASED) { 101552416Storek vx = NULL; 101639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 101740108Smckusick if (vq->v_rdev != vp->v_rdev || 101840108Smckusick vq->v_type != vp->v_type) 101939615Smckusick continue; 102052416Storek if (vx) 102152416Storek break; 102239615Smckusick vx = vq; 102339615Smckusick } 102452416Storek if (vx == NULL) 102539615Smckusick panic("missing alias"); 102652416Storek if (vq == NULL) 102739615Smckusick vx->v_flag &= ~VALIASED; 102839615Smckusick vp->v_flag &= ~VALIASED; 102939615Smckusick } 103039615Smckusick FREE(vp->v_specinfo, M_VNODE); 103139615Smckusick vp->v_specinfo = NULL; 103239433Smckusick } 103339433Smckusick /* 103439433Smckusick * If it is on the freelist, move it to the head of the list. 103539433Smckusick */ 103639433Smckusick if (vp->v_freeb) { 103739433Smckusick if (vq = vp->v_freef) 103839433Smckusick vq->v_freeb = vp->v_freeb; 103939433Smckusick else 104039433Smckusick vfreet = vp->v_freeb; 104139433Smckusick *vp->v_freeb = vq; 104239433Smckusick vp->v_freef = vfreeh; 104339433Smckusick vp->v_freeb = &vfreeh; 104439433Smckusick vfreeh->v_freeb = &vp->v_freef; 104539433Smckusick vfreeh = vp; 104639433Smckusick } 104739484Smckusick vp->v_type = VBAD; 104839433Smckusick } 104939633Smckusick 105039633Smckusick /* 105139821Smckusick * Lookup a vnode by device number. 105239821Smckusick */ 105339821Smckusick vfinddev(dev, type, vpp) 105439821Smckusick dev_t dev; 105539821Smckusick enum vtype type; 105639821Smckusick struct vnode **vpp; 105739821Smckusick { 105839821Smckusick register struct vnode *vp; 105939821Smckusick 106039821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 106139821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 106239821Smckusick continue; 106339821Smckusick *vpp = vp; 106439821Smckusick return (0); 106539821Smckusick } 106639821Smckusick return (1); 106739821Smckusick } 106839821Smckusick 106939821Smckusick /* 107039633Smckusick * Calculate the total number of references to a special device. 107139633Smckusick */ 107239633Smckusick vcount(vp) 107339633Smckusick register struct vnode *vp; 107439633Smckusick { 107539809Smckusick register struct vnode *vq; 107639633Smckusick int count; 107739633Smckusick 107839633Smckusick if ((vp->v_flag & VALIASED) == 0) 107939809Smckusick return (vp->v_usecount); 108039633Smckusick loop: 108139809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 108240108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 108339633Smckusick continue; 108439633Smckusick /* 108539633Smckusick * Alias, but not in use, so flush it out. 108639633Smckusick */ 108739809Smckusick if (vq->v_usecount == 0) { 108839633Smckusick vgone(vq); 108939633Smckusick goto loop; 109039633Smckusick } 109139809Smckusick count += vq->v_usecount; 109239633Smckusick } 109339633Smckusick return (count); 109439633Smckusick } 109539667Smckusick 109639667Smckusick /* 109739667Smckusick * Print out a description of a vnode. 109839667Smckusick */ 109939667Smckusick static char *typename[] = 110040286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 110139667Smckusick 110239667Smckusick vprint(label, vp) 110339667Smckusick char *label; 110439667Smckusick register struct vnode *vp; 110539667Smckusick { 110653547Sheideman USES_VOP_PRINT; 110739913Smckusick char buf[64]; 110839667Smckusick 110939667Smckusick if (label != NULL) 111039667Smckusick printf("%s: ", label); 111150109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 111250109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 111350109Smckusick vp->v_holdcnt); 111439913Smckusick buf[0] = '\0'; 111539913Smckusick if (vp->v_flag & VROOT) 111639913Smckusick strcat(buf, "|VROOT"); 111739913Smckusick if (vp->v_flag & VTEXT) 111839913Smckusick strcat(buf, "|VTEXT"); 111941300Smckusick if (vp->v_flag & VSYSTEM) 112041300Smckusick strcat(buf, "|VSYSTEM"); 112141300Smckusick if (vp->v_flag & VXLOCK) 112241300Smckusick strcat(buf, "|VXLOCK"); 112341300Smckusick if (vp->v_flag & VXWANT) 112441300Smckusick strcat(buf, "|VXWANT"); 112541300Smckusick if (vp->v_flag & VBWAIT) 112641300Smckusick strcat(buf, "|VBWAIT"); 112739913Smckusick if (vp->v_flag & VALIASED) 112839913Smckusick strcat(buf, "|VALIASED"); 112939913Smckusick if (buf[0] != '\0') 113039913Smckusick printf(" flags (%s)", &buf[1]); 113139913Smckusick printf("\n\t"); 113239667Smckusick VOP_PRINT(vp); 113339667Smckusick } 113441110Smarc 113549691Smckusick #ifdef DEBUG 113649691Smckusick /* 113749691Smckusick * List all of the locked vnodes in the system. 113849691Smckusick * Called when debugging the kernel. 113949691Smckusick */ 114049691Smckusick printlockedvnodes() 114149691Smckusick { 114253547Sheideman USES_VOP_ISLOCKED; 114349691Smckusick register struct mount *mp; 114449691Smckusick register struct vnode *vp; 114549691Smckusick 114649691Smckusick printf("Locked vnodes\n"); 114749691Smckusick mp = rootfs; 114849691Smckusick do { 114949691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 115049691Smckusick if (VOP_ISLOCKED(vp)) 115149691Smckusick vprint((char *)0, vp); 115249691Smckusick mp = mp->mnt_next; 115349691Smckusick } while (mp != rootfs); 115449691Smckusick } 115549691Smckusick #endif 115649691Smckusick 115741110Smarc int kinfo_vdebug = 1; 115841110Smarc int kinfo_vgetfailed; 115941110Smarc #define KINFO_VNODESLOP 10 116041110Smarc /* 116141110Smarc * Dump vnode list (via kinfo). 116241110Smarc * Copyout address of vnode followed by vnode. 116341110Smarc */ 116445118Smckusick /* ARGSUSED */ 116541110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 116645118Smckusick int op; 116741110Smarc char *where; 116845118Smckusick int *acopysize, arg, *aneeded; 116941110Smarc { 117041110Smarc register struct mount *mp = rootfs; 117141300Smckusick struct mount *omp; 117241110Smarc struct vnode *vp; 117341110Smarc register char *bp = where, *savebp; 117453818Smckusick char *ewhere; 117541110Smarc int error; 117641110Smarc 117741110Smarc #define VPTRSZ sizeof (struct vnode *) 117841110Smarc #define VNODESZ sizeof (struct vnode) 117941110Smarc if (where == NULL) { 118041110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 118141110Smarc return (0); 118241110Smarc } 118353818Smckusick ewhere = where + *acopysize; 118441110Smarc 118541110Smarc do { 118641300Smckusick if (vfs_busy(mp)) { 118741400Smckusick mp = mp->mnt_next; 118841300Smckusick continue; 118941300Smckusick } 119041110Smarc savebp = bp; 119141110Smarc again: 119241421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 119341422Smckusick /* 119441422Smckusick * Check that the vp is still associated with 119541422Smckusick * this filesystem. RACE: could have been 119641422Smckusick * recycled onto the same filesystem. 119741422Smckusick */ 119841421Smckusick if (vp->v_mount != mp) { 119941421Smckusick if (kinfo_vdebug) 120041421Smckusick printf("kinfo: vp changed\n"); 120141421Smckusick bp = savebp; 120241421Smckusick goto again; 120341421Smckusick } 120441110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 120541110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 120641110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 120741422Smckusick VNODESZ)))) 120841110Smarc return (error); 120941110Smarc bp += VPTRSZ + VNODESZ; 121041110Smarc } 121141300Smckusick omp = mp; 121241400Smckusick mp = mp->mnt_next; 121341300Smckusick vfs_unbusy(omp); 121441110Smarc } while (mp != rootfs); 121541110Smarc 121641110Smarc *aneeded = bp - where; 121741110Smarc if (bp > ewhere) 121841110Smarc *acopysize = ewhere - where; 121941110Smarc else 122041110Smarc *acopysize = bp - where; 122141110Smarc return (0); 122241110Smarc } 1223