137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*49460Smckusick * @(#)vfs_subr.c 7.55 (Berkeley) 05/08/91 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1548024Smckusick #include "proc.h" 1637488Smckusick #include "mount.h" 1737488Smckusick #include "time.h" 1837488Smckusick #include "vnode.h" 1940652Smckusick #include "specdev.h" 2038265Smckusick #include "namei.h" 2138265Smckusick #include "ucred.h" 2249232Smckusick #include "buf.h" 2337488Smckusick #include "errno.h" 2439433Smckusick #include "malloc.h" 2537488Smckusick 2637488Smckusick /* 2737488Smckusick * Remove a mount point from the list of mounted filesystems. 2837488Smckusick * Unmount of the root is illegal. 2937488Smckusick */ 3037488Smckusick void 3137488Smckusick vfs_remove(mp) 3237488Smckusick register struct mount *mp; 3337488Smckusick { 3437488Smckusick 3537488Smckusick if (mp == rootfs) 3637488Smckusick panic("vfs_remove: unmounting root"); 3741400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3841400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3941400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 4037488Smckusick vfs_unlock(mp); 4137488Smckusick } 4237488Smckusick 4337488Smckusick /* 4437488Smckusick * Lock a filesystem. 4537488Smckusick * Used to prevent access to it while mounting and unmounting. 4637488Smckusick */ 4737488Smckusick vfs_lock(mp) 4837488Smckusick register struct mount *mp; 4937488Smckusick { 5037488Smckusick 5141400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5241400Smckusick mp->mnt_flag |= MNT_MWAIT; 5339045Smckusick sleep((caddr_t)mp, PVFS); 5439045Smckusick } 5541400Smckusick mp->mnt_flag |= MNT_MLOCK; 5637488Smckusick return (0); 5737488Smckusick } 5837488Smckusick 5937488Smckusick /* 6037488Smckusick * Unlock a locked filesystem. 6137488Smckusick * Panic if filesystem is not locked. 6237488Smckusick */ 6337488Smckusick void 6437488Smckusick vfs_unlock(mp) 6537488Smckusick register struct mount *mp; 6637488Smckusick { 6737488Smckusick 6841400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6941300Smckusick panic("vfs_unlock: not locked"); 7041400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7141400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7241400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7337488Smckusick wakeup((caddr_t)mp); 7437488Smckusick } 7537488Smckusick } 7637488Smckusick 7737488Smckusick /* 7841300Smckusick * Mark a mount point as busy. 7941300Smckusick * Used to synchronize access and to delay unmounting. 8041300Smckusick */ 8141300Smckusick vfs_busy(mp) 8241300Smckusick register struct mount *mp; 8341300Smckusick { 8441300Smckusick 8541400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8641400Smckusick mp->mnt_flag |= MNT_MPWANT; 8741400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8841300Smckusick } 8941419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 9041419Smckusick return (1); 9141400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9241300Smckusick return (0); 9341300Smckusick } 9441300Smckusick 9541300Smckusick /* 9641300Smckusick * Free a busy filesystem. 9741300Smckusick * Panic if filesystem is not busy. 9841300Smckusick */ 9941300Smckusick vfs_unbusy(mp) 10041300Smckusick register struct mount *mp; 10141300Smckusick { 10241300Smckusick 10341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10441300Smckusick panic("vfs_unbusy: not busy"); 10541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10941300Smckusick } 11041300Smckusick } 11141300Smckusick 11241300Smckusick /* 11337488Smckusick * Lookup a mount point by filesystem identifier. 11437488Smckusick */ 11537488Smckusick struct mount * 11637488Smckusick getvfs(fsid) 11737488Smckusick fsid_t *fsid; 11837488Smckusick { 11937488Smckusick register struct mount *mp; 12037488Smckusick 12138288Smckusick mp = rootfs; 12238288Smckusick do { 12341400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12441400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12538288Smckusick return (mp); 12637488Smckusick } 12741400Smckusick mp = mp->mnt_next; 12838288Smckusick } while (mp != rootfs); 12938288Smckusick return ((struct mount *)0); 13037488Smckusick } 13137488Smckusick 13237488Smckusick /* 13337488Smckusick * Set vnode attributes to VNOVAL 13437488Smckusick */ 13537488Smckusick void vattr_null(vap) 13637488Smckusick register struct vattr *vap; 13737488Smckusick { 13837488Smckusick 13937488Smckusick vap->va_type = VNON; 14037488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14137488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14240643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14340643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14437488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14537488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14638258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14738258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14837488Smckusick } 14938265Smckusick 15038265Smckusick /* 15138265Smckusick * Initialize a nameidata structure 15238265Smckusick */ 15338265Smckusick ndinit(ndp) 15438265Smckusick register struct nameidata *ndp; 15538265Smckusick { 15638265Smckusick 15738265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 15838265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 15938265Smckusick ndp->ni_iovcnt = 1; 16038265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 16138265Smckusick ndp->ni_rw = UIO_WRITE; 16239736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 16338265Smckusick } 16438265Smckusick 16538265Smckusick /* 16638265Smckusick * Duplicate a nameidata structure 16738265Smckusick */ 16838265Smckusick nddup(ndp, newndp) 16938265Smckusick register struct nameidata *ndp, *newndp; 17038265Smckusick { 17138265Smckusick 17238265Smckusick ndinit(newndp); 17338265Smckusick newndp->ni_cred = ndp->ni_cred; 17438265Smckusick crhold(newndp->ni_cred); 17538265Smckusick } 17638265Smckusick 17738265Smckusick /* 17838265Smckusick * Release a nameidata structure 17938265Smckusick */ 18038265Smckusick ndrele(ndp) 18138265Smckusick register struct nameidata *ndp; 18238265Smckusick { 18338265Smckusick 18438265Smckusick crfree(ndp->ni_cred); 18538265Smckusick } 18639397Smckusick 18739397Smckusick /* 18839397Smckusick * Routines having to do with the management of the vnode table. 18939397Smckusick */ 19039397Smckusick struct vnode *vfreeh, **vfreet; 19139447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 19239635Smckusick extern void vclean(); 19340883Smckusick long numvnodes; 19441363Smckusick struct vattr va_null; 19539397Smckusick 19639397Smckusick /* 19739433Smckusick * Initialize the vnode structures and initialize each file system type. 19839397Smckusick */ 19939433Smckusick vfsinit() 20039397Smckusick { 20139433Smckusick struct vfsops **vfsp; 20239397Smckusick 20339433Smckusick /* 20439433Smckusick * Initialize the vnode name cache 20539433Smckusick */ 20639433Smckusick nchinit(); 20739433Smckusick /* 20839433Smckusick * Initialize each file system type. 20939433Smckusick */ 21041363Smckusick vattr_null(&va_null); 21139433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 21239433Smckusick if (*vfsp == NULL) 21339433Smckusick continue; 21439433Smckusick (*(*vfsp)->vfs_init)(); 21539433Smckusick } 21639397Smckusick } 21739397Smckusick 21839397Smckusick /* 21939397Smckusick * Return the next vnode from the free list. 22039397Smckusick */ 22139397Smckusick getnewvnode(tag, mp, vops, vpp) 22239397Smckusick enum vtagtype tag; 22339397Smckusick struct mount *mp; 22439397Smckusick struct vnodeops *vops; 22539397Smckusick struct vnode **vpp; 22639397Smckusick { 22739397Smckusick register struct vnode *vp, *vq; 22839397Smckusick 22940883Smckusick if (numvnodes < desiredvnodes) { 23045118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 23145118Smckusick M_VNODE, M_WAITOK); 23240883Smckusick bzero((char *)vp, sizeof *vp); 23340883Smckusick numvnodes++; 23440883Smckusick } else { 23540883Smckusick if ((vp = vfreeh) == NULL) { 23640883Smckusick tablefull("vnode"); 23740883Smckusick *vpp = 0; 23840883Smckusick return (ENFILE); 23940883Smckusick } 24040883Smckusick if (vp->v_usecount) 24140883Smckusick panic("free vnode isn't"); 24240883Smckusick if (vq = vp->v_freef) 24340883Smckusick vq->v_freeb = &vfreeh; 24440883Smckusick else 24540883Smckusick vfreet = &vfreeh; 24640883Smckusick vfreeh = vq; 24740883Smckusick vp->v_freef = NULL; 24840883Smckusick vp->v_freeb = NULL; 24940883Smckusick if (vp->v_type != VBAD) 25040883Smckusick vgone(vp); 25140883Smckusick vp->v_flag = 0; 25240883Smckusick vp->v_lastr = 0; 25340883Smckusick vp->v_socket = 0; 25439397Smckusick } 25539512Smckusick vp->v_type = VNON; 25639397Smckusick cache_purge(vp); 25739397Smckusick vp->v_tag = tag; 25839433Smckusick vp->v_op = vops; 25939397Smckusick insmntque(vp, mp); 26039397Smckusick VREF(vp); 26139397Smckusick *vpp = vp; 26239397Smckusick return (0); 26339397Smckusick } 26439397Smckusick 26539397Smckusick /* 26639397Smckusick * Move a vnode from one mount queue to another. 26739397Smckusick */ 26839397Smckusick insmntque(vp, mp) 26939397Smckusick register struct vnode *vp; 27039397Smckusick register struct mount *mp; 27139397Smckusick { 27239397Smckusick struct vnode *vq; 27339397Smckusick 27439397Smckusick /* 27539397Smckusick * Delete from old mount point vnode list, if on one. 27639397Smckusick */ 27739397Smckusick if (vp->v_mountb) { 27839397Smckusick if (vq = vp->v_mountf) 27939397Smckusick vq->v_mountb = vp->v_mountb; 28039397Smckusick *vp->v_mountb = vq; 28139397Smckusick } 28239397Smckusick /* 28339397Smckusick * Insert into list of vnodes for the new mount point, if available. 28439397Smckusick */ 28539621Smckusick vp->v_mount = mp; 28639397Smckusick if (mp == NULL) { 28739397Smckusick vp->v_mountf = NULL; 28839397Smckusick vp->v_mountb = NULL; 28939397Smckusick return; 29039397Smckusick } 29141400Smckusick if (mp->mnt_mounth) { 29241400Smckusick vp->v_mountf = mp->mnt_mounth; 29341400Smckusick vp->v_mountb = &mp->mnt_mounth; 29441400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 29541400Smckusick mp->mnt_mounth = vp; 29639397Smckusick } else { 29741400Smckusick mp->mnt_mounth = vp; 29841400Smckusick vp->v_mountb = &mp->mnt_mounth; 29939397Smckusick vp->v_mountf = NULL; 30039397Smckusick } 30139397Smckusick } 30239397Smckusick 30339397Smckusick /* 30449232Smckusick * Make sure all write-behind blocks associated 30549232Smckusick * with mount point are flushed out (from sync). 30649232Smckusick */ 30749232Smckusick mntflushbuf(mountp, flags) 30849232Smckusick struct mount *mountp; 30949232Smckusick int flags; 31049232Smckusick { 31149232Smckusick register struct vnode *vp; 31249232Smckusick 31349232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 31449232Smckusick panic("mntflushbuf: not busy"); 31549232Smckusick loop: 31649232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 31749232Smckusick if (VOP_ISLOCKED(vp)) 31849232Smckusick continue; 31949232Smckusick if (vget(vp)) 32049232Smckusick goto loop; 32149232Smckusick vflushbuf(vp, flags); 32249232Smckusick vput(vp); 32349232Smckusick if (vp->v_mount != mountp) 32449232Smckusick goto loop; 32549232Smckusick } 32649232Smckusick } 32749232Smckusick 32849232Smckusick /* 32949232Smckusick * Flush all dirty buffers associated with a vnode. 33049232Smckusick */ 33149232Smckusick vflushbuf(vp, flags) 33249232Smckusick register struct vnode *vp; 33349232Smckusick int flags; 33449232Smckusick { 33549232Smckusick register struct buf *bp; 33649232Smckusick struct buf *nbp; 33749232Smckusick int s; 33849232Smckusick 33949232Smckusick loop: 34049232Smckusick s = splbio(); 34149232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 34249232Smckusick nbp = bp->b_blockf; 34349232Smckusick if ((bp->b_flags & B_BUSY)) 34449232Smckusick continue; 34549232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 34649232Smckusick panic("vflushbuf: not dirty"); 34749232Smckusick bremfree(bp); 34849232Smckusick bp->b_flags |= B_BUSY; 34949232Smckusick splx(s); 35049232Smckusick /* 35149232Smckusick * Wait for I/O associated with indirect blocks to complete, 35249232Smckusick * since there is no way to quickly wait for them below. 35349232Smckusick * NB: This is really specific to ufs, but is done here 35449232Smckusick * as it is easier and quicker. 35549232Smckusick */ 356*49460Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) 35749232Smckusick (void) bawrite(bp); 358*49460Smckusick else 35949232Smckusick (void) bwrite(bp); 360*49460Smckusick goto loop; 36149232Smckusick } 36249232Smckusick splx(s); 36349232Smckusick if ((flags & B_SYNC) == 0) 36449232Smckusick return; 36549232Smckusick s = splbio(); 36649232Smckusick while (vp->v_numoutput) { 36749232Smckusick vp->v_flag |= VBWAIT; 36849232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 36949232Smckusick } 37049232Smckusick splx(s); 37149232Smckusick if (vp->v_dirtyblkhd) { 37249232Smckusick vprint("vflushbuf: dirty", vp); 37349232Smckusick goto loop; 37449232Smckusick } 37549232Smckusick } 37649232Smckusick 37749232Smckusick /* 37849232Smckusick * Update outstanding I/O count and do wakeup if requested. 37949232Smckusick */ 38049232Smckusick vwakeup(bp) 38149232Smckusick register struct buf *bp; 38249232Smckusick { 38349232Smckusick register struct vnode *vp; 38449232Smckusick 38549232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 38649232Smckusick if (vp = bp->b_vp) { 38749232Smckusick vp->v_numoutput--; 38849232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 38949232Smckusick if (vp->v_numoutput < 0) 39049232Smckusick panic("vwakeup: neg numoutput"); 39149232Smckusick vp->v_flag &= ~VBWAIT; 39249232Smckusick wakeup((caddr_t)&vp->v_numoutput); 39349232Smckusick } 39449232Smckusick } 39549232Smckusick } 39649232Smckusick 39749232Smckusick /* 39849232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 39949232Smckusick * 40049232Smckusick * Go through the list of vnodes associated with the file system; 40149232Smckusick * for each vnode invalidate any buffers that it holds. Normally 40249232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 40349232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 40449232Smckusick * returns the count of dirty buffers when it is finished. 40549232Smckusick */ 40649232Smckusick mntinvalbuf(mountp) 40749232Smckusick struct mount *mountp; 40849232Smckusick { 40949232Smckusick register struct vnode *vp; 41049232Smckusick int dirty = 0; 41149232Smckusick 41249232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 41349232Smckusick panic("mntinvalbuf: not busy"); 41449232Smckusick loop: 41549232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 41649232Smckusick if (vget(vp)) 41749232Smckusick goto loop; 41849232Smckusick dirty += vinvalbuf(vp, 1); 41949232Smckusick vput(vp); 42049232Smckusick if (vp->v_mount != mountp) 42149232Smckusick goto loop; 42249232Smckusick } 42349232Smckusick return (dirty); 42449232Smckusick } 42549232Smckusick 42649232Smckusick /* 42749232Smckusick * Flush out and invalidate all buffers associated with a vnode. 42849232Smckusick * Called with the underlying object locked. 42949232Smckusick */ 43049232Smckusick vinvalbuf(vp, save) 43149232Smckusick register struct vnode *vp; 43249232Smckusick int save; 43349232Smckusick { 43449232Smckusick register struct buf *bp; 43549232Smckusick struct buf *nbp, *blist; 43649232Smckusick int s, dirty = 0; 43749232Smckusick 43849232Smckusick for (;;) { 43949232Smckusick if (blist = vp->v_dirtyblkhd) 44049232Smckusick /* void */; 44149232Smckusick else if (blist = vp->v_cleanblkhd) 44249232Smckusick /* void */; 44349232Smckusick else 44449232Smckusick break; 44549232Smckusick for (bp = blist; bp; bp = nbp) { 44649232Smckusick nbp = bp->b_blockf; 44749232Smckusick s = splbio(); 44849232Smckusick if (bp->b_flags & B_BUSY) { 44949232Smckusick bp->b_flags |= B_WANTED; 45049232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 45149232Smckusick splx(s); 45249232Smckusick break; 45349232Smckusick } 45449232Smckusick bremfree(bp); 45549232Smckusick bp->b_flags |= B_BUSY; 45649232Smckusick splx(s); 45749232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 45849232Smckusick dirty++; 45949232Smckusick (void) bwrite(bp); 46049232Smckusick break; 46149232Smckusick } 46249232Smckusick if (bp->b_vp != vp) 46349232Smckusick reassignbuf(bp, bp->b_vp); 46449232Smckusick else 46549232Smckusick bp->b_flags |= B_INVAL; 46649232Smckusick brelse(bp); 46749232Smckusick } 46849232Smckusick } 46949232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 47049232Smckusick panic("vinvalbuf: flush failed"); 47149232Smckusick return (dirty); 47249232Smckusick } 47349232Smckusick 47449232Smckusick /* 47549232Smckusick * Associate a buffer with a vnode. 47649232Smckusick */ 47749232Smckusick bgetvp(vp, bp) 47849232Smckusick register struct vnode *vp; 47949232Smckusick register struct buf *bp; 48049232Smckusick { 48149232Smckusick 48249232Smckusick if (bp->b_vp) 48349232Smckusick panic("bgetvp: not free"); 48449232Smckusick VHOLD(vp); 48549232Smckusick bp->b_vp = vp; 48649232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 48749232Smckusick bp->b_dev = vp->v_rdev; 48849232Smckusick else 48949232Smckusick bp->b_dev = NODEV; 49049232Smckusick /* 49149232Smckusick * Insert onto list for new vnode. 49249232Smckusick */ 49349232Smckusick if (vp->v_cleanblkhd) { 49449232Smckusick bp->b_blockf = vp->v_cleanblkhd; 49549232Smckusick bp->b_blockb = &vp->v_cleanblkhd; 49649232Smckusick vp->v_cleanblkhd->b_blockb = &bp->b_blockf; 49749232Smckusick vp->v_cleanblkhd = bp; 49849232Smckusick } else { 49949232Smckusick vp->v_cleanblkhd = bp; 50049232Smckusick bp->b_blockb = &vp->v_cleanblkhd; 50149232Smckusick bp->b_blockf = NULL; 50249232Smckusick } 50349232Smckusick } 50449232Smckusick 50549232Smckusick /* 50649232Smckusick * Disassociate a buffer from a vnode. 50749232Smckusick */ 50849232Smckusick brelvp(bp) 50949232Smckusick register struct buf *bp; 51049232Smckusick { 51149232Smckusick struct buf *bq; 51249232Smckusick struct vnode *vp; 51349232Smckusick 51449232Smckusick if (bp->b_vp == (struct vnode *) 0) 51549232Smckusick panic("brelvp: NULL"); 51649232Smckusick /* 51749232Smckusick * Delete from old vnode list, if on one. 51849232Smckusick */ 51949232Smckusick if (bp->b_blockb) { 52049232Smckusick if (bq = bp->b_blockf) 52149232Smckusick bq->b_blockb = bp->b_blockb; 52249232Smckusick *bp->b_blockb = bq; 52349232Smckusick bp->b_blockf = NULL; 52449232Smckusick bp->b_blockb = NULL; 52549232Smckusick } 52649232Smckusick vp = bp->b_vp; 52749232Smckusick bp->b_vp = (struct vnode *) 0; 52849232Smckusick HOLDRELE(vp); 52949232Smckusick } 53049232Smckusick 53149232Smckusick /* 53249232Smckusick * Reassign a buffer from one vnode to another. 53349232Smckusick * Used to assign file specific control information 53449232Smckusick * (indirect blocks) to the vnode to which they belong. 53549232Smckusick */ 53649232Smckusick reassignbuf(bp, newvp) 53749232Smckusick register struct buf *bp; 53849232Smckusick register struct vnode *newvp; 53949232Smckusick { 54049232Smckusick register struct buf *bq, **listheadp; 54149232Smckusick 54249232Smckusick if (newvp == NULL) 54349232Smckusick panic("reassignbuf: NULL"); 54449232Smckusick /* 54549232Smckusick * Delete from old vnode list, if on one. 54649232Smckusick */ 54749232Smckusick if (bp->b_blockb) { 54849232Smckusick if (bq = bp->b_blockf) 54949232Smckusick bq->b_blockb = bp->b_blockb; 55049232Smckusick *bp->b_blockb = bq; 55149232Smckusick } 55249232Smckusick /* 55349232Smckusick * If dirty, put on list of dirty buffers; 55449232Smckusick * otherwise insert onto list of clean buffers. 55549232Smckusick */ 55649232Smckusick if (bp->b_flags & B_DELWRI) 55749232Smckusick listheadp = &newvp->v_dirtyblkhd; 55849232Smckusick else 55949232Smckusick listheadp = &newvp->v_cleanblkhd; 56049232Smckusick if (*listheadp) { 56149232Smckusick bp->b_blockf = *listheadp; 56249232Smckusick bp->b_blockb = listheadp; 56349232Smckusick bp->b_blockf->b_blockb = &bp->b_blockf; 56449232Smckusick *listheadp = bp; 56549232Smckusick } else { 56649232Smckusick *listheadp = bp; 56749232Smckusick bp->b_blockb = listheadp; 56849232Smckusick bp->b_blockf = NULL; 56949232Smckusick } 57049232Smckusick } 57149232Smckusick 57249232Smckusick /* 57339433Smckusick * Create a vnode for a block device. 57439433Smckusick * Used for root filesystem, argdev, and swap areas. 57539433Smckusick * Also used for memory file system special devices. 57639397Smckusick */ 57739433Smckusick bdevvp(dev, vpp) 57839433Smckusick dev_t dev; 57939433Smckusick struct vnode **vpp; 58039433Smckusick { 58139433Smckusick register struct vnode *vp; 58239433Smckusick struct vnode *nvp; 58339433Smckusick int error; 58439433Smckusick 58546989Smckusick if (dev == NODEV) 58646989Smckusick return (0); 58739447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 58839433Smckusick if (error) { 58939433Smckusick *vpp = 0; 59039433Smckusick return (error); 59139433Smckusick } 59239433Smckusick vp = nvp; 59339433Smckusick vp->v_type = VBLK; 59439615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 59539433Smckusick vput(vp); 59639433Smckusick vp = nvp; 59739433Smckusick } 59839433Smckusick *vpp = vp; 59939433Smckusick return (0); 60039433Smckusick } 60139433Smckusick 60239433Smckusick /* 60339433Smckusick * Check to see if the new vnode represents a special device 60439433Smckusick * for which we already have a vnode (either because of 60539433Smckusick * bdevvp() or because of a different vnode representing 60639433Smckusick * the same block device). If such an alias exists, deallocate 60739509Smckusick * the existing contents and return the aliased vnode. The 60839433Smckusick * caller is responsible for filling it with its new contents. 60939433Smckusick */ 61039433Smckusick struct vnode * 61139615Smckusick checkalias(nvp, nvp_rdev, mp) 61239433Smckusick register struct vnode *nvp; 61339615Smckusick dev_t nvp_rdev; 61439433Smckusick struct mount *mp; 61539433Smckusick { 61639433Smckusick register struct vnode *vp; 61739615Smckusick struct vnode **vpp; 61839433Smckusick 61939433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 62041400Smckusick return (NULLVP); 62139615Smckusick 62239615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 62339433Smckusick loop: 62439615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 62539615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 62639433Smckusick continue; 62739615Smckusick /* 62839615Smckusick * Alias, but not in use, so flush it out. 62939615Smckusick */ 63039809Smckusick if (vp->v_usecount == 0) { 63139615Smckusick vgone(vp); 63239615Smckusick goto loop; 63339615Smckusick } 63439633Smckusick if (vget(vp)) 63539633Smckusick goto loop; 63639433Smckusick break; 63739433Smckusick } 63839615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 63939615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 64039615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 64139615Smckusick nvp->v_rdev = nvp_rdev; 64239809Smckusick nvp->v_hashchain = vpp; 64339615Smckusick nvp->v_specnext = *vpp; 64442152Smckusick nvp->v_specflags = 0; 64539615Smckusick *vpp = nvp; 64640640Smckusick if (vp != NULL) { 64740640Smckusick nvp->v_flag |= VALIASED; 64840640Smckusick vp->v_flag |= VALIASED; 64940640Smckusick vput(vp); 65040640Smckusick } 65141400Smckusick return (NULLVP); 65239433Smckusick } 65339484Smckusick VOP_UNLOCK(vp); 65439484Smckusick vclean(vp, 0); 65539433Smckusick vp->v_op = nvp->v_op; 65639433Smckusick vp->v_tag = nvp->v_tag; 65739433Smckusick nvp->v_type = VNON; 65839433Smckusick insmntque(vp, mp); 65939433Smckusick return (vp); 66039433Smckusick } 66139433Smckusick 66239433Smckusick /* 66339433Smckusick * Grab a particular vnode from the free list, increment its 66439433Smckusick * reference count and lock it. The vnode lock bit is set the 66539433Smckusick * vnode is being eliminated in vgone. The process is awakened 66639433Smckusick * when the transition is completed, and an error returned to 66739433Smckusick * indicate that the vnode is no longer usable (possibly having 66839433Smckusick * been changed to a new file system type). 66939433Smckusick */ 67039397Smckusick vget(vp) 67139397Smckusick register struct vnode *vp; 67239397Smckusick { 67339397Smckusick register struct vnode *vq; 67439397Smckusick 67539433Smckusick if (vp->v_flag & VXLOCK) { 67639433Smckusick vp->v_flag |= VXWANT; 67739433Smckusick sleep((caddr_t)vp, PINOD); 67839433Smckusick return (1); 67939433Smckusick } 68039809Smckusick if (vp->v_usecount == 0) { 68139433Smckusick if (vq = vp->v_freef) 68239433Smckusick vq->v_freeb = vp->v_freeb; 68339433Smckusick else 68439433Smckusick vfreet = vp->v_freeb; 68539433Smckusick *vp->v_freeb = vq; 68639433Smckusick vp->v_freef = NULL; 68739433Smckusick vp->v_freeb = NULL; 68839433Smckusick } 68939397Smckusick VREF(vp); 69039433Smckusick VOP_LOCK(vp); 69139433Smckusick return (0); 69239397Smckusick } 69339397Smckusick 69439397Smckusick /* 69539397Smckusick * Vnode reference, just increment the count 69639397Smckusick */ 69739397Smckusick void vref(vp) 69839397Smckusick struct vnode *vp; 69939397Smckusick { 70039397Smckusick 70139809Smckusick vp->v_usecount++; 70239397Smckusick } 70339397Smckusick 70439397Smckusick /* 70539397Smckusick * vput(), just unlock and vrele() 70639397Smckusick */ 70739397Smckusick void vput(vp) 70839397Smckusick register struct vnode *vp; 70939397Smckusick { 71039397Smckusick VOP_UNLOCK(vp); 71139397Smckusick vrele(vp); 71239397Smckusick } 71339397Smckusick 71439397Smckusick /* 71539397Smckusick * Vnode release. 71639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 71739397Smckusick */ 71839397Smckusick void vrele(vp) 71939397Smckusick register struct vnode *vp; 72039397Smckusick { 72148024Smckusick struct proc *p = curproc; /* XXX */ 72239397Smckusick 72339397Smckusick if (vp == NULL) 72439433Smckusick panic("vrele: null vp"); 72539809Smckusick vp->v_usecount--; 72639809Smckusick if (vp->v_usecount < 0) 72739667Smckusick vprint("vrele: bad ref count", vp); 72839809Smckusick if (vp->v_usecount > 0) 72939397Smckusick return; 73041400Smckusick if (vfreeh == NULLVP) { 73139397Smckusick /* 73239397Smckusick * insert into empty list 73339397Smckusick */ 73439397Smckusick vfreeh = vp; 73539397Smckusick vp->v_freeb = &vfreeh; 73639397Smckusick } else { 73739397Smckusick /* 73839397Smckusick * insert at tail of list 73939397Smckusick */ 74039397Smckusick *vfreet = vp; 74139397Smckusick vp->v_freeb = vfreet; 74239397Smckusick } 74339433Smckusick vp->v_freef = NULL; 74439433Smckusick vfreet = &vp->v_freef; 74548024Smckusick VOP_INACTIVE(vp, p); 74639397Smckusick } 74739433Smckusick 74839433Smckusick /* 74939809Smckusick * Page or buffer structure gets a reference. 75039809Smckusick */ 75139809Smckusick vhold(vp) 75239809Smckusick register struct vnode *vp; 75339809Smckusick { 75439809Smckusick 75539809Smckusick vp->v_holdcnt++; 75639809Smckusick } 75739809Smckusick 75839809Smckusick /* 75939809Smckusick * Page or buffer structure frees a reference. 76039809Smckusick */ 76139809Smckusick holdrele(vp) 76239809Smckusick register struct vnode *vp; 76339809Smckusick { 76439809Smckusick 76539809Smckusick if (vp->v_holdcnt <= 0) 76639809Smckusick panic("holdrele: holdcnt"); 76739809Smckusick vp->v_holdcnt--; 76839809Smckusick } 76939809Smckusick 77039809Smckusick /* 77139509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 77239509Smckusick * 77339509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 77439509Smckusick * return error if any are found (nb: this is a user error, not a 77539509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 77639509Smckusick * that are found. 77739509Smckusick */ 77839509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 77939509Smckusick 78039509Smckusick vflush(mp, skipvp, flags) 78139509Smckusick struct mount *mp; 78239509Smckusick struct vnode *skipvp; 78339509Smckusick int flags; 78439509Smckusick { 78539509Smckusick register struct vnode *vp, *nvp; 78639509Smckusick int busy = 0; 78739509Smckusick 78841400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 78941300Smckusick panic("vflush: not busy"); 79041421Smckusick loop: 79141400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 79241421Smckusick if (vp->v_mount != mp) 79341421Smckusick goto loop; 79439509Smckusick nvp = vp->v_mountf; 79539509Smckusick /* 79639509Smckusick * Skip over a selected vnode. 79739509Smckusick */ 79839509Smckusick if (vp == skipvp) 79939509Smckusick continue; 80039509Smckusick /* 80141300Smckusick * Skip over a vnodes marked VSYSTEM. 80241300Smckusick */ 80341300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 80441300Smckusick continue; 80541300Smckusick /* 80639809Smckusick * With v_usecount == 0, all we need to do is clear 80739509Smckusick * out the vnode data structures and we are done. 80839509Smckusick */ 80939809Smckusick if (vp->v_usecount == 0) { 81039509Smckusick vgone(vp); 81139509Smckusick continue; 81239509Smckusick } 81339509Smckusick /* 81439509Smckusick * For block or character devices, revert to an 81539509Smckusick * anonymous device. For all other files, just kill them. 81639509Smckusick */ 81741300Smckusick if (flags & FORCECLOSE) { 81839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 81939509Smckusick vgone(vp); 82039509Smckusick } else { 82139509Smckusick vclean(vp, 0); 82239509Smckusick vp->v_op = &spec_vnodeops; 82339509Smckusick insmntque(vp, (struct mount *)0); 82439509Smckusick } 82539509Smckusick continue; 82639509Smckusick } 82739509Smckusick if (busyprt) 82839667Smckusick vprint("vflush: busy vnode", vp); 82939509Smckusick busy++; 83039509Smckusick } 83139509Smckusick if (busy) 83239509Smckusick return (EBUSY); 83339509Smckusick return (0); 83439509Smckusick } 83539509Smckusick 83639509Smckusick /* 83739433Smckusick * Disassociate the underlying file system from a vnode. 83839433Smckusick */ 83941300Smckusick void vclean(vp, flags) 84039433Smckusick register struct vnode *vp; 84145118Smckusick int flags; 84239433Smckusick { 84339433Smckusick struct vnodeops *origops; 84439484Smckusick int active; 84548024Smckusick struct proc *p = curproc; /* XXX */ 84639433Smckusick 84739484Smckusick /* 84839484Smckusick * Check to see if the vnode is in use. 84939667Smckusick * If so we have to reference it before we clean it out 85039667Smckusick * so that its count cannot fall to zero and generate a 85139667Smckusick * race against ourselves to recycle it. 85239484Smckusick */ 85339809Smckusick if (active = vp->v_usecount) 85439484Smckusick VREF(vp); 85539484Smckusick /* 85639484Smckusick * Prevent the vnode from being recycled or 85739484Smckusick * brought into use while we clean it out. 85839484Smckusick */ 85939667Smckusick if (vp->v_flag & VXLOCK) 86039667Smckusick panic("vclean: deadlock"); 86139433Smckusick vp->v_flag |= VXLOCK; 86239433Smckusick /* 86339667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 86439667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 86539667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 86639667Smckusick * For active vnodes, it ensures that no other activity can 86739667Smckusick * occur while the buffer list is being cleaned out. 86839667Smckusick */ 86939667Smckusick VOP_LOCK(vp); 87041300Smckusick if (flags & DOCLOSE) 87139667Smckusick vinvalbuf(vp, 1); 87239667Smckusick /* 87339433Smckusick * Prevent any further operations on the vnode from 87439433Smckusick * being passed through to the old file system. 87539433Smckusick */ 87639433Smckusick origops = vp->v_op; 87739433Smckusick vp->v_op = &dead_vnodeops; 87839433Smckusick vp->v_tag = VT_NON; 87939433Smckusick /* 88039484Smckusick * If purging an active vnode, it must be unlocked, closed, 88139484Smckusick * and deactivated before being reclaimed. 88239433Smckusick */ 88339667Smckusick (*(origops->vn_unlock))(vp); 88439484Smckusick if (active) { 88541300Smckusick if (flags & DOCLOSE) 88648354Smckusick (*(origops->vn_close))(vp, IO_NDELAY, NOCRED, p); 88748024Smckusick (*(origops->vn_inactive))(vp, p); 88839433Smckusick } 88939433Smckusick /* 89039433Smckusick * Reclaim the vnode. 89139433Smckusick */ 89239433Smckusick if ((*(origops->vn_reclaim))(vp)) 89339433Smckusick panic("vclean: cannot reclaim"); 89439484Smckusick if (active) 89539484Smckusick vrele(vp); 89639433Smckusick /* 89739433Smckusick * Done with purge, notify sleepers in vget of the grim news. 89839433Smckusick */ 89939433Smckusick vp->v_flag &= ~VXLOCK; 90039433Smckusick if (vp->v_flag & VXWANT) { 90139433Smckusick vp->v_flag &= ~VXWANT; 90239433Smckusick wakeup((caddr_t)vp); 90339433Smckusick } 90439433Smckusick } 90539433Smckusick 90639433Smckusick /* 90739633Smckusick * Eliminate all activity associated with the requested vnode 90839633Smckusick * and with all vnodes aliased to the requested vnode. 90939633Smckusick */ 91039633Smckusick void vgoneall(vp) 91139633Smckusick register struct vnode *vp; 91239633Smckusick { 91339809Smckusick register struct vnode *vq; 91439633Smckusick 91540665Smckusick if (vp->v_flag & VALIASED) { 91640665Smckusick /* 91740665Smckusick * If a vgone (or vclean) is already in progress, 91840665Smckusick * wait until it is done and return. 91940665Smckusick */ 92040665Smckusick if (vp->v_flag & VXLOCK) { 92140665Smckusick vp->v_flag |= VXWANT; 92240665Smckusick sleep((caddr_t)vp, PINOD); 92340665Smckusick return; 92439633Smckusick } 92540665Smckusick /* 92640665Smckusick * Ensure that vp will not be vgone'd while we 92740665Smckusick * are eliminating its aliases. 92840665Smckusick */ 92940665Smckusick vp->v_flag |= VXLOCK; 93040665Smckusick while (vp->v_flag & VALIASED) { 93140665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 93240665Smckusick if (vq->v_rdev != vp->v_rdev || 93340665Smckusick vq->v_type != vp->v_type || vp == vq) 93440665Smckusick continue; 93540665Smckusick vgone(vq); 93640665Smckusick break; 93740665Smckusick } 93840665Smckusick } 93940665Smckusick /* 94040665Smckusick * Remove the lock so that vgone below will 94140665Smckusick * really eliminate the vnode after which time 94240665Smckusick * vgone will awaken any sleepers. 94340665Smckusick */ 94440665Smckusick vp->v_flag &= ~VXLOCK; 94539633Smckusick } 94639633Smckusick vgone(vp); 94739633Smckusick } 94839633Smckusick 94939633Smckusick /* 95039433Smckusick * Eliminate all activity associated with a vnode 95139433Smckusick * in preparation for reuse. 95239433Smckusick */ 95339433Smckusick void vgone(vp) 95439433Smckusick register struct vnode *vp; 95539433Smckusick { 95639809Smckusick register struct vnode *vq; 95739615Smckusick struct vnode *vx; 95839615Smckusick long count; 95939433Smckusick 96039433Smckusick /* 96140548Smckusick * If a vgone (or vclean) is already in progress, 96240548Smckusick * wait until it is done and return. 96340548Smckusick */ 96440548Smckusick if (vp->v_flag & VXLOCK) { 96540548Smckusick vp->v_flag |= VXWANT; 96640548Smckusick sleep((caddr_t)vp, PINOD); 96740548Smckusick return; 96840548Smckusick } 96940548Smckusick /* 97039433Smckusick * Clean out the filesystem specific data. 97139433Smckusick */ 97241300Smckusick vclean(vp, DOCLOSE); 97339433Smckusick /* 97439433Smckusick * Delete from old mount point vnode list, if on one. 97539433Smckusick */ 97639433Smckusick if (vp->v_mountb) { 97739433Smckusick if (vq = vp->v_mountf) 97839433Smckusick vq->v_mountb = vp->v_mountb; 97939433Smckusick *vp->v_mountb = vq; 98039433Smckusick vp->v_mountf = NULL; 98139433Smckusick vp->v_mountb = NULL; 98239433Smckusick } 98339433Smckusick /* 98439433Smckusick * If special device, remove it from special device alias list. 98539433Smckusick */ 98639433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 98739809Smckusick if (*vp->v_hashchain == vp) { 98839809Smckusick *vp->v_hashchain = vp->v_specnext; 98939433Smckusick } else { 99039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 99139615Smckusick if (vq->v_specnext != vp) 99239433Smckusick continue; 99339615Smckusick vq->v_specnext = vp->v_specnext; 99439433Smckusick break; 99539433Smckusick } 99639615Smckusick if (vq == NULL) 99739433Smckusick panic("missing bdev"); 99839433Smckusick } 99939615Smckusick if (vp->v_flag & VALIASED) { 100039809Smckusick count = 0; 100139809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 100240108Smckusick if (vq->v_rdev != vp->v_rdev || 100340108Smckusick vq->v_type != vp->v_type) 100439615Smckusick continue; 100539615Smckusick count++; 100639615Smckusick vx = vq; 100739615Smckusick } 100839615Smckusick if (count == 0) 100939615Smckusick panic("missing alias"); 101039615Smckusick if (count == 1) 101139615Smckusick vx->v_flag &= ~VALIASED; 101239615Smckusick vp->v_flag &= ~VALIASED; 101339615Smckusick } 101439615Smckusick FREE(vp->v_specinfo, M_VNODE); 101539615Smckusick vp->v_specinfo = NULL; 101639433Smckusick } 101739433Smckusick /* 101839433Smckusick * If it is on the freelist, move it to the head of the list. 101939433Smckusick */ 102039433Smckusick if (vp->v_freeb) { 102139433Smckusick if (vq = vp->v_freef) 102239433Smckusick vq->v_freeb = vp->v_freeb; 102339433Smckusick else 102439433Smckusick vfreet = vp->v_freeb; 102539433Smckusick *vp->v_freeb = vq; 102639433Smckusick vp->v_freef = vfreeh; 102739433Smckusick vp->v_freeb = &vfreeh; 102839433Smckusick vfreeh->v_freeb = &vp->v_freef; 102939433Smckusick vfreeh = vp; 103039433Smckusick } 103139484Smckusick vp->v_type = VBAD; 103239433Smckusick } 103339633Smckusick 103439633Smckusick /* 103539821Smckusick * Lookup a vnode by device number. 103639821Smckusick */ 103739821Smckusick vfinddev(dev, type, vpp) 103839821Smckusick dev_t dev; 103939821Smckusick enum vtype type; 104039821Smckusick struct vnode **vpp; 104139821Smckusick { 104239821Smckusick register struct vnode *vp; 104339821Smckusick 104439821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 104539821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 104639821Smckusick continue; 104739821Smckusick *vpp = vp; 104839821Smckusick return (0); 104939821Smckusick } 105039821Smckusick return (1); 105139821Smckusick } 105239821Smckusick 105339821Smckusick /* 105439633Smckusick * Calculate the total number of references to a special device. 105539633Smckusick */ 105639633Smckusick vcount(vp) 105739633Smckusick register struct vnode *vp; 105839633Smckusick { 105939809Smckusick register struct vnode *vq; 106039633Smckusick int count; 106139633Smckusick 106239633Smckusick if ((vp->v_flag & VALIASED) == 0) 106339809Smckusick return (vp->v_usecount); 106439633Smckusick loop: 106539809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 106640108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 106739633Smckusick continue; 106839633Smckusick /* 106939633Smckusick * Alias, but not in use, so flush it out. 107039633Smckusick */ 107139809Smckusick if (vq->v_usecount == 0) { 107239633Smckusick vgone(vq); 107339633Smckusick goto loop; 107439633Smckusick } 107539809Smckusick count += vq->v_usecount; 107639633Smckusick } 107739633Smckusick return (count); 107839633Smckusick } 107939667Smckusick 108039667Smckusick /* 108139667Smckusick * Print out a description of a vnode. 108239667Smckusick */ 108339667Smckusick static char *typename[] = 108440286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 108539667Smckusick 108639667Smckusick vprint(label, vp) 108739667Smckusick char *label; 108839667Smckusick register struct vnode *vp; 108939667Smckusick { 109039913Smckusick char buf[64]; 109139667Smckusick 109239667Smckusick if (label != NULL) 109339667Smckusick printf("%s: ", label); 109439913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 109539809Smckusick vp->v_usecount, vp->v_holdcnt); 109639913Smckusick buf[0] = '\0'; 109739913Smckusick if (vp->v_flag & VROOT) 109839913Smckusick strcat(buf, "|VROOT"); 109939913Smckusick if (vp->v_flag & VTEXT) 110039913Smckusick strcat(buf, "|VTEXT"); 110141300Smckusick if (vp->v_flag & VSYSTEM) 110241300Smckusick strcat(buf, "|VSYSTEM"); 110341300Smckusick if (vp->v_flag & VXLOCK) 110441300Smckusick strcat(buf, "|VXLOCK"); 110541300Smckusick if (vp->v_flag & VXWANT) 110641300Smckusick strcat(buf, "|VXWANT"); 110741300Smckusick if (vp->v_flag & VBWAIT) 110841300Smckusick strcat(buf, "|VBWAIT"); 110939913Smckusick if (vp->v_flag & VALIASED) 111039913Smckusick strcat(buf, "|VALIASED"); 111139913Smckusick if (buf[0] != '\0') 111239913Smckusick printf(" flags (%s)", &buf[1]); 111339913Smckusick printf("\n\t"); 111439667Smckusick VOP_PRINT(vp); 111539667Smckusick } 111641110Smarc 111741110Smarc int kinfo_vdebug = 1; 111841110Smarc int kinfo_vgetfailed; 111941110Smarc #define KINFO_VNODESLOP 10 112041110Smarc /* 112141110Smarc * Dump vnode list (via kinfo). 112241110Smarc * Copyout address of vnode followed by vnode. 112341110Smarc */ 112445118Smckusick /* ARGSUSED */ 112541110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 112645118Smckusick int op; 112741110Smarc char *where; 112845118Smckusick int *acopysize, arg, *aneeded; 112941110Smarc { 113041110Smarc register struct mount *mp = rootfs; 113141300Smckusick struct mount *omp; 113241110Smarc struct vnode *vp; 113341110Smarc register char *bp = where, *savebp; 113441110Smarc char *ewhere = where + *acopysize; 113541110Smarc int error; 113641110Smarc 113741110Smarc #define VPTRSZ sizeof (struct vnode *) 113841110Smarc #define VNODESZ sizeof (struct vnode) 113941110Smarc if (where == NULL) { 114041110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 114141110Smarc return (0); 114241110Smarc } 114341110Smarc 114441110Smarc do { 114541300Smckusick if (vfs_busy(mp)) { 114641400Smckusick mp = mp->mnt_next; 114741300Smckusick continue; 114841300Smckusick } 114941110Smarc savebp = bp; 115041110Smarc again: 115141421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 115241422Smckusick /* 115341422Smckusick * Check that the vp is still associated with 115441422Smckusick * this filesystem. RACE: could have been 115541422Smckusick * recycled onto the same filesystem. 115641422Smckusick */ 115741421Smckusick if (vp->v_mount != mp) { 115841421Smckusick if (kinfo_vdebug) 115941421Smckusick printf("kinfo: vp changed\n"); 116041421Smckusick bp = savebp; 116141421Smckusick goto again; 116241421Smckusick } 116341110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 116441110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 116541110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 116641422Smckusick VNODESZ)))) 116741110Smarc return (error); 116841110Smarc bp += VPTRSZ + VNODESZ; 116941110Smarc } 117041300Smckusick omp = mp; 117141400Smckusick mp = mp->mnt_next; 117241300Smckusick vfs_unbusy(omp); 117341110Smarc } while (mp != rootfs); 117441110Smarc 117541110Smarc *aneeded = bp - where; 117641110Smarc if (bp > ewhere) 117741110Smarc *acopysize = ewhere - where; 117841110Smarc else 117941110Smarc *acopysize = bp - where; 118041110Smarc return (0); 118141110Smarc } 1182