137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*53488Sheideman * @(#)vfs_subr.c 7.72 (Berkeley) 05/13/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; 167*53488Sheideman extern struct vnodeops dead_vnodeops; 168*53488Sheideman extern struct vnodeops spec_vnodeops; 16939635Smckusick extern void vclean(); 17040883Smckusick long numvnodes; 17141363Smckusick struct vattr va_null; 17239397Smckusick 17339397Smckusick /* 17439433Smckusick * Initialize the vnode structures and initialize each file system type. 17539397Smckusick */ 17639433Smckusick vfsinit() 17739397Smckusick { 17839433Smckusick struct vfsops **vfsp; 17939397Smckusick 18039433Smckusick /* 18139433Smckusick * Initialize the vnode name cache 18239433Smckusick */ 18339433Smckusick nchinit(); 18439433Smckusick /* 18539433Smckusick * Initialize each file system type. 18639433Smckusick */ 18741363Smckusick vattr_null(&va_null); 18839433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 18939433Smckusick if (*vfsp == NULL) 19039433Smckusick continue; 19139433Smckusick (*(*vfsp)->vfs_init)(); 19239433Smckusick } 19339397Smckusick } 19439397Smckusick 19539397Smckusick /* 19639397Smckusick * Return the next vnode from the free list. 19739397Smckusick */ 19839397Smckusick getnewvnode(tag, mp, vops, vpp) 19939397Smckusick enum vtagtype tag; 20039397Smckusick struct mount *mp; 20139397Smckusick struct vnodeops *vops; 20239397Smckusick struct vnode **vpp; 20339397Smckusick { 20439397Smckusick register struct vnode *vp, *vq; 20539397Smckusick 20640883Smckusick if (numvnodes < desiredvnodes) { 20745118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 20845118Smckusick M_VNODE, M_WAITOK); 20940883Smckusick bzero((char *)vp, sizeof *vp); 21040883Smckusick numvnodes++; 21140883Smckusick } else { 21240883Smckusick if ((vp = vfreeh) == NULL) { 21340883Smckusick tablefull("vnode"); 21440883Smckusick *vpp = 0; 21540883Smckusick return (ENFILE); 21640883Smckusick } 21740883Smckusick if (vp->v_usecount) 21840883Smckusick panic("free vnode isn't"); 21940883Smckusick if (vq = vp->v_freef) 22040883Smckusick vq->v_freeb = &vfreeh; 22140883Smckusick else 22240883Smckusick vfreet = &vfreeh; 22340883Smckusick vfreeh = vq; 22440883Smckusick vp->v_freef = NULL; 22540883Smckusick vp->v_freeb = NULL; 22652190Smckusick vp->v_lease = NULL; 22740883Smckusick if (vp->v_type != VBAD) 22840883Smckusick vgone(vp); 22952006Smckusick if (vp->v_data) 23052006Smckusick panic("cleaned vnode isn't"); 23140883Smckusick vp->v_flag = 0; 23240883Smckusick vp->v_lastr = 0; 23340883Smckusick vp->v_socket = 0; 23439397Smckusick } 23539512Smckusick vp->v_type = VNON; 23639397Smckusick cache_purge(vp); 23739397Smckusick vp->v_tag = tag; 23839433Smckusick vp->v_op = vops; 23939397Smckusick insmntque(vp, mp); 24039397Smckusick VREF(vp); 24139397Smckusick *vpp = vp; 24239397Smckusick return (0); 24339397Smckusick } 24439397Smckusick 24539397Smckusick /* 24639397Smckusick * Move a vnode from one mount queue to another. 24739397Smckusick */ 24839397Smckusick insmntque(vp, mp) 24939397Smckusick register struct vnode *vp; 25039397Smckusick register struct mount *mp; 25139397Smckusick { 25249973Smckusick register struct vnode *vq; 25339397Smckusick 25439397Smckusick /* 25539397Smckusick * Delete from old mount point vnode list, if on one. 25639397Smckusick */ 25739397Smckusick if (vp->v_mountb) { 25839397Smckusick if (vq = vp->v_mountf) 25939397Smckusick vq->v_mountb = vp->v_mountb; 26039397Smckusick *vp->v_mountb = vq; 26139397Smckusick } 26239397Smckusick /* 26339397Smckusick * Insert into list of vnodes for the new mount point, if available. 26439397Smckusick */ 26539621Smckusick vp->v_mount = mp; 26639397Smckusick if (mp == NULL) { 26739397Smckusick vp->v_mountf = NULL; 26839397Smckusick vp->v_mountb = NULL; 26939397Smckusick return; 27039397Smckusick } 27149973Smckusick if (vq = mp->mnt_mounth) 27249973Smckusick vq->v_mountb = &vp->v_mountf; 27349973Smckusick vp->v_mountf = vq; 27449973Smckusick vp->v_mountb = &mp->mnt_mounth; 27549973Smckusick mp->mnt_mounth = vp; 27639397Smckusick } 27739397Smckusick 27839397Smckusick /* 27949232Smckusick * Make sure all write-behind blocks associated 28049232Smckusick * with mount point are flushed out (from sync). 28149232Smckusick */ 28249232Smckusick mntflushbuf(mountp, flags) 28349232Smckusick struct mount *mountp; 28449232Smckusick int flags; 28549232Smckusick { 28649232Smckusick register struct vnode *vp; 28749232Smckusick 28849232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 28949232Smckusick panic("mntflushbuf: not busy"); 29049232Smckusick loop: 29149232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 29249232Smckusick if (VOP_ISLOCKED(vp)) 29349232Smckusick continue; 29449232Smckusick if (vget(vp)) 29549232Smckusick goto loop; 29649232Smckusick vflushbuf(vp, flags); 29749232Smckusick vput(vp); 29849232Smckusick if (vp->v_mount != mountp) 29949232Smckusick goto loop; 30049232Smckusick } 30149232Smckusick } 30249232Smckusick 30349232Smckusick /* 30449232Smckusick * Flush all dirty buffers associated with a vnode. 30549232Smckusick */ 30649232Smckusick vflushbuf(vp, flags) 30749232Smckusick register struct vnode *vp; 30849232Smckusick int flags; 30949232Smckusick { 31049232Smckusick register struct buf *bp; 31149232Smckusick struct buf *nbp; 31249232Smckusick int s; 31349232Smckusick 31449232Smckusick loop: 31549232Smckusick s = splbio(); 31649232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 31749232Smckusick nbp = bp->b_blockf; 31849232Smckusick if ((bp->b_flags & B_BUSY)) 31949232Smckusick continue; 32049232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 32149232Smckusick panic("vflushbuf: not dirty"); 32249232Smckusick bremfree(bp); 32349232Smckusick bp->b_flags |= B_BUSY; 32449232Smckusick splx(s); 32549232Smckusick /* 32649232Smckusick * Wait for I/O associated with indirect blocks to complete, 32749232Smckusick * since there is no way to quickly wait for them below. 32849232Smckusick * NB: This is really specific to ufs, but is done here 32949232Smckusick * as it is easier and quicker. 33049232Smckusick */ 33149460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 33249232Smckusick (void) bawrite(bp); 33349460Smckusick else 33449232Smckusick (void) bwrite(bp); 33549460Smckusick goto loop; 33649232Smckusick } 33749232Smckusick splx(s); 33849232Smckusick if ((flags & B_SYNC) == 0) 33949232Smckusick return; 34049232Smckusick s = splbio(); 34149232Smckusick while (vp->v_numoutput) { 34249232Smckusick vp->v_flag |= VBWAIT; 34349232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 34449232Smckusick } 34549232Smckusick splx(s); 34649232Smckusick if (vp->v_dirtyblkhd) { 34749232Smckusick vprint("vflushbuf: dirty", vp); 34849232Smckusick goto loop; 34949232Smckusick } 35049232Smckusick } 35149232Smckusick 35249232Smckusick /* 35349232Smckusick * Update outstanding I/O count and do wakeup if requested. 35449232Smckusick */ 35549232Smckusick vwakeup(bp) 35649232Smckusick register struct buf *bp; 35749232Smckusick { 35849232Smckusick register struct vnode *vp; 35949232Smckusick 36049232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 36149232Smckusick if (vp = bp->b_vp) { 36249232Smckusick vp->v_numoutput--; 36349232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 36449232Smckusick if (vp->v_numoutput < 0) 36549232Smckusick panic("vwakeup: neg numoutput"); 36649232Smckusick vp->v_flag &= ~VBWAIT; 36749232Smckusick wakeup((caddr_t)&vp->v_numoutput); 36849232Smckusick } 36949232Smckusick } 37049232Smckusick } 37149232Smckusick 37249232Smckusick /* 37349232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 37449232Smckusick * 37549232Smckusick * Go through the list of vnodes associated with the file system; 37649232Smckusick * for each vnode invalidate any buffers that it holds. Normally 37749232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 37849232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 37949232Smckusick * returns the count of dirty buffers when it is finished. 38049232Smckusick */ 38149232Smckusick mntinvalbuf(mountp) 38249232Smckusick struct mount *mountp; 38349232Smckusick { 38449232Smckusick register struct vnode *vp; 38549232Smckusick int dirty = 0; 38649232Smckusick 38749232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 38849232Smckusick panic("mntinvalbuf: not busy"); 38949232Smckusick loop: 39049232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 39149232Smckusick if (vget(vp)) 39249232Smckusick goto loop; 39349232Smckusick dirty += vinvalbuf(vp, 1); 39449232Smckusick vput(vp); 39549232Smckusick if (vp->v_mount != mountp) 39649232Smckusick goto loop; 39749232Smckusick } 39849232Smckusick return (dirty); 39949232Smckusick } 40049232Smckusick 40149232Smckusick /* 40249232Smckusick * Flush out and invalidate all buffers associated with a vnode. 40349232Smckusick * Called with the underlying object locked. 40449232Smckusick */ 40549232Smckusick vinvalbuf(vp, save) 40649232Smckusick register struct vnode *vp; 40749232Smckusick int save; 40849232Smckusick { 40949232Smckusick register struct buf *bp; 41049232Smckusick struct buf *nbp, *blist; 41149232Smckusick int s, dirty = 0; 41249232Smckusick 41349232Smckusick for (;;) { 41449232Smckusick if (blist = vp->v_dirtyblkhd) 41549232Smckusick /* void */; 41649232Smckusick else if (blist = vp->v_cleanblkhd) 41749232Smckusick /* void */; 41849232Smckusick else 41949232Smckusick break; 42049232Smckusick for (bp = blist; bp; bp = nbp) { 42149232Smckusick nbp = bp->b_blockf; 42249232Smckusick s = splbio(); 42349232Smckusick if (bp->b_flags & B_BUSY) { 42449232Smckusick bp->b_flags |= B_WANTED; 42549232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 42649232Smckusick splx(s); 42749232Smckusick break; 42849232Smckusick } 42949232Smckusick bremfree(bp); 43049232Smckusick bp->b_flags |= B_BUSY; 43149232Smckusick splx(s); 43249232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 43351568Smckusick dirty++; 43451568Smckusick (void) VOP_BWRITE(bp); 43549232Smckusick break; 43649232Smckusick } 43749232Smckusick if (bp->b_vp != vp) 43849232Smckusick reassignbuf(bp, bp->b_vp); 43949232Smckusick else 44049232Smckusick bp->b_flags |= B_INVAL; 44149232Smckusick brelse(bp); 44249232Smckusick } 44349232Smckusick } 44449232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 44549232Smckusick panic("vinvalbuf: flush failed"); 44649232Smckusick return (dirty); 44749232Smckusick } 44849232Smckusick 44949232Smckusick /* 45049232Smckusick * Associate a buffer with a vnode. 45149232Smckusick */ 45249232Smckusick bgetvp(vp, bp) 45349232Smckusick register struct vnode *vp; 45449232Smckusick register struct buf *bp; 45549232Smckusick { 45649973Smckusick register struct vnode *vq; 45749973Smckusick register struct buf *bq; 45849232Smckusick 45949232Smckusick if (bp->b_vp) 46049232Smckusick panic("bgetvp: not free"); 46149232Smckusick VHOLD(vp); 46249232Smckusick bp->b_vp = vp; 46349232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 46449232Smckusick bp->b_dev = vp->v_rdev; 46549232Smckusick else 46649232Smckusick bp->b_dev = NODEV; 46749232Smckusick /* 46849232Smckusick * Insert onto list for new vnode. 46949232Smckusick */ 47049973Smckusick if (bq = vp->v_cleanblkhd) 47149973Smckusick bq->b_blockb = &bp->b_blockf; 47249973Smckusick bp->b_blockf = bq; 47349973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 47449973Smckusick vp->v_cleanblkhd = bp; 47549232Smckusick } 47649232Smckusick 47749232Smckusick /* 47849232Smckusick * Disassociate a buffer from a vnode. 47949232Smckusick */ 48049232Smckusick brelvp(bp) 48149232Smckusick register struct buf *bp; 48249232Smckusick { 48349232Smckusick struct buf *bq; 48449232Smckusick struct vnode *vp; 48549232Smckusick 48649232Smckusick if (bp->b_vp == (struct vnode *) 0) 48749232Smckusick panic("brelvp: NULL"); 48849232Smckusick /* 48949232Smckusick * Delete from old vnode list, if on one. 49049232Smckusick */ 49149232Smckusick if (bp->b_blockb) { 49249232Smckusick if (bq = bp->b_blockf) 49349232Smckusick bq->b_blockb = bp->b_blockb; 49449232Smckusick *bp->b_blockb = bq; 49549232Smckusick bp->b_blockf = NULL; 49649232Smckusick bp->b_blockb = NULL; 49749232Smckusick } 49849232Smckusick vp = bp->b_vp; 49949232Smckusick bp->b_vp = (struct vnode *) 0; 50049232Smckusick HOLDRELE(vp); 50149232Smckusick } 50249232Smckusick 50349232Smckusick /* 50449232Smckusick * Reassign a buffer from one vnode to another. 50549232Smckusick * Used to assign file specific control information 50649232Smckusick * (indirect blocks) to the vnode to which they belong. 50749232Smckusick */ 50849232Smckusick reassignbuf(bp, newvp) 50949232Smckusick register struct buf *bp; 51049232Smckusick register struct vnode *newvp; 51149232Smckusick { 51249232Smckusick register struct buf *bq, **listheadp; 51349232Smckusick 51452655Smckusick if (newvp == NULL) { 51552655Smckusick printf("reassignbuf: NULL"); 51652655Smckusick return; 51752655Smckusick } 51849232Smckusick /* 51949232Smckusick * Delete from old vnode list, if on one. 52049232Smckusick */ 52149232Smckusick if (bp->b_blockb) { 52249232Smckusick if (bq = bp->b_blockf) 52349232Smckusick bq->b_blockb = bp->b_blockb; 52449232Smckusick *bp->b_blockb = bq; 52549232Smckusick } 52649232Smckusick /* 52749232Smckusick * If dirty, put on list of dirty buffers; 52849232Smckusick * otherwise insert onto list of clean buffers. 52949232Smckusick */ 53049232Smckusick if (bp->b_flags & B_DELWRI) 53149232Smckusick listheadp = &newvp->v_dirtyblkhd; 53249232Smckusick else 53349232Smckusick listheadp = &newvp->v_cleanblkhd; 53449973Smckusick if (bq = *listheadp) 53549973Smckusick bq->b_blockb = &bp->b_blockf; 53649973Smckusick bp->b_blockf = bq; 53749973Smckusick bp->b_blockb = listheadp; 53849973Smckusick *listheadp = bp; 53949232Smckusick } 54049232Smckusick 54149232Smckusick /* 54239433Smckusick * Create a vnode for a block device. 54339433Smckusick * Used for root filesystem, argdev, and swap areas. 54439433Smckusick * Also used for memory file system special devices. 54539397Smckusick */ 54639433Smckusick bdevvp(dev, vpp) 54739433Smckusick dev_t dev; 54839433Smckusick struct vnode **vpp; 54939433Smckusick { 55039433Smckusick register struct vnode *vp; 55139433Smckusick struct vnode *nvp; 55239433Smckusick int error; 55339433Smckusick 55446989Smckusick if (dev == NODEV) 55546989Smckusick return (0); 55639447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 55739433Smckusick if (error) { 55839433Smckusick *vpp = 0; 55939433Smckusick return (error); 56039433Smckusick } 56139433Smckusick vp = nvp; 56239433Smckusick vp->v_type = VBLK; 56339615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 56439433Smckusick vput(vp); 56539433Smckusick vp = nvp; 56639433Smckusick } 56739433Smckusick *vpp = vp; 56839433Smckusick return (0); 56939433Smckusick } 57039433Smckusick 57139433Smckusick /* 57239433Smckusick * Check to see if the new vnode represents a special device 57339433Smckusick * for which we already have a vnode (either because of 57439433Smckusick * bdevvp() or because of a different vnode representing 57539433Smckusick * the same block device). If such an alias exists, deallocate 57639509Smckusick * the existing contents and return the aliased vnode. The 57739433Smckusick * caller is responsible for filling it with its new contents. 57839433Smckusick */ 57939433Smckusick struct vnode * 58039615Smckusick checkalias(nvp, nvp_rdev, mp) 58139433Smckusick register struct vnode *nvp; 58239615Smckusick dev_t nvp_rdev; 58339433Smckusick struct mount *mp; 58439433Smckusick { 58539433Smckusick register struct vnode *vp; 58639615Smckusick struct vnode **vpp; 58739433Smckusick 58839433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 58941400Smckusick return (NULLVP); 59039615Smckusick 59139615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 59239433Smckusick loop: 59339615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 59439615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 59539433Smckusick continue; 59639615Smckusick /* 59739615Smckusick * Alias, but not in use, so flush it out. 59839615Smckusick */ 59939809Smckusick if (vp->v_usecount == 0) { 60039615Smckusick vgone(vp); 60139615Smckusick goto loop; 60239615Smckusick } 60339633Smckusick if (vget(vp)) 60439633Smckusick goto loop; 60539433Smckusick break; 60639433Smckusick } 60739615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 60839615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 60939615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 61039615Smckusick nvp->v_rdev = nvp_rdev; 61139809Smckusick nvp->v_hashchain = vpp; 61239615Smckusick nvp->v_specnext = *vpp; 61342152Smckusick nvp->v_specflags = 0; 61439615Smckusick *vpp = nvp; 61540640Smckusick if (vp != NULL) { 61640640Smckusick nvp->v_flag |= VALIASED; 61740640Smckusick vp->v_flag |= VALIASED; 61840640Smckusick vput(vp); 61940640Smckusick } 62041400Smckusick return (NULLVP); 62139433Smckusick } 62239484Smckusick VOP_UNLOCK(vp); 62339484Smckusick vclean(vp, 0); 62439433Smckusick vp->v_op = nvp->v_op; 62539433Smckusick vp->v_tag = nvp->v_tag; 62639433Smckusick nvp->v_type = VNON; 62739433Smckusick insmntque(vp, mp); 62839433Smckusick return (vp); 62939433Smckusick } 63039433Smckusick 63139433Smckusick /* 63239433Smckusick * Grab a particular vnode from the free list, increment its 63339433Smckusick * reference count and lock it. The vnode lock bit is set the 63439433Smckusick * vnode is being eliminated in vgone. The process is awakened 63539433Smckusick * when the transition is completed, and an error returned to 63639433Smckusick * indicate that the vnode is no longer usable (possibly having 63739433Smckusick * been changed to a new file system type). 63839433Smckusick */ 63939397Smckusick vget(vp) 64039397Smckusick register struct vnode *vp; 64139397Smckusick { 64239397Smckusick register struct vnode *vq; 64339397Smckusick 64439433Smckusick if (vp->v_flag & VXLOCK) { 64539433Smckusick vp->v_flag |= VXWANT; 64639433Smckusick sleep((caddr_t)vp, PINOD); 64739433Smckusick return (1); 64839433Smckusick } 64939809Smckusick if (vp->v_usecount == 0) { 65039433Smckusick if (vq = vp->v_freef) 65139433Smckusick vq->v_freeb = vp->v_freeb; 65239433Smckusick else 65339433Smckusick vfreet = vp->v_freeb; 65439433Smckusick *vp->v_freeb = vq; 65539433Smckusick vp->v_freef = NULL; 65639433Smckusick vp->v_freeb = NULL; 65739433Smckusick } 65839397Smckusick VREF(vp); 65939433Smckusick VOP_LOCK(vp); 66039433Smckusick return (0); 66139397Smckusick } 66239397Smckusick 66339397Smckusick /* 66439397Smckusick * Vnode reference, just increment the count 66539397Smckusick */ 66639397Smckusick void vref(vp) 66739397Smckusick struct vnode *vp; 66839397Smckusick { 66939397Smckusick 67039809Smckusick vp->v_usecount++; 67139397Smckusick } 67239397Smckusick 67339397Smckusick /* 67439397Smckusick * vput(), just unlock and vrele() 67539397Smckusick */ 67639397Smckusick void vput(vp) 67739397Smckusick register struct vnode *vp; 67839397Smckusick { 67952416Storek 68039397Smckusick VOP_UNLOCK(vp); 68139397Smckusick vrele(vp); 68239397Smckusick } 68339397Smckusick 68439397Smckusick /* 68539397Smckusick * Vnode release. 68639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 68739397Smckusick */ 68839397Smckusick void vrele(vp) 68939397Smckusick register struct vnode *vp; 69039397Smckusick { 69148024Smckusick struct proc *p = curproc; /* XXX */ 69239397Smckusick 69350109Smckusick #ifdef DIAGNOSTIC 69439397Smckusick if (vp == NULL) 69539433Smckusick panic("vrele: null vp"); 69650109Smckusick #endif 69739809Smckusick vp->v_usecount--; 69839809Smckusick if (vp->v_usecount > 0) 69939397Smckusick return; 70050109Smckusick #ifdef DIAGNOSTIC 70150109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 70250109Smckusick vprint("vrele: bad ref count", vp); 70350109Smckusick panic("vrele: ref cnt"); 70450109Smckusick } 70550109Smckusick #endif 70641400Smckusick if (vfreeh == NULLVP) { 70739397Smckusick /* 70839397Smckusick * insert into empty list 70939397Smckusick */ 71039397Smckusick vfreeh = vp; 71139397Smckusick vp->v_freeb = &vfreeh; 71239397Smckusick } else { 71339397Smckusick /* 71439397Smckusick * insert at tail of list 71539397Smckusick */ 71639397Smckusick *vfreet = vp; 71739397Smckusick vp->v_freeb = vfreet; 71839397Smckusick } 71939433Smckusick vp->v_freef = NULL; 72039433Smckusick vfreet = &vp->v_freef; 72148024Smckusick VOP_INACTIVE(vp, p); 72239397Smckusick } 72339433Smckusick 72439433Smckusick /* 72539809Smckusick * Page or buffer structure gets a reference. 72639809Smckusick */ 72753312Smckusick void vhold(vp) 72839809Smckusick register struct vnode *vp; 72939809Smckusick { 73039809Smckusick 73139809Smckusick vp->v_holdcnt++; 73239809Smckusick } 73339809Smckusick 73439809Smckusick /* 73539809Smckusick * Page or buffer structure frees a reference. 73639809Smckusick */ 73753312Smckusick void holdrele(vp) 73839809Smckusick register struct vnode *vp; 73939809Smckusick { 74039809Smckusick 74139809Smckusick if (vp->v_holdcnt <= 0) 74239809Smckusick panic("holdrele: holdcnt"); 74339809Smckusick vp->v_holdcnt--; 74439809Smckusick } 74539809Smckusick 74639809Smckusick /* 74739509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 74839509Smckusick * 74939509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 75039509Smckusick * return error if any are found (nb: this is a user error, not a 75139509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 75239509Smckusick * that are found. 75339509Smckusick */ 75439509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 75539509Smckusick 75639509Smckusick vflush(mp, skipvp, flags) 75739509Smckusick struct mount *mp; 75839509Smckusick struct vnode *skipvp; 75939509Smckusick int flags; 76039509Smckusick { 76139509Smckusick register struct vnode *vp, *nvp; 76239509Smckusick int busy = 0; 76339509Smckusick 76441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 76541300Smckusick panic("vflush: not busy"); 76641421Smckusick loop: 76741400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 76841421Smckusick if (vp->v_mount != mp) 76941421Smckusick goto loop; 77039509Smckusick nvp = vp->v_mountf; 77139509Smckusick /* 77239509Smckusick * Skip over a selected vnode. 77339509Smckusick */ 77439509Smckusick if (vp == skipvp) 77539509Smckusick continue; 77639509Smckusick /* 77741300Smckusick * Skip over a vnodes marked VSYSTEM. 77841300Smckusick */ 77941300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 78041300Smckusick continue; 78141300Smckusick /* 78239809Smckusick * With v_usecount == 0, all we need to do is clear 78339509Smckusick * out the vnode data structures and we are done. 78439509Smckusick */ 78539809Smckusick if (vp->v_usecount == 0) { 78639509Smckusick vgone(vp); 78739509Smckusick continue; 78839509Smckusick } 78939509Smckusick /* 79039509Smckusick * For block or character devices, revert to an 79139509Smckusick * anonymous device. For all other files, just kill them. 79239509Smckusick */ 79341300Smckusick if (flags & FORCECLOSE) { 79439509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 79539509Smckusick vgone(vp); 79639509Smckusick } else { 79739509Smckusick vclean(vp, 0); 79839509Smckusick vp->v_op = &spec_vnodeops; 79939509Smckusick insmntque(vp, (struct mount *)0); 80039509Smckusick } 80139509Smckusick continue; 80239509Smckusick } 80339509Smckusick if (busyprt) 80439667Smckusick vprint("vflush: busy vnode", vp); 80539509Smckusick busy++; 80639509Smckusick } 80739509Smckusick if (busy) 80839509Smckusick return (EBUSY); 80939509Smckusick return (0); 81039509Smckusick } 81139509Smckusick 81239509Smckusick /* 81339433Smckusick * Disassociate the underlying file system from a vnode. 81439433Smckusick */ 81541300Smckusick void vclean(vp, flags) 81639433Smckusick register struct vnode *vp; 81745118Smckusick int flags; 81839433Smckusick { 81939433Smckusick struct vnodeops *origops; 82039484Smckusick int active; 82148024Smckusick struct proc *p = curproc; /* XXX */ 82239433Smckusick 82339484Smckusick /* 82439484Smckusick * Check to see if the vnode is in use. 82539667Smckusick * If so we have to reference it before we clean it out 82639667Smckusick * so that its count cannot fall to zero and generate a 82739667Smckusick * race against ourselves to recycle it. 82839484Smckusick */ 82939809Smckusick if (active = vp->v_usecount) 83039484Smckusick VREF(vp); 83139484Smckusick /* 83239484Smckusick * Prevent the vnode from being recycled or 83339484Smckusick * brought into use while we clean it out. 83439484Smckusick */ 83539667Smckusick if (vp->v_flag & VXLOCK) 83639667Smckusick panic("vclean: deadlock"); 83739433Smckusick vp->v_flag |= VXLOCK; 83839433Smckusick /* 83939667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 84039667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 84139667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 84239667Smckusick * For active vnodes, it ensures that no other activity can 84339667Smckusick * occur while the buffer list is being cleaned out. 84439667Smckusick */ 84539667Smckusick VOP_LOCK(vp); 84641300Smckusick if (flags & DOCLOSE) 84739667Smckusick vinvalbuf(vp, 1); 84839667Smckusick /* 84939433Smckusick * Prevent any further operations on the vnode from 85039433Smckusick * being passed through to the old file system. 85139433Smckusick */ 85239433Smckusick origops = vp->v_op; 85339433Smckusick vp->v_op = &dead_vnodeops; 85439433Smckusick vp->v_tag = VT_NON; 85539433Smckusick /* 85639484Smckusick * If purging an active vnode, it must be unlocked, closed, 85739484Smckusick * and deactivated before being reclaimed. 85839433Smckusick */ 85949761Smckusick (*(origops->vop_unlock))(vp); 86039484Smckusick if (active) { 86141300Smckusick if (flags & DOCLOSE) 86249761Smckusick (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p); 86349761Smckusick (*(origops->vop_inactive))(vp, p); 86439433Smckusick } 86539433Smckusick /* 86639433Smckusick * Reclaim the vnode. 86739433Smckusick */ 86849761Smckusick if ((*(origops->vop_reclaim))(vp)) 86939433Smckusick panic("vclean: cannot reclaim"); 87039484Smckusick if (active) 87139484Smckusick vrele(vp); 87239433Smckusick /* 87339433Smckusick * Done with purge, notify sleepers in vget of the grim news. 87439433Smckusick */ 87539433Smckusick vp->v_flag &= ~VXLOCK; 87639433Smckusick if (vp->v_flag & VXWANT) { 87739433Smckusick vp->v_flag &= ~VXWANT; 87839433Smckusick wakeup((caddr_t)vp); 87939433Smckusick } 88039433Smckusick } 88139433Smckusick 88239433Smckusick /* 88339633Smckusick * Eliminate all activity associated with the requested vnode 88439633Smckusick * and with all vnodes aliased to the requested vnode. 88539633Smckusick */ 88639633Smckusick void vgoneall(vp) 88739633Smckusick register struct vnode *vp; 88839633Smckusick { 88939809Smckusick register struct vnode *vq; 89039633Smckusick 89140665Smckusick if (vp->v_flag & VALIASED) { 89240665Smckusick /* 89340665Smckusick * If a vgone (or vclean) is already in progress, 89440665Smckusick * wait until it is done and return. 89540665Smckusick */ 89640665Smckusick if (vp->v_flag & VXLOCK) { 89740665Smckusick vp->v_flag |= VXWANT; 89840665Smckusick sleep((caddr_t)vp, PINOD); 89940665Smckusick return; 90039633Smckusick } 90140665Smckusick /* 90240665Smckusick * Ensure that vp will not be vgone'd while we 90340665Smckusick * are eliminating its aliases. 90440665Smckusick */ 90540665Smckusick vp->v_flag |= VXLOCK; 90640665Smckusick while (vp->v_flag & VALIASED) { 90740665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 90840665Smckusick if (vq->v_rdev != vp->v_rdev || 90940665Smckusick vq->v_type != vp->v_type || vp == vq) 91040665Smckusick continue; 91140665Smckusick vgone(vq); 91240665Smckusick break; 91340665Smckusick } 91440665Smckusick } 91540665Smckusick /* 91640665Smckusick * Remove the lock so that vgone below will 91740665Smckusick * really eliminate the vnode after which time 91840665Smckusick * vgone will awaken any sleepers. 91940665Smckusick */ 92040665Smckusick vp->v_flag &= ~VXLOCK; 92139633Smckusick } 92239633Smckusick vgone(vp); 92339633Smckusick } 92439633Smckusick 92539633Smckusick /* 92639433Smckusick * Eliminate all activity associated with a vnode 92739433Smckusick * in preparation for reuse. 92839433Smckusick */ 92939433Smckusick void vgone(vp) 93039433Smckusick register struct vnode *vp; 93139433Smckusick { 93239809Smckusick register struct vnode *vq; 93339615Smckusick struct vnode *vx; 93439433Smckusick 93539433Smckusick /* 93640548Smckusick * If a vgone (or vclean) is already in progress, 93740548Smckusick * wait until it is done and return. 93840548Smckusick */ 93940548Smckusick if (vp->v_flag & VXLOCK) { 94040548Smckusick vp->v_flag |= VXWANT; 94140548Smckusick sleep((caddr_t)vp, PINOD); 94240548Smckusick return; 94340548Smckusick } 94440548Smckusick /* 94539433Smckusick * Clean out the filesystem specific data. 94639433Smckusick */ 94741300Smckusick vclean(vp, DOCLOSE); 94839433Smckusick /* 94939433Smckusick * Delete from old mount point vnode list, if on one. 95039433Smckusick */ 95139433Smckusick if (vp->v_mountb) { 95239433Smckusick if (vq = vp->v_mountf) 95339433Smckusick vq->v_mountb = vp->v_mountb; 95439433Smckusick *vp->v_mountb = vq; 95539433Smckusick vp->v_mountf = NULL; 95639433Smckusick vp->v_mountb = NULL; 95752311Smckusick vp->v_mount = NULL; 95839433Smckusick } 95939433Smckusick /* 96039433Smckusick * If special device, remove it from special device alias list. 96139433Smckusick */ 96239433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 96339809Smckusick if (*vp->v_hashchain == vp) { 96439809Smckusick *vp->v_hashchain = vp->v_specnext; 96539433Smckusick } else { 96639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 96739615Smckusick if (vq->v_specnext != vp) 96839433Smckusick continue; 96939615Smckusick vq->v_specnext = vp->v_specnext; 97039433Smckusick break; 97139433Smckusick } 97239615Smckusick if (vq == NULL) 97339433Smckusick panic("missing bdev"); 97439433Smckusick } 97539615Smckusick if (vp->v_flag & VALIASED) { 97652416Storek vx = NULL; 97739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97840108Smckusick if (vq->v_rdev != vp->v_rdev || 97940108Smckusick vq->v_type != vp->v_type) 98039615Smckusick continue; 98152416Storek if (vx) 98252416Storek break; 98339615Smckusick vx = vq; 98439615Smckusick } 98552416Storek if (vx == NULL) 98639615Smckusick panic("missing alias"); 98752416Storek if (vq == NULL) 98839615Smckusick vx->v_flag &= ~VALIASED; 98939615Smckusick vp->v_flag &= ~VALIASED; 99039615Smckusick } 99139615Smckusick FREE(vp->v_specinfo, M_VNODE); 99239615Smckusick vp->v_specinfo = NULL; 99339433Smckusick } 99439433Smckusick /* 99539433Smckusick * If it is on the freelist, move it to the head of the list. 99639433Smckusick */ 99739433Smckusick if (vp->v_freeb) { 99839433Smckusick if (vq = vp->v_freef) 99939433Smckusick vq->v_freeb = vp->v_freeb; 100039433Smckusick else 100139433Smckusick vfreet = vp->v_freeb; 100239433Smckusick *vp->v_freeb = vq; 100339433Smckusick vp->v_freef = vfreeh; 100439433Smckusick vp->v_freeb = &vfreeh; 100539433Smckusick vfreeh->v_freeb = &vp->v_freef; 100639433Smckusick vfreeh = vp; 100739433Smckusick } 100839484Smckusick vp->v_type = VBAD; 100939433Smckusick } 101039633Smckusick 101139633Smckusick /* 101239821Smckusick * Lookup a vnode by device number. 101339821Smckusick */ 101439821Smckusick vfinddev(dev, type, vpp) 101539821Smckusick dev_t dev; 101639821Smckusick enum vtype type; 101739821Smckusick struct vnode **vpp; 101839821Smckusick { 101939821Smckusick register struct vnode *vp; 102039821Smckusick 102139821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 102239821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 102339821Smckusick continue; 102439821Smckusick *vpp = vp; 102539821Smckusick return (0); 102639821Smckusick } 102739821Smckusick return (1); 102839821Smckusick } 102939821Smckusick 103039821Smckusick /* 103139633Smckusick * Calculate the total number of references to a special device. 103239633Smckusick */ 103339633Smckusick vcount(vp) 103439633Smckusick register struct vnode *vp; 103539633Smckusick { 103639809Smckusick register struct vnode *vq; 103739633Smckusick int count; 103839633Smckusick 103939633Smckusick if ((vp->v_flag & VALIASED) == 0) 104039809Smckusick return (vp->v_usecount); 104139633Smckusick loop: 104239809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 104340108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 104439633Smckusick continue; 104539633Smckusick /* 104639633Smckusick * Alias, but not in use, so flush it out. 104739633Smckusick */ 104839809Smckusick if (vq->v_usecount == 0) { 104939633Smckusick vgone(vq); 105039633Smckusick goto loop; 105139633Smckusick } 105239809Smckusick count += vq->v_usecount; 105339633Smckusick } 105439633Smckusick return (count); 105539633Smckusick } 105639667Smckusick 105739667Smckusick /* 105839667Smckusick * Print out a description of a vnode. 105939667Smckusick */ 106039667Smckusick static char *typename[] = 106140286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 106239667Smckusick 106339667Smckusick vprint(label, vp) 106439667Smckusick char *label; 106539667Smckusick register struct vnode *vp; 106639667Smckusick { 106739913Smckusick char buf[64]; 106839667Smckusick 106939667Smckusick if (label != NULL) 107039667Smckusick printf("%s: ", label); 107150109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 107250109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 107350109Smckusick vp->v_holdcnt); 107439913Smckusick buf[0] = '\0'; 107539913Smckusick if (vp->v_flag & VROOT) 107639913Smckusick strcat(buf, "|VROOT"); 107739913Smckusick if (vp->v_flag & VTEXT) 107839913Smckusick strcat(buf, "|VTEXT"); 107941300Smckusick if (vp->v_flag & VSYSTEM) 108041300Smckusick strcat(buf, "|VSYSTEM"); 108141300Smckusick if (vp->v_flag & VXLOCK) 108241300Smckusick strcat(buf, "|VXLOCK"); 108341300Smckusick if (vp->v_flag & VXWANT) 108441300Smckusick strcat(buf, "|VXWANT"); 108541300Smckusick if (vp->v_flag & VBWAIT) 108641300Smckusick strcat(buf, "|VBWAIT"); 108739913Smckusick if (vp->v_flag & VALIASED) 108839913Smckusick strcat(buf, "|VALIASED"); 108939913Smckusick if (buf[0] != '\0') 109039913Smckusick printf(" flags (%s)", &buf[1]); 109139913Smckusick printf("\n\t"); 109239667Smckusick VOP_PRINT(vp); 109339667Smckusick } 109441110Smarc 109549691Smckusick #ifdef DEBUG 109649691Smckusick /* 109749691Smckusick * List all of the locked vnodes in the system. 109849691Smckusick * Called when debugging the kernel. 109949691Smckusick */ 110049691Smckusick printlockedvnodes() 110149691Smckusick { 110249691Smckusick register struct mount *mp; 110349691Smckusick register struct vnode *vp; 110449691Smckusick 110549691Smckusick printf("Locked vnodes\n"); 110649691Smckusick mp = rootfs; 110749691Smckusick do { 110849691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 110949691Smckusick if (VOP_ISLOCKED(vp)) 111049691Smckusick vprint((char *)0, vp); 111149691Smckusick mp = mp->mnt_next; 111249691Smckusick } while (mp != rootfs); 111349691Smckusick } 111449691Smckusick #endif 111549691Smckusick 111641110Smarc int kinfo_vdebug = 1; 111741110Smarc int kinfo_vgetfailed; 111841110Smarc #define KINFO_VNODESLOP 10 111941110Smarc /* 112041110Smarc * Dump vnode list (via kinfo). 112141110Smarc * Copyout address of vnode followed by vnode. 112241110Smarc */ 112345118Smckusick /* ARGSUSED */ 112441110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 112545118Smckusick int op; 112641110Smarc char *where; 112745118Smckusick int *acopysize, arg, *aneeded; 112841110Smarc { 112941110Smarc register struct mount *mp = rootfs; 113041300Smckusick struct mount *omp; 113141110Smarc struct vnode *vp; 113241110Smarc register char *bp = where, *savebp; 113341110Smarc char *ewhere = where + *acopysize; 113441110Smarc int error; 113541110Smarc 113641110Smarc #define VPTRSZ sizeof (struct vnode *) 113741110Smarc #define VNODESZ sizeof (struct vnode) 113841110Smarc if (where == NULL) { 113941110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 114041110Smarc return (0); 114141110Smarc } 114241110Smarc 114341110Smarc do { 114441300Smckusick if (vfs_busy(mp)) { 114541400Smckusick mp = mp->mnt_next; 114641300Smckusick continue; 114741300Smckusick } 114841110Smarc savebp = bp; 114941110Smarc again: 115041421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 115141422Smckusick /* 115241422Smckusick * Check that the vp is still associated with 115341422Smckusick * this filesystem. RACE: could have been 115441422Smckusick * recycled onto the same filesystem. 115541422Smckusick */ 115641421Smckusick if (vp->v_mount != mp) { 115741421Smckusick if (kinfo_vdebug) 115841421Smckusick printf("kinfo: vp changed\n"); 115941421Smckusick bp = savebp; 116041421Smckusick goto again; 116141421Smckusick } 116241110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 116341110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 116441110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 116541422Smckusick VNODESZ)))) 116641110Smarc return (error); 116741110Smarc bp += VPTRSZ + VNODESZ; 116841110Smarc } 116941300Smckusick omp = mp; 117041400Smckusick mp = mp->mnt_next; 117141300Smckusick vfs_unbusy(omp); 117241110Smarc } while (mp != rootfs); 117341110Smarc 117441110Smarc *aneeded = bp - where; 117541110Smarc if (bp > ewhere) 117641110Smarc *acopysize = ewhere - where; 117741110Smarc else 117841110Smarc *acopysize = bp - where; 117941110Smarc return (0); 118041110Smarc } 1181