137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*52655Smckusick * @(#)vfs_subr.c 7.70 (Berkeley) 02/25/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> 1952415Smckusick #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 2752415Smckusick enum vtype iftovt_tab[16] = { 2852415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 2952415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3052415Smckusick }; 3152415Smckusick int vttoif_tab[9] = { 3252415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 3352415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 3452415Smckusick }; 3552415Smckusick 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 513*52655Smckusick if (newvp == NULL) { 514*52655Smckusick printf("reassignbuf: NULL"); 515*52655Smckusick return; 516*52655Smckusick } 51749232Smckusick /* 51849232Smckusick * Delete from old vnode list, if on one. 51949232Smckusick */ 52049232Smckusick if (bp->b_blockb) { 52149232Smckusick if (bq = bp->b_blockf) 52249232Smckusick bq->b_blockb = bp->b_blockb; 52349232Smckusick *bp->b_blockb = bq; 52449232Smckusick } 52549232Smckusick /* 52649232Smckusick * If dirty, put on list of dirty buffers; 52749232Smckusick * otherwise insert onto list of clean buffers. 52849232Smckusick */ 52949232Smckusick if (bp->b_flags & B_DELWRI) 53049232Smckusick listheadp = &newvp->v_dirtyblkhd; 53149232Smckusick else 53249232Smckusick listheadp = &newvp->v_cleanblkhd; 53349973Smckusick if (bq = *listheadp) 53449973Smckusick bq->b_blockb = &bp->b_blockf; 53549973Smckusick bp->b_blockf = bq; 53649973Smckusick bp->b_blockb = listheadp; 53749973Smckusick *listheadp = bp; 53849232Smckusick } 53949232Smckusick 54049232Smckusick /* 54139433Smckusick * Create a vnode for a block device. 54239433Smckusick * Used for root filesystem, argdev, and swap areas. 54339433Smckusick * Also used for memory file system special devices. 54439397Smckusick */ 54539433Smckusick bdevvp(dev, vpp) 54639433Smckusick dev_t dev; 54739433Smckusick struct vnode **vpp; 54839433Smckusick { 54939433Smckusick register struct vnode *vp; 55039433Smckusick struct vnode *nvp; 55139433Smckusick int error; 55239433Smckusick 55346989Smckusick if (dev == NODEV) 55446989Smckusick return (0); 55539447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 55639433Smckusick if (error) { 55739433Smckusick *vpp = 0; 55839433Smckusick return (error); 55939433Smckusick } 56039433Smckusick vp = nvp; 56139433Smckusick vp->v_type = VBLK; 56239615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 56339433Smckusick vput(vp); 56439433Smckusick vp = nvp; 56539433Smckusick } 56639433Smckusick *vpp = vp; 56739433Smckusick return (0); 56839433Smckusick } 56939433Smckusick 57039433Smckusick /* 57139433Smckusick * Check to see if the new vnode represents a special device 57239433Smckusick * for which we already have a vnode (either because of 57339433Smckusick * bdevvp() or because of a different vnode representing 57439433Smckusick * the same block device). If such an alias exists, deallocate 57539509Smckusick * the existing contents and return the aliased vnode. The 57639433Smckusick * caller is responsible for filling it with its new contents. 57739433Smckusick */ 57839433Smckusick struct vnode * 57939615Smckusick checkalias(nvp, nvp_rdev, mp) 58039433Smckusick register struct vnode *nvp; 58139615Smckusick dev_t nvp_rdev; 58239433Smckusick struct mount *mp; 58339433Smckusick { 58439433Smckusick register struct vnode *vp; 58539615Smckusick struct vnode **vpp; 58639433Smckusick 58739433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 58841400Smckusick return (NULLVP); 58939615Smckusick 59039615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 59139433Smckusick loop: 59239615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 59339615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 59439433Smckusick continue; 59539615Smckusick /* 59639615Smckusick * Alias, but not in use, so flush it out. 59739615Smckusick */ 59839809Smckusick if (vp->v_usecount == 0) { 59939615Smckusick vgone(vp); 60039615Smckusick goto loop; 60139615Smckusick } 60239633Smckusick if (vget(vp)) 60339633Smckusick goto loop; 60439433Smckusick break; 60539433Smckusick } 60639615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 60739615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 60839615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 60939615Smckusick nvp->v_rdev = nvp_rdev; 61039809Smckusick nvp->v_hashchain = vpp; 61139615Smckusick nvp->v_specnext = *vpp; 61242152Smckusick nvp->v_specflags = 0; 61339615Smckusick *vpp = nvp; 61440640Smckusick if (vp != NULL) { 61540640Smckusick nvp->v_flag |= VALIASED; 61640640Smckusick vp->v_flag |= VALIASED; 61740640Smckusick vput(vp); 61840640Smckusick } 61941400Smckusick return (NULLVP); 62039433Smckusick } 62139484Smckusick VOP_UNLOCK(vp); 62239484Smckusick vclean(vp, 0); 62339433Smckusick vp->v_op = nvp->v_op; 62439433Smckusick vp->v_tag = nvp->v_tag; 62539433Smckusick nvp->v_type = VNON; 62639433Smckusick insmntque(vp, mp); 62739433Smckusick return (vp); 62839433Smckusick } 62939433Smckusick 63039433Smckusick /* 63139433Smckusick * Grab a particular vnode from the free list, increment its 63239433Smckusick * reference count and lock it. The vnode lock bit is set the 63339433Smckusick * vnode is being eliminated in vgone. The process is awakened 63439433Smckusick * when the transition is completed, and an error returned to 63539433Smckusick * indicate that the vnode is no longer usable (possibly having 63639433Smckusick * been changed to a new file system type). 63739433Smckusick */ 63839397Smckusick vget(vp) 63939397Smckusick register struct vnode *vp; 64039397Smckusick { 64139397Smckusick register struct vnode *vq; 64239397Smckusick 64339433Smckusick if (vp->v_flag & VXLOCK) { 64439433Smckusick vp->v_flag |= VXWANT; 64539433Smckusick sleep((caddr_t)vp, PINOD); 64639433Smckusick return (1); 64739433Smckusick } 64839809Smckusick if (vp->v_usecount == 0) { 64939433Smckusick if (vq = vp->v_freef) 65039433Smckusick vq->v_freeb = vp->v_freeb; 65139433Smckusick else 65239433Smckusick vfreet = vp->v_freeb; 65339433Smckusick *vp->v_freeb = vq; 65439433Smckusick vp->v_freef = NULL; 65539433Smckusick vp->v_freeb = NULL; 65639433Smckusick } 65739397Smckusick VREF(vp); 65839433Smckusick VOP_LOCK(vp); 65939433Smckusick return (0); 66039397Smckusick } 66139397Smckusick 66239397Smckusick /* 66339397Smckusick * Vnode reference, just increment the count 66439397Smckusick */ 66539397Smckusick void vref(vp) 66639397Smckusick struct vnode *vp; 66739397Smckusick { 66839397Smckusick 66939809Smckusick vp->v_usecount++; 67039397Smckusick } 67139397Smckusick 67239397Smckusick /* 67339397Smckusick * vput(), just unlock and vrele() 67439397Smckusick */ 67539397Smckusick void vput(vp) 67639397Smckusick register struct vnode *vp; 67739397Smckusick { 67852416Storek 67939397Smckusick VOP_UNLOCK(vp); 68039397Smckusick vrele(vp); 68139397Smckusick } 68239397Smckusick 68339397Smckusick /* 68439397Smckusick * Vnode release. 68539397Smckusick * If count drops to zero, call inactive routine and return to freelist. 68639397Smckusick */ 68739397Smckusick void vrele(vp) 68839397Smckusick register struct vnode *vp; 68939397Smckusick { 69048024Smckusick struct proc *p = curproc; /* XXX */ 69139397Smckusick 69250109Smckusick #ifdef DIAGNOSTIC 69339397Smckusick if (vp == NULL) 69439433Smckusick panic("vrele: null vp"); 69550109Smckusick #endif 69639809Smckusick vp->v_usecount--; 69739809Smckusick if (vp->v_usecount > 0) 69839397Smckusick return; 69950109Smckusick #ifdef DIAGNOSTIC 70050109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 70150109Smckusick vprint("vrele: bad ref count", vp); 70250109Smckusick panic("vrele: ref cnt"); 70350109Smckusick } 70450109Smckusick #endif 70541400Smckusick if (vfreeh == NULLVP) { 70639397Smckusick /* 70739397Smckusick * insert into empty list 70839397Smckusick */ 70939397Smckusick vfreeh = vp; 71039397Smckusick vp->v_freeb = &vfreeh; 71139397Smckusick } else { 71239397Smckusick /* 71339397Smckusick * insert at tail of list 71439397Smckusick */ 71539397Smckusick *vfreet = vp; 71639397Smckusick vp->v_freeb = vfreet; 71739397Smckusick } 71839433Smckusick vp->v_freef = NULL; 71939433Smckusick vfreet = &vp->v_freef; 72048024Smckusick VOP_INACTIVE(vp, p); 72139397Smckusick } 72239433Smckusick 72339433Smckusick /* 72439809Smckusick * Page or buffer structure gets a reference. 72539809Smckusick */ 72639809Smckusick vhold(vp) 72739809Smckusick register struct vnode *vp; 72839809Smckusick { 72939809Smckusick 73039809Smckusick vp->v_holdcnt++; 73139809Smckusick } 73239809Smckusick 73339809Smckusick /* 73439809Smckusick * Page or buffer structure frees a reference. 73539809Smckusick */ 73639809Smckusick holdrele(vp) 73739809Smckusick register struct vnode *vp; 73839809Smckusick { 73939809Smckusick 74039809Smckusick if (vp->v_holdcnt <= 0) 74139809Smckusick panic("holdrele: holdcnt"); 74239809Smckusick vp->v_holdcnt--; 74339809Smckusick } 74439809Smckusick 74539809Smckusick /* 74639509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 74739509Smckusick * 74839509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 74939509Smckusick * return error if any are found (nb: this is a user error, not a 75039509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 75139509Smckusick * that are found. 75239509Smckusick */ 75339509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 75439509Smckusick 75539509Smckusick vflush(mp, skipvp, flags) 75639509Smckusick struct mount *mp; 75739509Smckusick struct vnode *skipvp; 75839509Smckusick int flags; 75939509Smckusick { 76039509Smckusick register struct vnode *vp, *nvp; 76139509Smckusick int busy = 0; 76239509Smckusick 76341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 76441300Smckusick panic("vflush: not busy"); 76541421Smckusick loop: 76641400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 76741421Smckusick if (vp->v_mount != mp) 76841421Smckusick goto loop; 76939509Smckusick nvp = vp->v_mountf; 77039509Smckusick /* 77139509Smckusick * Skip over a selected vnode. 77239509Smckusick */ 77339509Smckusick if (vp == skipvp) 77439509Smckusick continue; 77539509Smckusick /* 77641300Smckusick * Skip over a vnodes marked VSYSTEM. 77741300Smckusick */ 77841300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 77941300Smckusick continue; 78041300Smckusick /* 78139809Smckusick * With v_usecount == 0, all we need to do is clear 78239509Smckusick * out the vnode data structures and we are done. 78339509Smckusick */ 78439809Smckusick if (vp->v_usecount == 0) { 78539509Smckusick vgone(vp); 78639509Smckusick continue; 78739509Smckusick } 78839509Smckusick /* 78939509Smckusick * For block or character devices, revert to an 79039509Smckusick * anonymous device. For all other files, just kill them. 79139509Smckusick */ 79241300Smckusick if (flags & FORCECLOSE) { 79339509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 79439509Smckusick vgone(vp); 79539509Smckusick } else { 79639509Smckusick vclean(vp, 0); 79739509Smckusick vp->v_op = &spec_vnodeops; 79839509Smckusick insmntque(vp, (struct mount *)0); 79939509Smckusick } 80039509Smckusick continue; 80139509Smckusick } 80239509Smckusick if (busyprt) 80339667Smckusick vprint("vflush: busy vnode", vp); 80439509Smckusick busy++; 80539509Smckusick } 80639509Smckusick if (busy) 80739509Smckusick return (EBUSY); 80839509Smckusick return (0); 80939509Smckusick } 81039509Smckusick 81139509Smckusick /* 81239433Smckusick * Disassociate the underlying file system from a vnode. 81339433Smckusick */ 81441300Smckusick void vclean(vp, flags) 81539433Smckusick register struct vnode *vp; 81645118Smckusick int flags; 81739433Smckusick { 81839433Smckusick struct vnodeops *origops; 81939484Smckusick int active; 82048024Smckusick struct proc *p = curproc; /* XXX */ 82139433Smckusick 82239484Smckusick /* 82339484Smckusick * Check to see if the vnode is in use. 82439667Smckusick * If so we have to reference it before we clean it out 82539667Smckusick * so that its count cannot fall to zero and generate a 82639667Smckusick * race against ourselves to recycle it. 82739484Smckusick */ 82839809Smckusick if (active = vp->v_usecount) 82939484Smckusick VREF(vp); 83039484Smckusick /* 83139484Smckusick * Prevent the vnode from being recycled or 83239484Smckusick * brought into use while we clean it out. 83339484Smckusick */ 83439667Smckusick if (vp->v_flag & VXLOCK) 83539667Smckusick panic("vclean: deadlock"); 83639433Smckusick vp->v_flag |= VXLOCK; 83739433Smckusick /* 83839667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 83939667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 84039667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 84139667Smckusick * For active vnodes, it ensures that no other activity can 84239667Smckusick * occur while the buffer list is being cleaned out. 84339667Smckusick */ 84439667Smckusick VOP_LOCK(vp); 84541300Smckusick if (flags & DOCLOSE) 84639667Smckusick vinvalbuf(vp, 1); 84739667Smckusick /* 84839433Smckusick * Prevent any further operations on the vnode from 84939433Smckusick * being passed through to the old file system. 85039433Smckusick */ 85139433Smckusick origops = vp->v_op; 85239433Smckusick vp->v_op = &dead_vnodeops; 85339433Smckusick vp->v_tag = VT_NON; 85439433Smckusick /* 85539484Smckusick * If purging an active vnode, it must be unlocked, closed, 85639484Smckusick * and deactivated before being reclaimed. 85739433Smckusick */ 85849761Smckusick (*(origops->vop_unlock))(vp); 85939484Smckusick if (active) { 86041300Smckusick if (flags & DOCLOSE) 86149761Smckusick (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 86249761Smckusick (*(origops->vop_inactive))(vp, p); 86339433Smckusick } 86439433Smckusick /* 86539433Smckusick * Reclaim the vnode. 86639433Smckusick */ 86749761Smckusick if ((*(origops->vop_reclaim))(vp)) 86839433Smckusick panic("vclean: cannot reclaim"); 86939484Smckusick if (active) 87039484Smckusick vrele(vp); 87139433Smckusick /* 87239433Smckusick * Done with purge, notify sleepers in vget of the grim news. 87339433Smckusick */ 87439433Smckusick vp->v_flag &= ~VXLOCK; 87539433Smckusick if (vp->v_flag & VXWANT) { 87639433Smckusick vp->v_flag &= ~VXWANT; 87739433Smckusick wakeup((caddr_t)vp); 87839433Smckusick } 87939433Smckusick } 88039433Smckusick 88139433Smckusick /* 88239633Smckusick * Eliminate all activity associated with the requested vnode 88339633Smckusick * and with all vnodes aliased to the requested vnode. 88439633Smckusick */ 88539633Smckusick void vgoneall(vp) 88639633Smckusick register struct vnode *vp; 88739633Smckusick { 88839809Smckusick register struct vnode *vq; 88939633Smckusick 89040665Smckusick if (vp->v_flag & VALIASED) { 89140665Smckusick /* 89240665Smckusick * If a vgone (or vclean) is already in progress, 89340665Smckusick * wait until it is done and return. 89440665Smckusick */ 89540665Smckusick if (vp->v_flag & VXLOCK) { 89640665Smckusick vp->v_flag |= VXWANT; 89740665Smckusick sleep((caddr_t)vp, PINOD); 89840665Smckusick return; 89939633Smckusick } 90040665Smckusick /* 90140665Smckusick * Ensure that vp will not be vgone'd while we 90240665Smckusick * are eliminating its aliases. 90340665Smckusick */ 90440665Smckusick vp->v_flag |= VXLOCK; 90540665Smckusick while (vp->v_flag & VALIASED) { 90640665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90740665Smckusick if (vq->v_rdev != vp->v_rdev || 90840665Smckusick vq->v_type != vp->v_type || vp == vq) 90940665Smckusick continue; 91040665Smckusick vgone(vq); 91140665Smckusick break; 91240665Smckusick } 91340665Smckusick } 91440665Smckusick /* 91540665Smckusick * Remove the lock so that vgone below will 91640665Smckusick * really eliminate the vnode after which time 91740665Smckusick * vgone will awaken any sleepers. 91840665Smckusick */ 91940665Smckusick vp->v_flag &= ~VXLOCK; 92039633Smckusick } 92139633Smckusick vgone(vp); 92239633Smckusick } 92339633Smckusick 92439633Smckusick /* 92539433Smckusick * Eliminate all activity associated with a vnode 92639433Smckusick * in preparation for reuse. 92739433Smckusick */ 92839433Smckusick void vgone(vp) 92939433Smckusick register struct vnode *vp; 93039433Smckusick { 93139809Smckusick register struct vnode *vq; 93239615Smckusick struct vnode *vx; 93339433Smckusick 93439433Smckusick /* 93540548Smckusick * If a vgone (or vclean) is already in progress, 93640548Smckusick * wait until it is done and return. 93740548Smckusick */ 93840548Smckusick if (vp->v_flag & VXLOCK) { 93940548Smckusick vp->v_flag |= VXWANT; 94040548Smckusick sleep((caddr_t)vp, PINOD); 94140548Smckusick return; 94240548Smckusick } 94340548Smckusick /* 94439433Smckusick * Clean out the filesystem specific data. 94539433Smckusick */ 94641300Smckusick vclean(vp, DOCLOSE); 94739433Smckusick /* 94839433Smckusick * Delete from old mount point vnode list, if on one. 94939433Smckusick */ 95039433Smckusick if (vp->v_mountb) { 95139433Smckusick if (vq = vp->v_mountf) 95239433Smckusick vq->v_mountb = vp->v_mountb; 95339433Smckusick *vp->v_mountb = vq; 95439433Smckusick vp->v_mountf = NULL; 95539433Smckusick vp->v_mountb = NULL; 95652311Smckusick vp->v_mount = NULL; 95739433Smckusick } 95839433Smckusick /* 95939433Smckusick * If special device, remove it from special device alias list. 96039433Smckusick */ 96139433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 96239809Smckusick if (*vp->v_hashchain == vp) { 96339809Smckusick *vp->v_hashchain = vp->v_specnext; 96439433Smckusick } else { 96539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 96639615Smckusick if (vq->v_specnext != vp) 96739433Smckusick continue; 96839615Smckusick vq->v_specnext = vp->v_specnext; 96939433Smckusick break; 97039433Smckusick } 97139615Smckusick if (vq == NULL) 97239433Smckusick panic("missing bdev"); 97339433Smckusick } 97439615Smckusick if (vp->v_flag & VALIASED) { 97552416Storek vx = NULL; 97639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97740108Smckusick if (vq->v_rdev != vp->v_rdev || 97840108Smckusick vq->v_type != vp->v_type) 97939615Smckusick continue; 98052416Storek if (vx) 98152416Storek break; 98239615Smckusick vx = vq; 98339615Smckusick } 98452416Storek if (vx == NULL) 98539615Smckusick panic("missing alias"); 98652416Storek if (vq == NULL) 98739615Smckusick vx->v_flag &= ~VALIASED; 98839615Smckusick vp->v_flag &= ~VALIASED; 98939615Smckusick } 99039615Smckusick FREE(vp->v_specinfo, M_VNODE); 99139615Smckusick vp->v_specinfo = NULL; 99239433Smckusick } 99339433Smckusick /* 99439433Smckusick * If it is on the freelist, move it to the head of the list. 99539433Smckusick */ 99639433Smckusick if (vp->v_freeb) { 99739433Smckusick if (vq = vp->v_freef) 99839433Smckusick vq->v_freeb = vp->v_freeb; 99939433Smckusick else 100039433Smckusick vfreet = vp->v_freeb; 100139433Smckusick *vp->v_freeb = vq; 100239433Smckusick vp->v_freef = vfreeh; 100339433Smckusick vp->v_freeb = &vfreeh; 100439433Smckusick vfreeh->v_freeb = &vp->v_freef; 100539433Smckusick vfreeh = vp; 100639433Smckusick } 100739484Smckusick vp->v_type = VBAD; 100839433Smckusick } 100939633Smckusick 101039633Smckusick /* 101139821Smckusick * Lookup a vnode by device number. 101239821Smckusick */ 101339821Smckusick vfinddev(dev, type, vpp) 101439821Smckusick dev_t dev; 101539821Smckusick enum vtype type; 101639821Smckusick struct vnode **vpp; 101739821Smckusick { 101839821Smckusick register struct vnode *vp; 101939821Smckusick 102039821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 102139821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 102239821Smckusick continue; 102339821Smckusick *vpp = vp; 102439821Smckusick return (0); 102539821Smckusick } 102639821Smckusick return (1); 102739821Smckusick } 102839821Smckusick 102939821Smckusick /* 103039633Smckusick * Calculate the total number of references to a special device. 103139633Smckusick */ 103239633Smckusick vcount(vp) 103339633Smckusick register struct vnode *vp; 103439633Smckusick { 103539809Smckusick register struct vnode *vq; 103639633Smckusick int count; 103739633Smckusick 103839633Smckusick if ((vp->v_flag & VALIASED) == 0) 103939809Smckusick return (vp->v_usecount); 104039633Smckusick loop: 104139809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 104240108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 104339633Smckusick continue; 104439633Smckusick /* 104539633Smckusick * Alias, but not in use, so flush it out. 104639633Smckusick */ 104739809Smckusick if (vq->v_usecount == 0) { 104839633Smckusick vgone(vq); 104939633Smckusick goto loop; 105039633Smckusick } 105139809Smckusick count += vq->v_usecount; 105239633Smckusick } 105339633Smckusick return (count); 105439633Smckusick } 105539667Smckusick 105639667Smckusick /* 105739667Smckusick * Print out a description of a vnode. 105839667Smckusick */ 105939667Smckusick static char *typename[] = 106040286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 106139667Smckusick 106239667Smckusick vprint(label, vp) 106339667Smckusick char *label; 106439667Smckusick register struct vnode *vp; 106539667Smckusick { 106639913Smckusick char buf[64]; 106739667Smckusick 106839667Smckusick if (label != NULL) 106939667Smckusick printf("%s: ", label); 107050109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 107150109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 107250109Smckusick vp->v_holdcnt); 107339913Smckusick buf[0] = '\0'; 107439913Smckusick if (vp->v_flag & VROOT) 107539913Smckusick strcat(buf, "|VROOT"); 107639913Smckusick if (vp->v_flag & VTEXT) 107739913Smckusick strcat(buf, "|VTEXT"); 107841300Smckusick if (vp->v_flag & VSYSTEM) 107941300Smckusick strcat(buf, "|VSYSTEM"); 108041300Smckusick if (vp->v_flag & VXLOCK) 108141300Smckusick strcat(buf, "|VXLOCK"); 108241300Smckusick if (vp->v_flag & VXWANT) 108341300Smckusick strcat(buf, "|VXWANT"); 108441300Smckusick if (vp->v_flag & VBWAIT) 108541300Smckusick strcat(buf, "|VBWAIT"); 108639913Smckusick if (vp->v_flag & VALIASED) 108739913Smckusick strcat(buf, "|VALIASED"); 108839913Smckusick if (buf[0] != '\0') 108939913Smckusick printf(" flags (%s)", &buf[1]); 109039913Smckusick printf("\n\t"); 109139667Smckusick VOP_PRINT(vp); 109239667Smckusick } 109341110Smarc 109449691Smckusick #ifdef DEBUG 109549691Smckusick /* 109649691Smckusick * List all of the locked vnodes in the system. 109749691Smckusick * Called when debugging the kernel. 109849691Smckusick */ 109949691Smckusick printlockedvnodes() 110049691Smckusick { 110149691Smckusick register struct mount *mp; 110249691Smckusick register struct vnode *vp; 110349691Smckusick 110449691Smckusick printf("Locked vnodes\n"); 110549691Smckusick mp = rootfs; 110649691Smckusick do { 110749691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 110849691Smckusick if (VOP_ISLOCKED(vp)) 110949691Smckusick vprint((char *)0, vp); 111049691Smckusick mp = mp->mnt_next; 111149691Smckusick } while (mp != rootfs); 111249691Smckusick } 111349691Smckusick #endif 111449691Smckusick 111541110Smarc int kinfo_vdebug = 1; 111641110Smarc int kinfo_vgetfailed; 111741110Smarc #define KINFO_VNODESLOP 10 111841110Smarc /* 111941110Smarc * Dump vnode list (via kinfo). 112041110Smarc * Copyout address of vnode followed by vnode. 112141110Smarc */ 112245118Smckusick /* ARGSUSED */ 112341110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 112445118Smckusick int op; 112541110Smarc char *where; 112645118Smckusick int *acopysize, arg, *aneeded; 112741110Smarc { 112841110Smarc register struct mount *mp = rootfs; 112941300Smckusick struct mount *omp; 113041110Smarc struct vnode *vp; 113141110Smarc register char *bp = where, *savebp; 113241110Smarc char *ewhere = where + *acopysize; 113341110Smarc int error; 113441110Smarc 113541110Smarc #define VPTRSZ sizeof (struct vnode *) 113641110Smarc #define VNODESZ sizeof (struct vnode) 113741110Smarc if (where == NULL) { 113841110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 113941110Smarc return (0); 114041110Smarc } 114141110Smarc 114241110Smarc do { 114341300Smckusick if (vfs_busy(mp)) { 114441400Smckusick mp = mp->mnt_next; 114541300Smckusick continue; 114641300Smckusick } 114741110Smarc savebp = bp; 114841110Smarc again: 114941421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 115041422Smckusick /* 115141422Smckusick * Check that the vp is still associated with 115241422Smckusick * this filesystem. RACE: could have been 115341422Smckusick * recycled onto the same filesystem. 115441422Smckusick */ 115541421Smckusick if (vp->v_mount != mp) { 115641421Smckusick if (kinfo_vdebug) 115741421Smckusick printf("kinfo: vp changed\n"); 115841421Smckusick bp = savebp; 115941421Smckusick goto again; 116041421Smckusick } 116141110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 116241110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 116341110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 116441422Smckusick VNODESZ)))) 116541110Smarc return (error); 116641110Smarc bp += VPTRSZ + VNODESZ; 116741110Smarc } 116841300Smckusick omp = mp; 116941400Smckusick mp = mp->mnt_next; 117041300Smckusick vfs_unbusy(omp); 117141110Smarc } while (mp != rootfs); 117241110Smarc 117341110Smarc *aneeded = bp - where; 117441110Smarc if (bp > ewhere) 117541110Smarc *acopysize = ewhere - where; 117641110Smarc else 117741110Smarc *acopysize = bp - where; 117841110Smarc return (0); 117941110Smarc } 1180