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*65745Shibler * @(#)vfs_subr.c 8.8 (Berkeley) 01/14/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> 2665679Shibler #include <sys/domain.h> 2765679Shibler #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; 248*65745Shibler vp->v_ralen = 0; 249*65745Shibler vp->v_maxra = 0; 25057042Smargo vp->v_lastw = 0; 25157042Smargo vp->v_lasta = 0; 25257042Smargo vp->v_cstart = 0; 25357042Smargo vp->v_clen = 0; 25440883Smckusick vp->v_socket = 0; 25539397Smckusick } 25639512Smckusick vp->v_type = VNON; 25739397Smckusick cache_purge(vp); 25839397Smckusick vp->v_tag = tag; 25939433Smckusick vp->v_op = vops; 26039397Smckusick insmntque(vp, mp); 26139397Smckusick *vpp = vp; 26265505Smckusick vp->v_usecount = 1; 26365260Smckusick vp->v_data = 0; 26439397Smckusick return (0); 26539397Smckusick } 26665679Shibler 26739397Smckusick /* 26839397Smckusick * Move a vnode from one mount queue to another. 26939397Smckusick */ 27039397Smckusick insmntque(vp, mp) 27139397Smckusick register struct vnode *vp; 27239397Smckusick register struct mount *mp; 27339397Smckusick { 27439397Smckusick 27539397Smckusick /* 27639397Smckusick * Delete from old mount point vnode list, if on one. 27739397Smckusick */ 27865679Shibler if (vp->v_mount != NULL) 27965260Smckusick LIST_REMOVE(vp, v_mntvnodes); 28039397Smckusick /* 28139397Smckusick * Insert into list of vnodes for the new mount point, if available. 28239397Smckusick */ 28365260Smckusick if ((vp->v_mount = mp) == NULL) 28439397Smckusick return; 28565260Smckusick LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); 28639397Smckusick } 28739397Smckusick 28839397Smckusick /* 28949232Smckusick * Update outstanding I/O count and do wakeup if requested. 29049232Smckusick */ 29149232Smckusick vwakeup(bp) 29249232Smckusick register struct buf *bp; 29349232Smckusick { 29449232Smckusick register struct vnode *vp; 29549232Smckusick 29657810Smckusick bp->b_flags &= ~B_WRITEINPROG; 29749232Smckusick if (vp = bp->b_vp) { 29849232Smckusick vp->v_numoutput--; 29957042Smargo if (vp->v_numoutput < 0) 30057042Smargo panic("vwakeup: neg numoutput"); 30149232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 30249232Smckusick if (vp->v_numoutput < 0) 30349232Smckusick panic("vwakeup: neg numoutput"); 30449232Smckusick vp->v_flag &= ~VBWAIT; 30549232Smckusick wakeup((caddr_t)&vp->v_numoutput); 30649232Smckusick } 30749232Smckusick } 30849232Smckusick } 30949232Smckusick 31049232Smckusick /* 31149232Smckusick * Flush out and invalidate all buffers associated with a vnode. 31249232Smckusick * Called with the underlying object locked. 31349232Smckusick */ 31454442Smckusick int 31557792Smckusick vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 31649232Smckusick register struct vnode *vp; 31756459Smargo int flags; 31854442Smckusick struct ucred *cred; 31954442Smckusick struct proc *p; 32057792Smckusick int slpflag, slptimeo; 32149232Smckusick { 32249232Smckusick register struct buf *bp; 32349232Smckusick struct buf *nbp, *blist; 32454442Smckusick int s, error; 32549232Smckusick 32656459Smargo if (flags & V_SAVE) { 32754442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 32854442Smckusick return (error); 32965260Smckusick if (vp->v_dirtyblkhd.lh_first != NULL) 33054442Smckusick panic("vinvalbuf: dirty bufs"); 33154442Smckusick } 33249232Smckusick for (;;) { 33365260Smckusick if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA) 33456459Smargo while (blist && blist->b_lblkno < 0) 33565260Smckusick blist = blist->b_vnbufs.le_next; 33665260Smckusick if (!blist && (blist = vp->v_dirtyblkhd.lh_first) && 33756608Smckusick (flags & V_SAVEMETA)) 33856459Smargo while (blist && blist->b_lblkno < 0) 33965260Smckusick blist = blist->b_vnbufs.le_next; 34056459Smargo if (!blist) 34149232Smckusick break; 34256459Smargo 34349232Smckusick for (bp = blist; bp; bp = nbp) { 34465260Smckusick nbp = bp->b_vnbufs.le_next; 34556459Smargo if (flags & V_SAVEMETA && bp->b_lblkno < 0) 34656459Smargo continue; 34749232Smckusick s = splbio(); 34849232Smckusick if (bp->b_flags & B_BUSY) { 34949232Smckusick bp->b_flags |= B_WANTED; 35057792Smckusick error = tsleep((caddr_t)bp, 35157792Smckusick slpflag | (PRIBIO + 1), "vinvalbuf", 35257792Smckusick slptimeo); 35349232Smckusick splx(s); 35457792Smckusick if (error) 35557792Smckusick return (error); 35649232Smckusick break; 35749232Smckusick } 35849232Smckusick bremfree(bp); 35949232Smckusick bp->b_flags |= B_BUSY; 36049232Smckusick splx(s); 36157792Smckusick /* 36257792Smckusick * XXX Since there are no node locks for NFS, I believe 36357792Smckusick * there is a slight chance that a delayed write will 36457792Smckusick * occur while sleeping just above, so check for it. 36557792Smckusick */ 36657792Smckusick if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 36757792Smckusick (void) VOP_BWRITE(bp); 36857792Smckusick break; 36957792Smckusick } 37056459Smargo bp->b_flags |= B_INVAL; 37149232Smckusick brelse(bp); 37249232Smckusick } 37349232Smckusick } 37456608Smckusick if (!(flags & V_SAVEMETA) && 37565260Smckusick (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first)) 37649232Smckusick panic("vinvalbuf: flush failed"); 37754442Smckusick return (0); 37849232Smckusick } 37949232Smckusick 38049232Smckusick /* 38149232Smckusick * Associate a buffer with a vnode. 38249232Smckusick */ 38349232Smckusick bgetvp(vp, bp) 38449232Smckusick register struct vnode *vp; 38549232Smckusick register struct buf *bp; 38649232Smckusick { 38749232Smckusick 38849232Smckusick if (bp->b_vp) 38949232Smckusick panic("bgetvp: not free"); 39049232Smckusick VHOLD(vp); 39149232Smckusick bp->b_vp = vp; 39249232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 39349232Smckusick bp->b_dev = vp->v_rdev; 39449232Smckusick else 39549232Smckusick bp->b_dev = NODEV; 39649232Smckusick /* 39749232Smckusick * Insert onto list for new vnode. 39849232Smckusick */ 39956608Smckusick bufinsvn(bp, &vp->v_cleanblkhd); 40049232Smckusick } 40149232Smckusick 40249232Smckusick /* 40349232Smckusick * Disassociate a buffer from a vnode. 40449232Smckusick */ 40549232Smckusick brelvp(bp) 40649232Smckusick register struct buf *bp; 40749232Smckusick { 40849232Smckusick struct vnode *vp; 40949232Smckusick 41049232Smckusick if (bp->b_vp == (struct vnode *) 0) 41149232Smckusick panic("brelvp: NULL"); 41249232Smckusick /* 41349232Smckusick * Delete from old vnode list, if on one. 41449232Smckusick */ 41565260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 41656608Smckusick bufremvn(bp); 41749232Smckusick vp = bp->b_vp; 41849232Smckusick bp->b_vp = (struct vnode *) 0; 41949232Smckusick HOLDRELE(vp); 42049232Smckusick } 42149232Smckusick 42249232Smckusick /* 42349232Smckusick * Reassign a buffer from one vnode to another. 42449232Smckusick * Used to assign file specific control information 42549232Smckusick * (indirect blocks) to the vnode to which they belong. 42649232Smckusick */ 42749232Smckusick reassignbuf(bp, newvp) 42849232Smckusick register struct buf *bp; 42949232Smckusick register struct vnode *newvp; 43049232Smckusick { 43165260Smckusick register struct buflists *listheadp; 43249232Smckusick 43352655Smckusick if (newvp == NULL) { 43452655Smckusick printf("reassignbuf: NULL"); 43552655Smckusick return; 43652655Smckusick } 43749232Smckusick /* 43849232Smckusick * Delete from old vnode list, if on one. 43949232Smckusick */ 44065260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 44156608Smckusick bufremvn(bp); 44249232Smckusick /* 44349232Smckusick * If dirty, put on list of dirty buffers; 44449232Smckusick * otherwise insert onto list of clean buffers. 44549232Smckusick */ 44649232Smckusick if (bp->b_flags & B_DELWRI) 44749232Smckusick listheadp = &newvp->v_dirtyblkhd; 44849232Smckusick else 44949232Smckusick listheadp = &newvp->v_cleanblkhd; 45056608Smckusick bufinsvn(bp, listheadp); 45149232Smckusick } 45249232Smckusick 45349232Smckusick /* 45439433Smckusick * Create a vnode for a block device. 45539433Smckusick * Used for root filesystem, argdev, and swap areas. 45639433Smckusick * Also used for memory file system special devices. 45739397Smckusick */ 45839433Smckusick bdevvp(dev, vpp) 45939433Smckusick dev_t dev; 46039433Smckusick struct vnode **vpp; 46139433Smckusick { 46239433Smckusick register struct vnode *vp; 46339433Smckusick struct vnode *nvp; 46439433Smckusick int error; 46539433Smckusick 46646989Smckusick if (dev == NODEV) 46746989Smckusick return (0); 46853547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 46939433Smckusick if (error) { 47039433Smckusick *vpp = 0; 47139433Smckusick return (error); 47239433Smckusick } 47339433Smckusick vp = nvp; 47439433Smckusick vp->v_type = VBLK; 47539615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 47639433Smckusick vput(vp); 47739433Smckusick vp = nvp; 47839433Smckusick } 47939433Smckusick *vpp = vp; 48039433Smckusick return (0); 48139433Smckusick } 48239433Smckusick 48339433Smckusick /* 48439433Smckusick * Check to see if the new vnode represents a special device 48539433Smckusick * for which we already have a vnode (either because of 48639433Smckusick * bdevvp() or because of a different vnode representing 48739433Smckusick * the same block device). If such an alias exists, deallocate 48839509Smckusick * the existing contents and return the aliased vnode. The 48939433Smckusick * caller is responsible for filling it with its new contents. 49039433Smckusick */ 49139433Smckusick struct vnode * 49239615Smckusick checkalias(nvp, nvp_rdev, mp) 49339433Smckusick register struct vnode *nvp; 49439615Smckusick dev_t nvp_rdev; 49539433Smckusick struct mount *mp; 49639433Smckusick { 49739433Smckusick register struct vnode *vp; 49839615Smckusick struct vnode **vpp; 49939433Smckusick 50039433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 50141400Smckusick return (NULLVP); 50239615Smckusick 50339615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 50439433Smckusick loop: 50539615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 50639615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 50739433Smckusick continue; 50839615Smckusick /* 50939615Smckusick * Alias, but not in use, so flush it out. 51039615Smckusick */ 51139809Smckusick if (vp->v_usecount == 0) { 51239615Smckusick vgone(vp); 51339615Smckusick goto loop; 51439615Smckusick } 51565260Smckusick if (vget(vp, 1)) 51639633Smckusick goto loop; 51739433Smckusick break; 51839433Smckusick } 51939615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 52039615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 52139615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 52239615Smckusick nvp->v_rdev = nvp_rdev; 52339809Smckusick nvp->v_hashchain = vpp; 52439615Smckusick nvp->v_specnext = *vpp; 52542152Smckusick nvp->v_specflags = 0; 52639615Smckusick *vpp = nvp; 52740640Smckusick if (vp != NULL) { 52840640Smckusick nvp->v_flag |= VALIASED; 52940640Smckusick vp->v_flag |= VALIASED; 53040640Smckusick vput(vp); 53140640Smckusick } 53241400Smckusick return (NULLVP); 53339433Smckusick } 53439484Smckusick VOP_UNLOCK(vp); 53539484Smckusick vclean(vp, 0); 53639433Smckusick vp->v_op = nvp->v_op; 53739433Smckusick vp->v_tag = nvp->v_tag; 53839433Smckusick nvp->v_type = VNON; 53939433Smckusick insmntque(vp, mp); 54039433Smckusick return (vp); 54139433Smckusick } 54239433Smckusick 54339433Smckusick /* 54439433Smckusick * Grab a particular vnode from the free list, increment its 54539433Smckusick * reference count and lock it. The vnode lock bit is set the 54639433Smckusick * vnode is being eliminated in vgone. The process is awakened 54739433Smckusick * when the transition is completed, and an error returned to 54839433Smckusick * indicate that the vnode is no longer usable (possibly having 54939433Smckusick * been changed to a new file system type). 55039433Smckusick */ 55165260Smckusick vget(vp, lockflag) 55239397Smckusick register struct vnode *vp; 55365260Smckusick int lockflag; 55439397Smckusick { 55539397Smckusick 55639433Smckusick if (vp->v_flag & VXLOCK) { 55739433Smckusick vp->v_flag |= VXWANT; 55839433Smckusick sleep((caddr_t)vp, PINOD); 55939433Smckusick return (1); 56039433Smckusick } 56165679Shibler if (vp->v_usecount == 0) 56265260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 56359450Smckusick vp->v_usecount++; 56465260Smckusick if (lockflag) 56565260Smckusick VOP_LOCK(vp); 56639433Smckusick return (0); 56739397Smckusick } 56839397Smckusick 56939397Smckusick /* 57039397Smckusick * Vnode reference, just increment the count 57139397Smckusick */ 57239397Smckusick void vref(vp) 57339397Smckusick struct vnode *vp; 57439397Smckusick { 57539397Smckusick 57659450Smckusick if (vp->v_usecount <= 0) 57759450Smckusick panic("vref used where vget required"); 57839809Smckusick vp->v_usecount++; 57939397Smckusick } 58039397Smckusick 58139397Smckusick /* 58239397Smckusick * vput(), just unlock and vrele() 58339397Smckusick */ 58439397Smckusick void vput(vp) 58539397Smckusick register struct vnode *vp; 58639397Smckusick { 58752416Storek 58839397Smckusick VOP_UNLOCK(vp); 58939397Smckusick vrele(vp); 59039397Smckusick } 59139397Smckusick 59239397Smckusick /* 59339397Smckusick * Vnode release. 59439397Smckusick * If count drops to zero, call inactive routine and return to freelist. 59539397Smckusick */ 59639397Smckusick void vrele(vp) 59739397Smckusick register struct vnode *vp; 59839397Smckusick { 59939397Smckusick 60050109Smckusick #ifdef DIAGNOSTIC 60139397Smckusick if (vp == NULL) 60239433Smckusick panic("vrele: null vp"); 60350109Smckusick #endif 60439809Smckusick vp->v_usecount--; 60539809Smckusick if (vp->v_usecount > 0) 60639397Smckusick return; 60750109Smckusick #ifdef DIAGNOSTIC 60850109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 60950109Smckusick vprint("vrele: bad ref count", vp); 61050109Smckusick panic("vrele: ref cnt"); 61150109Smckusick } 61250109Smckusick #endif 61355468Smckusick /* 61455468Smckusick * insert at tail of LRU list 61555468Smckusick */ 61665260Smckusick TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 61754442Smckusick VOP_INACTIVE(vp); 61839397Smckusick } 61939433Smckusick 62039433Smckusick /* 62139809Smckusick * Page or buffer structure gets a reference. 62239809Smckusick */ 62353312Smckusick void vhold(vp) 62439809Smckusick register struct vnode *vp; 62539809Smckusick { 62639809Smckusick 62739809Smckusick vp->v_holdcnt++; 62839809Smckusick } 62939809Smckusick 63039809Smckusick /* 63139809Smckusick * Page or buffer structure frees a reference. 63239809Smckusick */ 63353312Smckusick void holdrele(vp) 63439809Smckusick register struct vnode *vp; 63539809Smckusick { 63639809Smckusick 63739809Smckusick if (vp->v_holdcnt <= 0) 63839809Smckusick panic("holdrele: holdcnt"); 63939809Smckusick vp->v_holdcnt--; 64039809Smckusick } 64139809Smckusick 64239809Smckusick /* 64339509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 64439509Smckusick * 64539509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 64639509Smckusick * return error if any are found (nb: this is a user error, not a 64739509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 64839509Smckusick * that are found. 64939509Smckusick */ 65065679Shibler #ifdef DIAGNOSTIC 65160930Smckusick int busyprt = 0; /* print out busy vnodes */ 65260930Smckusick struct ctldebug debug1 = { "busyprt", &busyprt }; 65365679Shibler #endif 65439509Smckusick 65539509Smckusick vflush(mp, skipvp, flags) 65639509Smckusick struct mount *mp; 65739509Smckusick struct vnode *skipvp; 65839509Smckusick int flags; 65939509Smckusick { 66039509Smckusick register struct vnode *vp, *nvp; 66139509Smckusick int busy = 0; 66239509Smckusick 66341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 66441300Smckusick panic("vflush: not busy"); 66541421Smckusick loop: 66665260Smckusick for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 66741421Smckusick if (vp->v_mount != mp) 66841421Smckusick goto loop; 66965260Smckusick nvp = vp->v_mntvnodes.le_next; 67039509Smckusick /* 67139509Smckusick * Skip over a selected vnode. 67239509Smckusick */ 67339509Smckusick if (vp == skipvp) 67439509Smckusick continue; 67539509Smckusick /* 67641300Smckusick * Skip over a vnodes marked VSYSTEM. 67741300Smckusick */ 67841300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 67941300Smckusick continue; 68041300Smckusick /* 68157040Smckusick * If WRITECLOSE is set, only flush out regular file 68257040Smckusick * vnodes open for writing. 68357040Smckusick */ 68457040Smckusick if ((flags & WRITECLOSE) && 68557040Smckusick (vp->v_writecount == 0 || vp->v_type != VREG)) 68657040Smckusick continue; 68757040Smckusick /* 68839809Smckusick * With v_usecount == 0, all we need to do is clear 68939509Smckusick * out the vnode data structures and we are done. 69039509Smckusick */ 69139809Smckusick if (vp->v_usecount == 0) { 69239509Smckusick vgone(vp); 69339509Smckusick continue; 69439509Smckusick } 69539509Smckusick /* 69657040Smckusick * If FORCECLOSE is set, forcibly close the vnode. 69739509Smckusick * For block or character devices, revert to an 69839509Smckusick * anonymous device. For all other files, just kill them. 69939509Smckusick */ 70041300Smckusick if (flags & FORCECLOSE) { 70139509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 70239509Smckusick vgone(vp); 70339509Smckusick } else { 70439509Smckusick vclean(vp, 0); 70553547Sheideman vp->v_op = spec_vnodeop_p; 70639509Smckusick insmntque(vp, (struct mount *)0); 70739509Smckusick } 70839509Smckusick continue; 70939509Smckusick } 71065679Shibler #ifdef DIAGNOSTIC 71139509Smckusick if (busyprt) 71239667Smckusick vprint("vflush: busy vnode", vp); 71365679Shibler #endif 71439509Smckusick busy++; 71539509Smckusick } 71639509Smckusick if (busy) 71739509Smckusick return (EBUSY); 71839509Smckusick return (0); 71939509Smckusick } 72039509Smckusick 72139509Smckusick /* 72239433Smckusick * Disassociate the underlying file system from a vnode. 72339433Smckusick */ 72454347Smckusick void 72554347Smckusick vclean(vp, flags) 72639433Smckusick register struct vnode *vp; 72745118Smckusick int flags; 72839433Smckusick { 72939484Smckusick int active; 73039433Smckusick 73139484Smckusick /* 73239484Smckusick * Check to see if the vnode is in use. 73339667Smckusick * If so we have to reference it before we clean it out 73439667Smckusick * so that its count cannot fall to zero and generate a 73539667Smckusick * race against ourselves to recycle it. 73639484Smckusick */ 73739809Smckusick if (active = vp->v_usecount) 73839484Smckusick VREF(vp); 73939484Smckusick /* 74056805Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 74156805Smckusick * have the object locked while it cleans it out. The VOP_LOCK 74256805Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 74356805Smckusick * For active vnodes, it ensures that no other activity can 74456805Smckusick * occur while the underlying object is being cleaned out. 74556805Smckusick */ 74656805Smckusick VOP_LOCK(vp); 74756805Smckusick /* 74839484Smckusick * Prevent the vnode from being recycled or 74939484Smckusick * brought into use while we clean it out. 75039484Smckusick */ 75139667Smckusick if (vp->v_flag & VXLOCK) 75239667Smckusick panic("vclean: deadlock"); 75339433Smckusick vp->v_flag |= VXLOCK; 75439433Smckusick /* 75556805Smckusick * Clean out any buffers associated with the vnode. 75639667Smckusick */ 75741300Smckusick if (flags & DOCLOSE) 75857792Smckusick vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); 75939667Smckusick /* 76056805Smckusick * Any other processes trying to obtain this lock must first 76156805Smckusick * wait for VXLOCK to clear, then call the new lock operation. 76239433Smckusick */ 76356805Smckusick VOP_UNLOCK(vp); 76439433Smckusick /* 76556805Smckusick * If purging an active vnode, it must be closed and 76656805Smckusick * deactivated before being reclaimed. 76739433Smckusick */ 76839484Smckusick if (active) { 76956805Smckusick if (flags & DOCLOSE) 77056805Smckusick VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL); 77156805Smckusick VOP_INACTIVE(vp); 77239433Smckusick } 77339433Smckusick /* 77439433Smckusick * Reclaim the vnode. 77539433Smckusick */ 77656805Smckusick if (VOP_RECLAIM(vp)) 77739433Smckusick panic("vclean: cannot reclaim"); 77839484Smckusick if (active) 77939484Smckusick vrele(vp); 78053580Sheideman 78139433Smckusick /* 78256805Smckusick * Done with purge, notify sleepers of the grim news. 78339433Smckusick */ 78456805Smckusick vp->v_op = dead_vnodeop_p; 78556805Smckusick vp->v_tag = VT_NON; 78639433Smckusick vp->v_flag &= ~VXLOCK; 78739433Smckusick if (vp->v_flag & VXWANT) { 78839433Smckusick vp->v_flag &= ~VXWANT; 78939433Smckusick wakeup((caddr_t)vp); 79039433Smckusick } 79139433Smckusick } 79239433Smckusick 79339433Smckusick /* 79439633Smckusick * Eliminate all activity associated with the requested vnode 79539633Smckusick * and with all vnodes aliased to the requested vnode. 79639633Smckusick */ 79739633Smckusick void vgoneall(vp) 79839633Smckusick register struct vnode *vp; 79939633Smckusick { 80039809Smckusick register struct vnode *vq; 80139633Smckusick 80240665Smckusick if (vp->v_flag & VALIASED) { 80340665Smckusick /* 80440665Smckusick * If a vgone (or vclean) is already in progress, 80540665Smckusick * wait until it is done and return. 80640665Smckusick */ 80740665Smckusick if (vp->v_flag & VXLOCK) { 80840665Smckusick vp->v_flag |= VXWANT; 80940665Smckusick sleep((caddr_t)vp, PINOD); 81040665Smckusick return; 81139633Smckusick } 81240665Smckusick /* 81340665Smckusick * Ensure that vp will not be vgone'd while we 81440665Smckusick * are eliminating its aliases. 81540665Smckusick */ 81640665Smckusick vp->v_flag |= VXLOCK; 81740665Smckusick while (vp->v_flag & VALIASED) { 81840665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 81940665Smckusick if (vq->v_rdev != vp->v_rdev || 82040665Smckusick vq->v_type != vp->v_type || vp == vq) 82140665Smckusick continue; 82240665Smckusick vgone(vq); 82340665Smckusick break; 82440665Smckusick } 82540665Smckusick } 82640665Smckusick /* 82740665Smckusick * Remove the lock so that vgone below will 82840665Smckusick * really eliminate the vnode after which time 82940665Smckusick * vgone will awaken any sleepers. 83040665Smckusick */ 83140665Smckusick vp->v_flag &= ~VXLOCK; 83239633Smckusick } 83339633Smckusick vgone(vp); 83439633Smckusick } 83539633Smckusick 83639633Smckusick /* 83739433Smckusick * Eliminate all activity associated with a vnode 83839433Smckusick * in preparation for reuse. 83939433Smckusick */ 84039433Smckusick void vgone(vp) 84139433Smckusick register struct vnode *vp; 84239433Smckusick { 84339809Smckusick register struct vnode *vq; 84439615Smckusick struct vnode *vx; 84539433Smckusick 84639433Smckusick /* 84740548Smckusick * If a vgone (or vclean) is already in progress, 84840548Smckusick * wait until it is done and return. 84940548Smckusick */ 85040548Smckusick if (vp->v_flag & VXLOCK) { 85140548Smckusick vp->v_flag |= VXWANT; 85240548Smckusick sleep((caddr_t)vp, PINOD); 85340548Smckusick return; 85440548Smckusick } 85540548Smckusick /* 85639433Smckusick * Clean out the filesystem specific data. 85739433Smckusick */ 85841300Smckusick vclean(vp, DOCLOSE); 85939433Smckusick /* 86039433Smckusick * Delete from old mount point vnode list, if on one. 86139433Smckusick */ 86265260Smckusick if (vp->v_mount != NULL) { 86365260Smckusick LIST_REMOVE(vp, v_mntvnodes); 86452311Smckusick vp->v_mount = NULL; 86539433Smckusick } 86639433Smckusick /* 86739433Smckusick * If special device, remove it from special device alias list. 86839433Smckusick */ 86939433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 87039809Smckusick if (*vp->v_hashchain == vp) { 87139809Smckusick *vp->v_hashchain = vp->v_specnext; 87239433Smckusick } else { 87339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 87439615Smckusick if (vq->v_specnext != vp) 87539433Smckusick continue; 87639615Smckusick vq->v_specnext = vp->v_specnext; 87739433Smckusick break; 87839433Smckusick } 87939615Smckusick if (vq == NULL) 88039433Smckusick panic("missing bdev"); 88139433Smckusick } 88239615Smckusick if (vp->v_flag & VALIASED) { 88352416Storek vx = NULL; 88439809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 88540108Smckusick if (vq->v_rdev != vp->v_rdev || 88640108Smckusick vq->v_type != vp->v_type) 88739615Smckusick continue; 88852416Storek if (vx) 88952416Storek break; 89039615Smckusick vx = vq; 89139615Smckusick } 89252416Storek if (vx == NULL) 89339615Smckusick panic("missing alias"); 89452416Storek if (vq == NULL) 89539615Smckusick vx->v_flag &= ~VALIASED; 89639615Smckusick vp->v_flag &= ~VALIASED; 89739615Smckusick } 89839615Smckusick FREE(vp->v_specinfo, M_VNODE); 89939615Smckusick vp->v_specinfo = NULL; 90039433Smckusick } 90139433Smckusick /* 90256932Smckusick * If it is on the freelist and not already at the head, 90365505Smckusick * move it to the head of the list. The test of the back 90465505Smckusick * pointer and the reference count of zero is because 90565505Smckusick * it will be removed from the free list by getnewvnode, 90665505Smckusick * but will not have its reference count incremented until 90765505Smckusick * after calling vgone. If the reference count were 90865505Smckusick * incremented first, vgone would (incorrectly) try to 90965505Smckusick * close the previous instance of the underlying object. 91065505Smckusick * So, the back pointer is explicitly set to `0xdeadb' in 91165505Smckusick * getnewvnode after removing it from the freelist to ensure 91265505Smckusick * that we do not try to move it here. 91339433Smckusick */ 91465505Smckusick if (vp->v_usecount == 0 && 91565505Smckusick vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb && 91665505Smckusick vnode_free_list.tqh_first != vp) { 91765260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 91865260Smckusick TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 91939433Smckusick } 92039484Smckusick vp->v_type = VBAD; 92139433Smckusick } 92239633Smckusick 92339633Smckusick /* 92439821Smckusick * Lookup a vnode by device number. 92539821Smckusick */ 92639821Smckusick vfinddev(dev, type, vpp) 92739821Smckusick dev_t dev; 92839821Smckusick enum vtype type; 92939821Smckusick struct vnode **vpp; 93039821Smckusick { 93139821Smckusick register struct vnode *vp; 93239821Smckusick 93339821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 93439821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 93539821Smckusick continue; 93639821Smckusick *vpp = vp; 93759484Smckusick return (1); 93839821Smckusick } 93959484Smckusick return (0); 94039821Smckusick } 94139821Smckusick 94239821Smckusick /* 94339633Smckusick * Calculate the total number of references to a special device. 94439633Smckusick */ 94539633Smckusick vcount(vp) 94639633Smckusick register struct vnode *vp; 94739633Smckusick { 94839809Smckusick register struct vnode *vq; 94939633Smckusick int count; 95039633Smckusick 95139633Smckusick if ((vp->v_flag & VALIASED) == 0) 95239809Smckusick return (vp->v_usecount); 95339633Smckusick loop: 95439809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 95540108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 95639633Smckusick continue; 95739633Smckusick /* 95839633Smckusick * Alias, but not in use, so flush it out. 95939633Smckusick */ 96039809Smckusick if (vq->v_usecount == 0) { 96139633Smckusick vgone(vq); 96239633Smckusick goto loop; 96339633Smckusick } 96439809Smckusick count += vq->v_usecount; 96539633Smckusick } 96639633Smckusick return (count); 96739633Smckusick } 96839667Smckusick 96939667Smckusick /* 97039667Smckusick * Print out a description of a vnode. 97139667Smckusick */ 97239667Smckusick static char *typename[] = 97340286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 97439667Smckusick 97539667Smckusick vprint(label, vp) 97639667Smckusick char *label; 97739667Smckusick register struct vnode *vp; 97839667Smckusick { 97939913Smckusick char buf[64]; 98039667Smckusick 98139667Smckusick if (label != NULL) 98239667Smckusick printf("%s: ", label); 98350109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 98450109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 98550109Smckusick vp->v_holdcnt); 98639913Smckusick buf[0] = '\0'; 98739913Smckusick if (vp->v_flag & VROOT) 98839913Smckusick strcat(buf, "|VROOT"); 98939913Smckusick if (vp->v_flag & VTEXT) 99039913Smckusick strcat(buf, "|VTEXT"); 99141300Smckusick if (vp->v_flag & VSYSTEM) 99241300Smckusick strcat(buf, "|VSYSTEM"); 99341300Smckusick if (vp->v_flag & VXLOCK) 99441300Smckusick strcat(buf, "|VXLOCK"); 99541300Smckusick if (vp->v_flag & VXWANT) 99641300Smckusick strcat(buf, "|VXWANT"); 99741300Smckusick if (vp->v_flag & VBWAIT) 99841300Smckusick strcat(buf, "|VBWAIT"); 99939913Smckusick if (vp->v_flag & VALIASED) 100039913Smckusick strcat(buf, "|VALIASED"); 100139913Smckusick if (buf[0] != '\0') 100239913Smckusick printf(" flags (%s)", &buf[1]); 100365260Smckusick if (vp->v_data == NULL) { 100465260Smckusick printf("\n"); 100565260Smckusick } else { 100665260Smckusick printf("\n\t"); 100765260Smckusick VOP_PRINT(vp); 100865260Smckusick } 100939667Smckusick } 101041110Smarc 101149691Smckusick #ifdef DEBUG 101249691Smckusick /* 101349691Smckusick * List all of the locked vnodes in the system. 101449691Smckusick * Called when debugging the kernel. 101549691Smckusick */ 101649691Smckusick printlockedvnodes() 101749691Smckusick { 101849691Smckusick register struct mount *mp; 101949691Smckusick register struct vnode *vp; 102049691Smckusick 102149691Smckusick printf("Locked vnodes\n"); 102265260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { 102365260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 102465260Smckusick vp != NULL; 102565260Smckusick vp = vp->v_mntvnodes.le_next) 102649691Smckusick if (VOP_ISLOCKED(vp)) 102749691Smckusick vprint((char *)0, vp); 102865260Smckusick } 102949691Smckusick } 103049691Smckusick #endif 103149691Smckusick 103241110Smarc int kinfo_vdebug = 1; 103341110Smarc int kinfo_vgetfailed; 103441110Smarc #define KINFO_VNODESLOP 10 103541110Smarc /* 103657841Smckusick * Dump vnode list (via sysctl). 103741110Smarc * Copyout address of vnode followed by vnode. 103841110Smarc */ 103945118Smckusick /* ARGSUSED */ 104057841Smckusick sysctl_vnode(where, sizep) 104141110Smarc char *where; 104258465Sbostic size_t *sizep; 104341110Smarc { 104465260Smckusick register struct mount *mp, *nmp; 104541110Smarc struct vnode *vp; 104641110Smarc register char *bp = where, *savebp; 104753818Smckusick char *ewhere; 104841110Smarc int error; 104941110Smarc 105041110Smarc #define VPTRSZ sizeof (struct vnode *) 105141110Smarc #define VNODESZ sizeof (struct vnode) 105241110Smarc if (where == NULL) { 105357841Smckusick *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 105441110Smarc return (0); 105541110Smarc } 105657841Smckusick ewhere = where + *sizep; 105741110Smarc 105865260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 105965260Smckusick nmp = mp->mnt_list.tqe_next; 106065260Smckusick if (vfs_busy(mp)) 106141300Smckusick continue; 106241110Smarc savebp = bp; 106341110Smarc again: 106465260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 106565260Smckusick vp != NULL; 106665260Smckusick vp = vp->v_mntvnodes.le_next) { 106741422Smckusick /* 106841422Smckusick * Check that the vp is still associated with 106941422Smckusick * this filesystem. RACE: could have been 107041422Smckusick * recycled onto the same filesystem. 107141422Smckusick */ 107241421Smckusick if (vp->v_mount != mp) { 107341421Smckusick if (kinfo_vdebug) 107441421Smckusick printf("kinfo: vp changed\n"); 107541421Smckusick bp = savebp; 107641421Smckusick goto again; 107741421Smckusick } 107857841Smckusick if (bp + VPTRSZ + VNODESZ > ewhere) { 107957841Smckusick *sizep = bp - where; 108057841Smckusick return (ENOMEM); 108157841Smckusick } 108257841Smckusick if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 108357841Smckusick (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ))) 108441110Smarc return (error); 108541110Smarc bp += VPTRSZ + VNODESZ; 108641110Smarc } 108765260Smckusick vfs_unbusy(mp); 108865260Smckusick } 108941110Smarc 109057841Smckusick *sizep = bp - where; 109141110Smarc return (0); 109241110Smarc } 109365679Shibler 109465679Shibler /* 109565679Shibler * Check to see if a filesystem is mounted on a block device. 109665679Shibler */ 109765679Shibler int 109865679Shibler vfs_mountedon(vp) 109965679Shibler register struct vnode *vp; 110065679Shibler { 110165679Shibler register struct vnode *vq; 110265679Shibler 110365679Shibler if (vp->v_specflags & SI_MOUNTEDON) 110465679Shibler return (EBUSY); 110565679Shibler if (vp->v_flag & VALIASED) { 110665679Shibler for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 110765679Shibler if (vq->v_rdev != vp->v_rdev || 110865679Shibler vq->v_type != vp->v_type) 110965679Shibler continue; 111065679Shibler if (vq->v_specflags & SI_MOUNTEDON) 111165679Shibler return (EBUSY); 111265679Shibler } 111365679Shibler } 111465679Shibler return (0); 111565679Shibler } 111665679Shibler 111765679Shibler /* 111865679Shibler * Build hash lists of net addresses and hang them off the mount point. 111965679Shibler * Called by ufs_mount() to set up the lists of export addresses. 112065679Shibler */ 112165679Shibler static int 112265679Shibler vfs_hang_addrlist(mp, nep, argp) 112365679Shibler struct mount *mp; 112465679Shibler struct netexport *nep; 112565679Shibler struct export_args *argp; 112665679Shibler { 112765679Shibler register struct netcred *np; 112865679Shibler register struct radix_node_head *rnh; 112965679Shibler register int i; 113065679Shibler struct radix_node *rn; 113165679Shibler struct sockaddr *saddr, *smask = 0; 113265679Shibler struct domain *dom; 113365679Shibler int error; 113465679Shibler 113565679Shibler if (argp->ex_addrlen == 0) { 113665679Shibler if (mp->mnt_flag & MNT_DEFEXPORTED) 113765679Shibler return (EPERM); 113865679Shibler np = &nep->ne_defexported; 113965679Shibler np->netc_exflags = argp->ex_flags; 114065679Shibler np->netc_anon = argp->ex_anon; 114165679Shibler np->netc_anon.cr_ref = 1; 114265679Shibler mp->mnt_flag |= MNT_DEFEXPORTED; 114365679Shibler return (0); 114465679Shibler } 114565679Shibler i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 114665679Shibler np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); 114765679Shibler bzero((caddr_t)np, i); 114865679Shibler saddr = (struct sockaddr *)(np + 1); 114965679Shibler if (error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen)) 115065679Shibler goto out; 115165679Shibler if (saddr->sa_len > argp->ex_addrlen) 115265679Shibler saddr->sa_len = argp->ex_addrlen; 115365679Shibler if (argp->ex_masklen) { 115465679Shibler smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); 115565679Shibler error = copyin(argp->ex_addr, (caddr_t)smask, argp->ex_masklen); 115665679Shibler if (error) 115765679Shibler goto out; 115865679Shibler if (smask->sa_len > argp->ex_masklen) 115965679Shibler smask->sa_len = argp->ex_masklen; 116065679Shibler } 116165679Shibler i = saddr->sa_family; 116265679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 116365679Shibler /* 116465679Shibler * Seems silly to initialize every AF when most are not 116565679Shibler * used, do so on demand here 116665679Shibler */ 116765679Shibler for (dom = domains; dom; dom = dom->dom_next) 116865679Shibler if (dom->dom_family == i && dom->dom_rtattach) { 116965679Shibler dom->dom_rtattach((void **)&nep->ne_rtable[i], 117065679Shibler dom->dom_rtoffset); 117165679Shibler break; 117265679Shibler } 117365679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 117465679Shibler error = ENOBUFS; 117565679Shibler goto out; 117665679Shibler } 117765679Shibler } 117865679Shibler rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, 117965679Shibler np->netc_rnodes); 118065679Shibler if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ 118165679Shibler error = EPERM; 118265679Shibler goto out; 118365679Shibler } 118465679Shibler np->netc_exflags = argp->ex_flags; 118565679Shibler np->netc_anon = argp->ex_anon; 118665679Shibler np->netc_anon.cr_ref = 1; 118765679Shibler return (0); 118865679Shibler out: 118965679Shibler free(np, M_NETADDR); 119065679Shibler return (error); 119165679Shibler } 119265679Shibler 119365679Shibler /* ARGSUSED */ 119465679Shibler static int 119565679Shibler vfs_free_netcred(rn, w) 119665679Shibler struct radix_node *rn; 119765679Shibler caddr_t w; 119865679Shibler { 119965679Shibler register struct radix_node_head *rnh = (struct radix_node_head *)w; 120065679Shibler 120165679Shibler (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); 120265679Shibler free((caddr_t)rn, M_NETADDR); 120365679Shibler return (0); 120465679Shibler } 120565679Shibler 120665679Shibler /* 120765679Shibler * Free the net address hash lists that are hanging off the mount points. 120865679Shibler */ 120965679Shibler static void 121065679Shibler vfs_free_addrlist(nep) 121165679Shibler struct netexport *nep; 121265679Shibler { 121365679Shibler register int i; 121465679Shibler register struct radix_node_head *rnh; 121565679Shibler 121665679Shibler for (i = 0; i <= AF_MAX; i++) 121765679Shibler if (rnh = nep->ne_rtable[i]) { 121865679Shibler (*rnh->rnh_walktree)(rnh, vfs_free_netcred, 121965679Shibler (caddr_t)rnh); 122065679Shibler free((caddr_t)rnh, M_RTABLE); 122165679Shibler nep->ne_rtable[i] = 0; 122265679Shibler } 122365679Shibler } 122465679Shibler 122565679Shibler int 122665679Shibler vfs_export(mp, nep, argp) 122765679Shibler struct mount *mp; 122865679Shibler struct netexport *nep; 122965679Shibler struct export_args *argp; 123065679Shibler { 123165679Shibler int error; 123265679Shibler 123365679Shibler if (argp->ex_flags & MNT_DELEXPORT) { 123465679Shibler vfs_free_addrlist(nep); 123565679Shibler mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 123665679Shibler } 123765679Shibler if (argp->ex_flags & MNT_EXPORTED) { 123865679Shibler if (error = vfs_hang_addrlist(mp, nep, argp)) 123965679Shibler return (error); 124065679Shibler mp->mnt_flag |= MNT_EXPORTED; 124165679Shibler } 124265679Shibler return (0); 124365679Shibler } 124465679Shibler 124565679Shibler struct netcred * 124665679Shibler vfs_export_lookup(mp, nep, nam) 124765679Shibler register struct mount *mp; 124865679Shibler struct netexport *nep; 124965679Shibler struct mbuf *nam; 125065679Shibler { 125165679Shibler register struct netcred *np; 125265679Shibler register struct radix_node_head *rnh; 125365679Shibler struct sockaddr *saddr; 125465679Shibler 125565679Shibler np = NULL; 125665679Shibler if (mp->mnt_flag & MNT_EXPORTED) { 125765679Shibler /* 125865679Shibler * Lookup in the export list first. 125965679Shibler */ 126065679Shibler if (nam != NULL) { 126165679Shibler saddr = mtod(nam, struct sockaddr *); 126265679Shibler rnh = nep->ne_rtable[saddr->sa_family]; 126365679Shibler if (rnh != NULL) { 126465679Shibler np = (struct netcred *) 126565679Shibler (*rnh->rnh_matchaddr)((caddr_t)saddr, 126665679Shibler rnh); 126765679Shibler if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 126865679Shibler np = NULL; 126965679Shibler } 127065679Shibler } 127165679Shibler /* 127265679Shibler * If no address match, use the default if it exists. 127365679Shibler */ 127465679Shibler if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 127565679Shibler np = &nep->ne_defexported; 127665679Shibler } 127765679Shibler return (np); 127865679Shibler } 1279