137488Smckusick /* 263180Sbostic * Copyright (c) 1989, 1993 363180Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 937488Smckusick * 1044458Sbostic * %sccs.include.redist.c% 1137488Smckusick * 12*68319Scgd * @(#)vfs_subr.c 8.15 (Berkeley) 02/14/95 1337488Smckusick */ 1437488Smckusick 1537488Smckusick /* 1637488Smckusick * External virtual filesystem routines 1737488Smckusick */ 1837488Smckusick 1951460Sbostic #include <sys/param.h> 2053829Spendry #include <sys/systm.h> 2151460Sbostic #include <sys/proc.h> 2251460Sbostic #include <sys/mount.h> 2351460Sbostic #include <sys/time.h> 2451460Sbostic #include <sys/vnode.h> 2552415Smckusick #include <sys/stat.h> 2651460Sbostic #include <sys/namei.h> 2751460Sbostic #include <sys/ucred.h> 2851460Sbostic #include <sys/buf.h> 2951460Sbostic #include <sys/errno.h> 3051460Sbostic #include <sys/malloc.h> 3165679Shibler #include <sys/domain.h> 3265679Shibler #include <sys/mbuf.h> 3337488Smckusick 3460930Smckusick #include <vm/vm.h> 3560930Smckusick #include <sys/sysctl.h> 3660930Smckusick 3755050Spendry #include <miscfs/specfs/specdev.h> 3855050Spendry 3952415Smckusick enum vtype iftovt_tab[16] = { 4052415Smckusick VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 4152415Smckusick VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 4252415Smckusick }; 4352415Smckusick int vttoif_tab[9] = { 4452415Smckusick 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 4552415Smckusick S_IFSOCK, S_IFIFO, S_IFMT, 4652415Smckusick }; 4752415Smckusick 4837488Smckusick /* 4956608Smckusick * Insq/Remq for the vnode usage lists. 5056608Smckusick */ 5165260Smckusick #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) 52*68319Scgd #define bufremvn(bp) { \ 53*68319Scgd LIST_REMOVE(bp, b_vnbufs); \ 54*68319Scgd (bp)->b_vnbufs.le_next = NOLIST; \ 5565260Smckusick } 5665260Smckusick TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ 5765260Smckusick struct mntlist mountlist; /* mounted filesystem list */ 5865260Smckusick 5956608Smckusick /* 6065260Smckusick * Initialize the vnode management data structures. 6137488Smckusick */ 62*68319Scgd void 6365260Smckusick vntblinit() 6437488Smckusick { 6537488Smckusick 6665260Smckusick TAILQ_INIT(&vnode_free_list); 6765260Smckusick TAILQ_INIT(&mountlist); 6837488Smckusick } 6937488Smckusick 7037488Smckusick /* 7137488Smckusick * Lock a filesystem. 7237488Smckusick * Used to prevent access to it while mounting and unmounting. 7337488Smckusick */ 74*68319Scgd int 7537488Smckusick vfs_lock(mp) 7637488Smckusick register struct mount *mp; 7737488Smckusick { 7837488Smckusick 79*68319Scgd while (mp->mnt_flag & MNT_MLOCK) { 8041400Smckusick mp->mnt_flag |= MNT_MWAIT; 81*68319Scgd tsleep((caddr_t)mp, PVFS, "vfslock", 0); 8239045Smckusick } 8341400Smckusick mp->mnt_flag |= MNT_MLOCK; 8437488Smckusick return (0); 8537488Smckusick } 8637488Smckusick 8737488Smckusick /* 8837488Smckusick * Unlock a locked filesystem. 8937488Smckusick * Panic if filesystem is not locked. 9037488Smckusick */ 9137488Smckusick void 9237488Smckusick vfs_unlock(mp) 9337488Smckusick register struct mount *mp; 9437488Smckusick { 9537488Smckusick 9641400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 9741300Smckusick panic("vfs_unlock: not locked"); 9841400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 9941400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 10041400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 10137488Smckusick wakeup((caddr_t)mp); 10237488Smckusick } 10337488Smckusick } 10437488Smckusick 10537488Smckusick /* 10641300Smckusick * Mark a mount point as busy. 10741300Smckusick * Used to synchronize access and to delay unmounting. 10841300Smckusick */ 109*68319Scgd int 11041300Smckusick vfs_busy(mp) 11141300Smckusick register struct mount *mp; 11241300Smckusick { 11341300Smckusick 114*68319Scgd while (mp->mnt_flag & MNT_MPBUSY) { 11541400Smckusick mp->mnt_flag |= MNT_MPWANT; 116*68319Scgd tsleep((caddr_t)&mp->mnt_flag, PVFS, "vfsbusy", 0); 11741300Smckusick } 11841419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 11941419Smckusick return (1); 12041400Smckusick mp->mnt_flag |= MNT_MPBUSY; 12141300Smckusick return (0); 12241300Smckusick } 12341300Smckusick 12441300Smckusick /* 12541300Smckusick * Free a busy filesystem. 12641300Smckusick * Panic if filesystem is not busy. 12741300Smckusick */ 128*68319Scgd void 12941300Smckusick vfs_unbusy(mp) 13041300Smckusick register struct mount *mp; 13141300Smckusick { 13241300Smckusick 13341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 13441300Smckusick panic("vfs_unbusy: not busy"); 13541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 13641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 13741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 13841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 13941300Smckusick } 14041300Smckusick } 14141300Smckusick 14241300Smckusick /* 14337488Smckusick * Lookup a mount point by filesystem identifier. 14437488Smckusick */ 14537488Smckusick struct mount * 14637488Smckusick getvfs(fsid) 14737488Smckusick fsid_t *fsid; 14837488Smckusick { 14937488Smckusick register struct mount *mp; 15037488Smckusick 15165260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { 15241400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 15365260Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) 15438288Smckusick return (mp); 15565260Smckusick } 15638288Smckusick return ((struct mount *)0); 15737488Smckusick } 15837488Smckusick 15937488Smckusick /* 16053829Spendry * Get a new unique fsid 16153829Spendry */ 16253829Spendry void 16353829Spendry getnewfsid(mp, mtype) 16453829Spendry struct mount *mp; 16553829Spendry int mtype; 16653829Spendry { 16753829Spendry static u_short xxxfs_mntid; 16853829Spendry 16953829Spendry fsid_t tfsid; 17053829Spendry 17165507Spendry mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); 17253829Spendry mp->mnt_stat.f_fsid.val[1] = mtype; 17353829Spendry if (xxxfs_mntid == 0) 17453829Spendry ++xxxfs_mntid; 17565507Spendry tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); 17653829Spendry tfsid.val[1] = mtype; 17765260Smckusick if (mountlist.tqh_first != NULL) { 17853936Spendry while (getvfs(&tfsid)) { 17953936Spendry tfsid.val[0]++; 18053936Spendry xxxfs_mntid++; 18153936Spendry } 18253829Spendry } 18353829Spendry mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 18453829Spendry } 18553829Spendry 18653829Spendry /* 18737488Smckusick * Set vnode attributes to VNOVAL 18837488Smckusick */ 189*68319Scgd void 190*68319Scgd vattr_null(vap) 19137488Smckusick register struct vattr *vap; 19237488Smckusick { 19337488Smckusick 19437488Smckusick vap->va_type = VNON; 19552005Smckusick vap->va_size = vap->va_bytes = VNOVAL; 19637488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 19752005Smckusick vap->va_fsid = vap->va_fileid = 19852005Smckusick vap->va_blocksize = vap->va_rdev = 19954347Smckusick vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 20054347Smckusick vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 20154347Smckusick vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 20238258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 20358548Sbostic vap->va_vaflags = 0; 20437488Smckusick } 20538265Smckusick 20638265Smckusick /* 20739397Smckusick * Routines having to do with the management of the vnode table. 20839397Smckusick */ 20953547Sheideman extern int (**dead_vnodeop_p)(); 21039635Smckusick extern void vclean(); 21140883Smckusick long numvnodes; 21253493Sheideman extern struct vattr va_null; 21339397Smckusick 21439397Smckusick /* 21539397Smckusick * Return the next vnode from the free list. 21639397Smckusick */ 217*68319Scgd int 21839397Smckusick getnewvnode(tag, mp, vops, vpp) 21939397Smckusick enum vtagtype tag; 22039397Smckusick struct mount *mp; 22153495Sheideman int (**vops)(); 22239397Smckusick struct vnode **vpp; 22339397Smckusick { 22465511Smckusick register struct vnode *vp; 22557042Smargo int s; 22639397Smckusick 22765260Smckusick if ((vnode_free_list.tqh_first == NULL && 22865260Smckusick numvnodes < 2 * desiredvnodes) || 22954347Smckusick numvnodes < desiredvnodes) { 23045118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 23145118Smckusick M_VNODE, M_WAITOK); 23240883Smckusick bzero((char *)vp, sizeof *vp); 23340883Smckusick numvnodes++; 23440883Smckusick } else { 23565260Smckusick if ((vp = vnode_free_list.tqh_first) == NULL) { 23640883Smckusick tablefull("vnode"); 23740883Smckusick *vpp = 0; 23840883Smckusick return (ENFILE); 23940883Smckusick } 24040883Smckusick if (vp->v_usecount) 24140883Smckusick panic("free vnode isn't"); 24265260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 24365505Smckusick /* see comment on why 0xdeadb is set at end of vgone (below) */ 24465505Smckusick vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb; 24552190Smckusick vp->v_lease = NULL; 24640883Smckusick if (vp->v_type != VBAD) 24740883Smckusick vgone(vp); 24857042Smargo #ifdef DIAGNOSTIC 24952006Smckusick if (vp->v_data) 25052006Smckusick panic("cleaned vnode isn't"); 25157042Smargo s = splbio(); 25257042Smargo if (vp->v_numoutput) 25357042Smargo panic("Clean vnode has pending I/O's"); 25457042Smargo splx(s); 25557042Smargo #endif 25640883Smckusick vp->v_flag = 0; 25740883Smckusick vp->v_lastr = 0; 25865745Shibler vp->v_ralen = 0; 25965745Shibler vp->v_maxra = 0; 26057042Smargo vp->v_lastw = 0; 26157042Smargo vp->v_lasta = 0; 26257042Smargo vp->v_cstart = 0; 26357042Smargo vp->v_clen = 0; 26440883Smckusick vp->v_socket = 0; 26539397Smckusick } 26639512Smckusick vp->v_type = VNON; 26739397Smckusick cache_purge(vp); 26839397Smckusick vp->v_tag = tag; 26939433Smckusick vp->v_op = vops; 27039397Smckusick insmntque(vp, mp); 27139397Smckusick *vpp = vp; 27265505Smckusick vp->v_usecount = 1; 27365260Smckusick vp->v_data = 0; 27439397Smckusick return (0); 27539397Smckusick } 27665679Shibler 27739397Smckusick /* 27839397Smckusick * Move a vnode from one mount queue to another. 27939397Smckusick */ 280*68319Scgd void 28139397Smckusick insmntque(vp, mp) 28239397Smckusick register struct vnode *vp; 28339397Smckusick register struct mount *mp; 28439397Smckusick { 28539397Smckusick 28639397Smckusick /* 28739397Smckusick * Delete from old mount point vnode list, if on one. 28839397Smckusick */ 28965679Shibler if (vp->v_mount != NULL) 29065260Smckusick LIST_REMOVE(vp, v_mntvnodes); 29139397Smckusick /* 29239397Smckusick * Insert into list of vnodes for the new mount point, if available. 29339397Smckusick */ 29465260Smckusick if ((vp->v_mount = mp) == NULL) 29539397Smckusick return; 29665260Smckusick LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); 29739397Smckusick } 29839397Smckusick 29939397Smckusick /* 30049232Smckusick * Update outstanding I/O count and do wakeup if requested. 30149232Smckusick */ 302*68319Scgd void 30349232Smckusick vwakeup(bp) 30449232Smckusick register struct buf *bp; 30549232Smckusick { 30649232Smckusick register struct vnode *vp; 30749232Smckusick 30857810Smckusick bp->b_flags &= ~B_WRITEINPROG; 30949232Smckusick if (vp = bp->b_vp) { 310*68319Scgd if (--vp->v_numoutput < 0) 31157042Smargo panic("vwakeup: neg numoutput"); 31249232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 31349232Smckusick if (vp->v_numoutput < 0) 314*68319Scgd panic("vwakeup: neg numoutput 2"); 31549232Smckusick vp->v_flag &= ~VBWAIT; 31649232Smckusick wakeup((caddr_t)&vp->v_numoutput); 31749232Smckusick } 31849232Smckusick } 31949232Smckusick } 32049232Smckusick 32149232Smckusick /* 32249232Smckusick * Flush out and invalidate all buffers associated with a vnode. 32349232Smckusick * Called with the underlying object locked. 32449232Smckusick */ 32554442Smckusick int 32657792Smckusick vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 32749232Smckusick register struct vnode *vp; 32856459Smargo int flags; 32954442Smckusick struct ucred *cred; 33054442Smckusick struct proc *p; 33157792Smckusick int slpflag, slptimeo; 33249232Smckusick { 33349232Smckusick register struct buf *bp; 33449232Smckusick struct buf *nbp, *blist; 33554442Smckusick int s, error; 33649232Smckusick 33756459Smargo if (flags & V_SAVE) { 33854442Smckusick if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) 33954442Smckusick return (error); 34065260Smckusick if (vp->v_dirtyblkhd.lh_first != NULL) 34154442Smckusick panic("vinvalbuf: dirty bufs"); 34254442Smckusick } 34349232Smckusick for (;;) { 34465260Smckusick if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA) 34556459Smargo while (blist && blist->b_lblkno < 0) 34665260Smckusick blist = blist->b_vnbufs.le_next; 347*68319Scgd if (!blist && (blist = vp->v_dirtyblkhd.lh_first) && 34856608Smckusick (flags & V_SAVEMETA)) 34956459Smargo while (blist && blist->b_lblkno < 0) 35065260Smckusick blist = blist->b_vnbufs.le_next; 35156459Smargo if (!blist) 35249232Smckusick break; 35356459Smargo 35449232Smckusick for (bp = blist; bp; bp = nbp) { 35565260Smckusick nbp = bp->b_vnbufs.le_next; 35656459Smargo if (flags & V_SAVEMETA && bp->b_lblkno < 0) 35756459Smargo continue; 35849232Smckusick s = splbio(); 35949232Smckusick if (bp->b_flags & B_BUSY) { 36049232Smckusick bp->b_flags |= B_WANTED; 36157792Smckusick error = tsleep((caddr_t)bp, 36257792Smckusick slpflag | (PRIBIO + 1), "vinvalbuf", 36357792Smckusick slptimeo); 36449232Smckusick splx(s); 36557792Smckusick if (error) 36657792Smckusick return (error); 36749232Smckusick break; 36849232Smckusick } 36949232Smckusick bremfree(bp); 37049232Smckusick bp->b_flags |= B_BUSY; 37149232Smckusick splx(s); 37257792Smckusick /* 37357792Smckusick * XXX Since there are no node locks for NFS, I believe 37457792Smckusick * there is a slight chance that a delayed write will 37557792Smckusick * occur while sleeping just above, so check for it. 37657792Smckusick */ 37757792Smckusick if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 37857792Smckusick (void) VOP_BWRITE(bp); 37957792Smckusick break; 38057792Smckusick } 38156459Smargo bp->b_flags |= B_INVAL; 38249232Smckusick brelse(bp); 38349232Smckusick } 38449232Smckusick } 38556608Smckusick if (!(flags & V_SAVEMETA) && 38665260Smckusick (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first)) 38749232Smckusick panic("vinvalbuf: flush failed"); 38854442Smckusick return (0); 38949232Smckusick } 39049232Smckusick 39149232Smckusick /* 39249232Smckusick * Associate a buffer with a vnode. 39349232Smckusick */ 394*68319Scgd void 39549232Smckusick bgetvp(vp, bp) 39649232Smckusick register struct vnode *vp; 39749232Smckusick register struct buf *bp; 39849232Smckusick { 39949232Smckusick 40049232Smckusick if (bp->b_vp) 40149232Smckusick panic("bgetvp: not free"); 40249232Smckusick VHOLD(vp); 40349232Smckusick bp->b_vp = vp; 40449232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 40549232Smckusick bp->b_dev = vp->v_rdev; 40649232Smckusick else 40749232Smckusick bp->b_dev = NODEV; 40849232Smckusick /* 40949232Smckusick * Insert onto list for new vnode. 41049232Smckusick */ 41156608Smckusick bufinsvn(bp, &vp->v_cleanblkhd); 41249232Smckusick } 41349232Smckusick 41449232Smckusick /* 41549232Smckusick * Disassociate a buffer from a vnode. 41649232Smckusick */ 417*68319Scgd void 41849232Smckusick brelvp(bp) 41949232Smckusick register struct buf *bp; 42049232Smckusick { 42149232Smckusick struct vnode *vp; 42249232Smckusick 42349232Smckusick if (bp->b_vp == (struct vnode *) 0) 42449232Smckusick panic("brelvp: NULL"); 42549232Smckusick /* 42649232Smckusick * Delete from old vnode list, if on one. 42749232Smckusick */ 42865260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 42956608Smckusick bufremvn(bp); 43049232Smckusick vp = bp->b_vp; 43149232Smckusick bp->b_vp = (struct vnode *) 0; 43249232Smckusick HOLDRELE(vp); 43349232Smckusick } 43449232Smckusick 43549232Smckusick /* 43649232Smckusick * Reassign a buffer from one vnode to another. 43749232Smckusick * Used to assign file specific control information 43849232Smckusick * (indirect blocks) to the vnode to which they belong. 43949232Smckusick */ 440*68319Scgd void 44149232Smckusick reassignbuf(bp, newvp) 44249232Smckusick register struct buf *bp; 44349232Smckusick register struct vnode *newvp; 44449232Smckusick { 44565260Smckusick register struct buflists *listheadp; 44649232Smckusick 44752655Smckusick if (newvp == NULL) { 44852655Smckusick printf("reassignbuf: NULL"); 44952655Smckusick return; 45052655Smckusick } 45149232Smckusick /* 45249232Smckusick * Delete from old vnode list, if on one. 45349232Smckusick */ 45465260Smckusick if (bp->b_vnbufs.le_next != NOLIST) 45556608Smckusick bufremvn(bp); 45649232Smckusick /* 45749232Smckusick * If dirty, put on list of dirty buffers; 45849232Smckusick * otherwise insert onto list of clean buffers. 45949232Smckusick */ 46049232Smckusick if (bp->b_flags & B_DELWRI) 46149232Smckusick listheadp = &newvp->v_dirtyblkhd; 46249232Smckusick else 46349232Smckusick listheadp = &newvp->v_cleanblkhd; 46456608Smckusick bufinsvn(bp, listheadp); 46549232Smckusick } 46649232Smckusick 46749232Smckusick /* 46839433Smckusick * Create a vnode for a block device. 46939433Smckusick * Used for root filesystem, argdev, and swap areas. 47039433Smckusick * Also used for memory file system special devices. 47139397Smckusick */ 472*68319Scgd int 47339433Smckusick bdevvp(dev, vpp) 47439433Smckusick dev_t dev; 47539433Smckusick struct vnode **vpp; 47639433Smckusick { 47739433Smckusick register struct vnode *vp; 47839433Smckusick struct vnode *nvp; 47939433Smckusick int error; 48039433Smckusick 48146989Smckusick if (dev == NODEV) 48246989Smckusick return (0); 48353547Sheideman error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); 48439433Smckusick if (error) { 485*68319Scgd *vpp = NULLVP; 48639433Smckusick return (error); 48739433Smckusick } 48839433Smckusick vp = nvp; 48939433Smckusick vp->v_type = VBLK; 49039615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 49139433Smckusick vput(vp); 49239433Smckusick vp = nvp; 49339433Smckusick } 49439433Smckusick *vpp = vp; 49539433Smckusick return (0); 49639433Smckusick } 49739433Smckusick 49839433Smckusick /* 49939433Smckusick * Check to see if the new vnode represents a special device 50039433Smckusick * for which we already have a vnode (either because of 50139433Smckusick * bdevvp() or because of a different vnode representing 50239433Smckusick * the same block device). If such an alias exists, deallocate 50339509Smckusick * the existing contents and return the aliased vnode. The 50439433Smckusick * caller is responsible for filling it with its new contents. 50539433Smckusick */ 50639433Smckusick struct vnode * 50739615Smckusick checkalias(nvp, nvp_rdev, mp) 50839433Smckusick register struct vnode *nvp; 50939615Smckusick dev_t nvp_rdev; 51039433Smckusick struct mount *mp; 51139433Smckusick { 51239433Smckusick register struct vnode *vp; 51339615Smckusick struct vnode **vpp; 51439433Smckusick 51539433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 51641400Smckusick return (NULLVP); 51739615Smckusick 51839615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 51939433Smckusick loop: 52039615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 52139615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 52239433Smckusick continue; 52339615Smckusick /* 52439615Smckusick * Alias, but not in use, so flush it out. 52539615Smckusick */ 52639809Smckusick if (vp->v_usecount == 0) { 52739615Smckusick vgone(vp); 52839615Smckusick goto loop; 52939615Smckusick } 53065260Smckusick if (vget(vp, 1)) 53139633Smckusick goto loop; 53239433Smckusick break; 53339433Smckusick } 53439615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 53539615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 53639615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 53739615Smckusick nvp->v_rdev = nvp_rdev; 53839809Smckusick nvp->v_hashchain = vpp; 53939615Smckusick nvp->v_specnext = *vpp; 54042152Smckusick nvp->v_specflags = 0; 54139615Smckusick *vpp = nvp; 54240640Smckusick if (vp != NULL) { 54340640Smckusick nvp->v_flag |= VALIASED; 54440640Smckusick vp->v_flag |= VALIASED; 54540640Smckusick vput(vp); 54640640Smckusick } 54741400Smckusick return (NULLVP); 54839433Smckusick } 54939484Smckusick VOP_UNLOCK(vp); 55039484Smckusick vclean(vp, 0); 55139433Smckusick vp->v_op = nvp->v_op; 55239433Smckusick vp->v_tag = nvp->v_tag; 55339433Smckusick nvp->v_type = VNON; 55439433Smckusick insmntque(vp, mp); 55539433Smckusick return (vp); 55639433Smckusick } 55739433Smckusick 55839433Smckusick /* 55939433Smckusick * Grab a particular vnode from the free list, increment its 56039433Smckusick * reference count and lock it. The vnode lock bit is set the 56139433Smckusick * vnode is being eliminated in vgone. The process is awakened 56239433Smckusick * when the transition is completed, and an error returned to 56339433Smckusick * indicate that the vnode is no longer usable (possibly having 56439433Smckusick * been changed to a new file system type). 56539433Smckusick */ 566*68319Scgd int 56765260Smckusick vget(vp, lockflag) 56839397Smckusick register struct vnode *vp; 56965260Smckusick int lockflag; 57039397Smckusick { 57139397Smckusick 57266897Smckusick /* 57366897Smckusick * If the vnode is in the process of being cleaned out for 57466897Smckusick * another use, we wait for the cleaning to finish and then 57566897Smckusick * return failure. Cleaning is determined either by checking 57666897Smckusick * that the VXLOCK flag is set, or that the use count is 57766897Smckusick * zero with the back pointer set to show that it has been 57866897Smckusick * removed from the free list by getnewvnode. The VXLOCK 57966897Smckusick * flag may not have been set yet because vclean is blocked in 58066897Smckusick * the VOP_LOCK call waiting for the VOP_INACTIVE to complete. 58166897Smckusick */ 58266897Smckusick if ((vp->v_flag & VXLOCK) || 58366897Smckusick (vp->v_usecount == 0 && 58466897Smckusick vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)) { 58539433Smckusick vp->v_flag |= VXWANT; 586*68319Scgd tsleep((caddr_t)vp, PINOD, "vget", 0); 58739433Smckusick return (1); 58839433Smckusick } 58966897Smckusick if (vp->v_usecount == 0) 59065260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 59159450Smckusick vp->v_usecount++; 59265260Smckusick if (lockflag) 59365260Smckusick VOP_LOCK(vp); 59439433Smckusick return (0); 59539397Smckusick } 59639397Smckusick 59739397Smckusick /* 59839397Smckusick * Vnode reference, just increment the count 59939397Smckusick */ 600*68319Scgd void 601*68319Scgd vref(vp) 60239397Smckusick struct vnode *vp; 60339397Smckusick { 60439397Smckusick 60559450Smckusick if (vp->v_usecount <= 0) 60659450Smckusick panic("vref used where vget required"); 60739809Smckusick vp->v_usecount++; 60839397Smckusick } 60939397Smckusick 61039397Smckusick /* 61139397Smckusick * vput(), just unlock and vrele() 61239397Smckusick */ 613*68319Scgd void 614*68319Scgd vput(vp) 61539397Smckusick register struct vnode *vp; 61639397Smckusick { 61752416Storek 61839397Smckusick VOP_UNLOCK(vp); 61939397Smckusick vrele(vp); 62039397Smckusick } 62139397Smckusick 62239397Smckusick /* 62339397Smckusick * Vnode release. 62439397Smckusick * If count drops to zero, call inactive routine and return to freelist. 62539397Smckusick */ 626*68319Scgd void 627*68319Scgd vrele(vp) 62839397Smckusick register struct vnode *vp; 62939397Smckusick { 63039397Smckusick 63150109Smckusick #ifdef DIAGNOSTIC 63239397Smckusick if (vp == NULL) 63339433Smckusick panic("vrele: null vp"); 63450109Smckusick #endif 63539809Smckusick vp->v_usecount--; 63639809Smckusick if (vp->v_usecount > 0) 63739397Smckusick return; 63850109Smckusick #ifdef DIAGNOSTIC 63950109Smckusick if (vp->v_usecount != 0 || vp->v_writecount != 0) { 64050109Smckusick vprint("vrele: bad ref count", vp); 64150109Smckusick panic("vrele: ref cnt"); 64250109Smckusick } 64350109Smckusick #endif 64455468Smckusick /* 64555468Smckusick * insert at tail of LRU list 64655468Smckusick */ 64765260Smckusick TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 64854442Smckusick VOP_INACTIVE(vp); 64939397Smckusick } 65039433Smckusick 65139433Smckusick /* 65239809Smckusick * Page or buffer structure gets a reference. 65339809Smckusick */ 654*68319Scgd void 655*68319Scgd vhold(vp) 65639809Smckusick register struct vnode *vp; 65739809Smckusick { 65839809Smckusick 65939809Smckusick vp->v_holdcnt++; 66039809Smckusick } 66139809Smckusick 66239809Smckusick /* 66339809Smckusick * Page or buffer structure frees a reference. 66439809Smckusick */ 665*68319Scgd void 666*68319Scgd holdrele(vp) 66739809Smckusick register struct vnode *vp; 66839809Smckusick { 66939809Smckusick 67039809Smckusick if (vp->v_holdcnt <= 0) 67139809Smckusick panic("holdrele: holdcnt"); 67239809Smckusick vp->v_holdcnt--; 67339809Smckusick } 67439809Smckusick 67539809Smckusick /* 67639509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 67739509Smckusick * 67839509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 67939509Smckusick * return error if any are found (nb: this is a user error, not a 68039509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 68139509Smckusick * that are found. 68239509Smckusick */ 68365679Shibler #ifdef DIAGNOSTIC 68460930Smckusick int busyprt = 0; /* print out busy vnodes */ 68560930Smckusick struct ctldebug debug1 = { "busyprt", &busyprt }; 68665679Shibler #endif 68739509Smckusick 688*68319Scgd int 68939509Smckusick vflush(mp, skipvp, flags) 69039509Smckusick struct mount *mp; 69139509Smckusick struct vnode *skipvp; 69239509Smckusick int flags; 69339509Smckusick { 69439509Smckusick register struct vnode *vp, *nvp; 69539509Smckusick int busy = 0; 69639509Smckusick 69741400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 69841300Smckusick panic("vflush: not busy"); 69941421Smckusick loop: 70065260Smckusick for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 70141421Smckusick if (vp->v_mount != mp) 70241421Smckusick goto loop; 70365260Smckusick nvp = vp->v_mntvnodes.le_next; 70439509Smckusick /* 70539509Smckusick * Skip over a selected vnode. 70639509Smckusick */ 70739509Smckusick if (vp == skipvp) 70839509Smckusick continue; 70939509Smckusick /* 71041300Smckusick * Skip over a vnodes marked VSYSTEM. 71141300Smckusick */ 71241300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 71341300Smckusick continue; 71441300Smckusick /* 71557040Smckusick * If WRITECLOSE is set, only flush out regular file 71657040Smckusick * vnodes open for writing. 71757040Smckusick */ 71857040Smckusick if ((flags & WRITECLOSE) && 71957040Smckusick (vp->v_writecount == 0 || vp->v_type != VREG)) 72057040Smckusick continue; 72157040Smckusick /* 72239809Smckusick * With v_usecount == 0, all we need to do is clear 72339509Smckusick * out the vnode data structures and we are done. 72439509Smckusick */ 72539809Smckusick if (vp->v_usecount == 0) { 72639509Smckusick vgone(vp); 72739509Smckusick continue; 72839509Smckusick } 72939509Smckusick /* 73057040Smckusick * If FORCECLOSE is set, forcibly close the vnode. 73139509Smckusick * For block or character devices, revert to an 73239509Smckusick * anonymous device. For all other files, just kill them. 73339509Smckusick */ 73441300Smckusick if (flags & FORCECLOSE) { 73539509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 73639509Smckusick vgone(vp); 73739509Smckusick } else { 73839509Smckusick vclean(vp, 0); 73953547Sheideman vp->v_op = spec_vnodeop_p; 74039509Smckusick insmntque(vp, (struct mount *)0); 74139509Smckusick } 74239509Smckusick continue; 74339509Smckusick } 74465679Shibler #ifdef DIAGNOSTIC 74539509Smckusick if (busyprt) 74639667Smckusick vprint("vflush: busy vnode", vp); 74765679Shibler #endif 74839509Smckusick busy++; 74939509Smckusick } 75039509Smckusick if (busy) 75139509Smckusick return (EBUSY); 75239509Smckusick return (0); 75339509Smckusick } 75439509Smckusick 75539509Smckusick /* 75639433Smckusick * Disassociate the underlying file system from a vnode. 75739433Smckusick */ 75854347Smckusick void 75954347Smckusick vclean(vp, flags) 76039433Smckusick register struct vnode *vp; 76145118Smckusick int flags; 76239433Smckusick { 76339484Smckusick int active; 76439433Smckusick 76539484Smckusick /* 76639484Smckusick * Check to see if the vnode is in use. 76739667Smckusick * If so we have to reference it before we clean it out 76839667Smckusick * so that its count cannot fall to zero and generate a 76939667Smckusick * race against ourselves to recycle it. 77039484Smckusick */ 77139809Smckusick if (active = vp->v_usecount) 77239484Smckusick VREF(vp); 77339484Smckusick /* 77456805Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 77556805Smckusick * have the object locked while it cleans it out. The VOP_LOCK 77656805Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 77756805Smckusick * For active vnodes, it ensures that no other activity can 77856805Smckusick * occur while the underlying object is being cleaned out. 77956805Smckusick */ 78056805Smckusick VOP_LOCK(vp); 78156805Smckusick /* 78239484Smckusick * Prevent the vnode from being recycled or 78339484Smckusick * brought into use while we clean it out. 78439484Smckusick */ 78539667Smckusick if (vp->v_flag & VXLOCK) 78639667Smckusick panic("vclean: deadlock"); 78739433Smckusick vp->v_flag |= VXLOCK; 78839433Smckusick /* 78956805Smckusick * Clean out any buffers associated with the vnode. 79039667Smckusick */ 79141300Smckusick if (flags & DOCLOSE) 79257792Smckusick vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); 79339667Smckusick /* 79456805Smckusick * Any other processes trying to obtain this lock must first 79556805Smckusick * wait for VXLOCK to clear, then call the new lock operation. 79639433Smckusick */ 79756805Smckusick VOP_UNLOCK(vp); 79839433Smckusick /* 79956805Smckusick * If purging an active vnode, it must be closed and 80056805Smckusick * deactivated before being reclaimed. 80139433Smckusick */ 80239484Smckusick if (active) { 80356805Smckusick if (flags & DOCLOSE) 80456805Smckusick VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL); 80556805Smckusick VOP_INACTIVE(vp); 80639433Smckusick } 80739433Smckusick /* 80839433Smckusick * Reclaim the vnode. 80939433Smckusick */ 81056805Smckusick if (VOP_RECLAIM(vp)) 81139433Smckusick panic("vclean: cannot reclaim"); 81239484Smckusick if (active) 81339484Smckusick vrele(vp); 81453580Sheideman 81539433Smckusick /* 81656805Smckusick * Done with purge, notify sleepers of the grim news. 81739433Smckusick */ 81856805Smckusick vp->v_op = dead_vnodeop_p; 81956805Smckusick vp->v_tag = VT_NON; 82039433Smckusick vp->v_flag &= ~VXLOCK; 82139433Smckusick if (vp->v_flag & VXWANT) { 82239433Smckusick vp->v_flag &= ~VXWANT; 82339433Smckusick wakeup((caddr_t)vp); 82439433Smckusick } 82539433Smckusick } 82639433Smckusick 82739433Smckusick /* 82839633Smckusick * Eliminate all activity associated with the requested vnode 82939633Smckusick * and with all vnodes aliased to the requested vnode. 83039633Smckusick */ 831*68319Scgd void 832*68319Scgd vgoneall(vp) 83339633Smckusick register struct vnode *vp; 83439633Smckusick { 83539809Smckusick register struct vnode *vq; 83639633Smckusick 83740665Smckusick if (vp->v_flag & VALIASED) { 83840665Smckusick /* 83940665Smckusick * If a vgone (or vclean) is already in progress, 84040665Smckusick * wait until it is done and return. 84140665Smckusick */ 84240665Smckusick if (vp->v_flag & VXLOCK) { 84340665Smckusick vp->v_flag |= VXWANT; 844*68319Scgd tsleep((caddr_t)vp, PINOD, "vgoneall", 0); 84540665Smckusick return; 84639633Smckusick } 84740665Smckusick /* 84840665Smckusick * Ensure that vp will not be vgone'd while we 84940665Smckusick * are eliminating its aliases. 85040665Smckusick */ 85140665Smckusick vp->v_flag |= VXLOCK; 85240665Smckusick while (vp->v_flag & VALIASED) { 85340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 85440665Smckusick if (vq->v_rdev != vp->v_rdev || 85540665Smckusick vq->v_type != vp->v_type || vp == vq) 85640665Smckusick continue; 85740665Smckusick vgone(vq); 85840665Smckusick break; 85940665Smckusick } 86040665Smckusick } 86140665Smckusick /* 86240665Smckusick * Remove the lock so that vgone below will 86340665Smckusick * really eliminate the vnode after which time 86440665Smckusick * vgone will awaken any sleepers. 86540665Smckusick */ 86640665Smckusick vp->v_flag &= ~VXLOCK; 86739633Smckusick } 86839633Smckusick vgone(vp); 86939633Smckusick } 87039633Smckusick 87139633Smckusick /* 87239433Smckusick * Eliminate all activity associated with a vnode 87339433Smckusick * in preparation for reuse. 87439433Smckusick */ 875*68319Scgd void 876*68319Scgd vgone(vp) 87739433Smckusick register struct vnode *vp; 87839433Smckusick { 87939809Smckusick register struct vnode *vq; 88039615Smckusick struct vnode *vx; 88139433Smckusick 88239433Smckusick /* 88340548Smckusick * If a vgone (or vclean) is already in progress, 88440548Smckusick * wait until it is done and return. 88540548Smckusick */ 88640548Smckusick if (vp->v_flag & VXLOCK) { 88740548Smckusick vp->v_flag |= VXWANT; 888*68319Scgd tsleep((caddr_t)vp, PINOD, "vgone", 0); 88940548Smckusick return; 89040548Smckusick } 89140548Smckusick /* 89239433Smckusick * Clean out the filesystem specific data. 89339433Smckusick */ 89441300Smckusick vclean(vp, DOCLOSE); 89539433Smckusick /* 89639433Smckusick * Delete from old mount point vnode list, if on one. 89739433Smckusick */ 89865260Smckusick if (vp->v_mount != NULL) { 89965260Smckusick LIST_REMOVE(vp, v_mntvnodes); 90052311Smckusick vp->v_mount = NULL; 90139433Smckusick } 90239433Smckusick /* 90339433Smckusick * If special device, remove it from special device alias list. 90439433Smckusick */ 90539433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 90639809Smckusick if (*vp->v_hashchain == vp) { 90739809Smckusick *vp->v_hashchain = vp->v_specnext; 90839433Smckusick } else { 90939809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 91039615Smckusick if (vq->v_specnext != vp) 91139433Smckusick continue; 91239615Smckusick vq->v_specnext = vp->v_specnext; 91339433Smckusick break; 91439433Smckusick } 91539615Smckusick if (vq == NULL) 91639433Smckusick panic("missing bdev"); 91739433Smckusick } 91839615Smckusick if (vp->v_flag & VALIASED) { 91952416Storek vx = NULL; 92039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 92140108Smckusick if (vq->v_rdev != vp->v_rdev || 92240108Smckusick vq->v_type != vp->v_type) 92339615Smckusick continue; 92452416Storek if (vx) 92552416Storek break; 92639615Smckusick vx = vq; 92739615Smckusick } 92852416Storek if (vx == NULL) 92939615Smckusick panic("missing alias"); 93052416Storek if (vq == NULL) 93139615Smckusick vx->v_flag &= ~VALIASED; 93239615Smckusick vp->v_flag &= ~VALIASED; 93339615Smckusick } 93439615Smckusick FREE(vp->v_specinfo, M_VNODE); 93539615Smckusick vp->v_specinfo = NULL; 93639433Smckusick } 93739433Smckusick /* 93856932Smckusick * If it is on the freelist and not already at the head, 93965505Smckusick * move it to the head of the list. The test of the back 94065505Smckusick * pointer and the reference count of zero is because 94165505Smckusick * it will be removed from the free list by getnewvnode, 94265505Smckusick * but will not have its reference count incremented until 94365505Smckusick * after calling vgone. If the reference count were 94465505Smckusick * incremented first, vgone would (incorrectly) try to 94565505Smckusick * close the previous instance of the underlying object. 94665505Smckusick * So, the back pointer is explicitly set to `0xdeadb' in 94765505Smckusick * getnewvnode after removing it from the freelist to ensure 94865505Smckusick * that we do not try to move it here. 94939433Smckusick */ 95065505Smckusick if (vp->v_usecount == 0 && 95165505Smckusick vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb && 95265505Smckusick vnode_free_list.tqh_first != vp) { 95365260Smckusick TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 95465260Smckusick TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 95539433Smckusick } 95639484Smckusick vp->v_type = VBAD; 95739433Smckusick } 95839633Smckusick 95939633Smckusick /* 96039821Smckusick * Lookup a vnode by device number. 96139821Smckusick */ 962*68319Scgd int 96339821Smckusick vfinddev(dev, type, vpp) 96439821Smckusick dev_t dev; 96539821Smckusick enum vtype type; 96639821Smckusick struct vnode **vpp; 96739821Smckusick { 96839821Smckusick register struct vnode *vp; 96939821Smckusick 97039821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 97139821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 97239821Smckusick continue; 97339821Smckusick *vpp = vp; 97459484Smckusick return (1); 97539821Smckusick } 97659484Smckusick return (0); 97739821Smckusick } 97839821Smckusick 97939821Smckusick /* 98039633Smckusick * Calculate the total number of references to a special device. 98139633Smckusick */ 982*68319Scgd int 98339633Smckusick vcount(vp) 98439633Smckusick register struct vnode *vp; 98539633Smckusick { 98666742Smckusick register struct vnode *vq, *vnext; 98739633Smckusick int count; 98839633Smckusick 98966742Smckusick loop: 99039633Smckusick if ((vp->v_flag & VALIASED) == 0) 99139809Smckusick return (vp->v_usecount); 99266742Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) { 99366742Smckusick vnext = vq->v_specnext; 99440108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 99539633Smckusick continue; 99639633Smckusick /* 99739633Smckusick * Alias, but not in use, so flush it out. 99839633Smckusick */ 99966742Smckusick if (vq->v_usecount == 0 && vq != vp) { 100039633Smckusick vgone(vq); 100139633Smckusick goto loop; 100239633Smckusick } 100339809Smckusick count += vq->v_usecount; 100439633Smckusick } 100539633Smckusick return (count); 100639633Smckusick } 100739667Smckusick 100839667Smckusick /* 100939667Smckusick * Print out a description of a vnode. 101039667Smckusick */ 101139667Smckusick static char *typename[] = 101240286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 101339667Smckusick 101468171Scgd void 101539667Smckusick vprint(label, vp) 101639667Smckusick char *label; 101739667Smckusick register struct vnode *vp; 101839667Smckusick { 101939913Smckusick char buf[64]; 102039667Smckusick 102139667Smckusick if (label != NULL) 102239667Smckusick printf("%s: ", label); 102350109Smckusick printf("type %s, usecount %d, writecount %d, refcount %d,", 102450109Smckusick typename[vp->v_type], vp->v_usecount, vp->v_writecount, 102550109Smckusick vp->v_holdcnt); 102639913Smckusick buf[0] = '\0'; 102739913Smckusick if (vp->v_flag & VROOT) 102839913Smckusick strcat(buf, "|VROOT"); 102939913Smckusick if (vp->v_flag & VTEXT) 103039913Smckusick strcat(buf, "|VTEXT"); 103141300Smckusick if (vp->v_flag & VSYSTEM) 103241300Smckusick strcat(buf, "|VSYSTEM"); 103341300Smckusick if (vp->v_flag & VXLOCK) 103441300Smckusick strcat(buf, "|VXLOCK"); 103541300Smckusick if (vp->v_flag & VXWANT) 103641300Smckusick strcat(buf, "|VXWANT"); 103741300Smckusick if (vp->v_flag & VBWAIT) 103841300Smckusick strcat(buf, "|VBWAIT"); 103939913Smckusick if (vp->v_flag & VALIASED) 104039913Smckusick strcat(buf, "|VALIASED"); 104139913Smckusick if (buf[0] != '\0') 104239913Smckusick printf(" flags (%s)", &buf[1]); 104365260Smckusick if (vp->v_data == NULL) { 104465260Smckusick printf("\n"); 104565260Smckusick } else { 104665260Smckusick printf("\n\t"); 104765260Smckusick VOP_PRINT(vp); 104865260Smckusick } 104939667Smckusick } 105041110Smarc 105149691Smckusick #ifdef DEBUG 105249691Smckusick /* 105349691Smckusick * List all of the locked vnodes in the system. 105449691Smckusick * Called when debugging the kernel. 105549691Smckusick */ 1056*68319Scgd void 105749691Smckusick printlockedvnodes() 105849691Smckusick { 105949691Smckusick register struct mount *mp; 106049691Smckusick register struct vnode *vp; 106149691Smckusick 106249691Smckusick printf("Locked vnodes\n"); 106365260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { 106465260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 106565260Smckusick vp != NULL; 106665260Smckusick vp = vp->v_mntvnodes.le_next) 106749691Smckusick if (VOP_ISLOCKED(vp)) 106849691Smckusick vprint((char *)0, vp); 106965260Smckusick } 107049691Smckusick } 107149691Smckusick #endif 107249691Smckusick 107341110Smarc int kinfo_vdebug = 1; 107441110Smarc int kinfo_vgetfailed; 107541110Smarc #define KINFO_VNODESLOP 10 107641110Smarc /* 107757841Smckusick * Dump vnode list (via sysctl). 107841110Smarc * Copyout address of vnode followed by vnode. 107941110Smarc */ 108045118Smckusick /* ARGSUSED */ 1081*68319Scgd int 108257841Smckusick sysctl_vnode(where, sizep) 108341110Smarc char *where; 108458465Sbostic size_t *sizep; 108541110Smarc { 108665260Smckusick register struct mount *mp, *nmp; 108741110Smarc struct vnode *vp; 108841110Smarc register char *bp = where, *savebp; 108953818Smckusick char *ewhere; 109041110Smarc int error; 109141110Smarc 109241110Smarc #define VPTRSZ sizeof (struct vnode *) 109341110Smarc #define VNODESZ sizeof (struct vnode) 109441110Smarc if (where == NULL) { 109557841Smckusick *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 109641110Smarc return (0); 109741110Smarc } 109857841Smckusick ewhere = where + *sizep; 109941110Smarc 110065260Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 110165260Smckusick nmp = mp->mnt_list.tqe_next; 110265260Smckusick if (vfs_busy(mp)) 110341300Smckusick continue; 110441110Smarc savebp = bp; 110541110Smarc again: 110665260Smckusick for (vp = mp->mnt_vnodelist.lh_first; 110765260Smckusick vp != NULL; 110865260Smckusick vp = vp->v_mntvnodes.le_next) { 110941422Smckusick /* 111041422Smckusick * Check that the vp is still associated with 111141422Smckusick * this filesystem. RACE: could have been 111241422Smckusick * recycled onto the same filesystem. 111341422Smckusick */ 111441421Smckusick if (vp->v_mount != mp) { 111541421Smckusick if (kinfo_vdebug) 111641421Smckusick printf("kinfo: vp changed\n"); 111741421Smckusick bp = savebp; 111841421Smckusick goto again; 111941421Smckusick } 112057841Smckusick if (bp + VPTRSZ + VNODESZ > ewhere) { 112157841Smckusick *sizep = bp - where; 112257841Smckusick return (ENOMEM); 112357841Smckusick } 112457841Smckusick if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 112557841Smckusick (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ))) 112641110Smarc return (error); 112741110Smarc bp += VPTRSZ + VNODESZ; 112841110Smarc } 112965260Smckusick vfs_unbusy(mp); 113065260Smckusick } 113141110Smarc 113257841Smckusick *sizep = bp - where; 113341110Smarc return (0); 113441110Smarc } 113565679Shibler 113665679Shibler /* 113765679Shibler * Check to see if a filesystem is mounted on a block device. 113865679Shibler */ 113965679Shibler int 114065679Shibler vfs_mountedon(vp) 114165679Shibler register struct vnode *vp; 114265679Shibler { 114365679Shibler register struct vnode *vq; 114465679Shibler 114565679Shibler if (vp->v_specflags & SI_MOUNTEDON) 114665679Shibler return (EBUSY); 114765679Shibler if (vp->v_flag & VALIASED) { 114865679Shibler for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 114965679Shibler if (vq->v_rdev != vp->v_rdev || 115065679Shibler vq->v_type != vp->v_type) 115165679Shibler continue; 115265679Shibler if (vq->v_specflags & SI_MOUNTEDON) 115365679Shibler return (EBUSY); 115465679Shibler } 115565679Shibler } 115665679Shibler return (0); 115765679Shibler } 115865679Shibler 115965679Shibler /* 116065679Shibler * Build hash lists of net addresses and hang them off the mount point. 116165679Shibler * Called by ufs_mount() to set up the lists of export addresses. 116265679Shibler */ 116365679Shibler static int 116465679Shibler vfs_hang_addrlist(mp, nep, argp) 116565679Shibler struct mount *mp; 116665679Shibler struct netexport *nep; 116765679Shibler struct export_args *argp; 116865679Shibler { 116965679Shibler register struct netcred *np; 117065679Shibler register struct radix_node_head *rnh; 117165679Shibler register int i; 117265679Shibler struct radix_node *rn; 117365679Shibler struct sockaddr *saddr, *smask = 0; 117465679Shibler struct domain *dom; 117565679Shibler int error; 117665679Shibler 117765679Shibler if (argp->ex_addrlen == 0) { 117865679Shibler if (mp->mnt_flag & MNT_DEFEXPORTED) 117965679Shibler return (EPERM); 118065679Shibler np = &nep->ne_defexported; 118165679Shibler np->netc_exflags = argp->ex_flags; 118265679Shibler np->netc_anon = argp->ex_anon; 118365679Shibler np->netc_anon.cr_ref = 1; 118465679Shibler mp->mnt_flag |= MNT_DEFEXPORTED; 118565679Shibler return (0); 118665679Shibler } 118765679Shibler i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 118865679Shibler np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); 118965679Shibler bzero((caddr_t)np, i); 119065679Shibler saddr = (struct sockaddr *)(np + 1); 119165679Shibler if (error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen)) 119265679Shibler goto out; 119365679Shibler if (saddr->sa_len > argp->ex_addrlen) 119465679Shibler saddr->sa_len = argp->ex_addrlen; 119565679Shibler if (argp->ex_masklen) { 119665679Shibler smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); 119765679Shibler error = copyin(argp->ex_addr, (caddr_t)smask, argp->ex_masklen); 119865679Shibler if (error) 119965679Shibler goto out; 120065679Shibler if (smask->sa_len > argp->ex_masklen) 120165679Shibler smask->sa_len = argp->ex_masklen; 120265679Shibler } 120365679Shibler i = saddr->sa_family; 120465679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 120565679Shibler /* 120665679Shibler * Seems silly to initialize every AF when most are not 120765679Shibler * used, do so on demand here 120865679Shibler */ 120965679Shibler for (dom = domains; dom; dom = dom->dom_next) 121065679Shibler if (dom->dom_family == i && dom->dom_rtattach) { 121165679Shibler dom->dom_rtattach((void **)&nep->ne_rtable[i], 121265679Shibler dom->dom_rtoffset); 121365679Shibler break; 121465679Shibler } 121565679Shibler if ((rnh = nep->ne_rtable[i]) == 0) { 121665679Shibler error = ENOBUFS; 121765679Shibler goto out; 121865679Shibler } 121965679Shibler } 122065679Shibler rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, 122165679Shibler np->netc_rnodes); 122265679Shibler if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ 122365679Shibler error = EPERM; 122465679Shibler goto out; 122565679Shibler } 122665679Shibler np->netc_exflags = argp->ex_flags; 122765679Shibler np->netc_anon = argp->ex_anon; 122865679Shibler np->netc_anon.cr_ref = 1; 122965679Shibler return (0); 123065679Shibler out: 123165679Shibler free(np, M_NETADDR); 123265679Shibler return (error); 123365679Shibler } 123465679Shibler 123565679Shibler /* ARGSUSED */ 123665679Shibler static int 123765679Shibler vfs_free_netcred(rn, w) 123865679Shibler struct radix_node *rn; 123965679Shibler caddr_t w; 124065679Shibler { 124165679Shibler register struct radix_node_head *rnh = (struct radix_node_head *)w; 124265679Shibler 124365679Shibler (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); 124465679Shibler free((caddr_t)rn, M_NETADDR); 124565679Shibler return (0); 124665679Shibler } 1247*68319Scgd 124865679Shibler /* 124965679Shibler * Free the net address hash lists that are hanging off the mount points. 125065679Shibler */ 125165679Shibler static void 125265679Shibler vfs_free_addrlist(nep) 125365679Shibler struct netexport *nep; 125465679Shibler { 125565679Shibler register int i; 125665679Shibler register struct radix_node_head *rnh; 125765679Shibler 125865679Shibler for (i = 0; i <= AF_MAX; i++) 125965679Shibler if (rnh = nep->ne_rtable[i]) { 126065679Shibler (*rnh->rnh_walktree)(rnh, vfs_free_netcred, 126165679Shibler (caddr_t)rnh); 126265679Shibler free((caddr_t)rnh, M_RTABLE); 126365679Shibler nep->ne_rtable[i] = 0; 126465679Shibler } 126565679Shibler } 126665679Shibler 126765679Shibler int 126865679Shibler vfs_export(mp, nep, argp) 126965679Shibler struct mount *mp; 127065679Shibler struct netexport *nep; 127165679Shibler struct export_args *argp; 127265679Shibler { 127365679Shibler int error; 127465679Shibler 127565679Shibler if (argp->ex_flags & MNT_DELEXPORT) { 127665679Shibler vfs_free_addrlist(nep); 127765679Shibler mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 127865679Shibler } 127965679Shibler if (argp->ex_flags & MNT_EXPORTED) { 128065679Shibler if (error = vfs_hang_addrlist(mp, nep, argp)) 128165679Shibler return (error); 128265679Shibler mp->mnt_flag |= MNT_EXPORTED; 128365679Shibler } 128465679Shibler return (0); 128565679Shibler } 128665679Shibler 128765679Shibler struct netcred * 128865679Shibler vfs_export_lookup(mp, nep, nam) 128965679Shibler register struct mount *mp; 129065679Shibler struct netexport *nep; 129165679Shibler struct mbuf *nam; 129265679Shibler { 129365679Shibler register struct netcred *np; 129465679Shibler register struct radix_node_head *rnh; 129565679Shibler struct sockaddr *saddr; 129665679Shibler 129765679Shibler np = NULL; 129865679Shibler if (mp->mnt_flag & MNT_EXPORTED) { 129965679Shibler /* 130065679Shibler * Lookup in the export list first. 130165679Shibler */ 130265679Shibler if (nam != NULL) { 130365679Shibler saddr = mtod(nam, struct sockaddr *); 130465679Shibler rnh = nep->ne_rtable[saddr->sa_family]; 130565679Shibler if (rnh != NULL) { 130665679Shibler np = (struct netcred *) 130765679Shibler (*rnh->rnh_matchaddr)((caddr_t)saddr, 130865679Shibler rnh); 130965679Shibler if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 131065679Shibler np = NULL; 131165679Shibler } 131265679Shibler } 131365679Shibler /* 131465679Shibler * If no address match, use the default if it exists. 131565679Shibler */ 131665679Shibler if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 131765679Shibler np = &nep->ne_defexported; 131865679Shibler } 131965679Shibler return (np); 132065679Shibler } 1321