137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*52415Smckusick * @(#)vfs_subr.c 7.68 (Berkeley) 02/05/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> 19*52415Smckusick #include <sys/stat.h> 2051460Sbostic #include <sys/specdev.h> 2151460Sbostic #include <sys/namei.h> 2251460Sbostic #include <sys/ucred.h> 2351460Sbostic #include <sys/buf.h> 2451460Sbostic #include <sys/errno.h> 2551460Sbostic #include <sys/malloc.h> 2637488Smckusick 27*52415Smckusick enum vtype iftovt_tab[16] = { 28*52415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 29*52415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 30*52415Smckusick }; 31*52415Smckusick int vttoif_tab[9] = { 32*52415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 33*52415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 34*52415Smckusick }; 35*52415Smckusick 3637488Smckusick /* 3737488Smckusick * Remove a mount point from the list of mounted filesystems. 3837488Smckusick * Unmount of the root is illegal. 3937488Smckusick */ 4037488Smckusick void 4137488Smckusick vfs_remove(mp) 4237488Smckusick register struct mount *mp; 4337488Smckusick { 4437488Smckusick 4537488Smckusick if (mp == rootfs) 4637488Smckusick panic("vfs_remove: unmounting root"); 4741400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 4841400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 4941400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 5037488Smckusick vfs_unlock(mp); 5137488Smckusick } 5237488Smckusick 5337488Smckusick /* 5437488Smckusick * Lock a filesystem. 5537488Smckusick * Used to prevent access to it while mounting and unmounting. 5637488Smckusick */ 5737488Smckusick vfs_lock(mp) 5837488Smckusick register struct mount *mp; 5937488Smckusick { 6037488Smckusick 6141400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 6241400Smckusick mp->mnt_flag |= MNT_MWAIT; 6339045Smckusick sleep((caddr_t)mp, PVFS); 6439045Smckusick } 6541400Smckusick mp->mnt_flag |= MNT_MLOCK; 6637488Smckusick return (0); 6737488Smckusick } 6837488Smckusick 6937488Smckusick /* 7037488Smckusick * Unlock a locked filesystem. 7137488Smckusick * Panic if filesystem is not locked. 7237488Smckusick */ 7337488Smckusick void 7437488Smckusick vfs_unlock(mp) 7537488Smckusick register struct mount *mp; 7637488Smckusick { 7737488Smckusick 7841400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 7941300Smckusick panic("vfs_unlock: not locked"); 8041400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 8141400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 8241400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 8337488Smckusick wakeup((caddr_t)mp); 8437488Smckusick } 8537488Smckusick } 8637488Smckusick 8737488Smckusick /* 8841300Smckusick * Mark a mount point as busy. 8941300Smckusick * Used to synchronize access and to delay unmounting. 9041300Smckusick */ 9141300Smckusick vfs_busy(mp) 9241300Smckusick register struct mount *mp; 9341300Smckusick { 9441300Smckusick 9541400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 9641400Smckusick mp->mnt_flag |= MNT_MPWANT; 9741400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 9841300Smckusick } 9941419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 10041419Smckusick return (1); 10141400Smckusick mp->mnt_flag |= MNT_MPBUSY; 10241300Smckusick return (0); 10341300Smckusick } 10441300Smckusick 10541300Smckusick /* 10641300Smckusick * Free a busy filesystem. 10741300Smckusick * Panic if filesystem is not busy. 10841300Smckusick */ 10941300Smckusick vfs_unbusy(mp) 11041300Smckusick register struct mount *mp; 11141300Smckusick { 11241300Smckusick 11341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 11441300Smckusick panic("vfs_unbusy: not busy"); 11541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 11641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 11741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 11841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 11941300Smckusick } 12041300Smckusick } 12141300Smckusick 12241300Smckusick /* 12337488Smckusick * Lookup a mount point by filesystem identifier. 12437488Smckusick */ 12537488Smckusick struct mount * 12637488Smckusick getvfs(fsid) 12737488Smckusick fsid_t *fsid; 12837488Smckusick { 12937488Smckusick register struct mount *mp; 13037488Smckusick 13138288Smckusick mp = rootfs; 13238288Smckusick do { 13341400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 13441400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 13538288Smckusick return (mp); 13637488Smckusick } 13741400Smckusick mp = mp->mnt_next; 13838288Smckusick } while (mp != rootfs); 13938288Smckusick return ((struct mount *)0); 14037488Smckusick } 14137488Smckusick 14237488Smckusick /* 14337488Smckusick * Set vnode attributes to VNOVAL 14437488Smckusick */ 14537488Smckusick void vattr_null(vap) 14637488Smckusick register struct vattr *vap; 14737488Smckusick { 14837488Smckusick 14937488Smckusick vap->va_type = VNON; 15052005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 15152005Smckusick #ifdef _NOQUAD 15252005Smckusick vap->va_size_rsv = vap->va_bytes_rsv = VNOVAL; 15352005Smckusick #endif 15437488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 15552005Smckusick vap->va_fsid = vap->va_fileid = 15652005Smckusick vap->va_blocksize = vap->va_rdev = 15737488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 15837488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 15938258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 16038258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 16137488Smckusick } 16238265Smckusick 16338265Smckusick /* 16439397Smckusick * Routines having to do with the management of the vnode table. 16539397Smckusick */ 16639397Smckusick struct vnode *vfreeh, **vfreet; 16739447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 16839635Smckusick extern void vclean(); 16940883Smckusick long numvnodes; 17041363Smckusick struct vattr va_null; 17139397Smckusick 17239397Smckusick /* 17339433Smckusick * Initialize the vnode structures and initialize each file system type. 17439397Smckusick */ 17539433Smckusick vfsinit() 17639397Smckusick { 17739433Smckusick struct vfsops **vfsp; 17839397Smckusick 17939433Smckusick /* 18039433Smckusick * Initialize the vnode name cache 18139433Smckusick */ 18239433Smckusick nchinit(); 18339433Smckusick /* 18439433Smckusick * Initialize each file system type. 18539433Smckusick */ 18641363Smckusick vattr_null(&va_null); 18739433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 18839433Smckusick if (*vfsp == NULL) 18939433Smckusick continue; 19039433Smckusick (*(*vfsp)->vfs_init)(); 19139433Smckusick } 19239397Smckusick } 19339397Smckusick 19439397Smckusick /* 19539397Smckusick * Return the next vnode from the free list. 19639397Smckusick */ 19739397Smckusick getnewvnode(tag, mp, vops, vpp) 19839397Smckusick enum vtagtype tag; 19939397Smckusick struct mount *mp; 20039397Smckusick struct vnodeops *vops; 20139397Smckusick struct vnode **vpp; 20239397Smckusick { 20339397Smckusick register struct vnode *vp, *vq; 20439397Smckusick 20540883Smckusick if (numvnodes < desiredvnodes) { 20645118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 20745118Smckusick M_VNODE, M_WAITOK); 20840883Smckusick bzero((char *)vp, sizeof *vp); 20940883Smckusick numvnodes++; 21040883Smckusick } else { 21140883Smckusick if ((vp = vfreeh) == NULL) { 21240883Smckusick tablefull("vnode"); 21340883Smckusick *vpp = 0; 21440883Smckusick return (ENFILE); 21540883Smckusick } 21640883Smckusick if (vp->v_usecount) 21740883Smckusick panic("free vnode isn't"); 21840883Smckusick if (vq = vp->v_freef) 21940883Smckusick vq->v_freeb = &vfreeh; 22040883Smckusick else 22140883Smckusick vfreet = &vfreeh; 22240883Smckusick vfreeh = vq; 22340883Smckusick vp->v_freef = NULL; 22440883Smckusick vp->v_freeb = NULL; 22552190Smckusick vp->v_lease = NULL; 22640883Smckusick if (vp->v_type != VBAD) 22740883Smckusick vgone(vp); 22852006Smckusick if (vp->v_data) 22952006Smckusick panic("cleaned vnode isn't"); 23040883Smckusick vp->v_flag = 0; 23140883Smckusick vp->v_lastr = 0; 23240883Smckusick vp->v_socket = 0; 23339397Smckusick } 23439512Smckusick vp->v_type = VNON; 23539397Smckusick cache_purge(vp); 23639397Smckusick vp->v_tag = tag; 23739433Smckusick vp->v_op = vops; 23839397Smckusick insmntque(vp, mp); 23939397Smckusick VREF(vp); 24039397Smckusick *vpp = vp; 24139397Smckusick return (0); 24239397Smckusick } 24339397Smckusick 24439397Smckusick /* 24539397Smckusick * Move a vnode from one mount queue to another. 24639397Smckusick */ 24739397Smckusick insmntque(vp, mp) 24839397Smckusick register struct vnode *vp; 24939397Smckusick register struct mount *mp; 25039397Smckusick { 25149973Smckusick register struct vnode *vq; 25239397Smckusick 25339397Smckusick /* 25439397Smckusick * Delete from old mount point vnode list, if on one. 25539397Smckusick */ 25639397Smckusick if (vp->v_mountb) { 25739397Smckusick if (vq = vp->v_mountf) 25839397Smckusick vq->v_mountb = vp->v_mountb; 25939397Smckusick *vp->v_mountb = vq; 26039397Smckusick } 26139397Smckusick /* 26239397Smckusick * Insert into list of vnodes for the new mount point, if available. 26339397Smckusick */ 26439621Smckusick vp->v_mount = mp; 26539397Smckusick if (mp == NULL) { 26639397Smckusick vp->v_mountf = NULL; 26739397Smckusick vp->v_mountb = NULL; 26839397Smckusick return; 26939397Smckusick } 27049973Smckusick if (vq = mp->mnt_mounth) 27149973Smckusick vq->v_mountb = &vp->v_mountf; 27249973Smckusick vp->v_mountf = vq; 27349973Smckusick vp->v_mountb = &mp->mnt_mounth; 27449973Smckusick mp->mnt_mounth = vp; 27539397Smckusick } 27639397Smckusick 27739397Smckusick /* 27849232Smckusick * Make sure all write-behind blocks associated 27949232Smckusick * with mount point are flushed out (from sync). 28049232Smckusick */ 28149232Smckusick mntflushbuf(mountp, flags) 28249232Smckusick struct mount *mountp; 28349232Smckusick int flags; 28449232Smckusick { 28549232Smckusick register struct vnode *vp; 28649232Smckusick 28749232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 28849232Smckusick panic("mntflushbuf: not busy"); 28949232Smckusick loop: 29049232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 29149232Smckusick if (VOP_ISLOCKED(vp)) 29249232Smckusick continue; 29349232Smckusick if (vget(vp)) 29449232Smckusick goto loop; 29549232Smckusick vflushbuf(vp, flags); 29649232Smckusick vput(vp); 29749232Smckusick if (vp->v_mount != mountp) 29849232Smckusick goto loop; 29949232Smckusick } 30049232Smckusick } 30149232Smckusick 30249232Smckusick /* 30349232Smckusick * Flush all dirty buffers associated with a vnode. 30449232Smckusick */ 30549232Smckusick vflushbuf(vp, flags) 30649232Smckusick register struct vnode *vp; 30749232Smckusick int flags; 30849232Smckusick { 30949232Smckusick register struct buf *bp; 31049232Smckusick struct buf *nbp; 31149232Smckusick int s; 31249232Smckusick 31349232Smckusick loop: 31449232Smckusick s = splbio(); 31549232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 31649232Smckusick nbp = bp->b_blockf; 31749232Smckusick if ((bp->b_flags & B_BUSY)) 31849232Smckusick continue; 31949232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 32049232Smckusick panic("vflushbuf: not dirty"); 32149232Smckusick bremfree(bp); 32249232Smckusick bp->b_flags |= B_BUSY; 32349232Smckusick splx(s); 32449232Smckusick /* 32549232Smckusick * Wait for I/O associated with indirect blocks to complete, 32649232Smckusick * since there is no way to quickly wait for them below. 32749232Smckusick * NB: This is really specific to ufs, but is done here 32849232Smckusick * as it is easier and quicker. 32949232Smckusick */ 33049460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 33149232Smckusick (void) bawrite(bp); 33249460Smckusick else 33349232Smckusick (void) bwrite(bp); 33449460Smckusick goto loop; 33549232Smckusick } 33649232Smckusick splx(s); 33749232Smckusick if ((flags & B_SYNC) == 0) 33849232Smckusick return; 33949232Smckusick s = splbio(); 34049232Smckusick while (vp->v_numoutput) { 34149232Smckusick vp->v_flag |= VBWAIT; 34249232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 34349232Smckusick } 34449232Smckusick splx(s); 34549232Smckusick if (vp->v_dirtyblkhd) { 34649232Smckusick vprint("vflushbuf: dirty", vp); 34749232Smckusick goto loop; 34849232Smckusick } 34949232Smckusick } 35049232Smckusick 35149232Smckusick /* 35249232Smckusick * Update outstanding I/O count and do wakeup if requested. 35349232Smckusick */ 35449232Smckusick vwakeup(bp) 35549232Smckusick register struct buf *bp; 35649232Smckusick { 35749232Smckusick register struct vnode *vp; 35849232Smckusick 35949232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 36049232Smckusick if (vp = bp->b_vp) { 36149232Smckusick vp->v_numoutput--; 36249232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 36349232Smckusick if (vp->v_numoutput < 0) 36449232Smckusick panic("vwakeup: neg numoutput"); 36549232Smckusick vp->v_flag &= ~VBWAIT; 36649232Smckusick wakeup((caddr_t)&vp->v_numoutput); 36749232Smckusick } 36849232Smckusick } 36949232Smckusick } 37049232Smckusick 37149232Smckusick /* 37249232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 37349232Smckusick * 37449232Smckusick * Go through the list of vnodes associated with the file system; 37549232Smckusick * for each vnode invalidate any buffers that it holds. Normally 37649232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 37749232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 37849232Smckusick * returns the count of dirty buffers when it is finished. 37949232Smckusick */ 38049232Smckusick mntinvalbuf(mountp) 38149232Smckusick struct mount *mountp; 38249232Smckusick { 38349232Smckusick register struct vnode *vp; 38449232Smckusick int dirty = 0; 38549232Smckusick 38649232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 38749232Smckusick panic("mntinvalbuf: not busy"); 38849232Smckusick loop: 38949232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 39049232Smckusick if (vget(vp)) 39149232Smckusick goto loop; 39249232Smckusick dirty += vinvalbuf(vp, 1); 39349232Smckusick vput(vp); 39449232Smckusick if (vp->v_mount != mountp) 39549232Smckusick goto loop; 39649232Smckusick } 39749232Smckusick return (dirty); 39849232Smckusick } 39949232Smckusick 40049232Smckusick /* 40149232Smckusick * Flush out and invalidate all buffers associated with a vnode. 40249232Smckusick * Called with the underlying object locked. 40349232Smckusick */ 40449232Smckusick vinvalbuf(vp, save) 40549232Smckusick register struct vnode *vp; 40649232Smckusick int save; 40749232Smckusick { 40849232Smckusick register struct buf *bp; 40949232Smckusick struct buf *nbp, *blist; 41049232Smckusick int s, dirty = 0; 41149232Smckusick 41249232Smckusick for (;;) { 41349232Smckusick if (blist = vp->v_dirtyblkhd) 41449232Smckusick /* void */; 41549232Smckusick else if (blist = vp->v_cleanblkhd) 41649232Smckusick /* void */; 41749232Smckusick else 41849232Smckusick break; 41949232Smckusick for (bp = blist; bp; bp = nbp) { 42049232Smckusick nbp = bp->b_blockf; 42149232Smckusick s = splbio(); 42249232Smckusick if (bp->b_flags & B_BUSY) { 42349232Smckusick bp->b_flags |= B_WANTED; 42449232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 42549232Smckusick splx(s); 42649232Smckusick break; 42749232Smckusick } 42849232Smckusick bremfree(bp); 42949232Smckusick bp->b_flags |= B_BUSY; 43049232Smckusick splx(s); 43149232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 43251568Smckusick dirty++; 43351568Smckusick (void) VOP_BWRITE(bp); 43449232Smckusick break; 43549232Smckusick } 43649232Smckusick if (bp->b_vp != vp) 43749232Smckusick reassignbuf(bp, bp->b_vp); 43849232Smckusick else 43949232Smckusick bp->b_flags |= B_INVAL; 44049232Smckusick brelse(bp); 44149232Smckusick } 44249232Smckusick } 44349232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 44449232Smckusick panic("vinvalbuf: flush failed"); 44549232Smckusick return (dirty); 44649232Smckusick } 44749232Smckusick 44849232Smckusick /* 44949232Smckusick * Associate a buffer with a vnode. 45049232Smckusick */ 45149232Smckusick bgetvp(vp, bp) 45249232Smckusick register struct vnode *vp; 45349232Smckusick register struct buf *bp; 45449232Smckusick { 45549973Smckusick register struct vnode *vq; 45649973Smckusick register struct buf *bq; 45749232Smckusick 45849232Smckusick if (bp->b_vp) 45949232Smckusick panic("bgetvp: not free"); 46049232Smckusick VHOLD(vp); 46149232Smckusick bp->b_vp = vp; 46249232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 46349232Smckusick bp->b_dev = vp->v_rdev; 46449232Smckusick else 46549232Smckusick bp->b_dev = NODEV; 46649232Smckusick /* 46749232Smckusick * Insert onto list for new vnode. 46849232Smckusick */ 46949973Smckusick if (bq = vp->v_cleanblkhd) 47049973Smckusick bq->b_blockb = &bp->b_blockf; 47149973Smckusick bp->b_blockf = bq; 47249973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 47349973Smckusick vp->v_cleanblkhd = bp; 47449232Smckusick } 47549232Smckusick 47649232Smckusick /* 47749232Smckusick * Disassociate a buffer from a vnode. 47849232Smckusick */ 47949232Smckusick brelvp(bp) 48049232Smckusick register struct buf *bp; 48149232Smckusick { 48249232Smckusick struct buf *bq; 48349232Smckusick struct vnode *vp; 48449232Smckusick 48549232Smckusick if (bp->b_vp == (struct vnode *) 0) 48649232Smckusick panic("brelvp: NULL"); 48749232Smckusick /* 48849232Smckusick * Delete from old vnode list, if on one. 48949232Smckusick */ 49049232Smckusick if (bp->b_blockb) { 49149232Smckusick if (bq = bp->b_blockf) 49249232Smckusick bq->b_blockb = bp->b_blockb; 49349232Smckusick *bp->b_blockb = bq; 49449232Smckusick bp->b_blockf = NULL; 49549232Smckusick bp->b_blockb = NULL; 49649232Smckusick } 49749232Smckusick vp = bp->b_vp; 49849232Smckusick bp->b_vp = (struct vnode *) 0; 49949232Smckusick HOLDRELE(vp); 50049232Smckusick } 50149232Smckusick 50249232Smckusick /* 50349232Smckusick * Reassign a buffer from one vnode to another. 50449232Smckusick * Used to assign file specific control information 50549232Smckusick * (indirect blocks) to the vnode to which they belong. 50649232Smckusick */ 50749232Smckusick reassignbuf(bp, newvp) 50849232Smckusick register struct buf *bp; 50949232Smckusick register struct vnode *newvp; 51049232Smckusick { 51149232Smckusick register struct buf *bq, **listheadp; 51249232Smckusick 51349232Smckusick if (newvp == NULL) 51449232Smckusick panic("reassignbuf: NULL"); 51549232Smckusick /* 51649232Smckusick * Delete from old vnode list, if on one. 51749232Smckusick */ 51849232Smckusick if (bp->b_blockb) { 51949232Smckusick if (bq = bp->b_blockf) 52049232Smckusick bq->b_blockb = bp->b_blockb; 52149232Smckusick *bp->b_blockb = bq; 52249232Smckusick } 52349232Smckusick /* 52449232Smckusick * If dirty, put on list of dirty buffers; 52549232Smckusick * otherwise insert onto list of clean buffers. 52649232Smckusick */ 52749232Smckusick if (bp->b_flags & B_DELWRI) 52849232Smckusick listheadp = &newvp->v_dirtyblkhd; 52949232Smckusick else 53049232Smckusick listheadp = &newvp->v_cleanblkhd; 53149973Smckusick if (bq = *listheadp) 53249973Smckusick bq->b_blockb = &bp->b_blockf; 53349973Smckusick bp->b_blockf = bq; 53449973Smckusick bp->b_blockb = listheadp; 53549973Smckusick *listheadp = bp; 53649232Smckusick } 53749232Smckusick 53849232Smckusick /* 53939433Smckusick * Create a vnode for a block device. 54039433Smckusick * Used for root filesystem, argdev, and swap areas. 54139433Smckusick * Also used for memory file system special devices. 54239397Smckusick */ 54339433Smckusick bdevvp(dev, vpp) 54439433Smckusick dev_t dev; 54539433Smckusick struct vnode **vpp; 54639433Smckusick { 54739433Smckusick register struct vnode *vp; 54839433Smckusick struct vnode *nvp; 54939433Smckusick int error; 55039433Smckusick 55146989Smckusick if (dev == NODEV) 55246989Smckusick return (0); 55339447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 55439433Smckusick if (error) { 55539433Smckusick *vpp = 0; 55639433Smckusick return (error); 55739433Smckusick } 55839433Smckusick vp = nvp; 55939433Smckusick vp->v_type = VBLK; 56039615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 56139433Smckusick vput(vp); 56239433Smckusick vp = nvp; 56339433Smckusick } 56439433Smckusick *vpp = vp; 56539433Smckusick return (0); 56639433Smckusick } 56739433Smckusick 56839433Smckusick /* 56939433Smckusick * Check to see if the new vnode represents a special device 57039433Smckusick * for which we already have a vnode (either because of 57139433Smckusick * bdevvp() or because of a different vnode representing 57239433Smckusick * the same block device). If such an alias exists, deallocate 57339509Smckusick * the existing contents and return the aliased vnode. The 57439433Smckusick * caller is responsible for filling it with its new contents. 57539433Smckusick */ 57639433Smckusick struct vnode * 57739615Smckusick checkalias(nvp, nvp_rdev, mp) 57839433Smckusick register struct vnode *nvp; 57939615Smckusick dev_t nvp_rdev; 58039433Smckusick struct mount *mp; 58139433Smckusick { 58239433Smckusick register struct vnode *vp; 58339615Smckusick struct vnode **vpp; 58439433Smckusick 58539433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 58641400Smckusick return (NULLVP); 58739615Smckusick 58839615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 58939433Smckusick loop: 59039615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 59139615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 59239433Smckusick continue; 59339615Smckusick /* 59439615Smckusick * Alias, but not in use, so flush it out. 59539615Smckusick */ 59639809Smckusick if (vp->v_usecount == 0) { 59739615Smckusick vgone(vp); 59839615Smckusick goto loop; 59939615Smckusick } 60039633Smckusick if (vget(vp)) 60139633Smckusick goto loop; 60239433Smckusick break; 60339433Smckusick } 60439615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 60539615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 60639615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 60739615Smckusick nvp->v_rdev = nvp_rdev; 60839809Smckusick nvp->v_hashchain = vpp; 60939615Smckusick nvp->v_specnext = *vpp; 61042152Smckusick nvp->v_specflags = 0; 61139615Smckusick *vpp = nvp; 61240640Smckusick if (vp != NULL) { 61340640Smckusick nvp->v_flag |= VALIASED; 61440640Smckusick vp->v_flag |= VALIASED; 61540640Smckusick vput(vp); 61640640Smckusick } 61741400Smckusick return (NULLVP); 61839433Smckusick } 61939484Smckusick VOP_UNLOCK(vp); 62039484Smckusick vclean(vp, 0); 62139433Smckusick vp->v_op = nvp->v_op; 62239433Smckusick vp->v_tag = nvp->v_tag; 62339433Smckusick nvp->v_type = VNON; 62439433Smckusick insmntque(vp, mp); 62539433Smckusick return (vp); 62639433Smckusick } 62739433Smckusick 62839433Smckusick /* 62939433Smckusick * Grab a particular vnode from the free list, increment its 63039433Smckusick * reference count and lock it. The vnode lock bit is set the 63139433Smckusick * vnode is being eliminated in vgone. The process is awakened 63239433Smckusick * when the transition is completed, and an error returned to 63339433Smckusick * indicate that the vnode is no longer usable (possibly having 63439433Smckusick * been changed to a new file system type). 63539433Smckusick */ 63639397Smckusick vget(vp) 63739397Smckusick register struct vnode *vp; 63839397Smckusick { 63939397Smckusick register struct vnode *vq; 64039397Smckusick 64139433Smckusick if (vp->v_flag & VXLOCK) { 64239433Smckusick vp->v_flag |= VXWANT; 64339433Smckusick sleep((caddr_t)vp, PINOD); 64439433Smckusick return (1); 64539433Smckusick } 64639809Smckusick if (vp->v_usecount == 0) { 64739433Smckusick if (vq = vp->v_freef) 64839433Smckusick vq->v_freeb = vp->v_freeb; 64939433Smckusick else 65039433Smckusick vfreet = vp->v_freeb; 65139433Smckusick *vp->v_freeb = vq; 65239433Smckusick vp->v_freef = NULL; 65339433Smckusick vp->v_freeb = NULL; 65439433Smckusick } 65539397Smckusick VREF(vp); 65639433Smckusick VOP_LOCK(vp); 65739433Smckusick return (0); 65839397Smckusick } 65939397Smckusick 66039397Smckusick /* 66139397Smckusick * Vnode reference, just increment the count 66239397Smckusick */ 66339397Smckusick void vref(vp) 66439397Smckusick struct vnode *vp; 66539397Smckusick { 66639397Smckusick 66739809Smckusick vp->v_usecount++; 66839397Smckusick } 66939397Smckusick 67039397Smckusick /* 67139397Smckusick * vput(), just unlock and vrele() 67239397Smckusick */ 67339397Smckusick void vput(vp) 67439397Smckusick register struct vnode *vp; 67539397Smckusick { 67639397Smckusick VOP_UNLOCK(vp); 67739397Smckusick vrele(vp); 67839397Smckusick } 67939397Smckusick 68039397Smckusick /* 68139397Smckusick * Vnode release. 68239397Smckusick * If count drops to zero, call inactive routine and return to freelist. 68339397Smckusick */ 68439397Smckusick void vrele(vp) 68539397Smckusick register struct vnode *vp; 68639397Smckusick { 68748024Smckusick struct proc *p = curproc; /* XXX */ 68839397Smckusick 68950109Smckusick #ifdef DIAGNOSTIC 69039397Smckusick if (vp == NULL) 69139433Smckusick panic("vrele: null vp"); 69250109Smckusick #endif 69339809Smckusick vp->v_usecount--; 69439809Smckusick if (vp->v_usecount > 0) 69539397Smckusick return; 69650109Smckusick #ifdef DIAGNOSTIC 69750109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 69850109Smckusick vprint("vrele: bad ref count", vp); 69950109Smckusick panic("vrele: ref cnt"); 70050109Smckusick } 70150109Smckusick #endif 70241400Smckusick if (vfreeh == NULLVP) { 70339397Smckusick /* 70439397Smckusick * insert into empty list 70539397Smckusick */ 70639397Smckusick vfreeh = vp; 70739397Smckusick vp->v_freeb = &vfreeh; 70839397Smckusick } else { 70939397Smckusick /* 71039397Smckusick * insert at tail of list 71139397Smckusick */ 71239397Smckusick *vfreet = vp; 71339397Smckusick vp->v_freeb = vfreet; 71439397Smckusick } 71539433Smckusick vp->v_freef = NULL; 71639433Smckusick vfreet = &vp->v_freef; 71748024Smckusick VOP_INACTIVE(vp, p); 71839397Smckusick } 71939433Smckusick 72039433Smckusick /* 72139809Smckusick * Page or buffer structure gets a reference. 72239809Smckusick */ 72339809Smckusick vhold(vp) 72439809Smckusick register struct vnode *vp; 72539809Smckusick { 72639809Smckusick 72739809Smckusick vp->v_holdcnt++; 72839809Smckusick } 72939809Smckusick 73039809Smckusick /* 73139809Smckusick * Page or buffer structure frees a reference. 73239809Smckusick */ 73339809Smckusick holdrele(vp) 73439809Smckusick register struct vnode *vp; 73539809Smckusick { 73639809Smckusick 73739809Smckusick if (vp->v_holdcnt <= 0) 73839809Smckusick panic("holdrele: holdcnt"); 73939809Smckusick vp->v_holdcnt--; 74039809Smckusick } 74139809Smckusick 74239809Smckusick /* 74339509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 74439509Smckusick * 74539509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 74639509Smckusick * return error if any are found (nb: this is a user error, not a 74739509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 74839509Smckusick * that are found. 74939509Smckusick */ 75039509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 75139509Smckusick 75239509Smckusick vflush(mp, skipvp, flags) 75339509Smckusick struct mount *mp; 75439509Smckusick struct vnode *skipvp; 75539509Smckusick int flags; 75639509Smckusick { 75739509Smckusick register struct vnode *vp, *nvp; 75839509Smckusick int busy = 0; 75939509Smckusick 76041400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 76141300Smckusick panic("vflush: not busy"); 76241421Smckusick loop: 76341400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 76441421Smckusick if (vp->v_mount != mp) 76541421Smckusick goto loop; 76639509Smckusick nvp = vp->v_mountf; 76739509Smckusick /* 76839509Smckusick * Skip over a selected vnode. 76939509Smckusick */ 77039509Smckusick if (vp == skipvp) 77139509Smckusick continue; 77239509Smckusick /* 77341300Smckusick * Skip over a vnodes marked VSYSTEM. 77441300Smckusick */ 77541300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 77641300Smckusick continue; 77741300Smckusick /* 77839809Smckusick * With v_usecount == 0, all we need to do is clear 77939509Smckusick * out the vnode data structures and we are done. 78039509Smckusick */ 78139809Smckusick if (vp->v_usecount == 0) { 78239509Smckusick vgone(vp); 78339509Smckusick continue; 78439509Smckusick } 78539509Smckusick /* 78639509Smckusick * For block or character devices, revert to an 78739509Smckusick * anonymous device. For all other files, just kill them. 78839509Smckusick */ 78941300Smckusick if (flags & FORCECLOSE) { 79039509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 79139509Smckusick vgone(vp); 79239509Smckusick } else { 79339509Smckusick vclean(vp, 0); 79439509Smckusick vp->v_op = &spec_vnodeops; 79539509Smckusick insmntque(vp, (struct mount *)0); 79639509Smckusick } 79739509Smckusick continue; 79839509Smckusick } 79939509Smckusick if (busyprt) 80039667Smckusick vprint("vflush: busy vnode", vp); 80139509Smckusick busy++; 80239509Smckusick } 80339509Smckusick if (busy) 80439509Smckusick return (EBUSY); 80539509Smckusick return (0); 80639509Smckusick } 80739509Smckusick 80839509Smckusick /* 80939433Smckusick * Disassociate the underlying file system from a vnode. 81039433Smckusick */ 81141300Smckusick void vclean(vp, flags) 81239433Smckusick register struct vnode *vp; 81345118Smckusick int flags; 81439433Smckusick { 81539433Smckusick struct vnodeops *origops; 81639484Smckusick int active; 81748024Smckusick struct proc *p = curproc; /* XXX */ 81839433Smckusick 81939484Smckusick /* 82039484Smckusick * Check to see if the vnode is in use. 82139667Smckusick * If so we have to reference it before we clean it out 82239667Smckusick * so that its count cannot fall to zero and generate a 82339667Smckusick * race against ourselves to recycle it. 82439484Smckusick */ 82539809Smckusick if (active = vp->v_usecount) 82639484Smckusick VREF(vp); 82739484Smckusick /* 82839484Smckusick * Prevent the vnode from being recycled or 82939484Smckusick * brought into use while we clean it out. 83039484Smckusick */ 83139667Smckusick if (vp->v_flag & VXLOCK) 83239667Smckusick panic("vclean: deadlock"); 83339433Smckusick vp->v_flag |= VXLOCK; 83439433Smckusick /* 83539667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 83639667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 83739667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 83839667Smckusick * For active vnodes, it ensures that no other activity can 83939667Smckusick * occur while the buffer list is being cleaned out. 84039667Smckusick */ 84139667Smckusick VOP_LOCK(vp); 84241300Smckusick if (flags & DOCLOSE) 84339667Smckusick vinvalbuf(vp, 1); 84439667Smckusick /* 84539433Smckusick * Prevent any further operations on the vnode from 84639433Smckusick * being passed through to the old file system. 84739433Smckusick */ 84839433Smckusick origops = vp->v_op; 84939433Smckusick vp->v_op = &dead_vnodeops; 85039433Smckusick vp->v_tag = VT_NON; 85139433Smckusick /* 85239484Smckusick * If purging an active vnode, it must be unlocked, closed, 85339484Smckusick * and deactivated before being reclaimed. 85439433Smckusick */ 85549761Smckusick (*(origops->vop_unlock))(vp); 85639484Smckusick if (active) { 85741300Smckusick if (flags & DOCLOSE) 85849761Smckusick (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 85949761Smckusick (*(origops->vop_inactive))(vp, p); 86039433Smckusick } 86139433Smckusick /* 86239433Smckusick * Reclaim the vnode. 86339433Smckusick */ 86449761Smckusick if ((*(origops->vop_reclaim))(vp)) 86539433Smckusick panic("vclean: cannot reclaim"); 86639484Smckusick if (active) 86739484Smckusick vrele(vp); 86839433Smckusick /* 86939433Smckusick * Done with purge, notify sleepers in vget of the grim news. 87039433Smckusick */ 87139433Smckusick vp->v_flag &= ~VXLOCK; 87239433Smckusick if (vp->v_flag & VXWANT) { 87339433Smckusick vp->v_flag &= ~VXWANT; 87439433Smckusick wakeup((caddr_t)vp); 87539433Smckusick } 87639433Smckusick } 87739433Smckusick 87839433Smckusick /* 87939633Smckusick * Eliminate all activity associated with the requested vnode 88039633Smckusick * and with all vnodes aliased to the requested vnode. 88139633Smckusick */ 88239633Smckusick void vgoneall(vp) 88339633Smckusick register struct vnode *vp; 88439633Smckusick { 88539809Smckusick register struct vnode *vq; 88639633Smckusick 88740665Smckusick if (vp->v_flag & VALIASED) { 88840665Smckusick /* 88940665Smckusick * If a vgone (or vclean) is already in progress, 89040665Smckusick * wait until it is done and return. 89140665Smckusick */ 89240665Smckusick if (vp->v_flag & VXLOCK) { 89340665Smckusick vp->v_flag |= VXWANT; 89440665Smckusick sleep((caddr_t)vp, PINOD); 89540665Smckusick return; 89639633Smckusick } 89740665Smckusick /* 89840665Smckusick * Ensure that vp will not be vgone'd while we 89940665Smckusick * are eliminating its aliases. 90040665Smckusick */ 90140665Smckusick vp->v_flag |= VXLOCK; 90240665Smckusick while (vp->v_flag & VALIASED) { 90340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90440665Smckusick if (vq->v_rdev != vp->v_rdev || 90540665Smckusick vq->v_type != vp->v_type || vp == vq) 90640665Smckusick continue; 90740665Smckusick vgone(vq); 90840665Smckusick break; 90940665Smckusick } 91040665Smckusick } 91140665Smckusick /* 91240665Smckusick * Remove the lock so that vgone below will 91340665Smckusick * really eliminate the vnode after which time 91440665Smckusick * vgone will awaken any sleepers. 91540665Smckusick */ 91640665Smckusick vp->v_flag &= ~VXLOCK; 91739633Smckusick } 91839633Smckusick vgone(vp); 91939633Smckusick } 92039633Smckusick 92139633Smckusick /* 92239433Smckusick * Eliminate all activity associated with a vnode 92339433Smckusick * in preparation for reuse. 92439433Smckusick */ 92539433Smckusick void vgone(vp) 92639433Smckusick register struct vnode *vp; 92739433Smckusick { 92839809Smckusick register struct vnode *vq; 92939615Smckusick struct vnode *vx; 93039615Smckusick long count; 93139433Smckusick 93239433Smckusick /* 93340548Smckusick * If a vgone (or vclean) is already in progress, 93440548Smckusick * wait until it is done and return. 93540548Smckusick */ 93640548Smckusick if (vp->v_flag & VXLOCK) { 93740548Smckusick vp->v_flag |= VXWANT; 93840548Smckusick sleep((caddr_t)vp, PINOD); 93940548Smckusick return; 94040548Smckusick } 94140548Smckusick /* 94239433Smckusick * Clean out the filesystem specific data. 94339433Smckusick */ 94441300Smckusick vclean(vp, DOCLOSE); 94539433Smckusick /* 94639433Smckusick * Delete from old mount point vnode list, if on one. 94739433Smckusick */ 94839433Smckusick if (vp->v_mountb) { 94939433Smckusick if (vq = vp->v_mountf) 95039433Smckusick vq->v_mountb = vp->v_mountb; 95139433Smckusick *vp->v_mountb = vq; 95239433Smckusick vp->v_mountf = NULL; 95339433Smckusick vp->v_mountb = NULL; 95452311Smckusick vp->v_mount = NULL; 95539433Smckusick } 95639433Smckusick /* 95739433Smckusick * If special device, remove it from special device alias list. 95839433Smckusick */ 95939433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 96039809Smckusick if (*vp->v_hashchain == vp) { 96139809Smckusick *vp->v_hashchain = vp->v_specnext; 96239433Smckusick } else { 96339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 96439615Smckusick if (vq->v_specnext != vp) 96539433Smckusick continue; 96639615Smckusick vq->v_specnext = vp->v_specnext; 96739433Smckusick break; 96839433Smckusick } 96939615Smckusick if (vq == NULL) 97039433Smckusick panic("missing bdev"); 97139433Smckusick } 97239615Smckusick if (vp->v_flag & VALIASED) { 97339809Smckusick count = 0; 97439809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97540108Smckusick if (vq->v_rdev != vp->v_rdev || 97640108Smckusick vq->v_type != vp->v_type) 97739615Smckusick continue; 97839615Smckusick count++; 97939615Smckusick vx = vq; 98039615Smckusick } 98139615Smckusick if (count == 0) 98239615Smckusick panic("missing alias"); 98339615Smckusick if (count == 1) 98439615Smckusick vx->v_flag &= ~VALIASED; 98539615Smckusick vp->v_flag &= ~VALIASED; 98639615Smckusick } 98739615Smckusick FREE(vp->v_specinfo, M_VNODE); 98839615Smckusick vp->v_specinfo = NULL; 98939433Smckusick } 99039433Smckusick /* 99139433Smckusick * If it is on the freelist, move it to the head of the list. 99239433Smckusick */ 99339433Smckusick if (vp->v_freeb) { 99439433Smckusick if (vq = vp->v_freef) 99539433Smckusick vq->v_freeb = vp->v_freeb; 99639433Smckusick else 99739433Smckusick vfreet = vp->v_freeb; 99839433Smckusick *vp->v_freeb = vq; 99939433Smckusick vp->v_freef = vfreeh; 100039433Smckusick vp->v_freeb = &vfreeh; 100139433Smckusick vfreeh->v_freeb = &vp->v_freef; 100239433Smckusick vfreeh = vp; 100339433Smckusick } 100439484Smckusick vp->v_type = VBAD; 100539433Smckusick } 100639633Smckusick 100739633Smckusick /* 100839821Smckusick * Lookup a vnode by device number. 100939821Smckusick */ 101039821Smckusick vfinddev(dev, type, vpp) 101139821Smckusick dev_t dev; 101239821Smckusick enum vtype type; 101339821Smckusick struct vnode **vpp; 101439821Smckusick { 101539821Smckusick register struct vnode *vp; 101639821Smckusick 101739821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 101839821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 101939821Smckusick continue; 102039821Smckusick *vpp = vp; 102139821Smckusick return (0); 102239821Smckusick } 102339821Smckusick return (1); 102439821Smckusick } 102539821Smckusick 102639821Smckusick /* 102739633Smckusick * Calculate the total number of references to a special device. 102839633Smckusick */ 102939633Smckusick vcount(vp) 103039633Smckusick register struct vnode *vp; 103139633Smckusick { 103239809Smckusick register struct vnode *vq; 103339633Smckusick int count; 103439633Smckusick 103539633Smckusick if ((vp->v_flag & VALIASED) == 0) 103639809Smckusick return (vp->v_usecount); 103739633Smckusick loop: 103839809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 103940108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 104039633Smckusick continue; 104139633Smckusick /* 104239633Smckusick * Alias, but not in use, so flush it out. 104339633Smckusick */ 104439809Smckusick if (vq->v_usecount == 0) { 104539633Smckusick vgone(vq); 104639633Smckusick goto loop; 104739633Smckusick } 104839809Smckusick count += vq->v_usecount; 104939633Smckusick } 105039633Smckusick return (count); 105139633Smckusick } 105239667Smckusick 105339667Smckusick /* 105439667Smckusick * Print out a description of a vnode. 105539667Smckusick */ 105639667Smckusick static char *typename[] = 105740286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 105839667Smckusick 105939667Smckusick vprint(label, vp) 106039667Smckusick char *label; 106139667Smckusick register struct vnode *vp; 106239667Smckusick { 106339913Smckusick char buf[64]; 106439667Smckusick 106539667Smckusick if (label != NULL) 106639667Smckusick printf("%s: ", label); 106750109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 106850109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 106950109Smckusick vp->v_holdcnt); 107039913Smckusick buf[0] = '\0'; 107139913Smckusick if (vp->v_flag & VROOT) 107239913Smckusick strcat(buf, "|VROOT"); 107339913Smckusick if (vp->v_flag & VTEXT) 107439913Smckusick strcat(buf, "|VTEXT"); 107541300Smckusick if (vp->v_flag & VSYSTEM) 107641300Smckusick strcat(buf, "|VSYSTEM"); 107741300Smckusick if (vp->v_flag & VXLOCK) 107841300Smckusick strcat(buf, "|VXLOCK"); 107941300Smckusick if (vp->v_flag & VXWANT) 108041300Smckusick strcat(buf, "|VXWANT"); 108141300Smckusick if (vp->v_flag & VBWAIT) 108241300Smckusick strcat(buf, "|VBWAIT"); 108339913Smckusick if (vp->v_flag & VALIASED) 108439913Smckusick strcat(buf, "|VALIASED"); 108539913Smckusick if (buf[0] != '\0') 108639913Smckusick printf(" flags (%s)", &buf[1]); 108739913Smckusick printf("\n\t"); 108839667Smckusick VOP_PRINT(vp); 108939667Smckusick } 109041110Smarc 109149691Smckusick #ifdef DEBUG 109249691Smckusick /* 109349691Smckusick * List all of the locked vnodes in the system. 109449691Smckusick * Called when debugging the kernel. 109549691Smckusick */ 109649691Smckusick printlockedvnodes() 109749691Smckusick { 109849691Smckusick register struct mount *mp; 109949691Smckusick register struct vnode *vp; 110049691Smckusick 110149691Smckusick printf("Locked vnodes\n"); 110249691Smckusick mp = rootfs; 110349691Smckusick do { 110449691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 110549691Smckusick if (VOP_ISLOCKED(vp)) 110649691Smckusick vprint((char *)0, vp); 110749691Smckusick mp = mp->mnt_next; 110849691Smckusick } while (mp != rootfs); 110949691Smckusick } 111049691Smckusick #endif 111149691Smckusick 111241110Smarc int kinfo_vdebug = 1; 111341110Smarc int kinfo_vgetfailed; 111441110Smarc #define KINFO_VNODESLOP 10 111541110Smarc /* 111641110Smarc * Dump vnode list (via kinfo). 111741110Smarc * Copyout address of vnode followed by vnode. 111841110Smarc */ 111945118Smckusick /* ARGSUSED */ 112041110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 112145118Smckusick int op; 112241110Smarc char *where; 112345118Smckusick int *acopysize, arg, *aneeded; 112441110Smarc { 112541110Smarc register struct mount *mp = rootfs; 112641300Smckusick struct mount *omp; 112741110Smarc struct vnode *vp; 112841110Smarc register char *bp = where, *savebp; 112941110Smarc char *ewhere = where + *acopysize; 113041110Smarc int error; 113141110Smarc 113241110Smarc #define VPTRSZ sizeof (struct vnode *) 113341110Smarc #define VNODESZ sizeof (struct vnode) 113441110Smarc if (where == NULL) { 113541110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 113641110Smarc return (0); 113741110Smarc } 113841110Smarc 113941110Smarc do { 114041300Smckusick if (vfs_busy(mp)) { 114141400Smckusick mp = mp->mnt_next; 114241300Smckusick continue; 114341300Smckusick } 114441110Smarc savebp = bp; 114541110Smarc again: 114641421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 114741422Smckusick /* 114841422Smckusick * Check that the vp is still associated with 114941422Smckusick * this filesystem. RACE: could have been 115041422Smckusick * recycled onto the same filesystem. 115141422Smckusick */ 115241421Smckusick if (vp->v_mount != mp) { 115341421Smckusick if (kinfo_vdebug) 115441421Smckusick printf("kinfo: vp changed\n"); 115541421Smckusick bp = savebp; 115641421Smckusick goto again; 115741421Smckusick } 115841110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 115941110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 116041110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 116141422Smckusick VNODESZ)))) 116241110Smarc return (error); 116341110Smarc bp += VPTRSZ + VNODESZ; 116441110Smarc } 116541300Smckusick omp = mp; 116641400Smckusick mp = mp->mnt_next; 116741300Smckusick vfs_unbusy(omp); 116841110Smarc } while (mp != rootfs); 116941110Smarc 117041110Smarc *aneeded = bp - where; 117141110Smarc if (bp > ewhere) 117241110Smarc *acopysize = ewhere - where; 117341110Smarc else 117441110Smarc *acopysize = bp - where; 117541110Smarc return (0); 117641110Smarc } 1177