137488Smckusick /* 263180Sbostic * Copyright (c) 1989, 1993 363180Sbostic * The Regents of the University of California. All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*65679Shibler * @(#)vfs_subr.c 8.7 (Berkeley) 01/12/94 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1451460Sbostic #include <sys/param.h> 1553829Spendry #include <sys/systm.h> 1651460Sbostic #include <sys/proc.h> 1751460Sbostic #include <sys/mount.h> 1851460Sbostic #include <sys/time.h> 1951460Sbostic #include <sys/vnode.h> 2052415Smckusick #include <sys/stat.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> 26*65679Shibler #include <sys/domain.h> 27*65679Shibler #include <sys/mbuf.h> 2837488Smckusick 2960930Smckusick #include <vm/vm.h> 3060930Smckusick #include <sys/sysctl.h> 3160930Smckusick 3255050Spendry #include <miscfs/specfs/specdev.h> 3355050Spendry 3452415Smckusick enum vtype iftovt_tab[16] = { 3552415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 3652415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 3752415Smckusick }; 3852415Smckusick int vttoif_tab[9] = { 3952415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 4052415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 4152415Smckusick }; 4252415Smckusick 4337488Smckusick /* 4456608Smckusick * Insq/Remq for the vnode usage lists. 4556608Smckusick */ 4665260Smckusick #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) 4765260Smckusick #define bufremvn(bp) { \ 4865260Smckusick LIST_REMOVE(bp, b_vnbufs); \ 4965260Smckusick (bp)->b_vnbufs.le_next = NOLIST; \ 5065260Smckusick } 5156608Smckusick 5265260Smckusick TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ 5365260Smckusick struct mntlist mountlist; /* mounted filesystem list */ 5465260Smckusick 5556608Smckusick /* 5665260Smckusick * Initialize the vnode management data structures. 5737488Smckusick */ 5865260Smckusick vntblinit() 5937488Smckusick { 6037488Smckusick 6165260Smckusick TAILQ_INIT(&vnode_free_list); 6265260Smckusick TAILQ_INIT(&mountlist); 6337488Smckusick } 6437488Smckusick 6537488Smckusick /* 6637488Smckusick * Lock a filesystem. 6737488Smckusick * Used to prevent access to it while mounting and unmounting. 6837488Smckusick */ 6937488Smckusick vfs_lock(mp) 7037488Smckusick register struct mount *mp; 7137488Smckusick { 7237488Smckusick 7341400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 7441400Smckusick mp->mnt_flag |= MNT_MWAIT; 7539045Smckusick sleep((caddr_t)mp, PVFS); 7639045Smckusick } 7741400Smckusick mp->mnt_flag |= MNT_MLOCK; 7837488Smckusick return (0); 7937488Smckusick } 8037488Smckusick 8137488Smckusick /* 8237488Smckusick * Unlock a locked filesystem. 8337488Smckusick * Panic if filesystem is not locked. 8437488Smckusick */ 8537488Smckusick void 8637488Smckusick vfs_unlock(mp) 8737488Smckusick register struct mount *mp; 8837488Smckusick { 8937488Smckusick 9041400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 9141300Smckusick panic("vfs_unlock: not locked"); 9241400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 9341400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 9441400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 9537488Smckusick wakeup((caddr_t)mp); 9637488Smckusick } 9737488Smckusick } 9837488Smckusick 9937488Smckusick /* 10041300Smckusick * Mark a mount point as busy. 10141300Smckusick * Used to synchronize access and to delay unmounting. 10241300Smckusick */ 10341300Smckusick vfs_busy(mp) 10441300Smckusick register struct mount *mp; 10541300Smckusick { 10641300Smckusick 10741400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 10841400Smckusick mp->mnt_flag |= MNT_MPWANT; 10941400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 11041300Smckusick } 11141419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 11241419Smckusick return (1); 11341400Smckusick mp->mnt_flag |= MNT_MPBUSY; 11441300Smckusick return (0); 11541300Smckusick } 11641300Smckusick 11741300Smckusick /* 11841300Smckusick * Free a busy filesystem. 11941300Smckusick * Panic if filesystem is not busy. 12041300Smckusick */ 12141300Smckusick vfs_unbusy(mp) 12241300Smckusick register struct mount *mp; 12341300Smckusick { 12441300Smckusick 12541400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 12641300Smckusick panic("vfs_unbusy: not busy"); 12741400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 12841400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 12941400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 13041400Smckusick wakeup((caddr_t)&mp->mnt_flag); 13141300Smckusick } 13241300Smckusick } 13341300Smckusick 13441300Smckusick /* 13537488Smckusick * Lookup a mount point by filesystem identifier. 13637488Smckusick */ 13737488Smckusick struct mount * 13837488Smckusick getvfs(fsid) 13937488Smckusick fsid_t *fsid; 14037488Smckusick { 14137488Smckusick register struct mount *mp; 14237488Smckusick 14365260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { 14441400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 14565260Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) 14638288Smckusick return (mp); 14765260Smckusick } 14838288Smckusick return ((struct mount *)0); 14937488Smckusick } 15037488Smckusick 15137488Smckusick /* 15253829Spendry * Get a new unique fsid 15353829Spendry */ 15453829Spendry void 15553829Spendry getnewfsid(mp, mtype) 15653829Spendry struct mount *mp; 15753829Spendry int mtype; 15853829Spendry { 15953829Spendry static u_short xxxfs_mntid; 16053829Spendry 16153829Spendry fsid_t tfsid; 16253829Spendry 16365507Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); 16453829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 16553829Spendry if (xxxfs_mntid == 0) 16653829Spendry ++xxxfs_mntid; 16765507Spendry tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); 16853829Spendry tfsid.val[1] = mtype; 16965260Smckusick if (mountlist.tqh_first != NULL) { 17053936Spendry while (getvfs(&tfsid)) { 17153936Spendry tfsid.val[0]++; 17253936Spendry xxxfs_mntid++; 17353936Spendry } 17453829Spendry } 17553829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 17653829Spendry } 17753829Spendry 17853829Spendry /* 17937488Smckusick * Set vnode attributes to VNOVAL 18037488Smckusick */ 18137488Smckusick void vattr_null(vap) 18237488Smckusick register struct vattr *vap; 18337488Smckusick { 18437488Smckusick 18537488Smckusick vap->va_type = VNON; 18652005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 18737488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 18852005Smckusick vap->va_fsid = vap->va_fileid = 18952005Smckusick vap->va_blocksize = vap->va_rdev = 19054347Smckusick vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 19154347Smckusick vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 19254347Smckusick vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 19338258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 19458548Sbostic vap->va_vaflags = 0; 19537488Smckusick } 19638265Smckusick 19738265Smckusick /* 19839397Smckusick * Routines having to do with the management of the vnode table. 19939397Smckusick */ 20053547Sheideman extern int (**dead_vnodeop_p)(); 20139635Smckusick extern void vclean(); 20240883Smckusick long numvnodes; 20353493Sheideman extern struct vattr va_null; 20439397Smckusick 20539397Smckusick /* 20639397Smckusick * Return the next vnode from the free list. 20739397Smckusick */ 20839397Smckusick getnewvnode(tag, mp, vops, vpp) 20939397Smckusick enum vtagtype tag; 21039397Smckusick struct mount *mp; 21153495Sheideman int (**vops)(); 21239397Smckusick struct vnode **vpp; 21339397Smckusick { 21465511Smckusick register struct vnode *vp; 21557042Smargo int s; 21639397Smckusick 21765260Smckusick if ((vnode_free_list.tqh_first == NULL && 21865260Smckusick numvnodes < 2 * desiredvnodes) || 21954347Smckusick numvnodes < desiredvnodes) { 22045118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 22145118Smckusick M_VNODE, M_WAITOK); 22240883Smckusick bzero((char *)vp, sizeof *vp); 22340883Smckusick numvnodes++; 22440883Smckusick } else { 22565260Smckusick if ((vp = vnode_free_list.tqh_first) == NULL) { 22640883Smckusick tablefull("vnode"); 22740883Smckusick *vpp = 0; 22840883Smckusick return (ENFILE); 22940883Smckusick } 23040883Smckusick if (vp->v_usecount) 23140883Smckusick panic("free vnode isn't"); 23265260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 23365505Smckusick /* see comment on why 0xdeadb is set at end of vgone (below) */ 23465505Smckusick vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb; 23552190Smckusick vp->v_lease = NULL; 23640883Smckusick if (vp->v_type != VBAD) 23740883Smckusick vgone(vp); 23857042Smargo #ifdef DIAGNOSTIC 23952006Smckusick if (vp->v_data) 24052006Smckusick panic("cleaned vnode isn't"); 24157042Smargo s = splbio(); 24257042Smargo if (vp->v_numoutput) 24357042Smargo panic("Clean vnode has pending I/O's"); 24457042Smargo splx(s); 24557042Smargo #endif 24640883Smckusick vp->v_flag = 0; 24740883Smckusick vp->v_lastr = 0; 24857042Smargo vp->v_lastw = 0; 24957042Smargo vp->v_lasta = 0; 25057042Smargo vp->v_cstart = 0; 25157042Smargo vp->v_clen = 0; 25240883Smckusick vp->v_socket = 0; 25339397Smckusick } 25457042Smargo vp->v_ralen = 1; 25539512Smckusick vp->v_type = VNON; 25639397Smckusick cache_purge(vp); 25739397Smckusick vp->v_tag = tag; 25839433Smckusick vp->v_op = vops; 25939397Smckusick insmntque(vp, mp); 26039397Smckusick *vpp = vp; 26165505Smckusick vp->v_usecount = 1; 26265260Smckusick vp->v_data = 0; 26339397Smckusick return (0); 26439397Smckusick } 265*65679Shibler 26639397Smckusick /* 26739397Smckusick * Move a vnode from one mount queue to another. 26839397Smckusick */ 26939397Smckusick insmntque(vp, mp) 27039397Smckusick register struct vnode *vp; 27139397Smckusick register struct mount *mp; 27239397Smckusick { 27339397Smckusick 27439397Smckusick /* 27539397Smckusick * Delete from old mount point vnode list, if on one. 27639397Smckusick */ 277*65679Shibler if (vp->v_mount != NULL) 27865260Smckusick LIST_REMOVE(vp, v_mntvnodes); 27939397Smckusick /* 28039397Smckusick * Insert into list of vnodes for the new mount point, if available. 28139397Smckusick */ 28265260Smckusick if ((vp->v_mount = mp) == NULL) 28339397Smckusick return; 28465260Smckusick LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); 28539397Smckusick } 28639397Smckusick 28739397Smckusick /* 28849232Smckusick * Update outstanding I/O count and do wakeup if requested. 28949232Smckusick */ 29049232Smckusick vwakeup(bp) 29149232Smckusick register struct buf *bp; 29249232Smckusick { 29349232Smckusick register struct vnode *vp; 29449232Smckusick 29557810Smckusick bp->b_flags &= ~B_WRITEINPROG; 29649232Smckusick if (vp = bp->b_vp) { 29749232Smckusick vp->v_numoutput--; 29857042Smargo if (vp->v_numoutput < 0) 29957042Smargo panic("vwakeup: neg numoutput"); 30049232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 30149232Smckusick if (vp->v_numoutput < 0) 30249232Smckusick panic("vwakeup: neg numoutput"); 30349232Smckusick vp->v_flag &= ~VBWAIT; 30449232Smckusick wakeup((caddr_t)&vp->v_numoutput); 30549232Smckusick } 30649232Smckusick } 30749232Smckusick } 30849232Smckusick 30949232Smckusick /* 31049232Smckusick * Flush out and invalidate all buffers associated with a vnode. 31149232Smckusick * Called with the underlying object locked. 31249232Smckusick */ 31354442Smckusick int 31457792Smckusick vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 31549232Smckusick register struct vnode *vp; 31656459Smargo int flags; 31754442Smckusick struct ucred *cred; 31854442Smckusick struct proc *p; 31957792Smckusick int slpflag, slptimeo; 32049232Smckusick { 32149232Smckusick register struct buf *bp; 32249232Smckusick struct buf *nbp, *blist; 32354442Smckusick int s, error; 32449232Smckusick 32556459Smargo if (flags & V_SAVE) { 32654442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 32754442Smckusick return (error); 32865260Smckusick if (vp->v_dirtyblkhd.lh_first != NULL) 32954442Smckusick panic("vinvalbuf: dirty bufs"); 33054442Smckusick } 33149232Smckusick for (;;) { 33265260Smckusick if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA) 33356459Smargo while (blist && blist->b_lblkno < 0) 33465260Smckusick blist = blist->b_vnbufs.le_next; 33565260Smckusick if (!blist && (blist = vp->v_dirtyblkhd.lh_first) && 33656608Smckusick (flags & V_SAVEMETA)) 33756459Smargo while (blist && blist->b_lblkno < 0) 33865260Smckusick blist = blist->b_vnbufs.le_next; 33956459Smargo if (!blist) 34049232Smckusick break; 34156459Smargo 34249232Smckusick for (bp = blist; bp; bp = nbp) { 34365260Smckusick nbp = bp->b_vnbufs.le_next; 34456459Smargo if (flags & V_SAVEMETA && bp->b_lblkno < 0) 34556459Smargo continue; 34649232Smckusick s = splbio(); 34749232Smckusick if (bp->b_flags & B_BUSY) { 34849232Smckusick bp->b_flags |= B_WANTED; 34957792Smckusick error = tsleep((caddr_t)bp, 35057792Smckusick slpflag | (PRIBIO + 1), "vinvalbuf", 35157792Smckusick slptimeo); 35249232Smckusick splx(s); 35357792Smckusick if (error) 35457792Smckusick return (error); 35549232Smckusick break; 35649232Smckusick } 35749232Smckusick bremfree(bp); 35849232Smckusick bp->b_flags |= B_BUSY; 35949232Smckusick splx(s); 36057792Smckusick /* 36157792Smckusick * XXX Since there are no node locks for NFS, I believe 36257792Smckusick * there is a slight chance that a delayed write will 36357792Smckusick * occur while sleeping just above, so check for it. 36457792Smckusick */ 36557792Smckusick if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 36657792Smckusick (void) VOP_BWRITE(bp); 36757792Smckusick break; 36857792Smckusick } 36956459Smargo bp->b_flags |= B_INVAL; 37049232Smckusick brelse(bp); 37149232Smckusick } 37249232Smckusick } 37356608Smckusick if (!(flags & V_SAVEMETA) && 37465260Smckusick (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first)) 37549232Smckusick panic("vinvalbuf: flush failed"); 37654442Smckusick return (0); 37749232Smckusick } 37849232Smckusick 37949232Smckusick /* 38049232Smckusick * Associate a buffer with a vnode. 38149232Smckusick */ 38249232Smckusick bgetvp(vp, bp) 38349232Smckusick register struct vnode *vp; 38449232Smckusick register struct buf *bp; 38549232Smckusick { 38649232Smckusick 38749232Smckusick if (bp->b_vp) 38849232Smckusick panic("bgetvp: not free"); 38949232Smckusick VHOLD(vp); 39049232Smckusick bp->b_vp = vp; 39149232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 39249232Smckusick bp->b_dev = vp->v_rdev; 39349232Smckusick else 39449232Smckusick bp->b_dev = NODEV; 39549232Smckusick /* 39649232Smckusick * Insert onto list for new vnode. 39749232Smckusick */ 39856608Smckusick bufinsvn(bp, &vp->v_cleanblkhd); 39949232Smckusick } 40049232Smckusick 40149232Smckusick /* 40249232Smckusick * Disassociate a buffer from a vnode. 40349232Smckusick */ 40449232Smckusick brelvp(bp) 40549232Smckusick register struct buf *bp; 40649232Smckusick { 40749232Smckusick struct vnode *vp; 40849232Smckusick 40949232Smckusick if (bp->b_vp == (struct vnode *) 0) 41049232Smckusick panic("brelvp: NULL"); 41149232Smckusick /* 41249232Smckusick * Delete from old vnode list, if on one. 41349232Smckusick */ 41465260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 41556608Smckusick bufremvn(bp); 41649232Smckusick vp = bp->b_vp; 41749232Smckusick bp->b_vp = (struct vnode *) 0; 41849232Smckusick HOLDRELE(vp); 41949232Smckusick } 42049232Smckusick 42149232Smckusick /* 42249232Smckusick * Reassign a buffer from one vnode to another. 42349232Smckusick * Used to assign file specific control information 42449232Smckusick * (indirect blocks) to the vnode to which they belong. 42549232Smckusick */ 42649232Smckusick reassignbuf(bp, newvp) 42749232Smckusick register struct buf *bp; 42849232Smckusick register struct vnode *newvp; 42949232Smckusick { 43065260Smckusick register struct buflists *listheadp; 43149232Smckusick 43252655Smckusick if (newvp == NULL) { 43352655Smckusick printf("reassignbuf: NULL"); 43452655Smckusick return; 43552655Smckusick } 43649232Smckusick /* 43749232Smckusick * Delete from old vnode list, if on one. 43849232Smckusick */ 43965260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 44056608Smckusick bufremvn(bp); 44149232Smckusick /* 44249232Smckusick * If dirty, put on list of dirty buffers; 44349232Smckusick * otherwise insert onto list of clean buffers. 44449232Smckusick */ 44549232Smckusick if (bp->b_flags & B_DELWRI) 44649232Smckusick listheadp = &newvp->v_dirtyblkhd; 44749232Smckusick else 44849232Smckusick listheadp = &newvp->v_cleanblkhd; 44956608Smckusick bufinsvn(bp, listheadp); 45049232Smckusick } 45149232Smckusick 45249232Smckusick /* 45339433Smckusick * Create a vnode for a block device. 45439433Smckusick * Used for root filesystem, argdev, and swap areas. 45539433Smckusick * Also used for memory file system special devices. 45639397Smckusick */ 45739433Smckusick bdevvp(dev, vpp) 45839433Smckusick dev_t dev; 45939433Smckusick struct vnode **vpp; 46039433Smckusick { 46139433Smckusick register struct vnode *vp; 46239433Smckusick struct vnode *nvp; 46339433Smckusick int error; 46439433Smckusick 46546989Smckusick if (dev == NODEV) 46646989Smckusick return (0); 46753547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 46839433Smckusick if (error) { 46939433Smckusick *vpp = 0; 47039433Smckusick return (error); 47139433Smckusick } 47239433Smckusick vp = nvp; 47339433Smckusick vp->v_type = VBLK; 47439615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 47539433Smckusick vput(vp); 47639433Smckusick vp = nvp; 47739433Smckusick } 47839433Smckusick *vpp = vp; 47939433Smckusick return (0); 48039433Smckusick } 48139433Smckusick 48239433Smckusick /* 48339433Smckusick * Check to see if the new vnode represents a special device 48439433Smckusick * for which we already have a vnode (either because of 48539433Smckusick * bdevvp() or because of a different vnode representing 48639433Smckusick * the same block device). If such an alias exists, deallocate 48739509Smckusick * the existing contents and return the aliased vnode. The 48839433Smckusick * caller is responsible for filling it with its new contents. 48939433Smckusick */ 49039433Smckusick struct vnode * 49139615Smckusick checkalias(nvp, nvp_rdev, mp) 49239433Smckusick register struct vnode *nvp; 49339615Smckusick dev_t nvp_rdev; 49439433Smckusick struct mount *mp; 49539433Smckusick { 49639433Smckusick register struct vnode *vp; 49739615Smckusick struct vnode **vpp; 49839433Smckusick 49939433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 50041400Smckusick return (NULLVP); 50139615Smckusick 50239615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 50339433Smckusick loop: 50439615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 50539615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50639433Smckusick continue; 50739615Smckusick /* 50839615Smckusick * Alias, but not in use, so flush it out. 50939615Smckusick */ 51039809Smckusick if (vp->v_usecount == 0) { 51139615Smckusick vgone(vp); 51239615Smckusick goto loop; 51339615Smckusick } 51465260Smckusick if (vget(vp, 1)) 51539633Smckusick goto loop; 51639433Smckusick break; 51739433Smckusick } 51839615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 51939615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 52039615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 52139615Smckusick nvp->v_rdev = nvp_rdev; 52239809Smckusick nvp->v_hashchain = vpp; 52339615Smckusick nvp->v_specnext = *vpp; 52442152Smckusick nvp->v_specflags = 0; 52539615Smckusick *vpp = nvp; 52640640Smckusick if (vp != NULL) { 52740640Smckusick nvp->v_flag |= VALIASED; 52840640Smckusick vp->v_flag |= VALIASED; 52940640Smckusick vput(vp); 53040640Smckusick } 53141400Smckusick return (NULLVP); 53239433Smckusick } 53339484Smckusick VOP_UNLOCK(vp); 53439484Smckusick vclean(vp, 0); 53539433Smckusick vp->v_op = nvp->v_op; 53639433Smckusick vp->v_tag = nvp->v_tag; 53739433Smckusick nvp->v_type = VNON; 53839433Smckusick insmntque(vp, mp); 53939433Smckusick return (vp); 54039433Smckusick } 54139433Smckusick 54239433Smckusick /* 54339433Smckusick * Grab a particular vnode from the free list, increment its 54439433Smckusick * reference count and lock it. The vnode lock bit is set the 54539433Smckusick * vnode is being eliminated in vgone. The process is awakened 54639433Smckusick * when the transition is completed, and an error returned to 54739433Smckusick * indicate that the vnode is no longer usable (possibly having 54839433Smckusick * been changed to a new file system type). 54939433Smckusick */ 55065260Smckusick vget(vp, lockflag) 55139397Smckusick register struct vnode *vp; 55265260Smckusick int lockflag; 55339397Smckusick { 55439397Smckusick 55539433Smckusick if (vp->v_flag & VXLOCK) { 55639433Smckusick vp->v_flag |= VXWANT; 55739433Smckusick sleep((caddr_t)vp, PINOD); 55839433Smckusick return (1); 55939433Smckusick } 560*65679Shibler if (vp->v_usecount == 0) 56165260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 56259450Smckusick vp->v_usecount++; 56365260Smckusick if (lockflag) 56465260Smckusick VOP_LOCK(vp); 56539433Smckusick return (0); 56639397Smckusick } 56739397Smckusick 56839397Smckusick /* 56939397Smckusick * Vnode reference, just increment the count 57039397Smckusick */ 57139397Smckusick void vref(vp) 57239397Smckusick struct vnode *vp; 57339397Smckusick { 57439397Smckusick 57559450Smckusick if (vp->v_usecount <= 0) 57659450Smckusick panic("vref used where vget required"); 57739809Smckusick vp->v_usecount++; 57839397Smckusick } 57939397Smckusick 58039397Smckusick /* 58139397Smckusick * vput(), just unlock and vrele() 58239397Smckusick */ 58339397Smckusick void vput(vp) 58439397Smckusick register struct vnode *vp; 58539397Smckusick { 58652416Storek 58739397Smckusick VOP_UNLOCK(vp); 58839397Smckusick vrele(vp); 58939397Smckusick } 59039397Smckusick 59139397Smckusick /* 59239397Smckusick * Vnode release. 59339397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59439397Smckusick */ 59539397Smckusick void vrele(vp) 59639397Smckusick register struct vnode *vp; 59739397Smckusick { 59839397Smckusick 59950109Smckusick #ifdef DIAGNOSTIC 60039397Smckusick if (vp == NULL) 60139433Smckusick panic("vrele: null vp"); 60250109Smckusick #endif 60339809Smckusick vp->v_usecount--; 60439809Smckusick if (vp->v_usecount > 0) 60539397Smckusick return; 60650109Smckusick #ifdef DIAGNOSTIC 60750109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 60850109Smckusick vprint("vrele: bad ref count", vp); 60950109Smckusick panic("vrele: ref cnt"); 61050109Smckusick } 61150109Smckusick #endif 61255468Smckusick /* 61355468Smckusick * insert at tail of LRU list 61455468Smckusick */ 61565260Smckusick TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 61654442Smckusick VOP_INACTIVE(vp); 61739397Smckusick } 61839433Smckusick 61939433Smckusick /* 62039809Smckusick * Page or buffer structure gets a reference. 62139809Smckusick */ 62253312Smckusick void vhold(vp) 62339809Smckusick register struct vnode *vp; 62439809Smckusick { 62539809Smckusick 62639809Smckusick vp->v_holdcnt++; 62739809Smckusick } 62839809Smckusick 62939809Smckusick /* 63039809Smckusick * Page or buffer structure frees a reference. 63139809Smckusick */ 63253312Smckusick void holdrele(vp) 63339809Smckusick register struct vnode *vp; 63439809Smckusick { 63539809Smckusick 63639809Smckusick if (vp->v_holdcnt <= 0) 63739809Smckusick panic("holdrele: holdcnt"); 63839809Smckusick vp->v_holdcnt--; 63939809Smckusick } 64039809Smckusick 64139809Smckusick /* 64239509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 64339509Smckusick * 64439509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 64539509Smckusick * return error if any are found (nb: this is a user error, not a 64639509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 64739509Smckusick * that are found. 64839509Smckusick */ 649*65679Shibler #ifdef DIAGNOSTIC 65060930Smckusick int busyprt = 0; /* print out busy vnodes */ 65160930Smckusick struct ctldebug debug1 = { "busyprt", &busyprt }; 652*65679Shibler #endif 65339509Smckusick 65439509Smckusick vflush(mp, skipvp, flags) 65539509Smckusick struct mount *mp; 65639509Smckusick struct vnode *skipvp; 65739509Smckusick int flags; 65839509Smckusick { 65939509Smckusick register struct vnode *vp, *nvp; 66039509Smckusick int busy = 0; 66139509Smckusick 66241400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 66341300Smckusick panic("vflush: not busy"); 66441421Smckusick loop: 66565260Smckusick for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 66641421Smckusick if (vp->v_mount != mp) 66741421Smckusick goto loop; 66865260Smckusick nvp = vp->v_mntvnodes.le_next; 66939509Smckusick /* 67039509Smckusick * Skip over a selected vnode. 67139509Smckusick */ 67239509Smckusick if (vp == skipvp) 67339509Smckusick continue; 67439509Smckusick /* 67541300Smckusick * Skip over a vnodes marked VSYSTEM. 67641300Smckusick */ 67741300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 67841300Smckusick continue; 67941300Smckusick /* 68057040Smckusick * If WRITECLOSE is set, only flush out regular file 68157040Smckusick * vnodes open for writing. 68257040Smckusick */ 68357040Smckusick if ((flags & WRITECLOSE) && 68457040Smckusick (vp->v_writecount == 0 || vp->v_type != VREG)) 68557040Smckusick continue; 68657040Smckusick /* 68739809Smckusick * With v_usecount == 0, all we need to do is clear 68839509Smckusick * out the vnode data structures and we are done. 68939509Smckusick */ 69039809Smckusick if (vp->v_usecount == 0) { 69139509Smckusick vgone(vp); 69239509Smckusick continue; 69339509Smckusick } 69439509Smckusick /* 69557040Smckusick * If FORCECLOSE is set, forcibly close the vnode. 69639509Smckusick * For block or character devices, revert to an 69739509Smckusick * anonymous device. For all other files, just kill them. 69839509Smckusick */ 69941300Smckusick if (flags & FORCECLOSE) { 70039509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 70139509Smckusick vgone(vp); 70239509Smckusick } else { 70339509Smckusick vclean(vp, 0); 70453547Sheideman vp->v_op = spec_vnodeop_p; 70539509Smckusick insmntque(vp, (struct mount *)0); 70639509Smckusick } 70739509Smckusick continue; 70839509Smckusick } 709*65679Shibler #ifdef DIAGNOSTIC 71039509Smckusick if (busyprt) 71139667Smckusick vprint("vflush: busy vnode", vp); 712*65679Shibler #endif 71339509Smckusick busy++; 71439509Smckusick } 71539509Smckusick if (busy) 71639509Smckusick return (EBUSY); 71739509Smckusick return (0); 71839509Smckusick } 71939509Smckusick 72039509Smckusick /* 72139433Smckusick * Disassociate the underlying file system from a vnode. 72239433Smckusick */ 72354347Smckusick void 72454347Smckusick vclean(vp, flags) 72539433Smckusick register struct vnode *vp; 72645118Smckusick int flags; 72739433Smckusick { 72839484Smckusick int active; 72939433Smckusick 73039484Smckusick /* 73139484Smckusick * Check to see if the vnode is in use. 73239667Smckusick * If so we have to reference it before we clean it out 73339667Smckusick * so that its count cannot fall to zero and generate a 73439667Smckusick * race against ourselves to recycle it. 73539484Smckusick */ 73639809Smckusick if (active = vp->v_usecount) 73739484Smckusick VREF(vp); 73839484Smckusick /* 73956805Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 74056805Smckusick * have the object locked while it cleans it out. The VOP_LOCK 74156805Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 74256805Smckusick * For active vnodes, it ensures that no other activity can 74356805Smckusick * occur while the underlying object is being cleaned out. 74456805Smckusick */ 74556805Smckusick VOP_LOCK(vp); 74656805Smckusick /* 74739484Smckusick * Prevent the vnode from being recycled or 74839484Smckusick * brought into use while we clean it out. 74939484Smckusick */ 75039667Smckusick if (vp->v_flag & VXLOCK) 75139667Smckusick panic("vclean: deadlock"); 75239433Smckusick vp->v_flag |= VXLOCK; 75339433Smckusick /* 75456805Smckusick * Clean out any buffers associated with the vnode. 75539667Smckusick */ 75641300Smckusick if (flags & DOCLOSE) 75757792Smckusick vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); 75839667Smckusick /* 75956805Smckusick * Any other processes trying to obtain this lock must first 76056805Smckusick * wait for VXLOCK to clear, then call the new lock operation. 76139433Smckusick */ 76256805Smckusick VOP_UNLOCK(vp); 76339433Smckusick /* 76456805Smckusick * If purging an active vnode, it must be closed and 76556805Smckusick * deactivated before being reclaimed. 76639433Smckusick */ 76739484Smckusick if (active) { 76856805Smckusick if (flags & DOCLOSE) 76956805Smckusick VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL); 77056805Smckusick VOP_INACTIVE(vp); 77139433Smckusick } 77239433Smckusick /* 77339433Smckusick * Reclaim the vnode. 77439433Smckusick */ 77556805Smckusick if (VOP_RECLAIM(vp)) 77639433Smckusick panic("vclean: cannot reclaim"); 77739484Smckusick if (active) 77839484Smckusick vrele(vp); 77953580Sheideman 78039433Smckusick /* 78156805Smckusick * Done with purge, notify sleepers of the grim news. 78239433Smckusick */ 78356805Smckusick vp->v_op = dead_vnodeop_p; 78456805Smckusick vp->v_tag = VT_NON; 78539433Smckusick vp->v_flag &= ~VXLOCK; 78639433Smckusick if (vp->v_flag & VXWANT) { 78739433Smckusick vp->v_flag &= ~VXWANT; 78839433Smckusick wakeup((caddr_t)vp); 78939433Smckusick } 79039433Smckusick } 79139433Smckusick 79239433Smckusick /* 79339633Smckusick * Eliminate all activity associated with the requested vnode 79439633Smckusick * and with all vnodes aliased to the requested vnode. 79539633Smckusick */ 79639633Smckusick void vgoneall(vp) 79739633Smckusick register struct vnode *vp; 79839633Smckusick { 79939809Smckusick register struct vnode *vq; 80039633Smckusick 80140665Smckusick if (vp->v_flag & VALIASED) { 80240665Smckusick /* 80340665Smckusick * If a vgone (or vclean) is already in progress, 80440665Smckusick * wait until it is done and return. 80540665Smckusick */ 80640665Smckusick if (vp->v_flag & VXLOCK) { 80740665Smckusick vp->v_flag |= VXWANT; 80840665Smckusick sleep((caddr_t)vp, PINOD); 80940665Smckusick return; 81039633Smckusick } 81140665Smckusick /* 81240665Smckusick * Ensure that vp will not be vgone'd while we 81340665Smckusick * are eliminating its aliases. 81440665Smckusick */ 81540665Smckusick vp->v_flag |= VXLOCK; 81640665Smckusick while (vp->v_flag & VALIASED) { 81740665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 81840665Smckusick if (vq->v_rdev != vp->v_rdev || 81940665Smckusick vq->v_type != vp->v_type || vp == vq) 82040665Smckusick continue; 82140665Smckusick vgone(vq); 82240665Smckusick break; 82340665Smckusick } 82440665Smckusick } 82540665Smckusick /* 82640665Smckusick * Remove the lock so that vgone below will 82740665Smckusick * really eliminate the vnode after which time 82840665Smckusick * vgone will awaken any sleepers. 82940665Smckusick */ 83040665Smckusick vp->v_flag &= ~VXLOCK; 83139633Smckusick } 83239633Smckusick vgone(vp); 83339633Smckusick } 83439633Smckusick 83539633Smckusick /* 83639433Smckusick * Eliminate all activity associated with a vnode 83739433Smckusick * in preparation for reuse. 83839433Smckusick */ 83939433Smckusick void vgone(vp) 84039433Smckusick register struct vnode *vp; 84139433Smckusick { 84239809Smckusick register struct vnode *vq; 84339615Smckusick struct vnode *vx; 84439433Smckusick 84539433Smckusick /* 84640548Smckusick * If a vgone (or vclean) is already in progress, 84740548Smckusick * wait until it is done and return. 84840548Smckusick */ 84940548Smckusick if (vp->v_flag & VXLOCK) { 85040548Smckusick vp->v_flag |= VXWANT; 85140548Smckusick sleep((caddr_t)vp, PINOD); 85240548Smckusick return; 85340548Smckusick } 85440548Smckusick /* 85539433Smckusick * Clean out the filesystem specific data. 85639433Smckusick */ 85741300Smckusick vclean(vp, DOCLOSE); 85839433Smckusick /* 85939433Smckusick * Delete from old mount point vnode list, if on one. 86039433Smckusick */ 86165260Smckusick if (vp->v_mount != NULL) { 86265260Smckusick LIST_REMOVE(vp, v_mntvnodes); 86352311Smckusick vp->v_mount = NULL; 86439433Smckusick } 86539433Smckusick /* 86639433Smckusick * If special device, remove it from special device alias list. 86739433Smckusick */ 86839433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 86939809Smckusick if (*vp->v_hashchain == vp) { 87039809Smckusick *vp->v_hashchain = vp->v_specnext; 87139433Smckusick } else { 87239809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 87339615Smckusick if (vq->v_specnext != vp) 87439433Smckusick continue; 87539615Smckusick vq->v_specnext = vp->v_specnext; 87639433Smckusick break; 87739433Smckusick } 87839615Smckusick if (vq == NULL) 87939433Smckusick panic("missing bdev"); 88039433Smckusick } 88139615Smckusick if (vp->v_flag & VALIASED) { 88252416Storek vx = NULL; 88339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 88440108Smckusick if (vq->v_rdev != vp->v_rdev || 88540108Smckusick vq->v_type != vp->v_type) 88639615Smckusick continue; 88752416Storek if (vx) 88852416Storek break; 88939615Smckusick vx = vq; 89039615Smckusick } 89152416Storek if (vx == NULL) 89239615Smckusick panic("missing alias"); 89352416Storek if (vq == NULL) 89439615Smckusick vx->v_flag &= ~VALIASED; 89539615Smckusick vp->v_flag &= ~VALIASED; 89639615Smckusick } 89739615Smckusick FREE(vp->v_specinfo, M_VNODE); 89839615Smckusick vp->v_specinfo = NULL; 89939433Smckusick } 90039433Smckusick /* 90156932Smckusick * If it is on the freelist and not already at the head, 90265505Smckusick * move it to the head of the list. The test of the back 90365505Smckusick * pointer and the reference count of zero is because 90465505Smckusick * it will be removed from the free list by getnewvnode, 90565505Smckusick * but will not have its reference count incremented until 90665505Smckusick * after calling vgone. If the reference count were 90765505Smckusick * incremented first, vgone would (incorrectly) try to 90865505Smckusick * close the previous instance of the underlying object. 90965505Smckusick * So, the back pointer is explicitly set to `0xdeadb' in 91065505Smckusick * getnewvnode after removing it from the freelist to ensure 91165505Smckusick * that we do not try to move it here. 91239433Smckusick */ 91365505Smckusick if (vp->v_usecount == 0 && 91465505Smckusick vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb && 91565505Smckusick vnode_free_list.tqh_first != vp) { 91665260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 91765260Smckusick TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 91839433Smckusick } 91939484Smckusick vp->v_type = VBAD; 92039433Smckusick } 92139633Smckusick 92239633Smckusick /* 92339821Smckusick * Lookup a vnode by device number. 92439821Smckusick */ 92539821Smckusick vfinddev(dev, type, vpp) 92639821Smckusick dev_t dev; 92739821Smckusick enum vtype type; 92839821Smckusick struct vnode **vpp; 92939821Smckusick { 93039821Smckusick register struct vnode *vp; 93139821Smckusick 93239821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 93339821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 93439821Smckusick continue; 93539821Smckusick *vpp = vp; 93659484Smckusick return (1); 93739821Smckusick } 93859484Smckusick return (0); 93939821Smckusick } 94039821Smckusick 94139821Smckusick /* 94239633Smckusick * Calculate the total number of references to a special device. 94339633Smckusick */ 94439633Smckusick vcount(vp) 94539633Smckusick register struct vnode *vp; 94639633Smckusick { 94739809Smckusick register struct vnode *vq; 94839633Smckusick int count; 94939633Smckusick 95039633Smckusick if ((vp->v_flag & VALIASED) == 0) 95139809Smckusick return (vp->v_usecount); 95239633Smckusick loop: 95339809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 95440108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 95539633Smckusick continue; 95639633Smckusick /* 95739633Smckusick * Alias, but not in use, so flush it out. 95839633Smckusick */ 95939809Smckusick if (vq->v_usecount == 0) { 96039633Smckusick vgone(vq); 96139633Smckusick goto loop; 96239633Smckusick } 96339809Smckusick count += vq->v_usecount; 96439633Smckusick } 96539633Smckusick return (count); 96639633Smckusick } 96739667Smckusick 96839667Smckusick /* 96939667Smckusick * Print out a description of a vnode. 97039667Smckusick */ 97139667Smckusick static char *typename[] = 97240286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 97339667Smckusick 97439667Smckusick vprint(label, vp) 97539667Smckusick char *label; 97639667Smckusick register struct vnode *vp; 97739667Smckusick { 97839913Smckusick char buf[64]; 97939667Smckusick 98039667Smckusick if (label != NULL) 98139667Smckusick printf("%s: ", label); 98250109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 98350109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 98450109Smckusick vp->v_holdcnt); 98539913Smckusick buf[0] = '\0'; 98639913Smckusick if (vp->v_flag & VROOT) 98739913Smckusick strcat(buf, "|VROOT"); 98839913Smckusick if (vp->v_flag & VTEXT) 98939913Smckusick strcat(buf, "|VTEXT"); 99041300Smckusick if (vp->v_flag & VSYSTEM) 99141300Smckusick strcat(buf, "|VSYSTEM"); 99241300Smckusick if (vp->v_flag & VXLOCK) 99341300Smckusick strcat(buf, "|VXLOCK"); 99441300Smckusick if (vp->v_flag & VXWANT) 99541300Smckusick strcat(buf, "|VXWANT"); 99641300Smckusick if (vp->v_flag & VBWAIT) 99741300Smckusick strcat(buf, "|VBWAIT"); 99839913Smckusick if (vp->v_flag & VALIASED) 99939913Smckusick strcat(buf, "|VALIASED"); 100039913Smckusick if (buf[0] != '\0') 100139913Smckusick printf(" flags (%s)", &buf[1]); 100265260Smckusick if (vp->v_data == NULL) { 100365260Smckusick printf("\n"); 100465260Smckusick } else { 100565260Smckusick printf("\n\t"); 100665260Smckusick VOP_PRINT(vp); 100765260Smckusick } 100839667Smckusick } 100941110Smarc 101049691Smckusick #ifdef DEBUG 101149691Smckusick /* 101249691Smckusick * List all of the locked vnodes in the system. 101349691Smckusick * Called when debugging the kernel. 101449691Smckusick */ 101549691Smckusick printlockedvnodes() 101649691Smckusick { 101749691Smckusick register struct mount *mp; 101849691Smckusick register struct vnode *vp; 101949691Smckusick 102049691Smckusick printf("Locked vnodes\n"); 102165260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { 102265260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 102365260Smckusick vp != NULL; 102465260Smckusick vp = vp->v_mntvnodes.le_next) 102549691Smckusick if (VOP_ISLOCKED(vp)) 102649691Smckusick vprint((char *)0, vp); 102765260Smckusick } 102849691Smckusick } 102949691Smckusick #endif 103049691Smckusick 103141110Smarc int kinfo_vdebug = 1; 103241110Smarc int kinfo_vgetfailed; 103341110Smarc #define KINFO_VNODESLOP 10 103441110Smarc /* 103557841Smckusick * Dump vnode list (via sysctl). 103641110Smarc * Copyout address of vnode followed by vnode. 103741110Smarc */ 103845118Smckusick /* ARGSUSED */ 103957841Smckusick sysctl_vnode(where, sizep) 104041110Smarc char *where; 104158465Sbostic size_t *sizep; 104241110Smarc { 104365260Smckusick register struct mount *mp, *nmp; 104441110Smarc struct vnode *vp; 104541110Smarc register char *bp = where, *savebp; 104653818Smckusick char *ewhere; 104741110Smarc int error; 104841110Smarc 104941110Smarc #define VPTRSZ sizeof (struct vnode *) 105041110Smarc #define VNODESZ sizeof (struct vnode) 105141110Smarc if (where == NULL) { 105257841Smckusick *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 105341110Smarc return (0); 105441110Smarc } 105557841Smckusick ewhere = where + *sizep; 105641110Smarc 105765260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 105865260Smckusick nmp = mp->mnt_list.tqe_next; 105965260Smckusick if (vfs_busy(mp)) 106041300Smckusick continue; 106141110Smarc savebp = bp; 106241110Smarc again: 106365260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 106465260Smckusick vp != NULL; 106565260Smckusick vp = vp->v_mntvnodes.le_next) { 106641422Smckusick /* 106741422Smckusick * Check that the vp is still associated with 106841422Smckusick * this filesystem. RACE: could have been 106941422Smckusick * recycled onto the same filesystem. 107041422Smckusick */ 107141421Smckusick if (vp->v_mount != mp) { 107241421Smckusick if (kinfo_vdebug) 107341421Smckusick printf("kinfo: vp changed\n"); 107441421Smckusick bp = savebp; 107541421Smckusick goto again; 107641421Smckusick } 107757841Smckusick if (bp + VPTRSZ + VNODESZ > ewhere) { 107857841Smckusick *sizep = bp - where; 107957841Smckusick return (ENOMEM); 108057841Smckusick } 108157841Smckusick if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 108257841Smckusick (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ))) 108341110Smarc return (error); 108441110Smarc bp += VPTRSZ + VNODESZ; 108541110Smarc } 108665260Smckusick vfs_unbusy(mp); 108765260Smckusick } 108841110Smarc 108957841Smckusick *sizep = bp - where; 109041110Smarc return (0); 109141110Smarc } 1092*65679Shibler 1093*65679Shibler /* 1094*65679Shibler * Check to see if a filesystem is mounted on a block device. 1095*65679Shibler */ 1096*65679Shibler int 1097*65679Shibler vfs_mountedon(vp) 1098*65679Shibler register struct vnode *vp; 1099*65679Shibler { 1100*65679Shibler register struct vnode *vq; 1101*65679Shibler 1102*65679Shibler if (vp->v_specflags & SI_MOUNTEDON) 1103*65679Shibler return (EBUSY); 1104*65679Shibler if (vp->v_flag & VALIASED) { 1105*65679Shibler for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1106*65679Shibler if (vq->v_rdev != vp->v_rdev || 1107*65679Shibler vq->v_type != vp->v_type) 1108*65679Shibler continue; 1109*65679Shibler if (vq->v_specflags & SI_MOUNTEDON) 1110*65679Shibler return (EBUSY); 1111*65679Shibler } 1112*65679Shibler } 1113*65679Shibler return (0); 1114*65679Shibler } 1115*65679Shibler 1116*65679Shibler /* 1117*65679Shibler * Build hash lists of net addresses and hang them off the mount point. 1118*65679Shibler * Called by ufs_mount() to set up the lists of export addresses. 1119*65679Shibler */ 1120*65679Shibler static int 1121*65679Shibler vfs_hang_addrlist(mp, nep, argp) 1122*65679Shibler struct mount *mp; 1123*65679Shibler struct netexport *nep; 1124*65679Shibler struct export_args *argp; 1125*65679Shibler { 1126*65679Shibler register struct netcred *np; 1127*65679Shibler register struct radix_node_head *rnh; 1128*65679Shibler register int i; 1129*65679Shibler struct radix_node *rn; 1130*65679Shibler struct sockaddr *saddr, *smask = 0; 1131*65679Shibler struct domain *dom; 1132*65679Shibler int error; 1133*65679Shibler 1134*65679Shibler if (argp->ex_addrlen == 0) { 1135*65679Shibler if (mp->mnt_flag & MNT_DEFEXPORTED) 1136*65679Shibler return (EPERM); 1137*65679Shibler np = &nep->ne_defexported; 1138*65679Shibler np->netc_exflags = argp->ex_flags; 1139*65679Shibler np->netc_anon = argp->ex_anon; 1140*65679Shibler np->netc_anon.cr_ref = 1; 1141*65679Shibler mp->mnt_flag |= MNT_DEFEXPORTED; 1142*65679Shibler return (0); 1143*65679Shibler } 1144*65679Shibler i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 1145*65679Shibler np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); 1146*65679Shibler bzero((caddr_t)np, i); 1147*65679Shibler saddr = (struct sockaddr *)(np + 1); 1148*65679Shibler if (error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen)) 1149*65679Shibler goto out; 1150*65679Shibler if (saddr->sa_len > argp->ex_addrlen) 1151*65679Shibler saddr->sa_len = argp->ex_addrlen; 1152*65679Shibler if (argp->ex_masklen) { 1153*65679Shibler smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); 1154*65679Shibler error = copyin(argp->ex_addr, (caddr_t)smask, argp->ex_masklen); 1155*65679Shibler if (error) 1156*65679Shibler goto out; 1157*65679Shibler if (smask->sa_len > argp->ex_masklen) 1158*65679Shibler smask->sa_len = argp->ex_masklen; 1159*65679Shibler } 1160*65679Shibler i = saddr->sa_family; 1161*65679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 1162*65679Shibler /* 1163*65679Shibler * Seems silly to initialize every AF when most are not 1164*65679Shibler * used, do so on demand here 1165*65679Shibler */ 1166*65679Shibler for (dom = domains; dom; dom = dom->dom_next) 1167*65679Shibler if (dom->dom_family == i && dom->dom_rtattach) { 1168*65679Shibler dom->dom_rtattach((void **)&nep->ne_rtable[i], 1169*65679Shibler dom->dom_rtoffset); 1170*65679Shibler break; 1171*65679Shibler } 1172*65679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 1173*65679Shibler error = ENOBUFS; 1174*65679Shibler goto out; 1175*65679Shibler } 1176*65679Shibler } 1177*65679Shibler rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, 1178*65679Shibler np->netc_rnodes); 1179*65679Shibler if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ 1180*65679Shibler error = EPERM; 1181*65679Shibler goto out; 1182*65679Shibler } 1183*65679Shibler np->netc_exflags = argp->ex_flags; 1184*65679Shibler np->netc_anon = argp->ex_anon; 1185*65679Shibler np->netc_anon.cr_ref = 1; 1186*65679Shibler return (0); 1187*65679Shibler out: 1188*65679Shibler free(np, M_NETADDR); 1189*65679Shibler return (error); 1190*65679Shibler } 1191*65679Shibler 1192*65679Shibler /* ARGSUSED */ 1193*65679Shibler static int 1194*65679Shibler vfs_free_netcred(rn, w) 1195*65679Shibler struct radix_node *rn; 1196*65679Shibler caddr_t w; 1197*65679Shibler { 1198*65679Shibler register struct radix_node_head *rnh = (struct radix_node_head *)w; 1199*65679Shibler 1200*65679Shibler (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); 1201*65679Shibler free((caddr_t)rn, M_NETADDR); 1202*65679Shibler return (0); 1203*65679Shibler } 1204*65679Shibler 1205*65679Shibler /* 1206*65679Shibler * Free the net address hash lists that are hanging off the mount points. 1207*65679Shibler */ 1208*65679Shibler static void 1209*65679Shibler vfs_free_addrlist(nep) 1210*65679Shibler struct netexport *nep; 1211*65679Shibler { 1212*65679Shibler register int i; 1213*65679Shibler register struct radix_node_head *rnh; 1214*65679Shibler 1215*65679Shibler for (i = 0; i <= AF_MAX; i++) 1216*65679Shibler if (rnh = nep->ne_rtable[i]) { 1217*65679Shibler (*rnh->rnh_walktree)(rnh, vfs_free_netcred, 1218*65679Shibler (caddr_t)rnh); 1219*65679Shibler free((caddr_t)rnh, M_RTABLE); 1220*65679Shibler nep->ne_rtable[i] = 0; 1221*65679Shibler } 1222*65679Shibler } 1223*65679Shibler 1224*65679Shibler int 1225*65679Shibler vfs_export(mp, nep, argp) 1226*65679Shibler struct mount *mp; 1227*65679Shibler struct netexport *nep; 1228*65679Shibler struct export_args *argp; 1229*65679Shibler { 1230*65679Shibler int error; 1231*65679Shibler 1232*65679Shibler if (argp->ex_flags & MNT_DELEXPORT) { 1233*65679Shibler vfs_free_addrlist(nep); 1234*65679Shibler mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 1235*65679Shibler } 1236*65679Shibler if (argp->ex_flags & MNT_EXPORTED) { 1237*65679Shibler if (error = vfs_hang_addrlist(mp, nep, argp)) 1238*65679Shibler return (error); 1239*65679Shibler mp->mnt_flag |= MNT_EXPORTED; 1240*65679Shibler } 1241*65679Shibler return (0); 1242*65679Shibler } 1243*65679Shibler 1244*65679Shibler struct netcred * 1245*65679Shibler vfs_export_lookup(mp, nep, nam) 1246*65679Shibler register struct mount *mp; 1247*65679Shibler struct netexport *nep; 1248*65679Shibler struct mbuf *nam; 1249*65679Shibler { 1250*65679Shibler register struct netcred *np; 1251*65679Shibler register struct radix_node_head *rnh; 1252*65679Shibler struct sockaddr *saddr; 1253*65679Shibler 1254*65679Shibler np = NULL; 1255*65679Shibler if (mp->mnt_flag & MNT_EXPORTED) { 1256*65679Shibler /* 1257*65679Shibler * Lookup in the export list first. 1258*65679Shibler */ 1259*65679Shibler if (nam != NULL) { 1260*65679Shibler saddr = mtod(nam, struct sockaddr *); 1261*65679Shibler rnh = nep->ne_rtable[saddr->sa_family]; 1262*65679Shibler if (rnh != NULL) { 1263*65679Shibler np = (struct netcred *) 1264*65679Shibler (*rnh->rnh_matchaddr)((caddr_t)saddr, 1265*65679Shibler rnh); 1266*65679Shibler if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 1267*65679Shibler np = NULL; 1268*65679Shibler } 1269*65679Shibler } 1270*65679Shibler /* 1271*65679Shibler * If no address match, use the default if it exists. 1272*65679Shibler */ 1273*65679Shibler if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 1274*65679Shibler np = &nep->ne_defexported; 1275*65679Shibler } 1276*65679Shibler return (np); 1277*65679Shibler } 1278