137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*53580Sheideman * @(#)vfs_subr.c 7.76 (Berkeley) 05/15/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 */ 16653493Sheideman extern struct vnode *vfreeh, **vfreet; 16753547Sheideman extern int (**dead_vnodeop_p)(); 16853547Sheideman extern int (**spec_vnodeop_p)(); 16939635Smckusick extern void vclean(); 17040883Smckusick long numvnodes; 17153493Sheideman extern struct vattr va_null; 17239397Smckusick 17339397Smckusick /* 17439397Smckusick * Return the next vnode from the free list. 17539397Smckusick */ 17639397Smckusick getnewvnode(tag, mp, vops, vpp) 17739397Smckusick enum vtagtype tag; 17839397Smckusick struct mount *mp; 17953495Sheideman int (**vops)(); 18039397Smckusick struct vnode **vpp; 18139397Smckusick { 18239397Smckusick register struct vnode *vp, *vq; 18339397Smckusick 18440883Smckusick if (numvnodes < desiredvnodes) { 18545118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 18645118Smckusick M_VNODE, M_WAITOK); 18740883Smckusick bzero((char *)vp, sizeof *vp); 18840883Smckusick numvnodes++; 18940883Smckusick } else { 19040883Smckusick if ((vp = vfreeh) == NULL) { 19140883Smckusick tablefull("vnode"); 19240883Smckusick *vpp = 0; 19340883Smckusick return (ENFILE); 19440883Smckusick } 19540883Smckusick if (vp->v_usecount) 19640883Smckusick panic("free vnode isn't"); 19740883Smckusick if (vq = vp->v_freef) 19840883Smckusick vq->v_freeb = &vfreeh; 19940883Smckusick else 20040883Smckusick vfreet = &vfreeh; 20140883Smckusick vfreeh = vq; 20240883Smckusick vp->v_freef = NULL; 20340883Smckusick vp->v_freeb = NULL; 20452190Smckusick vp->v_lease = NULL; 20540883Smckusick if (vp->v_type != VBAD) 20640883Smckusick vgone(vp); 20752006Smckusick if (vp->v_data) 20852006Smckusick panic("cleaned vnode isn't"); 20940883Smckusick vp->v_flag = 0; 21040883Smckusick vp->v_lastr = 0; 21140883Smckusick vp->v_socket = 0; 21239397Smckusick } 21339512Smckusick vp->v_type = VNON; 21439397Smckusick cache_purge(vp); 21539397Smckusick vp->v_tag = tag; 21639433Smckusick vp->v_op = vops; 21739397Smckusick insmntque(vp, mp); 21839397Smckusick VREF(vp); 21939397Smckusick *vpp = vp; 22039397Smckusick return (0); 22139397Smckusick } 22239397Smckusick 22339397Smckusick /* 22439397Smckusick * Move a vnode from one mount queue to another. 22539397Smckusick */ 22639397Smckusick insmntque(vp, mp) 22739397Smckusick register struct vnode *vp; 22839397Smckusick register struct mount *mp; 22939397Smckusick { 23049973Smckusick register struct vnode *vq; 23139397Smckusick 23239397Smckusick /* 23339397Smckusick * Delete from old mount point vnode list, if on one. 23439397Smckusick */ 23539397Smckusick if (vp->v_mountb) { 23639397Smckusick if (vq = vp->v_mountf) 23739397Smckusick vq->v_mountb = vp->v_mountb; 23839397Smckusick *vp->v_mountb = vq; 23939397Smckusick } 24039397Smckusick /* 24139397Smckusick * Insert into list of vnodes for the new mount point, if available. 24239397Smckusick */ 24339621Smckusick vp->v_mount = mp; 24439397Smckusick if (mp == NULL) { 24539397Smckusick vp->v_mountf = NULL; 24639397Smckusick vp->v_mountb = NULL; 24739397Smckusick return; 24839397Smckusick } 24949973Smckusick if (vq = mp->mnt_mounth) 25049973Smckusick vq->v_mountb = &vp->v_mountf; 25149973Smckusick vp->v_mountf = vq; 25249973Smckusick vp->v_mountb = &mp->mnt_mounth; 25349973Smckusick mp->mnt_mounth = vp; 25439397Smckusick } 25539397Smckusick 25639397Smckusick /* 25749232Smckusick * Make sure all write-behind blocks associated 25849232Smckusick * with mount point are flushed out (from sync). 25949232Smckusick */ 26049232Smckusick mntflushbuf(mountp, flags) 26149232Smckusick struct mount *mountp; 26249232Smckusick int flags; 26349232Smckusick { 26453547Sheideman USES_VOP_ISLOCKED; 26549232Smckusick register struct vnode *vp; 26649232Smckusick 26749232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 26849232Smckusick panic("mntflushbuf: not busy"); 26949232Smckusick loop: 27049232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 27149232Smckusick if (VOP_ISLOCKED(vp)) 27249232Smckusick continue; 27349232Smckusick if (vget(vp)) 27449232Smckusick goto loop; 27549232Smckusick vflushbuf(vp, flags); 27649232Smckusick vput(vp); 27749232Smckusick if (vp->v_mount != mountp) 27849232Smckusick goto loop; 27949232Smckusick } 28049232Smckusick } 28149232Smckusick 28249232Smckusick /* 28349232Smckusick * Flush all dirty buffers associated with a vnode. 28449232Smckusick */ 28549232Smckusick vflushbuf(vp, flags) 28649232Smckusick register struct vnode *vp; 28749232Smckusick int flags; 28849232Smckusick { 28949232Smckusick register struct buf *bp; 29049232Smckusick struct buf *nbp; 29149232Smckusick int s; 29249232Smckusick 29349232Smckusick loop: 29449232Smckusick s = splbio(); 29549232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 29649232Smckusick nbp = bp->b_blockf; 29749232Smckusick if ((bp->b_flags & B_BUSY)) 29849232Smckusick continue; 29949232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 30049232Smckusick panic("vflushbuf: not dirty"); 30149232Smckusick bremfree(bp); 30249232Smckusick bp->b_flags |= B_BUSY; 30349232Smckusick splx(s); 30449232Smckusick /* 30549232Smckusick * Wait for I/O associated with indirect blocks to complete, 30649232Smckusick * since there is no way to quickly wait for them below. 30749232Smckusick * NB: This is really specific to ufs, but is done here 30849232Smckusick * as it is easier and quicker. 30949232Smckusick */ 31049460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 31149232Smckusick (void) bawrite(bp); 31249460Smckusick else 31349232Smckusick (void) bwrite(bp); 31449460Smckusick goto loop; 31549232Smckusick } 31649232Smckusick splx(s); 31749232Smckusick if ((flags & B_SYNC) == 0) 31849232Smckusick return; 31949232Smckusick s = splbio(); 32049232Smckusick while (vp->v_numoutput) { 32149232Smckusick vp->v_flag |= VBWAIT; 32249232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 32349232Smckusick } 32449232Smckusick splx(s); 32549232Smckusick if (vp->v_dirtyblkhd) { 32649232Smckusick vprint("vflushbuf: dirty", vp); 32749232Smckusick goto loop; 32849232Smckusick } 32949232Smckusick } 33049232Smckusick 33149232Smckusick /* 33249232Smckusick * Update outstanding I/O count and do wakeup if requested. 33349232Smckusick */ 33449232Smckusick vwakeup(bp) 33549232Smckusick register struct buf *bp; 33649232Smckusick { 33749232Smckusick register struct vnode *vp; 33849232Smckusick 33949232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 34049232Smckusick if (vp = bp->b_vp) { 34149232Smckusick vp->v_numoutput--; 34249232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 34349232Smckusick if (vp->v_numoutput < 0) 34449232Smckusick panic("vwakeup: neg numoutput"); 34549232Smckusick vp->v_flag &= ~VBWAIT; 34649232Smckusick wakeup((caddr_t)&vp->v_numoutput); 34749232Smckusick } 34849232Smckusick } 34949232Smckusick } 35049232Smckusick 35149232Smckusick /* 35249232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 35349232Smckusick * 35449232Smckusick * Go through the list of vnodes associated with the file system; 35549232Smckusick * for each vnode invalidate any buffers that it holds. Normally 35649232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 35749232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 35849232Smckusick * returns the count of dirty buffers when it is finished. 35949232Smckusick */ 36049232Smckusick mntinvalbuf(mountp) 36149232Smckusick struct mount *mountp; 36249232Smckusick { 36349232Smckusick register struct vnode *vp; 36449232Smckusick int dirty = 0; 36549232Smckusick 36649232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 36749232Smckusick panic("mntinvalbuf: not busy"); 36849232Smckusick loop: 36949232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 37049232Smckusick if (vget(vp)) 37149232Smckusick goto loop; 37249232Smckusick dirty += vinvalbuf(vp, 1); 37349232Smckusick vput(vp); 37449232Smckusick if (vp->v_mount != mountp) 37549232Smckusick goto loop; 37649232Smckusick } 37749232Smckusick return (dirty); 37849232Smckusick } 37949232Smckusick 38049232Smckusick /* 38149232Smckusick * Flush out and invalidate all buffers associated with a vnode. 38249232Smckusick * Called with the underlying object locked. 38349232Smckusick */ 38449232Smckusick vinvalbuf(vp, save) 38549232Smckusick register struct vnode *vp; 38649232Smckusick int save; 38749232Smckusick { 38853547Sheideman USES_VOP_BWRITE; 38949232Smckusick register struct buf *bp; 39049232Smckusick struct buf *nbp, *blist; 39149232Smckusick int s, dirty = 0; 39249232Smckusick 39349232Smckusick for (;;) { 39449232Smckusick if (blist = vp->v_dirtyblkhd) 39549232Smckusick /* void */; 39649232Smckusick else if (blist = vp->v_cleanblkhd) 39749232Smckusick /* void */; 39849232Smckusick else 39949232Smckusick break; 40049232Smckusick for (bp = blist; bp; bp = nbp) { 40149232Smckusick nbp = bp->b_blockf; 40249232Smckusick s = splbio(); 40349232Smckusick if (bp->b_flags & B_BUSY) { 40449232Smckusick bp->b_flags |= B_WANTED; 40549232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 40649232Smckusick splx(s); 40749232Smckusick break; 40849232Smckusick } 40949232Smckusick bremfree(bp); 41049232Smckusick bp->b_flags |= B_BUSY; 41149232Smckusick splx(s); 41249232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 41351568Smckusick dirty++; 41451568Smckusick (void) VOP_BWRITE(bp); 41549232Smckusick break; 41649232Smckusick } 41749232Smckusick if (bp->b_vp != vp) 41849232Smckusick reassignbuf(bp, bp->b_vp); 41949232Smckusick else 42049232Smckusick bp->b_flags |= B_INVAL; 42149232Smckusick brelse(bp); 42249232Smckusick } 42349232Smckusick } 42449232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 42549232Smckusick panic("vinvalbuf: flush failed"); 42649232Smckusick return (dirty); 42749232Smckusick } 42849232Smckusick 42949232Smckusick /* 43049232Smckusick * Associate a buffer with a vnode. 43149232Smckusick */ 43249232Smckusick bgetvp(vp, bp) 43349232Smckusick register struct vnode *vp; 43449232Smckusick register struct buf *bp; 43549232Smckusick { 43649973Smckusick register struct vnode *vq; 43749973Smckusick register struct buf *bq; 43849232Smckusick 43949232Smckusick if (bp->b_vp) 44049232Smckusick panic("bgetvp: not free"); 44149232Smckusick VHOLD(vp); 44249232Smckusick bp->b_vp = vp; 44349232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 44449232Smckusick bp->b_dev = vp->v_rdev; 44549232Smckusick else 44649232Smckusick bp->b_dev = NODEV; 44749232Smckusick /* 44849232Smckusick * Insert onto list for new vnode. 44949232Smckusick */ 45049973Smckusick if (bq = vp->v_cleanblkhd) 45149973Smckusick bq->b_blockb = &bp->b_blockf; 45249973Smckusick bp->b_blockf = bq; 45349973Smckusick bp->b_blockb = &vp->v_cleanblkhd; 45449973Smckusick vp->v_cleanblkhd = bp; 45549232Smckusick } 45649232Smckusick 45749232Smckusick /* 45849232Smckusick * Disassociate a buffer from a vnode. 45949232Smckusick */ 46049232Smckusick brelvp(bp) 46149232Smckusick register struct buf *bp; 46249232Smckusick { 46349232Smckusick struct buf *bq; 46449232Smckusick struct vnode *vp; 46549232Smckusick 46649232Smckusick if (bp->b_vp == (struct vnode *) 0) 46749232Smckusick panic("brelvp: NULL"); 46849232Smckusick /* 46949232Smckusick * Delete from old vnode list, if on one. 47049232Smckusick */ 47149232Smckusick if (bp->b_blockb) { 47249232Smckusick if (bq = bp->b_blockf) 47349232Smckusick bq->b_blockb = bp->b_blockb; 47449232Smckusick *bp->b_blockb = bq; 47549232Smckusick bp->b_blockf = NULL; 47649232Smckusick bp->b_blockb = NULL; 47749232Smckusick } 47849232Smckusick vp = bp->b_vp; 47949232Smckusick bp->b_vp = (struct vnode *) 0; 48049232Smckusick HOLDRELE(vp); 48149232Smckusick } 48249232Smckusick 48349232Smckusick /* 48449232Smckusick * Reassign a buffer from one vnode to another. 48549232Smckusick * Used to assign file specific control information 48649232Smckusick * (indirect blocks) to the vnode to which they belong. 48749232Smckusick */ 48849232Smckusick reassignbuf(bp, newvp) 48949232Smckusick register struct buf *bp; 49049232Smckusick register struct vnode *newvp; 49149232Smckusick { 49249232Smckusick register struct buf *bq, **listheadp; 49349232Smckusick 49452655Smckusick if (newvp == NULL) { 49552655Smckusick printf("reassignbuf: NULL"); 49652655Smckusick return; 49752655Smckusick } 49849232Smckusick /* 49949232Smckusick * Delete from old vnode list, if on one. 50049232Smckusick */ 50149232Smckusick if (bp->b_blockb) { 50249232Smckusick if (bq = bp->b_blockf) 50349232Smckusick bq->b_blockb = bp->b_blockb; 50449232Smckusick *bp->b_blockb = bq; 50549232Smckusick } 50649232Smckusick /* 50749232Smckusick * If dirty, put on list of dirty buffers; 50849232Smckusick * otherwise insert onto list of clean buffers. 50949232Smckusick */ 51049232Smckusick if (bp->b_flags & B_DELWRI) 51149232Smckusick listheadp = &newvp->v_dirtyblkhd; 51249232Smckusick else 51349232Smckusick listheadp = &newvp->v_cleanblkhd; 51449973Smckusick if (bq = *listheadp) 51549973Smckusick bq->b_blockb = &bp->b_blockf; 51649973Smckusick bp->b_blockf = bq; 51749973Smckusick bp->b_blockb = listheadp; 51849973Smckusick *listheadp = bp; 51949232Smckusick } 52049232Smckusick 52149232Smckusick /* 52239433Smckusick * Create a vnode for a block device. 52339433Smckusick * Used for root filesystem, argdev, and swap areas. 52439433Smckusick * Also used for memory file system special devices. 52539397Smckusick */ 52639433Smckusick bdevvp(dev, vpp) 52739433Smckusick dev_t dev; 52839433Smckusick struct vnode **vpp; 52939433Smckusick { 53039433Smckusick register struct vnode *vp; 53139433Smckusick struct vnode *nvp; 53239433Smckusick int error; 53339433Smckusick 53446989Smckusick if (dev == NODEV) 53546989Smckusick return (0); 53653547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 53739433Smckusick if (error) { 53839433Smckusick *vpp = 0; 53939433Smckusick return (error); 54039433Smckusick } 54139433Smckusick vp = nvp; 54239433Smckusick vp->v_type = VBLK; 54339615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 54439433Smckusick vput(vp); 54539433Smckusick vp = nvp; 54639433Smckusick } 54739433Smckusick *vpp = vp; 54839433Smckusick return (0); 54939433Smckusick } 55039433Smckusick 55139433Smckusick /* 55239433Smckusick * Check to see if the new vnode represents a special device 55339433Smckusick * for which we already have a vnode (either because of 55439433Smckusick * bdevvp() or because of a different vnode representing 55539433Smckusick * the same block device). If such an alias exists, deallocate 55639509Smckusick * the existing contents and return the aliased vnode. The 55739433Smckusick * caller is responsible for filling it with its new contents. 55839433Smckusick */ 55939433Smckusick struct vnode * 56039615Smckusick checkalias(nvp, nvp_rdev, mp) 56139433Smckusick register struct vnode *nvp; 56239615Smckusick dev_t nvp_rdev; 56339433Smckusick struct mount *mp; 56439433Smckusick { 56553547Sheideman USES_VOP_UNLOCK; 56639433Smckusick register struct vnode *vp; 56739615Smckusick struct vnode **vpp; 56839433Smckusick 56939433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 57041400Smckusick return (NULLVP); 57139615Smckusick 57239615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 57339433Smckusick loop: 57439615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 57539615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 57639433Smckusick continue; 57739615Smckusick /* 57839615Smckusick * Alias, but not in use, so flush it out. 57939615Smckusick */ 58039809Smckusick if (vp->v_usecount == 0) { 58139615Smckusick vgone(vp); 58239615Smckusick goto loop; 58339615Smckusick } 58439633Smckusick if (vget(vp)) 58539633Smckusick goto loop; 58639433Smckusick break; 58739433Smckusick } 58839615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 58939615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 59039615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 59139615Smckusick nvp->v_rdev = nvp_rdev; 59239809Smckusick nvp->v_hashchain = vpp; 59339615Smckusick nvp->v_specnext = *vpp; 59442152Smckusick nvp->v_specflags = 0; 59539615Smckusick *vpp = nvp; 59640640Smckusick if (vp != NULL) { 59740640Smckusick nvp->v_flag |= VALIASED; 59840640Smckusick vp->v_flag |= VALIASED; 59940640Smckusick vput(vp); 60040640Smckusick } 60141400Smckusick return (NULLVP); 60239433Smckusick } 60339484Smckusick VOP_UNLOCK(vp); 60439484Smckusick vclean(vp, 0); 60539433Smckusick vp->v_op = nvp->v_op; 60639433Smckusick vp->v_tag = nvp->v_tag; 60739433Smckusick nvp->v_type = VNON; 60839433Smckusick insmntque(vp, mp); 60939433Smckusick return (vp); 61039433Smckusick } 61139433Smckusick 61239433Smckusick /* 61339433Smckusick * Grab a particular vnode from the free list, increment its 61439433Smckusick * reference count and lock it. The vnode lock bit is set the 61539433Smckusick * vnode is being eliminated in vgone. The process is awakened 61639433Smckusick * when the transition is completed, and an error returned to 61739433Smckusick * indicate that the vnode is no longer usable (possibly having 61839433Smckusick * been changed to a new file system type). 61939433Smckusick */ 62039397Smckusick vget(vp) 62139397Smckusick register struct vnode *vp; 62239397Smckusick { 62353547Sheideman USES_VOP_LOCK; 62439397Smckusick register struct vnode *vq; 62539397Smckusick 62639433Smckusick if (vp->v_flag & VXLOCK) { 62739433Smckusick vp->v_flag |= VXWANT; 62839433Smckusick sleep((caddr_t)vp, PINOD); 62939433Smckusick return (1); 63039433Smckusick } 63139809Smckusick if (vp->v_usecount == 0) { 63239433Smckusick if (vq = vp->v_freef) 63339433Smckusick vq->v_freeb = vp->v_freeb; 63439433Smckusick else 63539433Smckusick vfreet = vp->v_freeb; 63639433Smckusick *vp->v_freeb = vq; 63739433Smckusick vp->v_freef = NULL; 63839433Smckusick vp->v_freeb = NULL; 63939433Smckusick } 64039397Smckusick VREF(vp); 64139433Smckusick VOP_LOCK(vp); 64239433Smckusick return (0); 64339397Smckusick } 64439397Smckusick 64539397Smckusick /* 64639397Smckusick * Vnode reference, just increment the count 64739397Smckusick */ 64839397Smckusick void vref(vp) 64939397Smckusick struct vnode *vp; 65039397Smckusick { 65139397Smckusick 65239809Smckusick vp->v_usecount++; 65339397Smckusick } 65439397Smckusick 65539397Smckusick /* 65639397Smckusick * vput(), just unlock and vrele() 65739397Smckusick */ 65839397Smckusick void vput(vp) 65939397Smckusick register struct vnode *vp; 66039397Smckusick { 66153547Sheideman USES_VOP_UNLOCK; 66252416Storek 66339397Smckusick VOP_UNLOCK(vp); 66439397Smckusick vrele(vp); 66539397Smckusick } 66639397Smckusick 66739397Smckusick /* 66839397Smckusick * Vnode release. 66939397Smckusick * If count drops to zero, call inactive routine and return to freelist. 67039397Smckusick */ 67139397Smckusick void vrele(vp) 67239397Smckusick register struct vnode *vp; 67339397Smckusick { 67453547Sheideman USES_VOP_INACTIVE; 67548024Smckusick struct proc *p = curproc; /* XXX */ 67639397Smckusick 67750109Smckusick #ifdef DIAGNOSTIC 67839397Smckusick if (vp == NULL) 67939433Smckusick panic("vrele: null vp"); 68050109Smckusick #endif 68139809Smckusick vp->v_usecount--; 68239809Smckusick if (vp->v_usecount > 0) 68339397Smckusick return; 68450109Smckusick #ifdef DIAGNOSTIC 68550109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 68650109Smckusick vprint("vrele: bad ref count", vp); 68750109Smckusick panic("vrele: ref cnt"); 68850109Smckusick } 68950109Smckusick #endif 69041400Smckusick if (vfreeh == NULLVP) { 69139397Smckusick /* 69239397Smckusick * insert into empty list 69339397Smckusick */ 69439397Smckusick vfreeh = vp; 69539397Smckusick vp->v_freeb = &vfreeh; 69639397Smckusick } else { 69739397Smckusick /* 69839397Smckusick * insert at tail of list 69939397Smckusick */ 70039397Smckusick *vfreet = vp; 70139397Smckusick vp->v_freeb = vfreet; 70239397Smckusick } 70339433Smckusick vp->v_freef = NULL; 70439433Smckusick vfreet = &vp->v_freef; 70548024Smckusick VOP_INACTIVE(vp, p); 70639397Smckusick } 70739433Smckusick 70839433Smckusick /* 70939809Smckusick * Page or buffer structure gets a reference. 71039809Smckusick */ 71153312Smckusick void vhold(vp) 71239809Smckusick register struct vnode *vp; 71339809Smckusick { 71439809Smckusick 71539809Smckusick vp->v_holdcnt++; 71639809Smckusick } 71739809Smckusick 71839809Smckusick /* 71939809Smckusick * Page or buffer structure frees a reference. 72039809Smckusick */ 72153312Smckusick void holdrele(vp) 72239809Smckusick register struct vnode *vp; 72339809Smckusick { 72439809Smckusick 72539809Smckusick if (vp->v_holdcnt <= 0) 72639809Smckusick panic("holdrele: holdcnt"); 72739809Smckusick vp->v_holdcnt--; 72839809Smckusick } 72939809Smckusick 73039809Smckusick /* 73139509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 73239509Smckusick * 73339509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 73439509Smckusick * return error if any are found (nb: this is a user error, not a 73539509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 73639509Smckusick * that are found. 73739509Smckusick */ 73839509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 73939509Smckusick 74039509Smckusick vflush(mp, skipvp, flags) 74139509Smckusick struct mount *mp; 74239509Smckusick struct vnode *skipvp; 74339509Smckusick int flags; 74439509Smckusick { 74539509Smckusick register struct vnode *vp, *nvp; 74639509Smckusick int busy = 0; 74739509Smckusick 74841400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 74941300Smckusick panic("vflush: not busy"); 75041421Smckusick loop: 75141400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 75241421Smckusick if (vp->v_mount != mp) 75341421Smckusick goto loop; 75439509Smckusick nvp = vp->v_mountf; 75539509Smckusick /* 75639509Smckusick * Skip over a selected vnode. 75739509Smckusick */ 75839509Smckusick if (vp == skipvp) 75939509Smckusick continue; 76039509Smckusick /* 76141300Smckusick * Skip over a vnodes marked VSYSTEM. 76241300Smckusick */ 76341300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 76441300Smckusick continue; 76541300Smckusick /* 76639809Smckusick * With v_usecount == 0, all we need to do is clear 76739509Smckusick * out the vnode data structures and we are done. 76839509Smckusick */ 76939809Smckusick if (vp->v_usecount == 0) { 77039509Smckusick vgone(vp); 77139509Smckusick continue; 77239509Smckusick } 77339509Smckusick /* 77439509Smckusick * For block or character devices, revert to an 77539509Smckusick * anonymous device. For all other files, just kill them. 77639509Smckusick */ 77741300Smckusick if (flags & FORCECLOSE) { 77839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 77939509Smckusick vgone(vp); 78039509Smckusick } else { 78139509Smckusick vclean(vp, 0); 78253547Sheideman vp->v_op = spec_vnodeop_p; 78339509Smckusick insmntque(vp, (struct mount *)0); 78439509Smckusick } 78539509Smckusick continue; 78639509Smckusick } 78739509Smckusick if (busyprt) 78839667Smckusick vprint("vflush: busy vnode", vp); 78939509Smckusick busy++; 79039509Smckusick } 79139509Smckusick if (busy) 79239509Smckusick return (EBUSY); 79339509Smckusick return (0); 79439509Smckusick } 79539509Smckusick 79639509Smckusick /* 79739433Smckusick * Disassociate the underlying file system from a vnode. 79839433Smckusick */ 79941300Smckusick void vclean(vp, flags) 80039433Smckusick register struct vnode *vp; 80145118Smckusick int flags; 80239433Smckusick { 803*53580Sheideman USES_VOP_LOCK; 804*53580Sheideman USES_VOP_UNLOCK; 805*53580Sheideman USES_VOP_CLOSE; 80653547Sheideman USES_VOP_INACTIVE; 807*53580Sheideman USES_VOP_RECLAIM; 808*53580Sheideman int (**origops)(); 80939484Smckusick int active; 81048024Smckusick struct proc *p = curproc; /* XXX */ 81139433Smckusick 81239484Smckusick /* 81339484Smckusick * Check to see if the vnode is in use. 81439667Smckusick * If so we have to reference it before we clean it out 81539667Smckusick * so that its count cannot fall to zero and generate a 81639667Smckusick * race against ourselves to recycle it. 81739484Smckusick */ 81839809Smckusick if (active = vp->v_usecount) 81939484Smckusick VREF(vp); 82039484Smckusick /* 82139484Smckusick * Prevent the vnode from being recycled or 82239484Smckusick * brought into use while we clean it out. 82339484Smckusick */ 82439667Smckusick if (vp->v_flag & VXLOCK) 82539667Smckusick panic("vclean: deadlock"); 82639433Smckusick vp->v_flag |= VXLOCK; 82739433Smckusick /* 82839667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 82939667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 83039667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 83139667Smckusick * For active vnodes, it ensures that no other activity can 83239667Smckusick * occur while the buffer list is being cleaned out. 83339667Smckusick */ 83439667Smckusick VOP_LOCK(vp); 83541300Smckusick if (flags & DOCLOSE) 83639667Smckusick vinvalbuf(vp, 1); 83739667Smckusick /* 83839433Smckusick * Prevent any further operations on the vnode from 83939433Smckusick * being passed through to the old file system. 84039433Smckusick */ 84139433Smckusick origops = vp->v_op; 84253547Sheideman vp->v_op = dead_vnodeop_p; 84339433Smckusick vp->v_tag = VT_NON; 84439433Smckusick /* 84539484Smckusick * If purging an active vnode, it must be unlocked, closed, 84639484Smckusick * and deactivated before being reclaimed. 84739433Smckusick */ 848*53580Sheideman vop_unlock_a.a_desc = VDESC(vop_unlock); 849*53580Sheideman vop_unlock_a.a_vp = vp; 850*53580Sheideman VOCALL(origops,VOFFSET(vop_unlock),&vop_unlock_a); 85139484Smckusick if (active) { 852*53580Sheideman /* 853*53580Sheideman * Note: these next two calls imply 854*53580Sheideman * that vop_close and vop_inactive implementations 855*53580Sheideman * cannot count on the ops vector being correctly 856*53580Sheideman * set. 857*53580Sheideman */ 858*53580Sheideman if (flags & DOCLOSE) { 859*53580Sheideman vop_close_a.a_desc = VDESC(vop_close); 860*53580Sheideman vop_close_a.a_vp = vp; 861*53580Sheideman vop_close_a.a_fflag = IO_NDELAY; 862*53580Sheideman vop_close_a.a_p = p; 863*53580Sheideman VOCALL(origops,VOFFSET(vop_close),&vop_close_a); 864*53580Sheideman }; 865*53580Sheideman vop_inactive_a.a_desc = VDESC(vop_inactive); 866*53580Sheideman vop_inactive_a.a_vp = vp; 867*53580Sheideman vop_inactive_a.a_p = p; 868*53580Sheideman VOCALL(origops,VOFFSET(vop_inactive),&vop_inactive_a); 86939433Smckusick } 87039433Smckusick /* 87139433Smckusick * Reclaim the vnode. 87239433Smckusick */ 873*53580Sheideman /* 874*53580Sheideman * Emulate VOP_RECLAIM. 875*53580Sheideman */ 876*53580Sheideman vop_reclaim_a.a_desc = VDESC(vop_reclaim); 877*53580Sheideman vop_reclaim_a.a_vp = vp; 878*53580Sheideman if (VOCALL(origops,VOFFSET(vop_reclaim),&vop_reclaim_a)) 87939433Smckusick panic("vclean: cannot reclaim"); 88039484Smckusick if (active) 88139484Smckusick vrele(vp); 882*53580Sheideman 88339433Smckusick /* 88439433Smckusick * Done with purge, notify sleepers in vget of the grim news. 88539433Smckusick */ 88639433Smckusick vp->v_flag &= ~VXLOCK; 88739433Smckusick if (vp->v_flag & VXWANT) { 88839433Smckusick vp->v_flag &= ~VXWANT; 88939433Smckusick wakeup((caddr_t)vp); 89039433Smckusick } 89139433Smckusick } 89239433Smckusick 89339433Smckusick /* 89439633Smckusick * Eliminate all activity associated with the requested vnode 89539633Smckusick * and with all vnodes aliased to the requested vnode. 89639633Smckusick */ 89739633Smckusick void vgoneall(vp) 89839633Smckusick register struct vnode *vp; 89939633Smckusick { 90039809Smckusick register struct vnode *vq; 90139633Smckusick 90240665Smckusick if (vp->v_flag & VALIASED) { 90340665Smckusick /* 90440665Smckusick * If a vgone (or vclean) is already in progress, 90540665Smckusick * wait until it is done and return. 90640665Smckusick */ 90740665Smckusick if (vp->v_flag & VXLOCK) { 90840665Smckusick vp->v_flag |= VXWANT; 90940665Smckusick sleep((caddr_t)vp, PINOD); 91040665Smckusick return; 91139633Smckusick } 91240665Smckusick /* 91340665Smckusick * Ensure that vp will not be vgone'd while we 91440665Smckusick * are eliminating its aliases. 91540665Smckusick */ 91640665Smckusick vp->v_flag |= VXLOCK; 91740665Smckusick while (vp->v_flag & VALIASED) { 91840665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 91940665Smckusick if (vq->v_rdev != vp->v_rdev || 92040665Smckusick vq->v_type != vp->v_type || vp == vq) 92140665Smckusick continue; 92240665Smckusick vgone(vq); 92340665Smckusick break; 92440665Smckusick } 92540665Smckusick } 92640665Smckusick /* 92740665Smckusick * Remove the lock so that vgone below will 92840665Smckusick * really eliminate the vnode after which time 92940665Smckusick * vgone will awaken any sleepers. 93040665Smckusick */ 93140665Smckusick vp->v_flag &= ~VXLOCK; 93239633Smckusick } 93339633Smckusick vgone(vp); 93439633Smckusick } 93539633Smckusick 93639633Smckusick /* 93739433Smckusick * Eliminate all activity associated with a vnode 93839433Smckusick * in preparation for reuse. 93939433Smckusick */ 94039433Smckusick void vgone(vp) 94139433Smckusick register struct vnode *vp; 94239433Smckusick { 94339809Smckusick register struct vnode *vq; 94439615Smckusick struct vnode *vx; 94539433Smckusick 94639433Smckusick /* 94740548Smckusick * If a vgone (or vclean) is already in progress, 94840548Smckusick * wait until it is done and return. 94940548Smckusick */ 95040548Smckusick if (vp->v_flag & VXLOCK) { 95140548Smckusick vp->v_flag |= VXWANT; 95240548Smckusick sleep((caddr_t)vp, PINOD); 95340548Smckusick return; 95440548Smckusick } 95540548Smckusick /* 95639433Smckusick * Clean out the filesystem specific data. 95739433Smckusick */ 95841300Smckusick vclean(vp, DOCLOSE); 95939433Smckusick /* 96039433Smckusick * Delete from old mount point vnode list, if on one. 96139433Smckusick */ 96239433Smckusick if (vp->v_mountb) { 96339433Smckusick if (vq = vp->v_mountf) 96439433Smckusick vq->v_mountb = vp->v_mountb; 96539433Smckusick *vp->v_mountb = vq; 96639433Smckusick vp->v_mountf = NULL; 96739433Smckusick vp->v_mountb = NULL; 96852311Smckusick vp->v_mount = NULL; 96939433Smckusick } 97039433Smckusick /* 97139433Smckusick * If special device, remove it from special device alias list. 97239433Smckusick */ 97339433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 97439809Smckusick if (*vp->v_hashchain == vp) { 97539809Smckusick *vp->v_hashchain = vp->v_specnext; 97639433Smckusick } else { 97739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 97839615Smckusick if (vq->v_specnext != vp) 97939433Smckusick continue; 98039615Smckusick vq->v_specnext = vp->v_specnext; 98139433Smckusick break; 98239433Smckusick } 98339615Smckusick if (vq == NULL) 98439433Smckusick panic("missing bdev"); 98539433Smckusick } 98639615Smckusick if (vp->v_flag & VALIASED) { 98752416Storek vx = NULL; 98839809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 98940108Smckusick if (vq->v_rdev != vp->v_rdev || 99040108Smckusick vq->v_type != vp->v_type) 99139615Smckusick continue; 99252416Storek if (vx) 99352416Storek break; 99439615Smckusick vx = vq; 99539615Smckusick } 99652416Storek if (vx == NULL) 99739615Smckusick panic("missing alias"); 99852416Storek if (vq == NULL) 99939615Smckusick vx->v_flag &= ~VALIASED; 100039615Smckusick vp->v_flag &= ~VALIASED; 100139615Smckusick } 100239615Smckusick FREE(vp->v_specinfo, M_VNODE); 100339615Smckusick vp->v_specinfo = NULL; 100439433Smckusick } 100539433Smckusick /* 100639433Smckusick * If it is on the freelist, move it to the head of the list. 100739433Smckusick */ 100839433Smckusick if (vp->v_freeb) { 100939433Smckusick if (vq = vp->v_freef) 101039433Smckusick vq->v_freeb = vp->v_freeb; 101139433Smckusick else 101239433Smckusick vfreet = vp->v_freeb; 101339433Smckusick *vp->v_freeb = vq; 101439433Smckusick vp->v_freef = vfreeh; 101539433Smckusick vp->v_freeb = &vfreeh; 101639433Smckusick vfreeh->v_freeb = &vp->v_freef; 101739433Smckusick vfreeh = vp; 101839433Smckusick } 101939484Smckusick vp->v_type = VBAD; 102039433Smckusick } 102139633Smckusick 102239633Smckusick /* 102339821Smckusick * Lookup a vnode by device number. 102439821Smckusick */ 102539821Smckusick vfinddev(dev, type, vpp) 102639821Smckusick dev_t dev; 102739821Smckusick enum vtype type; 102839821Smckusick struct vnode **vpp; 102939821Smckusick { 103039821Smckusick register struct vnode *vp; 103139821Smckusick 103239821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 103339821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 103439821Smckusick continue; 103539821Smckusick *vpp = vp; 103639821Smckusick return (0); 103739821Smckusick } 103839821Smckusick return (1); 103939821Smckusick } 104039821Smckusick 104139821Smckusick /* 104239633Smckusick * Calculate the total number of references to a special device. 104339633Smckusick */ 104439633Smckusick vcount(vp) 104539633Smckusick register struct vnode *vp; 104639633Smckusick { 104739809Smckusick register struct vnode *vq; 104839633Smckusick int count; 104939633Smckusick 105039633Smckusick if ((vp->v_flag & VALIASED) == 0) 105139809Smckusick return (vp->v_usecount); 105239633Smckusick loop: 105339809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 105440108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 105539633Smckusick continue; 105639633Smckusick /* 105739633Smckusick * Alias, but not in use, so flush it out. 105839633Smckusick */ 105939809Smckusick if (vq->v_usecount == 0) { 106039633Smckusick vgone(vq); 106139633Smckusick goto loop; 106239633Smckusick } 106339809Smckusick count += vq->v_usecount; 106439633Smckusick } 106539633Smckusick return (count); 106639633Smckusick } 106739667Smckusick 106839667Smckusick /* 106939667Smckusick * Print out a description of a vnode. 107039667Smckusick */ 107139667Smckusick static char *typename[] = 107240286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 107339667Smckusick 107439667Smckusick vprint(label, vp) 107539667Smckusick char *label; 107639667Smckusick register struct vnode *vp; 107739667Smckusick { 107853547Sheideman USES_VOP_PRINT; 107939913Smckusick char buf[64]; 108039667Smckusick 108139667Smckusick if (label != NULL) 108239667Smckusick printf("%s: ", label); 108350109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 108450109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 108550109Smckusick vp->v_holdcnt); 108639913Smckusick buf[0] = '\0'; 108739913Smckusick if (vp->v_flag & VROOT) 108839913Smckusick strcat(buf, "|VROOT"); 108939913Smckusick if (vp->v_flag & VTEXT) 109039913Smckusick strcat(buf, "|VTEXT"); 109141300Smckusick if (vp->v_flag & VSYSTEM) 109241300Smckusick strcat(buf, "|VSYSTEM"); 109341300Smckusick if (vp->v_flag & VXLOCK) 109441300Smckusick strcat(buf, "|VXLOCK"); 109541300Smckusick if (vp->v_flag & VXWANT) 109641300Smckusick strcat(buf, "|VXWANT"); 109741300Smckusick if (vp->v_flag & VBWAIT) 109841300Smckusick strcat(buf, "|VBWAIT"); 109939913Smckusick if (vp->v_flag & VALIASED) 110039913Smckusick strcat(buf, "|VALIASED"); 110139913Smckusick if (buf[0] != '\0') 110239913Smckusick printf(" flags (%s)", &buf[1]); 110339913Smckusick printf("\n\t"); 110439667Smckusick VOP_PRINT(vp); 110539667Smckusick } 110641110Smarc 110749691Smckusick #ifdef DEBUG 110849691Smckusick /* 110949691Smckusick * List all of the locked vnodes in the system. 111049691Smckusick * Called when debugging the kernel. 111149691Smckusick */ 111249691Smckusick printlockedvnodes() 111349691Smckusick { 111453547Sheideman USES_VOP_ISLOCKED; 111549691Smckusick register struct mount *mp; 111649691Smckusick register struct vnode *vp; 111749691Smckusick 111849691Smckusick printf("Locked vnodes\n"); 111949691Smckusick mp = rootfs; 112049691Smckusick do { 112149691Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) 112249691Smckusick if (VOP_ISLOCKED(vp)) 112349691Smckusick vprint((char *)0, vp); 112449691Smckusick mp = mp->mnt_next; 112549691Smckusick } while (mp != rootfs); 112649691Smckusick } 112749691Smckusick #endif 112849691Smckusick 112941110Smarc int kinfo_vdebug = 1; 113041110Smarc int kinfo_vgetfailed; 113141110Smarc #define KINFO_VNODESLOP 10 113241110Smarc /* 113341110Smarc * Dump vnode list (via kinfo). 113441110Smarc * Copyout address of vnode followed by vnode. 113541110Smarc */ 113645118Smckusick /* ARGSUSED */ 113741110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 113845118Smckusick int op; 113941110Smarc char *where; 114045118Smckusick int *acopysize, arg, *aneeded; 114141110Smarc { 114241110Smarc register struct mount *mp = rootfs; 114341300Smckusick struct mount *omp; 114441110Smarc struct vnode *vp; 114541110Smarc register char *bp = where, *savebp; 114641110Smarc char *ewhere = where + *acopysize; 114741110Smarc int error; 114841110Smarc 114941110Smarc #define VPTRSZ sizeof (struct vnode *) 115041110Smarc #define VNODESZ sizeof (struct vnode) 115141110Smarc if (where == NULL) { 115241110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 115341110Smarc return (0); 115441110Smarc } 115541110Smarc 115641110Smarc do { 115741300Smckusick if (vfs_busy(mp)) { 115841400Smckusick mp = mp->mnt_next; 115941300Smckusick continue; 116041300Smckusick } 116141110Smarc savebp = bp; 116241110Smarc again: 116341421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 116441422Smckusick /* 116541422Smckusick * Check that the vp is still associated with 116641422Smckusick * this filesystem. RACE: could have been 116741422Smckusick * recycled onto the same filesystem. 116841422Smckusick */ 116941421Smckusick if (vp->v_mount != mp) { 117041421Smckusick if (kinfo_vdebug) 117141421Smckusick printf("kinfo: vp changed\n"); 117241421Smckusick bp = savebp; 117341421Smckusick goto again; 117441421Smckusick } 117541110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 117641110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 117741110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 117841422Smckusick VNODESZ)))) 117941110Smarc return (error); 118041110Smarc bp += VPTRSZ + VNODESZ; 118141110Smarc } 118241300Smckusick omp = mp; 118341400Smckusick mp = mp->mnt_next; 118441300Smckusick vfs_unbusy(omp); 118541110Smarc } while (mp != rootfs); 118641110Smarc 118741110Smarc *aneeded = bp - where; 118841110Smarc if (bp > ewhere) 118941110Smarc *acopysize = ewhere - where; 119041110Smarc else 119141110Smarc *acopysize = bp - where; 119241110Smarc return (0); 119341110Smarc } 1194