1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38996c772fSJohn Dyson * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 39f6b4c285SDoug Rabson * $Id: vfs_subr.c,v 1.88 1997/06/22 03:00:21 dyson Exp $ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes /* 43df8bae1dSRodney W. Grimes * External virtual filesystem routines 44df8bae1dSRodney W. Grimes */ 450e41ee30SGarrett Wollman #include "opt_ddb.h" 4619060a3aSPoul-Henning Kamp #include "opt_devfs.h" 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50986f4ce7SBruce Evans #include <sys/kernel.h> 516acceb40SBruce Evans #include <sys/file.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 53df8bae1dSRodney W. Grimes #include <sys/mount.h> 54df8bae1dSRodney W. Grimes #include <sys/time.h> 55df8bae1dSRodney W. Grimes #include <sys/vnode.h> 56df8bae1dSRodney W. Grimes #include <sys/stat.h> 57df8bae1dSRodney W. Grimes #include <sys/namei.h> 58df8bae1dSRodney W. Grimes #include <sys/ucred.h> 59df8bae1dSRodney W. Grimes #include <sys/buf.h> 60df8bae1dSRodney W. Grimes #include <sys/errno.h> 61df8bae1dSRodney W. Grimes #include <sys/malloc.h> 62df8bae1dSRodney W. Grimes #include <sys/domain.h> 63df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 64f6b4c285SDoug Rabson #include <sys/dirent.h> 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes #include <vm/vm.h> 67efeaf95aSDavid Greenman #include <vm/vm_param.h> 68efeaf95aSDavid Greenman #include <vm/vm_object.h> 69efeaf95aSDavid Greenman #include <vm/vm_extern.h> 706476c0d2SJohn Dyson #include <vm/vm_pager.h> 716476c0d2SJohn Dyson #include <vm/vnode_pager.h> 72df8bae1dSRodney W. Grimes #include <sys/sysctl.h> 73df8bae1dSRodney W. Grimes 74df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 75df8bae1dSRodney W. Grimes 7698d93822SBruce Evans #ifdef DDB 7798d93822SBruce Evans extern void printlockedvnodes __P((void)); 7898d93822SBruce Evans #endif 79996c772fSJohn Dyson static void vclean __P((struct vnode *vp, int flags, struct proc *p)); 800f1adf65SBruce Evans static void vgonel __P((struct vnode *vp, struct proc *p)); 81996c772fSJohn Dyson unsigned long numvnodes; 82b15a966eSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, ""); 8382b8e119SJohn Dyson static void vputrele __P((struct vnode *vp, int put)); 8498d93822SBruce Evans 85df8bae1dSRodney W. Grimes enum vtype iftovt_tab[16] = { 86df8bae1dSRodney W. Grimes VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 87df8bae1dSRodney W. Grimes VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 88df8bae1dSRodney W. Grimes }; 89df8bae1dSRodney W. Grimes int vttoif_tab[9] = { 90df8bae1dSRodney W. Grimes 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 91df8bae1dSRodney W. Grimes S_IFSOCK, S_IFIFO, S_IFMT, 92df8bae1dSRodney W. Grimes }; 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes /* 95df8bae1dSRodney W. Grimes * Insq/Remq for the vnode usage lists. 96df8bae1dSRodney W. Grimes */ 97df8bae1dSRodney W. Grimes #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) 98df8bae1dSRodney W. Grimes #define bufremvn(bp) { \ 99df8bae1dSRodney W. Grimes LIST_REMOVE(bp, b_vnbufs); \ 100df8bae1dSRodney W. Grimes (bp)->b_vnbufs.le_next = NOLIST; \ 101df8bae1dSRodney W. Grimes } 102df8bae1dSRodney W. Grimes TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ 103cba2a7c6SBruce Evans static u_long freevnodes = 0; 104fbd6e6c9SPoul-Henning Kamp 105df8bae1dSRodney W. Grimes struct mntlist mountlist; /* mounted filesystem list */ 106996c772fSJohn Dyson struct simplelock mountlist_slock; 107996c772fSJohn Dyson static struct simplelock mntid_slock; 108996c772fSJohn Dyson struct simplelock mntvnode_slock; 109996c772fSJohn Dyson struct simplelock vnode_free_list_slock; 110996c772fSJohn Dyson static struct simplelock spechash_slock; 111f6b4c285SDoug Rabson struct nfs_public nfs_pub; /* publicly exported FS */ 112df8bae1dSRodney W. Grimes 1130d94caffSDavid Greenman int desiredvnodes; 114b83ddf9cSBruce Evans SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW, &desiredvnodes, 0, ""); 1150d94caffSDavid Greenman 11698d93822SBruce Evans static void vfs_free_addrlist __P((struct netexport *nep)); 11798d93822SBruce Evans static int vfs_free_netcred __P((struct radix_node *rn, void *w)); 11898d93822SBruce Evans static int vfs_hang_addrlist __P((struct mount *mp, struct netexport *nep, 11998d93822SBruce Evans struct export_args *argp)); 12098d93822SBruce Evans 121df8bae1dSRodney W. Grimes /* 122df8bae1dSRodney W. Grimes * Initialize the vnode management data structures. 123df8bae1dSRodney W. Grimes */ 12426f9a767SRodney W. Grimes void 125df8bae1dSRodney W. Grimes vntblinit() 126df8bae1dSRodney W. Grimes { 127df8bae1dSRodney W. Grimes 1285131d64eSBruce Evans desiredvnodes = maxproc + vm_object_cache_max; 129996c772fSJohn Dyson simple_lock_init(&mntvnode_slock); 130996c772fSJohn Dyson simple_lock_init(&mntid_slock); 131996c772fSJohn Dyson simple_lock_init(&spechash_slock); 132df8bae1dSRodney W. Grimes TAILQ_INIT(&vnode_free_list); 133996c772fSJohn Dyson simple_lock_init(&vnode_free_list_slock); 134628641f8SDavid Greenman CIRCLEQ_INIT(&mountlist); 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes 137df8bae1dSRodney W. Grimes /* 138996c772fSJohn Dyson * Mark a mount point as busy. Used to synchronize access and to delay 139996c772fSJohn Dyson * unmounting. Interlock is not released on failure. 140df8bae1dSRodney W. Grimes */ 14126f9a767SRodney W. Grimes int 142996c772fSJohn Dyson vfs_busy(mp, flags, interlkp, p) 143996c772fSJohn Dyson struct mount *mp; 144996c772fSJohn Dyson int flags; 145996c772fSJohn Dyson struct simplelock *interlkp; 146996c772fSJohn Dyson struct proc *p; 147df8bae1dSRodney W. Grimes { 148996c772fSJohn Dyson int lkflags; 149df8bae1dSRodney W. Grimes 150996c772fSJohn Dyson if (mp->mnt_flag & MNT_UNMOUNT) { 151996c772fSJohn Dyson if (flags & LK_NOWAIT) 152996c772fSJohn Dyson return (ENOENT); 153df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_MWAIT; 154996c772fSJohn Dyson if (interlkp) { 155996c772fSJohn Dyson simple_unlock(interlkp); 156df8bae1dSRodney W. Grimes } 157df8bae1dSRodney W. Grimes /* 158996c772fSJohn Dyson * Since all busy locks are shared except the exclusive 159996c772fSJohn Dyson * lock granted when unmounting, the only place that a 160996c772fSJohn Dyson * wakeup needs to be done is at the release of the 161996c772fSJohn Dyson * exclusive lock at the end of dounmount. 162df8bae1dSRodney W. Grimes */ 163996c772fSJohn Dyson tsleep((caddr_t)mp, PVFS, "vfs_busy", 0); 164996c772fSJohn Dyson if (interlkp) { 165996c772fSJohn Dyson simple_lock(interlkp); 166df8bae1dSRodney W. Grimes } 167996c772fSJohn Dyson return (ENOENT); 168df8bae1dSRodney W. Grimes } 169996c772fSJohn Dyson lkflags = LK_SHARED; 170996c772fSJohn Dyson if (interlkp) 171996c772fSJohn Dyson lkflags |= LK_INTERLOCK; 172996c772fSJohn Dyson if (lockmgr(&mp->mnt_lock, lkflags, interlkp, p)) 173996c772fSJohn Dyson panic("vfs_busy: unexpected lock failure"); 174df8bae1dSRodney W. Grimes return (0); 175df8bae1dSRodney W. Grimes } 176df8bae1dSRodney W. Grimes 177df8bae1dSRodney W. Grimes /* 178df8bae1dSRodney W. Grimes * Free a busy filesystem. 179df8bae1dSRodney W. Grimes */ 18026f9a767SRodney W. Grimes void 181996c772fSJohn Dyson vfs_unbusy(mp, p) 182996c772fSJohn Dyson struct mount *mp; 183996c772fSJohn Dyson struct proc *p; 184df8bae1dSRodney W. Grimes { 185df8bae1dSRodney W. Grimes 186996c772fSJohn Dyson lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, p); 187e0e9c421SDavid Greenman } 188e0e9c421SDavid Greenman 189e0e9c421SDavid Greenman /* 190996c772fSJohn Dyson * Lookup a filesystem type, and if found allocate and initialize 191996c772fSJohn Dyson * a mount structure for it. 192996c772fSJohn Dyson * 193996c772fSJohn Dyson * Devname is usually updated by mount(8) after booting. 194e0e9c421SDavid Greenman */ 195996c772fSJohn Dyson int 196996c772fSJohn Dyson vfs_rootmountalloc(fstypename, devname, mpp) 197996c772fSJohn Dyson char *fstypename; 198996c772fSJohn Dyson char *devname; 199996c772fSJohn Dyson struct mount **mpp; 200e0e9c421SDavid Greenman { 201996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 202996c772fSJohn Dyson struct vfsconf *vfsp; 203996c772fSJohn Dyson struct mount *mp; 204996c772fSJohn Dyson 205996c772fSJohn Dyson for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 206996c772fSJohn Dyson if (!strcmp(vfsp->vfc_name, fstypename)) 207996c772fSJohn Dyson break; 208996c772fSJohn Dyson if (vfsp == NULL) 209996c772fSJohn Dyson return (ENODEV); 210996c772fSJohn Dyson mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 211996c772fSJohn Dyson bzero((char *)mp, (u_long)sizeof(struct mount)); 212996c772fSJohn Dyson lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 213996c772fSJohn Dyson (void)vfs_busy(mp, LK_NOWAIT, 0, p); 214996c772fSJohn Dyson LIST_INIT(&mp->mnt_vnodelist); 215996c772fSJohn Dyson mp->mnt_vfc = vfsp; 216996c772fSJohn Dyson mp->mnt_op = vfsp->vfc_vfsops; 217996c772fSJohn Dyson mp->mnt_flag = MNT_RDONLY; 218996c772fSJohn Dyson mp->mnt_vnodecovered = NULLVP; 219996c772fSJohn Dyson vfsp->vfc_refcount++; 220996c772fSJohn Dyson mp->mnt_stat.f_type = vfsp->vfc_typenum; 221996c772fSJohn Dyson mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 222996c772fSJohn Dyson strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 223996c772fSJohn Dyson mp->mnt_stat.f_mntonname[0] = '/'; 224996c772fSJohn Dyson mp->mnt_stat.f_mntonname[1] = 0; 225996c772fSJohn Dyson (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0); 226996c772fSJohn Dyson *mpp = mp; 227996c772fSJohn Dyson return (0); 228996c772fSJohn Dyson } 229996c772fSJohn Dyson 230996c772fSJohn Dyson /* 231996c772fSJohn Dyson * Find an appropriate filesystem to use for the root. If a filesystem 232996c772fSJohn Dyson * has not been preselected, walk through the list of known filesystems 233996c772fSJohn Dyson * trying those that have mountroot routines, and try them until one 234996c772fSJohn Dyson * works or we have tried them all. 235996c772fSJohn Dyson */ 236996c772fSJohn Dyson #ifdef notdef /* XXX JH */ 237996c772fSJohn Dyson int 238996c772fSJohn Dyson lite2_vfs_mountroot(void) 239996c772fSJohn Dyson { 240996c772fSJohn Dyson struct vfsconf *vfsp; 241996c772fSJohn Dyson extern int (*lite2_mountroot)(void); 242e0e9c421SDavid Greenman int error; 243e0e9c421SDavid Greenman 244996c772fSJohn Dyson if (lite2_mountroot != NULL) 245996c772fSJohn Dyson return ((*lite2_mountroot)()); 246996c772fSJohn Dyson for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { 247996c772fSJohn Dyson if (vfsp->vfc_mountroot == NULL) 248e0e9c421SDavid Greenman continue; 249996c772fSJohn Dyson if ((error = (*vfsp->vfc_mountroot)()) == 0) 250996c772fSJohn Dyson return (0); 251996c772fSJohn Dyson printf("%s_mountroot failed: %d\n", vfsp->vfc_name, error); 252e0e9c421SDavid Greenman } 253996c772fSJohn Dyson return (ENODEV); 254e0e9c421SDavid Greenman } 255996c772fSJohn Dyson #endif 256e0e9c421SDavid Greenman 257df8bae1dSRodney W. Grimes /* 258df8bae1dSRodney W. Grimes * Lookup a mount point by filesystem identifier. 259df8bae1dSRodney W. Grimes */ 260df8bae1dSRodney W. Grimes struct mount * 261996c772fSJohn Dyson vfs_getvfs(fsid) 262df8bae1dSRodney W. Grimes fsid_t *fsid; 263df8bae1dSRodney W. Grimes { 264df8bae1dSRodney W. Grimes register struct mount *mp; 265df8bae1dSRodney W. Grimes 266996c772fSJohn Dyson simple_lock(&mountlist_slock); 267628641f8SDavid Greenman for (mp = mountlist.cqh_first; mp != (void *)&mountlist; 268628641f8SDavid Greenman mp = mp->mnt_list.cqe_next) { 269df8bae1dSRodney W. Grimes if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 270996c772fSJohn Dyson mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 271996c772fSJohn Dyson simple_unlock(&mountlist_slock); 272df8bae1dSRodney W. Grimes return (mp); 273df8bae1dSRodney W. Grimes } 274996c772fSJohn Dyson } 275996c772fSJohn Dyson simple_unlock(&mountlist_slock); 276df8bae1dSRodney W. Grimes return ((struct mount *) 0); 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes /* 280df8bae1dSRodney W. Grimes * Get a new unique fsid 281df8bae1dSRodney W. Grimes */ 282df8bae1dSRodney W. Grimes void 283996c772fSJohn Dyson vfs_getnewfsid(mp) 284df8bae1dSRodney W. Grimes struct mount *mp; 285df8bae1dSRodney W. Grimes { 286df8bae1dSRodney W. Grimes static u_short xxxfs_mntid; 287df8bae1dSRodney W. Grimes 288df8bae1dSRodney W. Grimes fsid_t tfsid; 289996c772fSJohn Dyson int mtype; 290df8bae1dSRodney W. Grimes 291996c772fSJohn Dyson simple_lock(&mntid_slock); 292996c772fSJohn Dyson mtype = mp->mnt_vfc->vfc_typenum; 293df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); 294df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[1] = mtype; 295df8bae1dSRodney W. Grimes if (xxxfs_mntid == 0) 296df8bae1dSRodney W. Grimes ++xxxfs_mntid; 297df8bae1dSRodney W. Grimes tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); 298df8bae1dSRodney W. Grimes tfsid.val[1] = mtype; 299628641f8SDavid Greenman if (mountlist.cqh_first != (void *)&mountlist) { 300996c772fSJohn Dyson while (vfs_getvfs(&tfsid)) { 301df8bae1dSRodney W. Grimes tfsid.val[0]++; 302df8bae1dSRodney W. Grimes xxxfs_mntid++; 303df8bae1dSRodney W. Grimes } 304df8bae1dSRodney W. Grimes } 305df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 306996c772fSJohn Dyson simple_unlock(&mntid_slock); 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes /* 310df8bae1dSRodney W. Grimes * Set vnode attributes to VNOVAL 311df8bae1dSRodney W. Grimes */ 31226f9a767SRodney W. Grimes void 31326f9a767SRodney W. Grimes vattr_null(vap) 314df8bae1dSRodney W. Grimes register struct vattr *vap; 315df8bae1dSRodney W. Grimes { 316df8bae1dSRodney W. Grimes 317df8bae1dSRodney W. Grimes vap->va_type = VNON; 31826f9a767SRodney W. Grimes vap->va_size = VNOVAL; 31926f9a767SRodney W. Grimes vap->va_bytes = VNOVAL; 320df8bae1dSRodney W. Grimes vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 321df8bae1dSRodney W. Grimes vap->va_fsid = vap->va_fileid = 322df8bae1dSRodney W. Grimes vap->va_blocksize = vap->va_rdev = 323030e2e9eSNate Williams vap->va_atime.tv_sec = vap->va_atime.tv_nsec = 324030e2e9eSNate Williams vap->va_mtime.tv_sec = vap->va_mtime.tv_nsec = 325030e2e9eSNate Williams vap->va_ctime.tv_sec = vap->va_ctime.tv_nsec = 326df8bae1dSRodney W. Grimes vap->va_flags = vap->va_gen = VNOVAL; 327df8bae1dSRodney W. Grimes vap->va_vaflags = 0; 328df8bae1dSRodney W. Grimes } 329df8bae1dSRodney W. Grimes 330df8bae1dSRodney W. Grimes /* 331df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 332df8bae1dSRodney W. Grimes */ 333f57e6547SBruce Evans extern vop_t **dead_vnodeop_p; 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Return the next vnode from the free list. 337df8bae1dSRodney W. Grimes */ 33826f9a767SRodney W. Grimes int 339df8bae1dSRodney W. Grimes getnewvnode(tag, mp, vops, vpp) 340df8bae1dSRodney W. Grimes enum vtagtype tag; 341df8bae1dSRodney W. Grimes struct mount *mp; 342f57e6547SBruce Evans vop_t **vops; 343df8bae1dSRodney W. Grimes struct vnode **vpp; 344df8bae1dSRodney W. Grimes { 345996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 346996c772fSJohn Dyson struct vnode *vp; 347df8bae1dSRodney W. Grimes 348b15a966eSPoul-Henning Kamp /* 349b15a966eSPoul-Henning Kamp * We take the least recently used vnode from the freelist 350b15a966eSPoul-Henning Kamp * if we can get it and it has no cached pages, and no 351b15a966eSPoul-Henning Kamp * namecache entries are relative to it. 352b15a966eSPoul-Henning Kamp * Otherwise we allocate a new vnode 353b15a966eSPoul-Henning Kamp */ 354b15a966eSPoul-Henning Kamp 355996c772fSJohn Dyson simple_lock(&vnode_free_list_slock); 356b15a966eSPoul-Henning Kamp 357b15a966eSPoul-Henning Kamp TAILQ_FOREACH(vp, &vnode_free_list, v_freelist) { 358b15a966eSPoul-Henning Kamp if (!simple_lock_try(&vp->v_interlock)) 359b15a966eSPoul-Henning Kamp continue; 360996c772fSJohn Dyson if (vp->v_usecount) 361996c772fSJohn Dyson panic("free vnode isn't"); 362fbd6e6c9SPoul-Henning Kamp 363b15a966eSPoul-Henning Kamp if (vp->v_object && vp->v_object->resident_page_count) { 364b15a966eSPoul-Henning Kamp /* Don't recycle if it's caching some pages */ 365b15a966eSPoul-Henning Kamp simple_unlock(&vp->v_interlock); 366b15a966eSPoul-Henning Kamp continue; 367b15a966eSPoul-Henning Kamp } else if (LIST_FIRST(&vp->v_cache_src)) { 368b15a966eSPoul-Henning Kamp /* Don't recycle if active in the namecache */ 369b15a966eSPoul-Henning Kamp simple_unlock(&vp->v_interlock); 370b15a966eSPoul-Henning Kamp continue; 371b15a966eSPoul-Henning Kamp } else { 372b15a966eSPoul-Henning Kamp break; 373b15a966eSPoul-Henning Kamp } 374b15a966eSPoul-Henning Kamp } 375b15a966eSPoul-Henning Kamp if (vp) { 376b15a966eSPoul-Henning Kamp TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 377b15a966eSPoul-Henning Kamp freevnodes--; 378df8bae1dSRodney W. Grimes /* see comment on why 0xdeadb is set at end of vgone (below) */ 379df8bae1dSRodney W. Grimes vp->v_freelist.tqe_prev = (struct vnode **) 0xdeadb; 380996c772fSJohn Dyson simple_unlock(&vnode_free_list_slock); 381df8bae1dSRodney W. Grimes vp->v_lease = NULL; 382df8bae1dSRodney W. Grimes if (vp->v_type != VBAD) 383996c772fSJohn Dyson vgonel(vp, p); 384996c772fSJohn Dyson else { 385996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 386996c772fSJohn Dyson } 387bd7e5f99SJohn Dyson 388df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 389797f2d22SPoul-Henning Kamp { 390797f2d22SPoul-Henning Kamp int s; 3910d94caffSDavid Greenman 392df8bae1dSRodney W. Grimes if (vp->v_data) 393df8bae1dSRodney W. Grimes panic("cleaned vnode isn't"); 394df8bae1dSRodney W. Grimes s = splbio(); 395df8bae1dSRodney W. Grimes if (vp->v_numoutput) 396df8bae1dSRodney W. Grimes panic("Clean vnode has pending I/O's"); 397df8bae1dSRodney W. Grimes splx(s); 398797f2d22SPoul-Henning Kamp } 399df8bae1dSRodney W. Grimes #endif 400df8bae1dSRodney W. Grimes vp->v_flag = 0; 401df8bae1dSRodney W. Grimes vp->v_lastr = 0; 402df8bae1dSRodney W. Grimes vp->v_lastw = 0; 403df8bae1dSRodney W. Grimes vp->v_lasta = 0; 404df8bae1dSRodney W. Grimes vp->v_cstart = 0; 405df8bae1dSRodney W. Grimes vp->v_clen = 0; 406df8bae1dSRodney W. Grimes vp->v_socket = 0; 407e0c02154SDavid Greenman vp->v_writecount = 0; /* XXX */ 408b15a966eSPoul-Henning Kamp } else { 409b15a966eSPoul-Henning Kamp simple_unlock(&vnode_free_list_slock); 410b15a966eSPoul-Henning Kamp vp = (struct vnode *) malloc((u_long) sizeof *vp, 411b15a966eSPoul-Henning Kamp M_VNODE, M_WAITOK); 412b15a966eSPoul-Henning Kamp bzero((char *) vp, sizeof *vp); 413b15a966eSPoul-Henning Kamp vp->v_dd = vp; 414b15a966eSPoul-Henning Kamp LIST_INIT(&vp->v_cache_src); 415b15a966eSPoul-Henning Kamp TAILQ_INIT(&vp->v_cache_dst); 416b15a966eSPoul-Henning Kamp numvnodes++; 417df8bae1dSRodney W. Grimes } 418b15a966eSPoul-Henning Kamp 419f9ceb7c7SDavid Greenman vp->v_type = VNON; 4207500ed1dSDavid Greenman cache_purge(vp); 421df8bae1dSRodney W. Grimes vp->v_tag = tag; 422df8bae1dSRodney W. Grimes vp->v_op = vops; 423df8bae1dSRodney W. Grimes insmntque(vp, mp); 424df8bae1dSRodney W. Grimes *vpp = vp; 425df8bae1dSRodney W. Grimes vp->v_usecount = 1; 426df8bae1dSRodney W. Grimes vp->v_data = 0; 427df8bae1dSRodney W. Grimes return (0); 428df8bae1dSRodney W. Grimes } 429df8bae1dSRodney W. Grimes 430df8bae1dSRodney W. Grimes /* 431df8bae1dSRodney W. Grimes * Move a vnode from one mount queue to another. 432df8bae1dSRodney W. Grimes */ 43326f9a767SRodney W. Grimes void 434df8bae1dSRodney W. Grimes insmntque(vp, mp) 435df8bae1dSRodney W. Grimes register struct vnode *vp; 436df8bae1dSRodney W. Grimes register struct mount *mp; 437df8bae1dSRodney W. Grimes { 438df8bae1dSRodney W. Grimes 439996c772fSJohn Dyson simple_lock(&mntvnode_slock); 440df8bae1dSRodney W. Grimes /* 441df8bae1dSRodney W. Grimes * Delete from old mount point vnode list, if on one. 442df8bae1dSRodney W. Grimes */ 443df8bae1dSRodney W. Grimes if (vp->v_mount != NULL) 444df8bae1dSRodney W. Grimes LIST_REMOVE(vp, v_mntvnodes); 445df8bae1dSRodney W. Grimes /* 446df8bae1dSRodney W. Grimes * Insert into list of vnodes for the new mount point, if available. 447df8bae1dSRodney W. Grimes */ 448996c772fSJohn Dyson if ((vp->v_mount = mp) == NULL) { 449996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 450df8bae1dSRodney W. Grimes return; 451996c772fSJohn Dyson } 452df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); 453996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 454df8bae1dSRodney W. Grimes } 455df8bae1dSRodney W. Grimes 456df8bae1dSRodney W. Grimes /* 457df8bae1dSRodney W. Grimes * Update outstanding I/O count and do wakeup if requested. 458df8bae1dSRodney W. Grimes */ 45926f9a767SRodney W. Grimes void 460df8bae1dSRodney W. Grimes vwakeup(bp) 461df8bae1dSRodney W. Grimes register struct buf *bp; 462df8bae1dSRodney W. Grimes { 463df8bae1dSRodney W. Grimes register struct vnode *vp; 464df8bae1dSRodney W. Grimes 465df8bae1dSRodney W. Grimes bp->b_flags &= ~B_WRITEINPROG; 466bb56ec4aSPoul-Henning Kamp if ((vp = bp->b_vp)) { 467df8bae1dSRodney W. Grimes vp->v_numoutput--; 468df8bae1dSRodney W. Grimes if (vp->v_numoutput < 0) 469df8bae1dSRodney W. Grimes panic("vwakeup: neg numoutput"); 470a3a8bb29SDavid Greenman if ((vp->v_numoutput == 0) && (vp->v_flag & VBWAIT)) { 471df8bae1dSRodney W. Grimes vp->v_flag &= ~VBWAIT; 472df8bae1dSRodney W. Grimes wakeup((caddr_t) &vp->v_numoutput); 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes } 475df8bae1dSRodney W. Grimes } 476df8bae1dSRodney W. Grimes 477df8bae1dSRodney W. Grimes /* 478df8bae1dSRodney W. Grimes * Flush out and invalidate all buffers associated with a vnode. 479df8bae1dSRodney W. Grimes * Called with the underlying object locked. 480df8bae1dSRodney W. Grimes */ 481df8bae1dSRodney W. Grimes int 482df8bae1dSRodney W. Grimes vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 483df8bae1dSRodney W. Grimes register struct vnode *vp; 484df8bae1dSRodney W. Grimes int flags; 485df8bae1dSRodney W. Grimes struct ucred *cred; 486df8bae1dSRodney W. Grimes struct proc *p; 487df8bae1dSRodney W. Grimes int slpflag, slptimeo; 488df8bae1dSRodney W. Grimes { 489df8bae1dSRodney W. Grimes register struct buf *bp; 490df8bae1dSRodney W. Grimes struct buf *nbp, *blist; 491df8bae1dSRodney W. Grimes int s, error; 4921cdeb653SDavid Greenman vm_object_t object; 493df8bae1dSRodney W. Grimes 494df8bae1dSRodney W. Grimes if (flags & V_SAVE) { 495bb56ec4aSPoul-Henning Kamp if ((error = VOP_FSYNC(vp, cred, MNT_WAIT, p))) 496df8bae1dSRodney W. Grimes return (error); 497df8bae1dSRodney W. Grimes if (vp->v_dirtyblkhd.lh_first != NULL) 498df8bae1dSRodney W. Grimes panic("vinvalbuf: dirty bufs"); 499df8bae1dSRodney W. Grimes } 5006476c0d2SJohn Dyson 5016476c0d2SJohn Dyson s = splbio(); 502df8bae1dSRodney W. Grimes for (;;) { 5031cdeb653SDavid Greenman if ((blist = vp->v_cleanblkhd.lh_first) && (flags & V_SAVEMETA)) 504df8bae1dSRodney W. Grimes while (blist && blist->b_lblkno < 0) 505df8bae1dSRodney W. Grimes blist = blist->b_vnbufs.le_next; 506df8bae1dSRodney W. Grimes if (!blist && (blist = vp->v_dirtyblkhd.lh_first) && 507df8bae1dSRodney W. Grimes (flags & V_SAVEMETA)) 508df8bae1dSRodney W. Grimes while (blist && blist->b_lblkno < 0) 509df8bae1dSRodney W. Grimes blist = blist->b_vnbufs.le_next; 510df8bae1dSRodney W. Grimes if (!blist) 511df8bae1dSRodney W. Grimes break; 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes for (bp = blist; bp; bp = nbp) { 514df8bae1dSRodney W. Grimes nbp = bp->b_vnbufs.le_next; 5151cdeb653SDavid Greenman if ((flags & V_SAVEMETA) && bp->b_lblkno < 0) 516df8bae1dSRodney W. Grimes continue; 517df8bae1dSRodney W. Grimes if (bp->b_flags & B_BUSY) { 518df8bae1dSRodney W. Grimes bp->b_flags |= B_WANTED; 519df8bae1dSRodney W. Grimes error = tsleep((caddr_t) bp, 520df8bae1dSRodney W. Grimes slpflag | (PRIBIO + 1), "vinvalbuf", 521df8bae1dSRodney W. Grimes slptimeo); 5222f2160daSDavid Greenman if (error) { 523df8bae1dSRodney W. Grimes splx(s); 524df8bae1dSRodney W. Grimes return (error); 5252f2160daSDavid Greenman } 526df8bae1dSRodney W. Grimes break; 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes bremfree(bp); 529df8bae1dSRodney W. Grimes bp->b_flags |= B_BUSY; 530df8bae1dSRodney W. Grimes /* 5310d94caffSDavid Greenman * XXX Since there are no node locks for NFS, I 5320d94caffSDavid Greenman * believe there is a slight chance that a delayed 5330d94caffSDavid Greenman * write will occur while sleeping just above, so 5340d94caffSDavid Greenman * check for it. 535df8bae1dSRodney W. Grimes */ 536df8bae1dSRodney W. Grimes if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 537df8bae1dSRodney W. Grimes (void) VOP_BWRITE(bp); 538df8bae1dSRodney W. Grimes break; 539df8bae1dSRodney W. Grimes } 540213fd1b6SDavid Greenman bp->b_flags |= (B_INVAL|B_NOCACHE|B_RELBUF); 541df8bae1dSRodney W. Grimes brelse(bp); 542df8bae1dSRodney W. Grimes } 543df8bae1dSRodney W. Grimes } 5441cdeb653SDavid Greenman 5450d94caffSDavid Greenman while (vp->v_numoutput > 0) { 5460d94caffSDavid Greenman vp->v_flag |= VBWAIT; 5470d94caffSDavid Greenman tsleep(&vp->v_numoutput, PVM, "vnvlbv", 0); 5480d94caffSDavid Greenman } 5492f2160daSDavid Greenman 5500d94caffSDavid Greenman splx(s); 5510d94caffSDavid Greenman 552ff769afcSDavid Greenman /* 553ff769afcSDavid Greenman * Destroy the copy in the VM cache, too. 554ff769afcSDavid Greenman */ 555aa2cabb9SDavid Greenman object = vp->v_object; 55662b71ed6SDavid Greenman if (object != NULL) { 557b9461930SDavid Greenman vm_object_page_remove(object, 0, object->size, 558b9461930SDavid Greenman (flags & V_SAVE) ? TRUE : FALSE); 5591cdeb653SDavid Greenman } 560df8bae1dSRodney W. Grimes if (!(flags & V_SAVEMETA) && 561df8bae1dSRodney W. Grimes (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first)) 562df8bae1dSRodney W. Grimes panic("vinvalbuf: flush failed"); 563df8bae1dSRodney W. Grimes return (0); 564df8bae1dSRodney W. Grimes } 565df8bae1dSRodney W. Grimes 566df8bae1dSRodney W. Grimes /* 567df8bae1dSRodney W. Grimes * Associate a buffer with a vnode. 568df8bae1dSRodney W. Grimes */ 56926f9a767SRodney W. Grimes void 570df8bae1dSRodney W. Grimes bgetvp(vp, bp) 571df8bae1dSRodney W. Grimes register struct vnode *vp; 572df8bae1dSRodney W. Grimes register struct buf *bp; 573df8bae1dSRodney W. Grimes { 574602d2b48SDavid Greenman int s; 575df8bae1dSRodney W. Grimes 576df8bae1dSRodney W. Grimes if (bp->b_vp) 577df8bae1dSRodney W. Grimes panic("bgetvp: not free"); 578df8bae1dSRodney W. Grimes VHOLD(vp); 579df8bae1dSRodney W. Grimes bp->b_vp = vp; 580df8bae1dSRodney W. Grimes if (vp->v_type == VBLK || vp->v_type == VCHR) 581df8bae1dSRodney W. Grimes bp->b_dev = vp->v_rdev; 582df8bae1dSRodney W. Grimes else 583df8bae1dSRodney W. Grimes bp->b_dev = NODEV; 584df8bae1dSRodney W. Grimes /* 585df8bae1dSRodney W. Grimes * Insert onto list for new vnode. 586df8bae1dSRodney W. Grimes */ 587602d2b48SDavid Greenman s = splbio(); 588df8bae1dSRodney W. Grimes bufinsvn(bp, &vp->v_cleanblkhd); 589602d2b48SDavid Greenman splx(s); 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes 592df8bae1dSRodney W. Grimes /* 593df8bae1dSRodney W. Grimes * Disassociate a buffer from a vnode. 594df8bae1dSRodney W. Grimes */ 59526f9a767SRodney W. Grimes void 596df8bae1dSRodney W. Grimes brelvp(bp) 597df8bae1dSRodney W. Grimes register struct buf *bp; 598df8bae1dSRodney W. Grimes { 599df8bae1dSRodney W. Grimes struct vnode *vp; 600602d2b48SDavid Greenman int s; 601df8bae1dSRodney W. Grimes 602df8bae1dSRodney W. Grimes if (bp->b_vp == (struct vnode *) 0) 603df8bae1dSRodney W. Grimes panic("brelvp: NULL"); 604df8bae1dSRodney W. Grimes /* 605df8bae1dSRodney W. Grimes * Delete from old vnode list, if on one. 606df8bae1dSRodney W. Grimes */ 607602d2b48SDavid Greenman s = splbio(); 608df8bae1dSRodney W. Grimes if (bp->b_vnbufs.le_next != NOLIST) 609df8bae1dSRodney W. Grimes bufremvn(bp); 610602d2b48SDavid Greenman splx(s); 611602d2b48SDavid Greenman 612df8bae1dSRodney W. Grimes vp = bp->b_vp; 613df8bae1dSRodney W. Grimes bp->b_vp = (struct vnode *) 0; 614df8bae1dSRodney W. Grimes HOLDRELE(vp); 615df8bae1dSRodney W. Grimes } 616df8bae1dSRodney W. Grimes 617df8bae1dSRodney W. Grimes /* 6180d94caffSDavid Greenman * Associate a p-buffer with a vnode. 6190d94caffSDavid Greenman */ 6200d94caffSDavid Greenman void 6210d94caffSDavid Greenman pbgetvp(vp, bp) 6220d94caffSDavid Greenman register struct vnode *vp; 6230d94caffSDavid Greenman register struct buf *bp; 6240d94caffSDavid Greenman { 6250d955f71SJohn Dyson #if defined(DIAGNOSTIC) 6260d94caffSDavid Greenman if (bp->b_vp) 6270d94caffSDavid Greenman panic("pbgetvp: not free"); 6280d955f71SJohn Dyson #endif 6290d94caffSDavid Greenman bp->b_vp = vp; 6300d94caffSDavid Greenman if (vp->v_type == VBLK || vp->v_type == VCHR) 6310d94caffSDavid Greenman bp->b_dev = vp->v_rdev; 6320d94caffSDavid Greenman else 6330d94caffSDavid Greenman bp->b_dev = NODEV; 6340d94caffSDavid Greenman } 6350d94caffSDavid Greenman 6360d94caffSDavid Greenman /* 6370d94caffSDavid Greenman * Disassociate a p-buffer from a vnode. 6380d94caffSDavid Greenman */ 6390d94caffSDavid Greenman void 6400d94caffSDavid Greenman pbrelvp(bp) 6410d94caffSDavid Greenman register struct buf *bp; 6420d94caffSDavid Greenman { 6430d94caffSDavid Greenman struct vnode *vp; 6440d94caffSDavid Greenman 6450d955f71SJohn Dyson #if defined(DIAGNOSTIC) 6460d94caffSDavid Greenman if (bp->b_vp == (struct vnode *) 0) 647fd7f690fSJohn Dyson panic("pbrelvp: NULL"); 6480d955f71SJohn Dyson #endif 6490d94caffSDavid Greenman 6500d94caffSDavid Greenman bp->b_vp = (struct vnode *) 0; 6510d94caffSDavid Greenman } 6520d94caffSDavid Greenman 6530d94caffSDavid Greenman /* 654df8bae1dSRodney W. Grimes * Reassign a buffer from one vnode to another. 655df8bae1dSRodney W. Grimes * Used to assign file specific control information 656df8bae1dSRodney W. Grimes * (indirect blocks) to the vnode to which they belong. 657df8bae1dSRodney W. Grimes */ 65826f9a767SRodney W. Grimes void 659df8bae1dSRodney W. Grimes reassignbuf(bp, newvp) 660df8bae1dSRodney W. Grimes register struct buf *bp; 661df8bae1dSRodney W. Grimes register struct vnode *newvp; 662df8bae1dSRodney W. Grimes { 663619594e8SJohn Dyson int s; 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes if (newvp == NULL) { 666df8bae1dSRodney W. Grimes printf("reassignbuf: NULL"); 667df8bae1dSRodney W. Grimes return; 668df8bae1dSRodney W. Grimes } 669619594e8SJohn Dyson 670619594e8SJohn Dyson s = splbio(); 671df8bae1dSRodney W. Grimes /* 672df8bae1dSRodney W. Grimes * Delete from old vnode list, if on one. 673df8bae1dSRodney W. Grimes */ 674df8bae1dSRodney W. Grimes if (bp->b_vnbufs.le_next != NOLIST) 675df8bae1dSRodney W. Grimes bufremvn(bp); 676df8bae1dSRodney W. Grimes /* 6770d94caffSDavid Greenman * If dirty, put on list of dirty buffers; otherwise insert onto list 6780d94caffSDavid Greenman * of clean buffers. 679df8bae1dSRodney W. Grimes */ 6800d94caffSDavid Greenman if (bp->b_flags & B_DELWRI) { 6810d94caffSDavid Greenman struct buf *tbp; 6820d94caffSDavid Greenman 6830d94caffSDavid Greenman tbp = newvp->v_dirtyblkhd.lh_first; 6840d94caffSDavid Greenman if (!tbp || (tbp->b_lblkno > bp->b_lblkno)) { 6850d94caffSDavid Greenman bufinsvn(bp, &newvp->v_dirtyblkhd); 6860d94caffSDavid Greenman } else { 687bd7e5f99SJohn Dyson while (tbp->b_vnbufs.le_next && 688bd7e5f99SJohn Dyson (tbp->b_vnbufs.le_next->b_lblkno < bp->b_lblkno)) { 6890d94caffSDavid Greenman tbp = tbp->b_vnbufs.le_next; 6900d94caffSDavid Greenman } 6910d94caffSDavid Greenman LIST_INSERT_AFTER(tbp, bp, b_vnbufs); 6920d94caffSDavid Greenman } 6930d94caffSDavid Greenman } else { 6946476c0d2SJohn Dyson bufinsvn(bp, &newvp->v_cleanblkhd); 695df8bae1dSRodney W. Grimes } 696619594e8SJohn Dyson splx(s); 6970d94caffSDavid Greenman } 698df8bae1dSRodney W. Grimes 6998c2ff396SBruce Evans #ifndef DEVFS_ROOT 700df8bae1dSRodney W. Grimes /* 701df8bae1dSRodney W. Grimes * Create a vnode for a block device. 702df8bae1dSRodney W. Grimes * Used for root filesystem, argdev, and swap areas. 703df8bae1dSRodney W. Grimes * Also used for memory file system special devices. 704df8bae1dSRodney W. Grimes */ 70526f9a767SRodney W. Grimes int 706df8bae1dSRodney W. Grimes bdevvp(dev, vpp) 707df8bae1dSRodney W. Grimes dev_t dev; 708df8bae1dSRodney W. Grimes struct vnode **vpp; 709df8bae1dSRodney W. Grimes { 710df8bae1dSRodney W. Grimes register struct vnode *vp; 711df8bae1dSRodney W. Grimes struct vnode *nvp; 712df8bae1dSRodney W. Grimes int error; 713df8bae1dSRodney W. Grimes 714df8bae1dSRodney W. Grimes if (dev == NODEV) 715df8bae1dSRodney W. Grimes return (0); 716df8bae1dSRodney W. Grimes error = getnewvnode(VT_NON, (struct mount *) 0, spec_vnodeop_p, &nvp); 717df8bae1dSRodney W. Grimes if (error) { 718df8bae1dSRodney W. Grimes *vpp = 0; 719df8bae1dSRodney W. Grimes return (error); 720df8bae1dSRodney W. Grimes } 721df8bae1dSRodney W. Grimes vp = nvp; 722df8bae1dSRodney W. Grimes vp->v_type = VBLK; 723bb56ec4aSPoul-Henning Kamp if ((nvp = checkalias(vp, dev, (struct mount *) 0))) { 724df8bae1dSRodney W. Grimes vput(vp); 725df8bae1dSRodney W. Grimes vp = nvp; 726df8bae1dSRodney W. Grimes } 727df8bae1dSRodney W. Grimes *vpp = vp; 728df8bae1dSRodney W. Grimes return (0); 729df8bae1dSRodney W. Grimes } 7308c2ff396SBruce Evans #endif /* !DEVFS_ROOT */ 731df8bae1dSRodney W. Grimes 732df8bae1dSRodney W. Grimes /* 733df8bae1dSRodney W. Grimes * Check to see if the new vnode represents a special device 734df8bae1dSRodney W. Grimes * for which we already have a vnode (either because of 735df8bae1dSRodney W. Grimes * bdevvp() or because of a different vnode representing 736df8bae1dSRodney W. Grimes * the same block device). If such an alias exists, deallocate 737df8bae1dSRodney W. Grimes * the existing contents and return the aliased vnode. The 738df8bae1dSRodney W. Grimes * caller is responsible for filling it with its new contents. 739df8bae1dSRodney W. Grimes */ 740df8bae1dSRodney W. Grimes struct vnode * 741df8bae1dSRodney W. Grimes checkalias(nvp, nvp_rdev, mp) 742df8bae1dSRodney W. Grimes register struct vnode *nvp; 743df8bae1dSRodney W. Grimes dev_t nvp_rdev; 744df8bae1dSRodney W. Grimes struct mount *mp; 745df8bae1dSRodney W. Grimes { 746996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 747996c772fSJohn Dyson struct vnode *vp; 748df8bae1dSRodney W. Grimes struct vnode **vpp; 749df8bae1dSRodney W. Grimes 750df8bae1dSRodney W. Grimes if (nvp->v_type != VBLK && nvp->v_type != VCHR) 751df8bae1dSRodney W. Grimes return (NULLVP); 752df8bae1dSRodney W. Grimes 753df8bae1dSRodney W. Grimes vpp = &speclisth[SPECHASH(nvp_rdev)]; 754df8bae1dSRodney W. Grimes loop: 755996c772fSJohn Dyson simple_lock(&spechash_slock); 756df8bae1dSRodney W. Grimes for (vp = *vpp; vp; vp = vp->v_specnext) { 757df8bae1dSRodney W. Grimes if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 758df8bae1dSRodney W. Grimes continue; 759df8bae1dSRodney W. Grimes /* 760df8bae1dSRodney W. Grimes * Alias, but not in use, so flush it out. 761df8bae1dSRodney W. Grimes */ 762996c772fSJohn Dyson simple_lock(&vp->v_interlock); 763df8bae1dSRodney W. Grimes if (vp->v_usecount == 0) { 764996c772fSJohn Dyson simple_unlock(&spechash_slock); 765996c772fSJohn Dyson vgonel(vp, p); 766df8bae1dSRodney W. Grimes goto loop; 767df8bae1dSRodney W. Grimes } 768996c772fSJohn Dyson if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { 769b98afd0dSBruce Evans simple_unlock(&spechash_slock); 770df8bae1dSRodney W. Grimes goto loop; 771996c772fSJohn Dyson } 772df8bae1dSRodney W. Grimes break; 773df8bae1dSRodney W. Grimes } 774df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_tag != VT_NON) { 775df8bae1dSRodney W. Grimes MALLOC(nvp->v_specinfo, struct specinfo *, 776df8bae1dSRodney W. Grimes sizeof(struct specinfo), M_VNODE, M_WAITOK); 777df8bae1dSRodney W. Grimes nvp->v_rdev = nvp_rdev; 778df8bae1dSRodney W. Grimes nvp->v_hashchain = vpp; 779df8bae1dSRodney W. Grimes nvp->v_specnext = *vpp; 780df8bae1dSRodney W. Grimes nvp->v_specflags = 0; 781996c772fSJohn Dyson simple_unlock(&spechash_slock); 782df8bae1dSRodney W. Grimes *vpp = nvp; 783996c772fSJohn Dyson if (vp != NULLVP) { 784df8bae1dSRodney W. Grimes nvp->v_flag |= VALIASED; 785df8bae1dSRodney W. Grimes vp->v_flag |= VALIASED; 786df8bae1dSRodney W. Grimes vput(vp); 787df8bae1dSRodney W. Grimes } 788df8bae1dSRodney W. Grimes return (NULLVP); 789df8bae1dSRodney W. Grimes } 790996c772fSJohn Dyson simple_unlock(&spechash_slock); 791996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 792996c772fSJohn Dyson simple_lock(&vp->v_interlock); 793996c772fSJohn Dyson vclean(vp, 0, p); 794df8bae1dSRodney W. Grimes vp->v_op = nvp->v_op; 795df8bae1dSRodney W. Grimes vp->v_tag = nvp->v_tag; 796df8bae1dSRodney W. Grimes nvp->v_type = VNON; 797df8bae1dSRodney W. Grimes insmntque(vp, mp); 798df8bae1dSRodney W. Grimes return (vp); 799df8bae1dSRodney W. Grimes } 800df8bae1dSRodney W. Grimes 801df8bae1dSRodney W. Grimes /* 802df8bae1dSRodney W. Grimes * Grab a particular vnode from the free list, increment its 803df8bae1dSRodney W. Grimes * reference count and lock it. The vnode lock bit is set the 804df8bae1dSRodney W. Grimes * vnode is being eliminated in vgone. The process is awakened 805df8bae1dSRodney W. Grimes * when the transition is completed, and an error returned to 806df8bae1dSRodney W. Grimes * indicate that the vnode is no longer usable (possibly having 807df8bae1dSRodney W. Grimes * been changed to a new file system type). 808df8bae1dSRodney W. Grimes */ 80926f9a767SRodney W. Grimes int 810996c772fSJohn Dyson vget(vp, flags, p) 811df8bae1dSRodney W. Grimes register struct vnode *vp; 812996c772fSJohn Dyson int flags; 813996c772fSJohn Dyson struct proc *p; 814df8bae1dSRodney W. Grimes { 815996c772fSJohn Dyson int error; 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes /* 818996c772fSJohn Dyson * If the vnode is in the process of being cleaned out for 819996c772fSJohn Dyson * another use, we wait for the cleaning to finish and then 820996c772fSJohn Dyson * return failure. Cleaning is determined by checking that 821996c772fSJohn Dyson * the VXLOCK flag is set. 822df8bae1dSRodney W. Grimes */ 823996c772fSJohn Dyson if ((flags & LK_INTERLOCK) == 0) { 824996c772fSJohn Dyson simple_lock(&vp->v_interlock); 825996c772fSJohn Dyson } 826996c772fSJohn Dyson if (vp->v_flag & VXLOCK) { 827df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 828996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 829996c772fSJohn Dyson tsleep((caddr_t)vp, PINOD, "vget", 0); 830996c772fSJohn Dyson return (ENOENT); 831df8bae1dSRodney W. Grimes } 832fbd6e6c9SPoul-Henning Kamp if (vp->v_usecount == 0) { 833996c772fSJohn Dyson simple_lock(&vnode_free_list_slock); 834df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 835996c772fSJohn Dyson simple_unlock(&vnode_free_list_slock); 836fbd6e6c9SPoul-Henning Kamp freevnodes--; 837fbd6e6c9SPoul-Henning Kamp } 838df8bae1dSRodney W. Grimes vp->v_usecount++; 8396476c0d2SJohn Dyson /* 8406476c0d2SJohn Dyson * Create the VM object, if needed 8416476c0d2SJohn Dyson */ 8426476c0d2SJohn Dyson if ((vp->v_type == VREG) && 8436476c0d2SJohn Dyson ((vp->v_object == NULL) || 8443c631446SJohn Dyson (vp->v_object->flags & OBJ_VFS_REF) == 0 || 8453c631446SJohn Dyson (vp->v_object->flags & OBJ_DEAD))) { 846996c772fSJohn Dyson /* 847996c772fSJohn Dyson * XXX vfs_object_create probably needs the interlock. 848996c772fSJohn Dyson */ 849996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 8506476c0d2SJohn Dyson vfs_object_create(vp, curproc, curproc->p_ucred, 0); 851996c772fSJohn Dyson simple_lock(&vp->v_interlock); 8526476c0d2SJohn Dyson } 853996c772fSJohn Dyson if (flags & LK_TYPE_MASK) { 854996c772fSJohn Dyson if (error = vn_lock(vp, flags | LK_INTERLOCK, p)) 855996c772fSJohn Dyson vrele(vp); 856996c772fSJohn Dyson return (error); 857996c772fSJohn Dyson } 858996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 859df8bae1dSRodney W. Grimes return (0); 860df8bae1dSRodney W. Grimes } 861df8bae1dSRodney W. Grimes 862df8bae1dSRodney W. Grimes /* 863996c772fSJohn Dyson * Stubs to use when there is no locking to be done on the underlying object. 864996c772fSJohn Dyson * A minimal shared lock is necessary to ensure that the underlying object 865996c772fSJohn Dyson * is not revoked while an operation is in progress. So, an active shared 866996c772fSJohn Dyson * count is maintained in an auxillary vnode lock structure. 867996c772fSJohn Dyson */ 868996c772fSJohn Dyson int 869de15ef6aSDoug Rabson vop_sharedlock(ap) 870de15ef6aSDoug Rabson struct vop_lock_args /* { 871de15ef6aSDoug Rabson struct vnode *a_vp; 872de15ef6aSDoug Rabson int a_flags; 873de15ef6aSDoug Rabson struct proc *a_p; 874de15ef6aSDoug Rabson } */ *ap; 875de15ef6aSDoug Rabson { 876de15ef6aSDoug Rabson /* 877de15ef6aSDoug Rabson * This code cannot be used until all the non-locking filesystems 878de15ef6aSDoug Rabson * (notably NFS) are converted to properly lock and release nodes. 879de15ef6aSDoug Rabson * Also, certain vnode operations change the locking state within 880de15ef6aSDoug Rabson * the operation (create, mknod, remove, link, rename, mkdir, rmdir, 881de15ef6aSDoug Rabson * and symlink). Ideally these operations should not change the 882de15ef6aSDoug Rabson * lock state, but should be changed to let the caller of the 883de15ef6aSDoug Rabson * function unlock them. Otherwise all intermediate vnode layers 884de15ef6aSDoug Rabson * (such as union, umapfs, etc) must catch these functions to do 885de15ef6aSDoug Rabson * the necessary locking at their layer. Note that the inactive 886de15ef6aSDoug Rabson * and lookup operations also change their lock state, but this 887de15ef6aSDoug Rabson * cannot be avoided, so these two operations will always need 888de15ef6aSDoug Rabson * to be handled in intermediate layers. 889de15ef6aSDoug Rabson */ 890de15ef6aSDoug Rabson struct vnode *vp = ap->a_vp; 891de15ef6aSDoug Rabson int vnflags, flags = ap->a_flags; 892de15ef6aSDoug Rabson 893de15ef6aSDoug Rabson if (vp->v_vnlock == NULL) { 894de15ef6aSDoug Rabson if ((flags & LK_TYPE_MASK) == LK_DRAIN) 895de15ef6aSDoug Rabson return (0); 896de15ef6aSDoug Rabson MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock), 897de15ef6aSDoug Rabson M_VNODE, M_WAITOK); 898de15ef6aSDoug Rabson lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); 899de15ef6aSDoug Rabson } 900de15ef6aSDoug Rabson switch (flags & LK_TYPE_MASK) { 901de15ef6aSDoug Rabson case LK_DRAIN: 902de15ef6aSDoug Rabson vnflags = LK_DRAIN; 903de15ef6aSDoug Rabson break; 904de15ef6aSDoug Rabson case LK_EXCLUSIVE: 905de15ef6aSDoug Rabson #ifdef DEBUG_VFS_LOCKS 906de15ef6aSDoug Rabson /* 907de15ef6aSDoug Rabson * Normally, we use shared locks here, but that confuses 908de15ef6aSDoug Rabson * the locking assertions. 909de15ef6aSDoug Rabson */ 910de15ef6aSDoug Rabson vnflags = LK_EXCLUSIVE; 911de15ef6aSDoug Rabson break; 912de15ef6aSDoug Rabson #endif 913de15ef6aSDoug Rabson case LK_SHARED: 914de15ef6aSDoug Rabson vnflags = LK_SHARED; 915de15ef6aSDoug Rabson break; 916de15ef6aSDoug Rabson case LK_UPGRADE: 917de15ef6aSDoug Rabson case LK_EXCLUPGRADE: 918de15ef6aSDoug Rabson case LK_DOWNGRADE: 919de15ef6aSDoug Rabson return (0); 920de15ef6aSDoug Rabson case LK_RELEASE: 921de15ef6aSDoug Rabson default: 922de15ef6aSDoug Rabson panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK); 923de15ef6aSDoug Rabson } 924de15ef6aSDoug Rabson if (flags & LK_INTERLOCK) 925de15ef6aSDoug Rabson vnflags |= LK_INTERLOCK; 926de15ef6aSDoug Rabson return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p)); 927de15ef6aSDoug Rabson } 928de15ef6aSDoug Rabson 929de15ef6aSDoug Rabson /* 930de15ef6aSDoug Rabson * Stubs to use when there is no locking to be done on the underlying object. 931de15ef6aSDoug Rabson * A minimal shared lock is necessary to ensure that the underlying object 932de15ef6aSDoug Rabson * is not revoked while an operation is in progress. So, an active shared 933de15ef6aSDoug Rabson * count is maintained in an auxillary vnode lock structure. 934de15ef6aSDoug Rabson */ 935de15ef6aSDoug Rabson int 936996c772fSJohn Dyson vop_nolock(ap) 937996c772fSJohn Dyson struct vop_lock_args /* { 938996c772fSJohn Dyson struct vnode *a_vp; 939996c772fSJohn Dyson int a_flags; 940996c772fSJohn Dyson struct proc *a_p; 941996c772fSJohn Dyson } */ *ap; 942996c772fSJohn Dyson { 943996c772fSJohn Dyson #ifdef notyet 944996c772fSJohn Dyson /* 945996c772fSJohn Dyson * This code cannot be used until all the non-locking filesystems 946996c772fSJohn Dyson * (notably NFS) are converted to properly lock and release nodes. 947996c772fSJohn Dyson * Also, certain vnode operations change the locking state within 948996c772fSJohn Dyson * the operation (create, mknod, remove, link, rename, mkdir, rmdir, 949996c772fSJohn Dyson * and symlink). Ideally these operations should not change the 950996c772fSJohn Dyson * lock state, but should be changed to let the caller of the 951996c772fSJohn Dyson * function unlock them. Otherwise all intermediate vnode layers 952996c772fSJohn Dyson * (such as union, umapfs, etc) must catch these functions to do 953996c772fSJohn Dyson * the necessary locking at their layer. Note that the inactive 954996c772fSJohn Dyson * and lookup operations also change their lock state, but this 955996c772fSJohn Dyson * cannot be avoided, so these two operations will always need 956996c772fSJohn Dyson * to be handled in intermediate layers. 957996c772fSJohn Dyson */ 958996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 959996c772fSJohn Dyson int vnflags, flags = ap->a_flags; 960996c772fSJohn Dyson 961996c772fSJohn Dyson if (vp->v_vnlock == NULL) { 962996c772fSJohn Dyson if ((flags & LK_TYPE_MASK) == LK_DRAIN) 963996c772fSJohn Dyson return (0); 964996c772fSJohn Dyson MALLOC(vp->v_vnlock, struct lock *, sizeof(struct lock), 965996c772fSJohn Dyson M_VNODE, M_WAITOK); 966996c772fSJohn Dyson lockinit(vp->v_vnlock, PVFS, "vnlock", 0, 0); 967996c772fSJohn Dyson } 968996c772fSJohn Dyson switch (flags & LK_TYPE_MASK) { 969996c772fSJohn Dyson case LK_DRAIN: 970996c772fSJohn Dyson vnflags = LK_DRAIN; 971996c772fSJohn Dyson break; 972996c772fSJohn Dyson case LK_EXCLUSIVE: 973996c772fSJohn Dyson case LK_SHARED: 974996c772fSJohn Dyson vnflags = LK_SHARED; 975996c772fSJohn Dyson break; 976996c772fSJohn Dyson case LK_UPGRADE: 977996c772fSJohn Dyson case LK_EXCLUPGRADE: 978996c772fSJohn Dyson case LK_DOWNGRADE: 979996c772fSJohn Dyson return (0); 980996c772fSJohn Dyson case LK_RELEASE: 981996c772fSJohn Dyson default: 982996c772fSJohn Dyson panic("vop_nolock: bad operation %d", flags & LK_TYPE_MASK); 983996c772fSJohn Dyson } 984996c772fSJohn Dyson if (flags & LK_INTERLOCK) 985996c772fSJohn Dyson vnflags |= LK_INTERLOCK; 986996c772fSJohn Dyson return(lockmgr(vp->v_vnlock, vnflags, &vp->v_interlock, ap->a_p)); 987996c772fSJohn Dyson #else /* for now */ 988996c772fSJohn Dyson /* 989996c772fSJohn Dyson * Since we are not using the lock manager, we must clear 990996c772fSJohn Dyson * the interlock here. 991996c772fSJohn Dyson */ 992996c772fSJohn Dyson if (ap->a_flags & LK_INTERLOCK) { 993996c772fSJohn Dyson simple_unlock(&ap->a_vp->v_interlock); 994996c772fSJohn Dyson } 995996c772fSJohn Dyson return (0); 996996c772fSJohn Dyson #endif 997996c772fSJohn Dyson } 998996c772fSJohn Dyson 999996c772fSJohn Dyson /* 1000fd7f690fSJohn Dyson * Do the inverse of vop_nolock, handling the interlock in a compatible way. 1001996c772fSJohn Dyson */ 1002996c772fSJohn Dyson int 1003996c772fSJohn Dyson vop_nounlock(ap) 1004996c772fSJohn Dyson struct vop_unlock_args /* { 1005996c772fSJohn Dyson struct vnode *a_vp; 1006996c772fSJohn Dyson int a_flags; 1007996c772fSJohn Dyson struct proc *a_p; 1008996c772fSJohn Dyson } */ *ap; 1009996c772fSJohn Dyson { 1010996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 1011996c772fSJohn Dyson 1012fd7f690fSJohn Dyson if (vp->v_vnlock == NULL) { 1013fd7f690fSJohn Dyson if (ap->a_flags & LK_INTERLOCK) 1014fd7f690fSJohn Dyson simple_unlock(&ap->a_vp->v_interlock); 1015996c772fSJohn Dyson return (0); 1016fd7f690fSJohn Dyson } 1017fd7f690fSJohn Dyson return (lockmgr(vp->v_vnlock, LK_RELEASE | ap->a_flags, 1018fd7f690fSJohn Dyson &ap->a_vp->v_interlock, ap->a_p)); 1019996c772fSJohn Dyson } 1020996c772fSJohn Dyson 1021996c772fSJohn Dyson /* 1022996c772fSJohn Dyson * Return whether or not the node is in use. 1023996c772fSJohn Dyson */ 1024996c772fSJohn Dyson int 1025996c772fSJohn Dyson vop_noislocked(ap) 1026996c772fSJohn Dyson struct vop_islocked_args /* { 1027996c772fSJohn Dyson struct vnode *a_vp; 1028996c772fSJohn Dyson } */ *ap; 1029996c772fSJohn Dyson { 1030996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 1031996c772fSJohn Dyson 1032996c772fSJohn Dyson if (vp->v_vnlock == NULL) 1033996c772fSJohn Dyson return (0); 1034996c772fSJohn Dyson return (lockstatus(vp->v_vnlock)); 1035996c772fSJohn Dyson } 1036996c772fSJohn Dyson 1037996c772fSJohn Dyson /* #ifdef DIAGNOSTIC */ 1038996c772fSJohn Dyson /* 1039df8bae1dSRodney W. Grimes * Vnode reference, just increment the count 1040df8bae1dSRodney W. Grimes */ 104126f9a767SRodney W. Grimes void 104226f9a767SRodney W. Grimes vref(vp) 1043df8bae1dSRodney W. Grimes struct vnode *vp; 1044df8bae1dSRodney W. Grimes { 1045996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1046df8bae1dSRodney W. Grimes if (vp->v_usecount <= 0) 1047df8bae1dSRodney W. Grimes panic("vref used where vget required"); 10486476c0d2SJohn Dyson 1049a8f42fa9SJohn Dyson vp->v_usecount++; 1050a8f42fa9SJohn Dyson 10516476c0d2SJohn Dyson if ((vp->v_type == VREG) && 10526476c0d2SJohn Dyson ((vp->v_object == NULL) || 10533c631446SJohn Dyson ((vp->v_object->flags & OBJ_VFS_REF) == 0) || 10543c631446SJohn Dyson (vp->v_object->flags & OBJ_DEAD))) { 10556476c0d2SJohn Dyson /* 10566476c0d2SJohn Dyson * We need to lock to VP during the time that 10576476c0d2SJohn Dyson * the object is created. This is necessary to 10586476c0d2SJohn Dyson * keep the system from re-entrantly doing it 10596476c0d2SJohn Dyson * multiple times. 1060996c772fSJohn Dyson * XXX vfs_object_create probably needs the interlock? 10616476c0d2SJohn Dyson */ 1062996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 10636476c0d2SJohn Dyson vfs_object_create(vp, curproc, curproc->p_ucred, 0); 1064c35e283aSBruce Evans return; 10656476c0d2SJohn Dyson } 1066c35e283aSBruce Evans simple_unlock(&vp->v_interlock); 1067df8bae1dSRodney W. Grimes } 1068df8bae1dSRodney W. Grimes 1069df8bae1dSRodney W. Grimes /* 10700d955f71SJohn Dyson * Vnode put/release. 1071df8bae1dSRodney W. Grimes * If count drops to zero, call inactive routine and return to freelist. 1072df8bae1dSRodney W. Grimes */ 107382b8e119SJohn Dyson static void 10740d955f71SJohn Dyson vputrele(vp, put) 1075996c772fSJohn Dyson struct vnode *vp; 10760d955f71SJohn Dyson int put; 1077df8bae1dSRodney W. Grimes { 1078996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1079df8bae1dSRodney W. Grimes 1080df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1081df8bae1dSRodney W. Grimes if (vp == NULL) 10820d955f71SJohn Dyson panic("vputrele: null vp"); 1083df8bae1dSRodney W. Grimes #endif 1084996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1085df8bae1dSRodney W. Grimes vp->v_usecount--; 10866476c0d2SJohn Dyson 10876476c0d2SJohn Dyson if ((vp->v_usecount == 1) && 10886476c0d2SJohn Dyson vp->v_object && 10896476c0d2SJohn Dyson (vp->v_object->flags & OBJ_VFS_REF)) { 10906476c0d2SJohn Dyson vp->v_object->flags &= ~OBJ_VFS_REF; 10910d955f71SJohn Dyson if (put) { 1092fd7f690fSJohn Dyson VOP_UNLOCK(vp, LK_INTERLOCK, p); 1093fd7f690fSJohn Dyson } else { 1094fd7f690fSJohn Dyson simple_unlock(&vp->v_interlock); 10950d955f71SJohn Dyson } 10966476c0d2SJohn Dyson vm_object_deallocate(vp->v_object); 10976476c0d2SJohn Dyson return; 10986476c0d2SJohn Dyson } 10996476c0d2SJohn Dyson 1100996c772fSJohn Dyson if (vp->v_usecount > 0) { 11010d955f71SJohn Dyson if (put) { 1102fd7f690fSJohn Dyson VOP_UNLOCK(vp, LK_INTERLOCK, p); 1103fd7f690fSJohn Dyson } else { 1104fd7f690fSJohn Dyson simple_unlock(&vp->v_interlock); 11050d955f71SJohn Dyson } 1106df8bae1dSRodney W. Grimes return; 1107996c772fSJohn Dyson } 11086476c0d2SJohn Dyson 11096476c0d2SJohn Dyson if (vp->v_usecount < 0) { 1110864ef7d1SDavid Greenman #ifdef DIAGNOSTIC 11110d955f71SJohn Dyson vprint("vputrele: negative ref count", vp); 1112864ef7d1SDavid Greenman #endif 11130d955f71SJohn Dyson panic("vputrele: negative ref cnt"); 1114df8bae1dSRodney W. Grimes } 1115996c772fSJohn Dyson simple_lock(&vnode_free_list_slock); 1116acc835fdSDavid Greenman if (vp->v_flag & VAGE) { 1117acc835fdSDavid Greenman vp->v_flag &= ~VAGE; 11180d955f71SJohn Dyson if(vp->v_tag != VT_TFS) 11190d955f71SJohn Dyson TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 1120acc835fdSDavid Greenman } else { 11210082fb46SJordan K. Hubbard if(vp->v_tag != VT_TFS) 1122df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 1123acc835fdSDavid Greenman } 1124fbd6e6c9SPoul-Henning Kamp freevnodes++; 1125fd7f690fSJohn Dyson simple_unlock(&vnode_free_list_slock); 1126acc835fdSDavid Greenman 11270d955f71SJohn Dyson /* 11280d955f71SJohn Dyson * If we are doing a vput, the node is already locked, and we must 11290d955f71SJohn Dyson * call VOP_INACTIVE with the node locked. So, in the case of 11300d955f71SJohn Dyson * vrele, we explicitly lock the vnode before calling VOP_INACTIVE. 11310d955f71SJohn Dyson */ 1132fd7f690fSJohn Dyson if (put) { 1133fd7f690fSJohn Dyson simple_unlock(&vp->v_interlock); 1134996c772fSJohn Dyson VOP_INACTIVE(vp, p); 1135fd7f690fSJohn Dyson } else if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) { 1136fd7f690fSJohn Dyson VOP_INACTIVE(vp, p); 1137fd7f690fSJohn Dyson } 1138df8bae1dSRodney W. Grimes } 1139df8bae1dSRodney W. Grimes 11400d955f71SJohn Dyson /* 11410d955f71SJohn Dyson * vput(), just unlock and vrele() 11420d955f71SJohn Dyson */ 11430d955f71SJohn Dyson void 11440d955f71SJohn Dyson vput(vp) 11450d955f71SJohn Dyson struct vnode *vp; 11460d955f71SJohn Dyson { 11470d955f71SJohn Dyson vputrele(vp, 1); 11480d955f71SJohn Dyson } 11490d955f71SJohn Dyson 11500d955f71SJohn Dyson void 11510d955f71SJohn Dyson vrele(vp) 11520d955f71SJohn Dyson struct vnode *vp; 11530d955f71SJohn Dyson { 11540d955f71SJohn Dyson vputrele(vp, 0); 11550d955f71SJohn Dyson } 11560d955f71SJohn Dyson 1157430179f0SBruce Evans #ifdef DIAGNOSTIC 1158df8bae1dSRodney W. Grimes /* 1159df8bae1dSRodney W. Grimes * Page or buffer structure gets a reference. 1160df8bae1dSRodney W. Grimes */ 116126f9a767SRodney W. Grimes void 116226f9a767SRodney W. Grimes vhold(vp) 1163df8bae1dSRodney W. Grimes register struct vnode *vp; 1164df8bae1dSRodney W. Grimes { 1165df8bae1dSRodney W. Grimes 1166996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1167df8bae1dSRodney W. Grimes vp->v_holdcnt++; 1168996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1169df8bae1dSRodney W. Grimes } 1170df8bae1dSRodney W. Grimes 1171df8bae1dSRodney W. Grimes /* 1172df8bae1dSRodney W. Grimes * Page or buffer structure frees a reference. 1173df8bae1dSRodney W. Grimes */ 117426f9a767SRodney W. Grimes void 117526f9a767SRodney W. Grimes holdrele(vp) 1176df8bae1dSRodney W. Grimes register struct vnode *vp; 1177df8bae1dSRodney W. Grimes { 1178df8bae1dSRodney W. Grimes 1179996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1180df8bae1dSRodney W. Grimes if (vp->v_holdcnt <= 0) 1181df8bae1dSRodney W. Grimes panic("holdrele: holdcnt"); 1182df8bae1dSRodney W. Grimes vp->v_holdcnt--; 1183996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1184df8bae1dSRodney W. Grimes } 1185430179f0SBruce Evans #endif /* DIAGNOSTIC */ 1186df8bae1dSRodney W. Grimes 1187df8bae1dSRodney W. Grimes /* 1188df8bae1dSRodney W. Grimes * Remove any vnodes in the vnode table belonging to mount point mp. 1189df8bae1dSRodney W. Grimes * 1190df8bae1dSRodney W. Grimes * If MNT_NOFORCE is specified, there should not be any active ones, 1191df8bae1dSRodney W. Grimes * return error if any are found (nb: this is a user error, not a 1192df8bae1dSRodney W. Grimes * system error). If MNT_FORCE is specified, detach any active vnodes 1193df8bae1dSRodney W. Grimes * that are found. 1194df8bae1dSRodney W. Grimes */ 1195df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 119627a0b398SPoul-Henning Kamp static int busyprt = 0; /* print out busy vnodes */ 11970f1adf65SBruce Evans SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, ""); 1198df8bae1dSRodney W. Grimes #endif 1199df8bae1dSRodney W. Grimes 120026f9a767SRodney W. Grimes int 1201df8bae1dSRodney W. Grimes vflush(mp, skipvp, flags) 1202df8bae1dSRodney W. Grimes struct mount *mp; 1203df8bae1dSRodney W. Grimes struct vnode *skipvp; 1204df8bae1dSRodney W. Grimes int flags; 1205df8bae1dSRodney W. Grimes { 1206996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1207996c772fSJohn Dyson struct vnode *vp, *nvp; 1208df8bae1dSRodney W. Grimes int busy = 0; 1209df8bae1dSRodney W. Grimes 1210996c772fSJohn Dyson simple_lock(&mntvnode_slock); 1211df8bae1dSRodney W. Grimes loop: 1212df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 12133d2a8cf3SDavid Greenman /* 12143d2a8cf3SDavid Greenman * Make sure this vnode wasn't reclaimed in getnewvnode(). 12153d2a8cf3SDavid Greenman * Start over if it has (it won't be on the list anymore). 12163d2a8cf3SDavid Greenman */ 1217df8bae1dSRodney W. Grimes if (vp->v_mount != mp) 1218df8bae1dSRodney W. Grimes goto loop; 1219df8bae1dSRodney W. Grimes nvp = vp->v_mntvnodes.le_next; 1220df8bae1dSRodney W. Grimes /* 1221df8bae1dSRodney W. Grimes * Skip over a selected vnode. 1222df8bae1dSRodney W. Grimes */ 1223df8bae1dSRodney W. Grimes if (vp == skipvp) 1224df8bae1dSRodney W. Grimes continue; 1225996c772fSJohn Dyson 1226996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1227df8bae1dSRodney W. Grimes /* 1228df8bae1dSRodney W. Grimes * Skip over a vnodes marked VSYSTEM. 1229df8bae1dSRodney W. Grimes */ 1230996c772fSJohn Dyson if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { 1231996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1232df8bae1dSRodney W. Grimes continue; 1233996c772fSJohn Dyson } 1234df8bae1dSRodney W. Grimes /* 12350d94caffSDavid Greenman * If WRITECLOSE is set, only flush out regular file vnodes 12360d94caffSDavid Greenman * open for writing. 1237df8bae1dSRodney W. Grimes */ 1238df8bae1dSRodney W. Grimes if ((flags & WRITECLOSE) && 1239996c772fSJohn Dyson (vp->v_writecount == 0 || vp->v_type != VREG)) { 1240996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1241df8bae1dSRodney W. Grimes continue; 1242996c772fSJohn Dyson } 12436476c0d2SJohn Dyson 1244df8bae1dSRodney W. Grimes /* 12450d94caffSDavid Greenman * With v_usecount == 0, all we need to do is clear out the 12460d94caffSDavid Greenman * vnode data structures and we are done. 1247df8bae1dSRodney W. Grimes */ 1248df8bae1dSRodney W. Grimes if (vp->v_usecount == 0) { 1249996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 1250996c772fSJohn Dyson vgonel(vp, p); 1251996c772fSJohn Dyson simple_lock(&mntvnode_slock); 1252df8bae1dSRodney W. Grimes continue; 1253df8bae1dSRodney W. Grimes } 1254ad980522SJohn Dyson 1255df8bae1dSRodney W. Grimes /* 12560d94caffSDavid Greenman * If FORCECLOSE is set, forcibly close the vnode. For block 12570d94caffSDavid Greenman * or character devices, revert to an anonymous device. For 12580d94caffSDavid Greenman * all other files, just kill them. 1259df8bae1dSRodney W. Grimes */ 1260df8bae1dSRodney W. Grimes if (flags & FORCECLOSE) { 1261996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 1262df8bae1dSRodney W. Grimes if (vp->v_type != VBLK && vp->v_type != VCHR) { 1263996c772fSJohn Dyson vgonel(vp, p); 1264df8bae1dSRodney W. Grimes } else { 1265996c772fSJohn Dyson vclean(vp, 0, p); 1266df8bae1dSRodney W. Grimes vp->v_op = spec_vnodeop_p; 1267df8bae1dSRodney W. Grimes insmntque(vp, (struct mount *) 0); 1268df8bae1dSRodney W. Grimes } 1269996c772fSJohn Dyson simple_lock(&mntvnode_slock); 1270df8bae1dSRodney W. Grimes continue; 1271df8bae1dSRodney W. Grimes } 1272df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1273df8bae1dSRodney W. Grimes if (busyprt) 1274df8bae1dSRodney W. Grimes vprint("vflush: busy vnode", vp); 1275df8bae1dSRodney W. Grimes #endif 1276996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1277df8bae1dSRodney W. Grimes busy++; 1278df8bae1dSRodney W. Grimes } 1279996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 1280df8bae1dSRodney W. Grimes if (busy) 1281df8bae1dSRodney W. Grimes return (EBUSY); 1282df8bae1dSRodney W. Grimes return (0); 1283df8bae1dSRodney W. Grimes } 1284df8bae1dSRodney W. Grimes 1285df8bae1dSRodney W. Grimes /* 1286df8bae1dSRodney W. Grimes * Disassociate the underlying file system from a vnode. 1287df8bae1dSRodney W. Grimes */ 1288996c772fSJohn Dyson static void 1289996c772fSJohn Dyson vclean(struct vnode *vp, int flags, struct proc *p) 1290df8bae1dSRodney W. Grimes { 12913c631446SJohn Dyson int active, irefed; 12923c631446SJohn Dyson vm_object_t object; 1293df8bae1dSRodney W. Grimes 1294df8bae1dSRodney W. Grimes /* 12950d94caffSDavid Greenman * Check to see if the vnode is in use. If so we have to reference it 12960d94caffSDavid Greenman * before we clean it out so that its count cannot fall to zero and 12970d94caffSDavid Greenman * generate a race against ourselves to recycle it. 1298df8bae1dSRodney W. Grimes */ 1299bb56ec4aSPoul-Henning Kamp if ((active = vp->v_usecount)) 1300996c772fSJohn Dyson vp->v_usecount++; 1301df8bae1dSRodney W. Grimes /* 13020d94caffSDavid Greenman * Prevent the vnode from being recycled or brought into use while we 13030d94caffSDavid Greenman * clean it out. 1304df8bae1dSRodney W. Grimes */ 1305df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) 1306df8bae1dSRodney W. Grimes panic("vclean: deadlock"); 1307df8bae1dSRodney W. Grimes vp->v_flag |= VXLOCK; 1308df8bae1dSRodney W. Grimes /* 1309996c772fSJohn Dyson * Even if the count is zero, the VOP_INACTIVE routine may still 1310996c772fSJohn Dyson * have the object locked while it cleans it out. The VOP_LOCK 1311996c772fSJohn Dyson * ensures that the VOP_INACTIVE routine is done with its work. 1312996c772fSJohn Dyson * For active vnodes, it ensures that no other activity can 1313996c772fSJohn Dyson * occur while the underlying object is being cleaned out. 1314996c772fSJohn Dyson */ 1315996c772fSJohn Dyson VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p); 13163c631446SJohn Dyson 13173c631446SJohn Dyson object = vp->v_object; 13183c631446SJohn Dyson irefed = 0; 13193c631446SJohn Dyson if (object && ((object->flags & OBJ_DEAD) == 0)) { 13203c631446SJohn Dyson if (object->ref_count == 0) { 13213c631446SJohn Dyson vm_object_reference(object); 13223c631446SJohn Dyson irefed = 1; 13233c631446SJohn Dyson } 13243c631446SJohn Dyson ++object->ref_count; 13253c631446SJohn Dyson pager_cache(object, FALSE); 13263c631446SJohn Dyson } 13273c631446SJohn Dyson 1328996c772fSJohn Dyson /* 1329df8bae1dSRodney W. Grimes * Clean out any buffers associated with the vnode. 1330df8bae1dSRodney W. Grimes */ 1331df8bae1dSRodney W. Grimes if (flags & DOCLOSE) 1332996c772fSJohn Dyson vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0); 13333c631446SJohn Dyson 13343c631446SJohn Dyson if (irefed) { 13353c631446SJohn Dyson vm_object_deallocate(object); 13363c631446SJohn Dyson } 13373c631446SJohn Dyson 1338df8bae1dSRodney W. Grimes /* 1339996c772fSJohn Dyson * If purging an active vnode, it must be closed and 1340996c772fSJohn Dyson * deactivated before being reclaimed. Note that the 1341996c772fSJohn Dyson * VOP_INACTIVE will unlock the vnode. 1342df8bae1dSRodney W. Grimes */ 1343df8bae1dSRodney W. Grimes if (active) { 1344df8bae1dSRodney W. Grimes if (flags & DOCLOSE) 1345996c772fSJohn Dyson VOP_CLOSE(vp, IO_NDELAY, NOCRED, p); 1346996c772fSJohn Dyson VOP_INACTIVE(vp, p); 1347996c772fSJohn Dyson } else { 1348996c772fSJohn Dyson /* 1349996c772fSJohn Dyson * Any other processes trying to obtain this lock must first 1350996c772fSJohn Dyson * wait for VXLOCK to clear, then call the new lock operation. 1351996c772fSJohn Dyson */ 1352996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1353df8bae1dSRodney W. Grimes } 1354df8bae1dSRodney W. Grimes /* 1355df8bae1dSRodney W. Grimes * Reclaim the vnode. 1356df8bae1dSRodney W. Grimes */ 1357996c772fSJohn Dyson if (VOP_RECLAIM(vp, p)) 1358df8bae1dSRodney W. Grimes panic("vclean: cannot reclaim"); 1359df8bae1dSRodney W. Grimes if (active) 1360df8bae1dSRodney W. Grimes vrele(vp); 1361996c772fSJohn Dyson cache_purge(vp); 1362996c772fSJohn Dyson if (vp->v_vnlock) { 1363de15ef6aSDoug Rabson #ifdef DIAGNOSTIC 1364996c772fSJohn Dyson if ((vp->v_vnlock->lk_flags & LK_DRAINED) == 0) 1365996c772fSJohn Dyson vprint("vclean: lock not drained", vp); 1366de15ef6aSDoug Rabson #endif 1367996c772fSJohn Dyson FREE(vp->v_vnlock, M_VNODE); 1368996c772fSJohn Dyson vp->v_vnlock = NULL; 1369996c772fSJohn Dyson } 1370df8bae1dSRodney W. Grimes 1371df8bae1dSRodney W. Grimes /* 1372df8bae1dSRodney W. Grimes * Done with purge, notify sleepers of the grim news. 1373df8bae1dSRodney W. Grimes */ 1374df8bae1dSRodney W. Grimes vp->v_op = dead_vnodeop_p; 1375df8bae1dSRodney W. Grimes vp->v_tag = VT_NON; 1376df8bae1dSRodney W. Grimes vp->v_flag &= ~VXLOCK; 1377df8bae1dSRodney W. Grimes if (vp->v_flag & VXWANT) { 1378df8bae1dSRodney W. Grimes vp->v_flag &= ~VXWANT; 1379df8bae1dSRodney W. Grimes wakeup((caddr_t) vp); 1380df8bae1dSRodney W. Grimes } 1381df8bae1dSRodney W. Grimes } 1382df8bae1dSRodney W. Grimes 1383df8bae1dSRodney W. Grimes /* 1384df8bae1dSRodney W. Grimes * Eliminate all activity associated with the requested vnode 1385df8bae1dSRodney W. Grimes * and with all vnodes aliased to the requested vnode. 1386df8bae1dSRodney W. Grimes */ 1387996c772fSJohn Dyson int 1388996c772fSJohn Dyson vop_revoke(ap) 1389996c772fSJohn Dyson struct vop_revoke_args /* { 1390996c772fSJohn Dyson struct vnode *a_vp; 1391996c772fSJohn Dyson int a_flags; 1392996c772fSJohn Dyson } */ *ap; 1393df8bae1dSRodney W. Grimes { 1394996c772fSJohn Dyson struct vnode *vp, *vq; 1395996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1396996c772fSJohn Dyson 1397996c772fSJohn Dyson #ifdef DIAGNOSTIC 1398996c772fSJohn Dyson if ((ap->a_flags & REVOKEALL) == 0) 1399996c772fSJohn Dyson panic("vop_revoke"); 1400996c772fSJohn Dyson #endif 1401996c772fSJohn Dyson 1402996c772fSJohn Dyson vp = ap->a_vp; 1403996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1404df8bae1dSRodney W. Grimes 1405df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1406df8bae1dSRodney W. Grimes /* 1407996c772fSJohn Dyson * If a vgone (or vclean) is already in progress, 1408996c772fSJohn Dyson * wait until it is done and return. 1409df8bae1dSRodney W. Grimes */ 1410df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) { 1411df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 1412996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1413996c772fSJohn Dyson tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0); 1414996c772fSJohn Dyson return (0); 1415df8bae1dSRodney W. Grimes } 1416df8bae1dSRodney W. Grimes /* 1417996c772fSJohn Dyson * Ensure that vp will not be vgone'd while we 1418996c772fSJohn Dyson * are eliminating its aliases. 1419df8bae1dSRodney W. Grimes */ 1420df8bae1dSRodney W. Grimes vp->v_flag |= VXLOCK; 1421996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1422df8bae1dSRodney W. Grimes while (vp->v_flag & VALIASED) { 1423996c772fSJohn Dyson simple_lock(&spechash_slock); 1424df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1425df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1426df8bae1dSRodney W. Grimes vq->v_type != vp->v_type || vp == vq) 1427df8bae1dSRodney W. Grimes continue; 1428996c772fSJohn Dyson simple_unlock(&spechash_slock); 1429df8bae1dSRodney W. Grimes vgone(vq); 1430df8bae1dSRodney W. Grimes break; 1431df8bae1dSRodney W. Grimes } 1432996c772fSJohn Dyson if (vq == NULLVP) { 1433996c772fSJohn Dyson simple_unlock(&spechash_slock); 1434996c772fSJohn Dyson } 1435df8bae1dSRodney W. Grimes } 1436df8bae1dSRodney W. Grimes /* 1437996c772fSJohn Dyson * Remove the lock so that vgone below will 1438996c772fSJohn Dyson * really eliminate the vnode after which time 1439996c772fSJohn Dyson * vgone will awaken any sleepers. 1440df8bae1dSRodney W. Grimes */ 1441996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1442df8bae1dSRodney W. Grimes vp->v_flag &= ~VXLOCK; 1443df8bae1dSRodney W. Grimes } 1444996c772fSJohn Dyson vgonel(vp, p); 1445996c772fSJohn Dyson return (0); 1446996c772fSJohn Dyson } 1447996c772fSJohn Dyson 1448996c772fSJohn Dyson /* 1449996c772fSJohn Dyson * Recycle an unused vnode to the front of the free list. 1450996c772fSJohn Dyson * Release the passed interlock if the vnode will be recycled. 1451996c772fSJohn Dyson */ 1452996c772fSJohn Dyson int 1453996c772fSJohn Dyson vrecycle(vp, inter_lkp, p) 1454996c772fSJohn Dyson struct vnode *vp; 1455996c772fSJohn Dyson struct simplelock *inter_lkp; 1456996c772fSJohn Dyson struct proc *p; 1457996c772fSJohn Dyson { 1458996c772fSJohn Dyson 1459996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1460996c772fSJohn Dyson if (vp->v_usecount == 0) { 1461996c772fSJohn Dyson if (inter_lkp) { 1462996c772fSJohn Dyson simple_unlock(inter_lkp); 1463996c772fSJohn Dyson } 1464996c772fSJohn Dyson vgonel(vp, p); 1465996c772fSJohn Dyson return (1); 1466996c772fSJohn Dyson } 1467996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1468996c772fSJohn Dyson return (0); 1469df8bae1dSRodney W. Grimes } 1470df8bae1dSRodney W. Grimes 1471df8bae1dSRodney W. Grimes /* 1472df8bae1dSRodney W. Grimes * Eliminate all activity associated with a vnode 1473df8bae1dSRodney W. Grimes * in preparation for reuse. 1474df8bae1dSRodney W. Grimes */ 147526f9a767SRodney W. Grimes void 147626f9a767SRodney W. Grimes vgone(vp) 1477df8bae1dSRodney W. Grimes register struct vnode *vp; 1478df8bae1dSRodney W. Grimes { 1479996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1480996c772fSJohn Dyson 1481996c772fSJohn Dyson simple_lock(&vp->v_interlock); 1482996c772fSJohn Dyson vgonel(vp, p); 1483996c772fSJohn Dyson } 1484996c772fSJohn Dyson 1485996c772fSJohn Dyson /* 1486996c772fSJohn Dyson * vgone, with the vp interlock held. 1487996c772fSJohn Dyson */ 14880f1adf65SBruce Evans static void 1489996c772fSJohn Dyson vgonel(vp, p) 1490996c772fSJohn Dyson struct vnode *vp; 1491996c772fSJohn Dyson struct proc *p; 1492996c772fSJohn Dyson { 1493996c772fSJohn Dyson struct vnode *vq; 1494df8bae1dSRodney W. Grimes struct vnode *vx; 1495df8bae1dSRodney W. Grimes 1496df8bae1dSRodney W. Grimes /* 1497996c772fSJohn Dyson * If a vgone (or vclean) is already in progress, 1498996c772fSJohn Dyson * wait until it is done and return. 1499df8bae1dSRodney W. Grimes */ 1500df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) { 1501df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 1502996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 1503996c772fSJohn Dyson tsleep((caddr_t)vp, PINOD, "vgone", 0); 1504df8bae1dSRodney W. Grimes return; 1505df8bae1dSRodney W. Grimes } 1506ad980522SJohn Dyson 1507ad980522SJohn Dyson if (vp->v_object) { 1508ad980522SJohn Dyson vp->v_object->flags |= OBJ_VNODE_GONE; 1509ad980522SJohn Dyson } 1510ad980522SJohn Dyson 1511df8bae1dSRodney W. Grimes /* 1512df8bae1dSRodney W. Grimes * Clean out the filesystem specific data. 1513df8bae1dSRodney W. Grimes */ 1514996c772fSJohn Dyson vclean(vp, DOCLOSE, p); 1515df8bae1dSRodney W. Grimes /* 1516df8bae1dSRodney W. Grimes * Delete from old mount point vnode list, if on one. 1517df8bae1dSRodney W. Grimes */ 1518996c772fSJohn Dyson if (vp->v_mount != NULL) 1519996c772fSJohn Dyson insmntque(vp, (struct mount *)0); 1520df8bae1dSRodney W. Grimes /* 1521996c772fSJohn Dyson * If special device, remove it from special device alias list 1522996c772fSJohn Dyson * if it is on one. 1523df8bae1dSRodney W. Grimes */ 1524996c772fSJohn Dyson if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) { 1525996c772fSJohn Dyson simple_lock(&spechash_slock); 1526df8bae1dSRodney W. Grimes if (*vp->v_hashchain == vp) { 1527df8bae1dSRodney W. Grimes *vp->v_hashchain = vp->v_specnext; 1528df8bae1dSRodney W. Grimes } else { 1529df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1530df8bae1dSRodney W. Grimes if (vq->v_specnext != vp) 1531df8bae1dSRodney W. Grimes continue; 1532df8bae1dSRodney W. Grimes vq->v_specnext = vp->v_specnext; 1533df8bae1dSRodney W. Grimes break; 1534df8bae1dSRodney W. Grimes } 1535df8bae1dSRodney W. Grimes if (vq == NULL) 1536df8bae1dSRodney W. Grimes panic("missing bdev"); 1537df8bae1dSRodney W. Grimes } 1538df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1539df8bae1dSRodney W. Grimes vx = NULL; 1540df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1541df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1542df8bae1dSRodney W. Grimes vq->v_type != vp->v_type) 1543df8bae1dSRodney W. Grimes continue; 1544df8bae1dSRodney W. Grimes if (vx) 1545df8bae1dSRodney W. Grimes break; 1546df8bae1dSRodney W. Grimes vx = vq; 1547df8bae1dSRodney W. Grimes } 1548df8bae1dSRodney W. Grimes if (vx == NULL) 1549df8bae1dSRodney W. Grimes panic("missing alias"); 1550df8bae1dSRodney W. Grimes if (vq == NULL) 1551df8bae1dSRodney W. Grimes vx->v_flag &= ~VALIASED; 1552df8bae1dSRodney W. Grimes vp->v_flag &= ~VALIASED; 1553df8bae1dSRodney W. Grimes } 1554996c772fSJohn Dyson simple_unlock(&spechash_slock); 1555df8bae1dSRodney W. Grimes FREE(vp->v_specinfo, M_VNODE); 1556df8bae1dSRodney W. Grimes vp->v_specinfo = NULL; 1557df8bae1dSRodney W. Grimes } 1558996c772fSJohn Dyson 1559df8bae1dSRodney W. Grimes /* 1560996c772fSJohn Dyson * If it is on the freelist and not already at the head, 1561996c772fSJohn Dyson * move it to the head of the list. The test of the back 1562996c772fSJohn Dyson * pointer and the reference count of zero is because 1563996c772fSJohn Dyson * it will be removed from the free list by getnewvnode, 1564996c772fSJohn Dyson * but will not have its reference count incremented until 1565996c772fSJohn Dyson * after calling vgone. If the reference count were 1566996c772fSJohn Dyson * incremented first, vgone would (incorrectly) try to 1567996c772fSJohn Dyson * close the previous instance of the underlying object. 1568996c772fSJohn Dyson * So, the back pointer is explicitly set to `0xdeadb' in 1569996c772fSJohn Dyson * getnewvnode after removing it from the freelist to ensure 1570996c772fSJohn Dyson * that we do not try to move it here. 1571df8bae1dSRodney W. Grimes */ 1572996c772fSJohn Dyson if (vp->v_usecount == 0) { 1573996c772fSJohn Dyson simple_lock(&vnode_free_list_slock); 1574996c772fSJohn Dyson if ((vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) && 1575df8bae1dSRodney W. Grimes vnode_free_list.tqh_first != vp) { 1576df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 1577df8bae1dSRodney W. Grimes TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 1578df8bae1dSRodney W. Grimes } 1579996c772fSJohn Dyson simple_unlock(&vnode_free_list_slock); 15800082fb46SJordan K. Hubbard } 1581996c772fSJohn Dyson 1582df8bae1dSRodney W. Grimes vp->v_type = VBAD; 1583df8bae1dSRodney W. Grimes } 1584df8bae1dSRodney W. Grimes 1585df8bae1dSRodney W. Grimes /* 1586df8bae1dSRodney W. Grimes * Lookup a vnode by device number. 1587df8bae1dSRodney W. Grimes */ 158826f9a767SRodney W. Grimes int 1589df8bae1dSRodney W. Grimes vfinddev(dev, type, vpp) 1590df8bae1dSRodney W. Grimes dev_t dev; 1591df8bae1dSRodney W. Grimes enum vtype type; 1592df8bae1dSRodney W. Grimes struct vnode **vpp; 1593df8bae1dSRodney W. Grimes { 1594df8bae1dSRodney W. Grimes register struct vnode *vp; 1595b98afd0dSBruce Evans int rc = 0; 1596df8bae1dSRodney W. Grimes 1597b98afd0dSBruce Evans simple_lock(&spechash_slock); 1598df8bae1dSRodney W. Grimes for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 1599df8bae1dSRodney W. Grimes if (dev != vp->v_rdev || type != vp->v_type) 1600df8bae1dSRodney W. Grimes continue; 1601df8bae1dSRodney W. Grimes *vpp = vp; 1602b98afd0dSBruce Evans rc = 1; 1603b98afd0dSBruce Evans break; 1604df8bae1dSRodney W. Grimes } 1605b98afd0dSBruce Evans simple_unlock(&spechash_slock); 1606b98afd0dSBruce Evans return (rc); 1607df8bae1dSRodney W. Grimes } 1608df8bae1dSRodney W. Grimes 1609df8bae1dSRodney W. Grimes /* 1610df8bae1dSRodney W. Grimes * Calculate the total number of references to a special device. 1611df8bae1dSRodney W. Grimes */ 161226f9a767SRodney W. Grimes int 1613df8bae1dSRodney W. Grimes vcount(vp) 1614df8bae1dSRodney W. Grimes register struct vnode *vp; 1615df8bae1dSRodney W. Grimes { 1616996c772fSJohn Dyson struct vnode *vq, *vnext; 1617df8bae1dSRodney W. Grimes int count; 1618df8bae1dSRodney W. Grimes 1619df8bae1dSRodney W. Grimes loop: 1620df8bae1dSRodney W. Grimes if ((vp->v_flag & VALIASED) == 0) 1621df8bae1dSRodney W. Grimes return (vp->v_usecount); 1622b98afd0dSBruce Evans simple_lock(&spechash_slock); 1623df8bae1dSRodney W. Grimes for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) { 1624df8bae1dSRodney W. Grimes vnext = vq->v_specnext; 1625df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 1626df8bae1dSRodney W. Grimes continue; 1627df8bae1dSRodney W. Grimes /* 1628df8bae1dSRodney W. Grimes * Alias, but not in use, so flush it out. 1629df8bae1dSRodney W. Grimes */ 1630df8bae1dSRodney W. Grimes if (vq->v_usecount == 0 && vq != vp) { 1631b98afd0dSBruce Evans simple_unlock(&spechash_slock); 1632df8bae1dSRodney W. Grimes vgone(vq); 1633df8bae1dSRodney W. Grimes goto loop; 1634df8bae1dSRodney W. Grimes } 1635df8bae1dSRodney W. Grimes count += vq->v_usecount; 1636df8bae1dSRodney W. Grimes } 1637b98afd0dSBruce Evans simple_unlock(&spechash_slock); 1638df8bae1dSRodney W. Grimes return (count); 1639df8bae1dSRodney W. Grimes } 1640df8bae1dSRodney W. Grimes 1641df8bae1dSRodney W. Grimes /* 1642df8bae1dSRodney W. Grimes * Print out a description of a vnode. 1643df8bae1dSRodney W. Grimes */ 1644df8bae1dSRodney W. Grimes static char *typename[] = 1645df8bae1dSRodney W. Grimes {"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD"}; 1646df8bae1dSRodney W. Grimes 164726f9a767SRodney W. Grimes void 1648df8bae1dSRodney W. Grimes vprint(label, vp) 1649df8bae1dSRodney W. Grimes char *label; 1650df8bae1dSRodney W. Grimes register struct vnode *vp; 1651df8bae1dSRodney W. Grimes { 1652df8bae1dSRodney W. Grimes char buf[64]; 1653df8bae1dSRodney W. Grimes 1654df8bae1dSRodney W. Grimes if (label != NULL) 1655de15ef6aSDoug Rabson printf("%s: %x: ", label, vp); 1656de15ef6aSDoug Rabson else 1657de15ef6aSDoug Rabson printf("%x: ", vp); 1658bb56ec4aSPoul-Henning Kamp printf("type %s, usecount %d, writecount %d, refcount %ld,", 1659df8bae1dSRodney W. Grimes typename[vp->v_type], vp->v_usecount, vp->v_writecount, 1660df8bae1dSRodney W. Grimes vp->v_holdcnt); 1661df8bae1dSRodney W. Grimes buf[0] = '\0'; 1662df8bae1dSRodney W. Grimes if (vp->v_flag & VROOT) 1663df8bae1dSRodney W. Grimes strcat(buf, "|VROOT"); 1664df8bae1dSRodney W. Grimes if (vp->v_flag & VTEXT) 1665df8bae1dSRodney W. Grimes strcat(buf, "|VTEXT"); 1666df8bae1dSRodney W. Grimes if (vp->v_flag & VSYSTEM) 1667df8bae1dSRodney W. Grimes strcat(buf, "|VSYSTEM"); 1668df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) 1669df8bae1dSRodney W. Grimes strcat(buf, "|VXLOCK"); 1670df8bae1dSRodney W. Grimes if (vp->v_flag & VXWANT) 1671df8bae1dSRodney W. Grimes strcat(buf, "|VXWANT"); 1672df8bae1dSRodney W. Grimes if (vp->v_flag & VBWAIT) 1673df8bae1dSRodney W. Grimes strcat(buf, "|VBWAIT"); 1674df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) 1675df8bae1dSRodney W. Grimes strcat(buf, "|VALIASED"); 1676df8bae1dSRodney W. Grimes if (buf[0] != '\0') 1677df8bae1dSRodney W. Grimes printf(" flags (%s)", &buf[1]); 1678df8bae1dSRodney W. Grimes if (vp->v_data == NULL) { 1679df8bae1dSRodney W. Grimes printf("\n"); 1680df8bae1dSRodney W. Grimes } else { 1681df8bae1dSRodney W. Grimes printf("\n\t"); 1682df8bae1dSRodney W. Grimes VOP_PRINT(vp); 1683df8bae1dSRodney W. Grimes } 1684df8bae1dSRodney W. Grimes } 1685df8bae1dSRodney W. Grimes 16861a477b0cSDavid Greenman #ifdef DDB 1687df8bae1dSRodney W. Grimes /* 1688df8bae1dSRodney W. Grimes * List all of the locked vnodes in the system. 1689df8bae1dSRodney W. Grimes * Called when debugging the kernel. 1690df8bae1dSRodney W. Grimes */ 169126f9a767SRodney W. Grimes void 1692c35e283aSBruce Evans printlockedvnodes() 1693df8bae1dSRodney W. Grimes { 1694c35e283aSBruce Evans struct proc *p = curproc; /* XXX */ 1695c35e283aSBruce Evans struct mount *mp, *nmp; 1696c35e283aSBruce Evans struct vnode *vp; 1697df8bae1dSRodney W. Grimes 1698df8bae1dSRodney W. Grimes printf("Locked vnodes\n"); 1699c35e283aSBruce Evans simple_lock(&mountlist_slock); 1700c35e283aSBruce Evans for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 1701c35e283aSBruce Evans if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 1702c35e283aSBruce Evans nmp = mp->mnt_list.cqe_next; 1703c35e283aSBruce Evans continue; 1704c35e283aSBruce Evans } 1705df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; 1706df8bae1dSRodney W. Grimes vp != NULL; 1707c35e283aSBruce Evans vp = vp->v_mntvnodes.le_next) { 1708df8bae1dSRodney W. Grimes if (VOP_ISLOCKED(vp)) 1709df8bae1dSRodney W. Grimes vprint((char *)0, vp); 1710df8bae1dSRodney W. Grimes } 1711c35e283aSBruce Evans simple_lock(&mountlist_slock); 1712c35e283aSBruce Evans nmp = mp->mnt_list.cqe_next; 1713c35e283aSBruce Evans vfs_unbusy(mp, p); 1714c35e283aSBruce Evans } 1715c35e283aSBruce Evans simple_unlock(&mountlist_slock); 1716df8bae1dSRodney W. Grimes } 1717df8bae1dSRodney W. Grimes #endif 1718df8bae1dSRodney W. Grimes 17193a76a594SBruce Evans /* 17203a76a594SBruce Evans * Top level filesystem related information gathering. 17213a76a594SBruce Evans */ 17223a76a594SBruce Evans static int sysctl_ovfs_conf __P(SYSCTL_HANDLER_ARGS); 17233a76a594SBruce Evans 17244a8b9660SBruce Evans static int 17253a76a594SBruce Evans vfs_sysctl SYSCTL_HANDLER_ARGS 1726a896f025SBruce Evans { 17274a8b9660SBruce Evans int *name = (int *)arg1 - 1; /* XXX */ 17284a8b9660SBruce Evans u_int namelen = arg2 + 1; /* XXX */ 1729a896f025SBruce Evans struct vfsconf *vfsp; 1730a896f025SBruce Evans 17313a76a594SBruce Evans #ifndef NO_COMPAT_PRELITE2 17323a76a594SBruce Evans /* Resolve ambiguity between VFS_VFSCONF and VFS_GENERIC. */ 17334a8b9660SBruce Evans if (namelen == 1) 17343a76a594SBruce Evans return (sysctl_ovfs_conf(oidp, arg1, arg2, req)); 1735dc91a89eSBruce Evans #endif 1736a896f025SBruce Evans 17374a8b9660SBruce Evans #ifdef notyet 17383a76a594SBruce Evans /* all sysctl names at this level are at least name and field */ 17393a76a594SBruce Evans if (namelen < 2) 17403a76a594SBruce Evans return (ENOTDIR); /* overloaded */ 17413a76a594SBruce Evans if (name[0] != VFS_GENERIC) { 17423a76a594SBruce Evans for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 17433a76a594SBruce Evans if (vfsp->vfc_typenum == name[0]) 17443a76a594SBruce Evans break; 17453a76a594SBruce Evans if (vfsp == NULL) 17463a76a594SBruce Evans return (EOPNOTSUPP); 17473a76a594SBruce Evans return ((*vfsp->vfc_vfsops->vfs_sysctl)(&name[1], namelen - 1, 17483a76a594SBruce Evans oldp, oldlenp, newp, newlen, p)); 17493a76a594SBruce Evans } 17504a8b9660SBruce Evans #endif 17513a76a594SBruce Evans switch (name[1]) { 17523a76a594SBruce Evans case VFS_MAXTYPENUM: 17533a76a594SBruce Evans if (namelen != 2) 17543a76a594SBruce Evans return (ENOTDIR); 17553a76a594SBruce Evans return (SYSCTL_OUT(req, &maxvfsconf, sizeof(int))); 17563a76a594SBruce Evans case VFS_CONF: 17573a76a594SBruce Evans if (namelen != 3) 17583a76a594SBruce Evans return (ENOTDIR); /* overloaded */ 17593a76a594SBruce Evans for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 17603a76a594SBruce Evans if (vfsp->vfc_typenum == name[2]) 17613a76a594SBruce Evans break; 17623a76a594SBruce Evans if (vfsp == NULL) 17633a76a594SBruce Evans return (EOPNOTSUPP); 17643a76a594SBruce Evans return (SYSCTL_OUT(req, vfsp, sizeof *vfsp)); 17653a76a594SBruce Evans } 17663a76a594SBruce Evans return (EOPNOTSUPP); 17673a76a594SBruce Evans } 17683a76a594SBruce Evans 17694a8b9660SBruce Evans SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD, vfs_sysctl, 17704a8b9660SBruce Evans "Generic filesystem"); 17714a8b9660SBruce Evans 1772a896f025SBruce Evans #ifndef NO_COMPAT_PRELITE2 1773a896f025SBruce Evans 1774a896f025SBruce Evans static int 1775a896f025SBruce Evans sysctl_ovfs_conf SYSCTL_HANDLER_ARGS 1776a896f025SBruce Evans { 1777a896f025SBruce Evans int error; 1778a896f025SBruce Evans struct vfsconf *vfsp; 1779a896f025SBruce Evans struct ovfsconf ovfs; 17803a76a594SBruce Evans 17813a76a594SBruce Evans for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { 1782a896f025SBruce Evans ovfs.vfc_vfsops = vfsp->vfc_vfsops; /* XXX used as flag */ 1783a896f025SBruce Evans strcpy(ovfs.vfc_name, vfsp->vfc_name); 1784a896f025SBruce Evans ovfs.vfc_index = vfsp->vfc_typenum; 1785a896f025SBruce Evans ovfs.vfc_refcount = vfsp->vfc_refcount; 1786a896f025SBruce Evans ovfs.vfc_flags = vfsp->vfc_flags; 1787a896f025SBruce Evans error = SYSCTL_OUT(req, &ovfs, sizeof ovfs); 1788a896f025SBruce Evans if (error) 1789a896f025SBruce Evans return error; 1790a896f025SBruce Evans } 1791a896f025SBruce Evans return 0; 1792a896f025SBruce Evans } 1793a896f025SBruce Evans 1794a896f025SBruce Evans #endif /* !NO_COMPAT_PRELITE2 */ 1795a896f025SBruce Evans 1796df8bae1dSRodney W. Grimes int kinfo_vdebug = 1; 1797df8bae1dSRodney W. Grimes int kinfo_vgetfailed; 17980d94caffSDavid Greenman 1799df8bae1dSRodney W. Grimes #define KINFO_VNODESLOP 10 1800df8bae1dSRodney W. Grimes /* 1801df8bae1dSRodney W. Grimes * Dump vnode list (via sysctl). 1802df8bae1dSRodney W. Grimes * Copyout address of vnode followed by vnode. 1803df8bae1dSRodney W. Grimes */ 1804df8bae1dSRodney W. Grimes /* ARGSUSED */ 18054b2af45fSPoul-Henning Kamp static int 18064b2af45fSPoul-Henning Kamp sysctl_vnode SYSCTL_HANDLER_ARGS 1807df8bae1dSRodney W. Grimes { 1808996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1809c35e283aSBruce Evans struct mount *mp, *nmp; 1810c35e283aSBruce Evans struct vnode *nvp, *vp; 1811df8bae1dSRodney W. Grimes int error; 1812df8bae1dSRodney W. Grimes 1813df8bae1dSRodney W. Grimes #define VPTRSZ sizeof (struct vnode *) 1814df8bae1dSRodney W. Grimes #define VNODESZ sizeof (struct vnode) 18154b2af45fSPoul-Henning Kamp 18164b2af45fSPoul-Henning Kamp req->lock = 0; 18172d0b1d70SPoul-Henning Kamp if (!req->oldptr) /* Make an estimate */ 18184b2af45fSPoul-Henning Kamp return (SYSCTL_OUT(req, 0, 18194b2af45fSPoul-Henning Kamp (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ))); 1820df8bae1dSRodney W. Grimes 1821c35e283aSBruce Evans simple_lock(&mountlist_slock); 1822628641f8SDavid Greenman for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 1823c35e283aSBruce Evans if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 1824628641f8SDavid Greenman nmp = mp->mnt_list.cqe_next; 1825df8bae1dSRodney W. Grimes continue; 1826c35e283aSBruce Evans } 1827df8bae1dSRodney W. Grimes again: 1828c35e283aSBruce Evans simple_lock(&mntvnode_slock); 1829df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; 1830df8bae1dSRodney W. Grimes vp != NULL; 1831c35e283aSBruce Evans vp = nvp) { 1832df8bae1dSRodney W. Grimes /* 1833c35e283aSBruce Evans * Check that the vp is still associated with 1834c35e283aSBruce Evans * this filesystem. RACE: could have been 1835c35e283aSBruce Evans * recycled onto the same filesystem. 1836df8bae1dSRodney W. Grimes */ 1837df8bae1dSRodney W. Grimes if (vp->v_mount != mp) { 1838c35e283aSBruce Evans simple_unlock(&mntvnode_slock); 1839df8bae1dSRodney W. Grimes if (kinfo_vdebug) 1840df8bae1dSRodney W. Grimes printf("kinfo: vp changed\n"); 1841df8bae1dSRodney W. Grimes goto again; 1842df8bae1dSRodney W. Grimes } 1843c35e283aSBruce Evans nvp = vp->v_mntvnodes.le_next; 1844c35e283aSBruce Evans simple_unlock(&mntvnode_slock); 18454b2af45fSPoul-Henning Kamp if ((error = SYSCTL_OUT(req, &vp, VPTRSZ)) || 1846c35e283aSBruce Evans (error = SYSCTL_OUT(req, vp, VNODESZ))) 1847df8bae1dSRodney W. Grimes return (error); 1848c35e283aSBruce Evans simple_lock(&mntvnode_slock); 1849e887950aSBruce Evans } 1850c35e283aSBruce Evans simple_unlock(&mntvnode_slock); 1851c35e283aSBruce Evans simple_lock(&mountlist_slock); 1852c35e283aSBruce Evans nmp = mp->mnt_list.cqe_next; 1853996c772fSJohn Dyson vfs_unbusy(mp, p); 1854df8bae1dSRodney W. Grimes } 1855c35e283aSBruce Evans simple_unlock(&mountlist_slock); 1856df8bae1dSRodney W. Grimes 1857df8bae1dSRodney W. Grimes return (0); 1858df8bae1dSRodney W. Grimes } 1859df8bae1dSRodney W. Grimes 18602e58c0f8SDavid Greenman /* 18612e58c0f8SDavid Greenman * XXX 18622e58c0f8SDavid Greenman * Exporting the vnode list on large systems causes them to crash. 18632e58c0f8SDavid Greenman * Exporting the vnode list on medium systems causes sysctl to coredump. 18642e58c0f8SDavid Greenman */ 18652e58c0f8SDavid Greenman #if 0 186665d0bc13SPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD, 186765d0bc13SPoul-Henning Kamp 0, 0, sysctl_vnode, "S,vnode", ""); 18682e58c0f8SDavid Greenman #endif 18694b2af45fSPoul-Henning Kamp 1870df8bae1dSRodney W. Grimes /* 1871df8bae1dSRodney W. Grimes * Check to see if a filesystem is mounted on a block device. 1872df8bae1dSRodney W. Grimes */ 1873df8bae1dSRodney W. Grimes int 1874df8bae1dSRodney W. Grimes vfs_mountedon(vp) 1875996c772fSJohn Dyson struct vnode *vp; 1876df8bae1dSRodney W. Grimes { 1877996c772fSJohn Dyson struct vnode *vq; 1878996c772fSJohn Dyson int error = 0; 1879df8bae1dSRodney W. Grimes 1880df8bae1dSRodney W. Grimes if (vp->v_specflags & SI_MOUNTEDON) 1881df8bae1dSRodney W. Grimes return (EBUSY); 1882df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1883996c772fSJohn Dyson simple_lock(&spechash_slock); 1884df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1885df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1886df8bae1dSRodney W. Grimes vq->v_type != vp->v_type) 1887df8bae1dSRodney W. Grimes continue; 1888996c772fSJohn Dyson if (vq->v_specflags & SI_MOUNTEDON) { 1889996c772fSJohn Dyson error = EBUSY; 1890996c772fSJohn Dyson break; 1891df8bae1dSRodney W. Grimes } 1892df8bae1dSRodney W. Grimes } 1893996c772fSJohn Dyson simple_unlock(&spechash_slock); 1894996c772fSJohn Dyson } 1895996c772fSJohn Dyson return (error); 1896996c772fSJohn Dyson } 1897996c772fSJohn Dyson 1898996c772fSJohn Dyson /* 1899996c772fSJohn Dyson * Unmount all filesystems. The list is traversed in reverse order 19007c1557c4SBruce Evans * of mounting to avoid dependencies. 1901996c772fSJohn Dyson */ 1902996c772fSJohn Dyson void 1903996c772fSJohn Dyson vfs_unmountall() 1904996c772fSJohn Dyson { 19057c1557c4SBruce Evans struct mount *mp, *nmp; 19067c1557c4SBruce Evans struct proc *p = initproc; /* XXX XXX should this be proc0? */ 1907996c772fSJohn Dyson int error; 1908996c772fSJohn Dyson 19097c1557c4SBruce Evans /* 19107c1557c4SBruce Evans * Since this only runs when rebooting, it is not interlocked. 19117c1557c4SBruce Evans */ 1912996c772fSJohn Dyson for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { 1913996c772fSJohn Dyson nmp = mp->mnt_list.cqe_prev; 19147c1557c4SBruce Evans error = dounmount(mp, MNT_FORCE, p); 1915996c772fSJohn Dyson if (error) { 19167c1557c4SBruce Evans printf("unmount of %s failed (", 19177c1557c4SBruce Evans mp->mnt_stat.f_mntonname); 1918996c772fSJohn Dyson if (error == EBUSY) 1919996c772fSJohn Dyson printf("BUSY)\n"); 1920996c772fSJohn Dyson else 1921996c772fSJohn Dyson printf("%d)\n", error); 1922996c772fSJohn Dyson } 1923996c772fSJohn Dyson } 1924df8bae1dSRodney W. Grimes } 1925df8bae1dSRodney W. Grimes 1926df8bae1dSRodney W. Grimes /* 1927df8bae1dSRodney W. Grimes * Build hash lists of net addresses and hang them off the mount point. 1928df8bae1dSRodney W. Grimes * Called by ufs_mount() to set up the lists of export addresses. 1929df8bae1dSRodney W. Grimes */ 1930df8bae1dSRodney W. Grimes static int 19314b2af45fSPoul-Henning Kamp vfs_hang_addrlist(struct mount *mp, struct netexport *nep, 19324b2af45fSPoul-Henning Kamp struct export_args *argp) 1933df8bae1dSRodney W. Grimes { 1934df8bae1dSRodney W. Grimes register struct netcred *np; 1935df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1936df8bae1dSRodney W. Grimes register int i; 1937df8bae1dSRodney W. Grimes struct radix_node *rn; 1938df8bae1dSRodney W. Grimes struct sockaddr *saddr, *smask = 0; 1939df8bae1dSRodney W. Grimes struct domain *dom; 1940df8bae1dSRodney W. Grimes int error; 1941df8bae1dSRodney W. Grimes 1942df8bae1dSRodney W. Grimes if (argp->ex_addrlen == 0) { 1943df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_DEFEXPORTED) 1944df8bae1dSRodney W. Grimes return (EPERM); 1945df8bae1dSRodney W. Grimes np = &nep->ne_defexported; 1946df8bae1dSRodney W. Grimes np->netc_exflags = argp->ex_flags; 1947df8bae1dSRodney W. Grimes np->netc_anon = argp->ex_anon; 1948df8bae1dSRodney W. Grimes np->netc_anon.cr_ref = 1; 1949df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_DEFEXPORTED; 1950df8bae1dSRodney W. Grimes return (0); 1951df8bae1dSRodney W. Grimes } 1952df8bae1dSRodney W. Grimes i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 1953df8bae1dSRodney W. Grimes np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK); 1954df8bae1dSRodney W. Grimes bzero((caddr_t) np, i); 1955df8bae1dSRodney W. Grimes saddr = (struct sockaddr *) (np + 1); 1956bb56ec4aSPoul-Henning Kamp if ((error = copyin(argp->ex_addr, (caddr_t) saddr, argp->ex_addrlen))) 1957df8bae1dSRodney W. Grimes goto out; 1958df8bae1dSRodney W. Grimes if (saddr->sa_len > argp->ex_addrlen) 1959df8bae1dSRodney W. Grimes saddr->sa_len = argp->ex_addrlen; 1960df8bae1dSRodney W. Grimes if (argp->ex_masklen) { 1961df8bae1dSRodney W. Grimes smask = (struct sockaddr *) ((caddr_t) saddr + argp->ex_addrlen); 19625f61c81dSPeter Wemm error = copyin(argp->ex_mask, (caddr_t) smask, argp->ex_masklen); 1963df8bae1dSRodney W. Grimes if (error) 1964df8bae1dSRodney W. Grimes goto out; 1965df8bae1dSRodney W. Grimes if (smask->sa_len > argp->ex_masklen) 1966df8bae1dSRodney W. Grimes smask->sa_len = argp->ex_masklen; 1967df8bae1dSRodney W. Grimes } 1968df8bae1dSRodney W. Grimes i = saddr->sa_family; 1969df8bae1dSRodney W. Grimes if ((rnh = nep->ne_rtable[i]) == 0) { 1970df8bae1dSRodney W. Grimes /* 19710d94caffSDavid Greenman * Seems silly to initialize every AF when most are not used, 19720d94caffSDavid Greenman * do so on demand here 1973df8bae1dSRodney W. Grimes */ 1974df8bae1dSRodney W. Grimes for (dom = domains; dom; dom = dom->dom_next) 1975df8bae1dSRodney W. Grimes if (dom->dom_family == i && dom->dom_rtattach) { 1976df8bae1dSRodney W. Grimes dom->dom_rtattach((void **) &nep->ne_rtable[i], 1977df8bae1dSRodney W. Grimes dom->dom_rtoffset); 1978df8bae1dSRodney W. Grimes break; 1979df8bae1dSRodney W. Grimes } 1980df8bae1dSRodney W. Grimes if ((rnh = nep->ne_rtable[i]) == 0) { 1981df8bae1dSRodney W. Grimes error = ENOBUFS; 1982df8bae1dSRodney W. Grimes goto out; 1983df8bae1dSRodney W. Grimes } 1984df8bae1dSRodney W. Grimes } 1985df8bae1dSRodney W. Grimes rn = (*rnh->rnh_addaddr) ((caddr_t) saddr, (caddr_t) smask, rnh, 1986df8bae1dSRodney W. Grimes np->netc_rnodes); 1987df8bae1dSRodney W. Grimes if (rn == 0 || np != (struct netcred *) rn) { /* already exists */ 1988df8bae1dSRodney W. Grimes error = EPERM; 1989df8bae1dSRodney W. Grimes goto out; 1990df8bae1dSRodney W. Grimes } 1991df8bae1dSRodney W. Grimes np->netc_exflags = argp->ex_flags; 1992df8bae1dSRodney W. Grimes np->netc_anon = argp->ex_anon; 1993df8bae1dSRodney W. Grimes np->netc_anon.cr_ref = 1; 1994df8bae1dSRodney W. Grimes return (0); 1995df8bae1dSRodney W. Grimes out: 1996df8bae1dSRodney W. Grimes free(np, M_NETADDR); 1997df8bae1dSRodney W. Grimes return (error); 1998df8bae1dSRodney W. Grimes } 1999df8bae1dSRodney W. Grimes 2000df8bae1dSRodney W. Grimes /* ARGSUSED */ 2001df8bae1dSRodney W. Grimes static int 20024b2af45fSPoul-Henning Kamp vfs_free_netcred(struct radix_node *rn, void *w) 2003df8bae1dSRodney W. Grimes { 2004df8bae1dSRodney W. Grimes register struct radix_node_head *rnh = (struct radix_node_head *) w; 2005df8bae1dSRodney W. Grimes 2006df8bae1dSRodney W. Grimes (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh); 2007df8bae1dSRodney W. Grimes free((caddr_t) rn, M_NETADDR); 2008df8bae1dSRodney W. Grimes return (0); 2009df8bae1dSRodney W. Grimes } 2010df8bae1dSRodney W. Grimes 2011df8bae1dSRodney W. Grimes /* 2012df8bae1dSRodney W. Grimes * Free the net address hash lists that are hanging off the mount points. 2013df8bae1dSRodney W. Grimes */ 2014df8bae1dSRodney W. Grimes static void 20154b2af45fSPoul-Henning Kamp vfs_free_addrlist(struct netexport *nep) 2016df8bae1dSRodney W. Grimes { 2017df8bae1dSRodney W. Grimes register int i; 2018df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 2019df8bae1dSRodney W. Grimes 2020df8bae1dSRodney W. Grimes for (i = 0; i <= AF_MAX; i++) 2021bb56ec4aSPoul-Henning Kamp if ((rnh = nep->ne_rtable[i])) { 2022df8bae1dSRodney W. Grimes (*rnh->rnh_walktree) (rnh, vfs_free_netcred, 2023df8bae1dSRodney W. Grimes (caddr_t) rnh); 2024df8bae1dSRodney W. Grimes free((caddr_t) rnh, M_RTABLE); 2025df8bae1dSRodney W. Grimes nep->ne_rtable[i] = 0; 2026df8bae1dSRodney W. Grimes } 2027df8bae1dSRodney W. Grimes } 2028df8bae1dSRodney W. Grimes 2029df8bae1dSRodney W. Grimes int 2030df8bae1dSRodney W. Grimes vfs_export(mp, nep, argp) 2031df8bae1dSRodney W. Grimes struct mount *mp; 2032df8bae1dSRodney W. Grimes struct netexport *nep; 2033df8bae1dSRodney W. Grimes struct export_args *argp; 2034df8bae1dSRodney W. Grimes { 2035df8bae1dSRodney W. Grimes int error; 2036df8bae1dSRodney W. Grimes 2037df8bae1dSRodney W. Grimes if (argp->ex_flags & MNT_DELEXPORT) { 2038f6b4c285SDoug Rabson if (mp->mnt_flag & MNT_EXPUBLIC) { 2039f6b4c285SDoug Rabson vfs_setpublicfs(NULL, NULL, NULL); 2040f6b4c285SDoug Rabson mp->mnt_flag &= ~MNT_EXPUBLIC; 2041f6b4c285SDoug Rabson } 2042df8bae1dSRodney W. Grimes vfs_free_addrlist(nep); 2043df8bae1dSRodney W. Grimes mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 2044df8bae1dSRodney W. Grimes } 2045df8bae1dSRodney W. Grimes if (argp->ex_flags & MNT_EXPORTED) { 2046f6b4c285SDoug Rabson if (argp->ex_flags & MNT_EXPUBLIC) { 2047f6b4c285SDoug Rabson if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) 2048f6b4c285SDoug Rabson return (error); 2049f6b4c285SDoug Rabson mp->mnt_flag |= MNT_EXPUBLIC; 2050f6b4c285SDoug Rabson } 2051bb56ec4aSPoul-Henning Kamp if ((error = vfs_hang_addrlist(mp, nep, argp))) 2052df8bae1dSRodney W. Grimes return (error); 2053df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_EXPORTED; 2054df8bae1dSRodney W. Grimes } 2055df8bae1dSRodney W. Grimes return (0); 2056df8bae1dSRodney W. Grimes } 2057df8bae1dSRodney W. Grimes 2058f6b4c285SDoug Rabson 2059f6b4c285SDoug Rabson /* 2060f6b4c285SDoug Rabson * Set the publicly exported filesystem (WebNFS). Currently, only 2061f6b4c285SDoug Rabson * one public filesystem is possible in the spec (RFC 2054 and 2055) 2062f6b4c285SDoug Rabson */ 2063f6b4c285SDoug Rabson int 2064f6b4c285SDoug Rabson vfs_setpublicfs(mp, nep, argp) 2065f6b4c285SDoug Rabson struct mount *mp; 2066f6b4c285SDoug Rabson struct netexport *nep; 2067f6b4c285SDoug Rabson struct export_args *argp; 2068f6b4c285SDoug Rabson { 2069f6b4c285SDoug Rabson int error; 2070f6b4c285SDoug Rabson struct vnode *rvp; 2071f6b4c285SDoug Rabson char *cp; 2072f6b4c285SDoug Rabson 2073f6b4c285SDoug Rabson /* 2074f6b4c285SDoug Rabson * mp == NULL -> invalidate the current info, the FS is 2075f6b4c285SDoug Rabson * no longer exported. May be called from either vfs_export 2076f6b4c285SDoug Rabson * or unmount, so check if it hasn't already been done. 2077f6b4c285SDoug Rabson */ 2078f6b4c285SDoug Rabson if (mp == NULL) { 2079f6b4c285SDoug Rabson if (nfs_pub.np_valid) { 2080f6b4c285SDoug Rabson nfs_pub.np_valid = 0; 2081f6b4c285SDoug Rabson if (nfs_pub.np_index != NULL) { 2082f6b4c285SDoug Rabson FREE(nfs_pub.np_index, M_TEMP); 2083f6b4c285SDoug Rabson nfs_pub.np_index = NULL; 2084f6b4c285SDoug Rabson } 2085f6b4c285SDoug Rabson } 2086f6b4c285SDoug Rabson return (0); 2087f6b4c285SDoug Rabson } 2088f6b4c285SDoug Rabson 2089f6b4c285SDoug Rabson /* 2090f6b4c285SDoug Rabson * Only one allowed at a time. 2091f6b4c285SDoug Rabson */ 2092f6b4c285SDoug Rabson if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount) 2093f6b4c285SDoug Rabson return (EBUSY); 2094f6b4c285SDoug Rabson 2095f6b4c285SDoug Rabson /* 2096f6b4c285SDoug Rabson * Get real filehandle for root of exported FS. 2097f6b4c285SDoug Rabson */ 2098f6b4c285SDoug Rabson bzero((caddr_t)&nfs_pub.np_handle, sizeof(nfs_pub.np_handle)); 2099f6b4c285SDoug Rabson nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid; 2100f6b4c285SDoug Rabson 2101f6b4c285SDoug Rabson if ((error = VFS_ROOT(mp, &rvp))) 2102f6b4c285SDoug Rabson return (error); 2103f6b4c285SDoug Rabson 2104f6b4c285SDoug Rabson if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) 2105f6b4c285SDoug Rabson return (error); 2106f6b4c285SDoug Rabson 2107f6b4c285SDoug Rabson vput(rvp); 2108f6b4c285SDoug Rabson 2109f6b4c285SDoug Rabson /* 2110f6b4c285SDoug Rabson * If an indexfile was specified, pull it in. 2111f6b4c285SDoug Rabson */ 2112f6b4c285SDoug Rabson if (argp->ex_indexfile != NULL) { 2113f6b4c285SDoug Rabson MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP, 2114f6b4c285SDoug Rabson M_WAITOK); 2115f6b4c285SDoug Rabson error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, 2116f6b4c285SDoug Rabson MAXNAMLEN, (size_t *)0); 2117f6b4c285SDoug Rabson if (!error) { 2118f6b4c285SDoug Rabson /* 2119f6b4c285SDoug Rabson * Check for illegal filenames. 2120f6b4c285SDoug Rabson */ 2121f6b4c285SDoug Rabson for (cp = nfs_pub.np_index; *cp; cp++) { 2122f6b4c285SDoug Rabson if (*cp == '/') { 2123f6b4c285SDoug Rabson error = EINVAL; 2124f6b4c285SDoug Rabson break; 2125f6b4c285SDoug Rabson } 2126f6b4c285SDoug Rabson } 2127f6b4c285SDoug Rabson } 2128f6b4c285SDoug Rabson if (error) { 2129f6b4c285SDoug Rabson FREE(nfs_pub.np_index, M_TEMP); 2130f6b4c285SDoug Rabson return (error); 2131f6b4c285SDoug Rabson } 2132f6b4c285SDoug Rabson } 2133f6b4c285SDoug Rabson 2134f6b4c285SDoug Rabson nfs_pub.np_mount = mp; 2135f6b4c285SDoug Rabson nfs_pub.np_valid = 1; 2136f6b4c285SDoug Rabson return (0); 2137f6b4c285SDoug Rabson } 2138f6b4c285SDoug Rabson 2139df8bae1dSRodney W. Grimes struct netcred * 2140df8bae1dSRodney W. Grimes vfs_export_lookup(mp, nep, nam) 2141df8bae1dSRodney W. Grimes register struct mount *mp; 2142df8bae1dSRodney W. Grimes struct netexport *nep; 2143df8bae1dSRodney W. Grimes struct mbuf *nam; 2144df8bae1dSRodney W. Grimes { 2145df8bae1dSRodney W. Grimes register struct netcred *np; 2146df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 2147df8bae1dSRodney W. Grimes struct sockaddr *saddr; 2148df8bae1dSRodney W. Grimes 2149df8bae1dSRodney W. Grimes np = NULL; 2150df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_EXPORTED) { 2151df8bae1dSRodney W. Grimes /* 2152df8bae1dSRodney W. Grimes * Lookup in the export list first. 2153df8bae1dSRodney W. Grimes */ 2154df8bae1dSRodney W. Grimes if (nam != NULL) { 2155df8bae1dSRodney W. Grimes saddr = mtod(nam, struct sockaddr *); 2156df8bae1dSRodney W. Grimes rnh = nep->ne_rtable[saddr->sa_family]; 2157df8bae1dSRodney W. Grimes if (rnh != NULL) { 2158df8bae1dSRodney W. Grimes np = (struct netcred *) 2159df8bae1dSRodney W. Grimes (*rnh->rnh_matchaddr)((caddr_t)saddr, 2160df8bae1dSRodney W. Grimes rnh); 2161df8bae1dSRodney W. Grimes if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 2162df8bae1dSRodney W. Grimes np = NULL; 2163df8bae1dSRodney W. Grimes } 2164df8bae1dSRodney W. Grimes } 2165df8bae1dSRodney W. Grimes /* 2166df8bae1dSRodney W. Grimes * If no address match, use the default if it exists. 2167df8bae1dSRodney W. Grimes */ 2168df8bae1dSRodney W. Grimes if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 2169df8bae1dSRodney W. Grimes np = &nep->ne_defexported; 2170df8bae1dSRodney W. Grimes } 2171df8bae1dSRodney W. Grimes return (np); 2172df8bae1dSRodney W. Grimes } 217361f5d510SDavid Greenman 217461f5d510SDavid Greenman /* 217561f5d510SDavid Greenman * perform msync on all vnodes under a mount point 217661f5d510SDavid Greenman * the mount point must be locked. 217761f5d510SDavid Greenman */ 217861f5d510SDavid Greenman void 217961f5d510SDavid Greenman vfs_msync(struct mount *mp, int flags) { 2180a316d390SJohn Dyson struct vnode *vp, *nvp; 218161f5d510SDavid Greenman loop: 2182a316d390SJohn Dyson for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 218361f5d510SDavid Greenman 218461f5d510SDavid Greenman if (vp->v_mount != mp) 218561f5d510SDavid Greenman goto loop; 2186a316d390SJohn Dyson nvp = vp->v_mntvnodes.le_next; 218761f5d510SDavid Greenman if (VOP_ISLOCKED(vp) && (flags != MNT_WAIT)) 218861f5d510SDavid Greenman continue; 2189aa2cabb9SDavid Greenman if (vp->v_object && 21906476c0d2SJohn Dyson (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { 219124a1cce3SDavid Greenman vm_object_page_clean(vp->v_object, 0, 0, TRUE, TRUE); 219261f5d510SDavid Greenman } 219361f5d510SDavid Greenman } 219461f5d510SDavid Greenman } 21956476c0d2SJohn Dyson 21966476c0d2SJohn Dyson /* 21976476c0d2SJohn Dyson * Create the VM object needed for VMIO and mmap support. This 21986476c0d2SJohn Dyson * is done for all VREG files in the system. Some filesystems might 21996476c0d2SJohn Dyson * afford the additional metadata buffering capability of the 22006476c0d2SJohn Dyson * VMIO code by making the device node be VMIO mode also. 22016476c0d2SJohn Dyson */ 22026476c0d2SJohn Dyson int 22036476c0d2SJohn Dyson vfs_object_create(vp, p, cred, waslocked) 22046476c0d2SJohn Dyson struct vnode *vp; 22056476c0d2SJohn Dyson struct proc *p; 22066476c0d2SJohn Dyson struct ucred *cred; 22076476c0d2SJohn Dyson int waslocked; 22086476c0d2SJohn Dyson { 22096476c0d2SJohn Dyson struct vattr vat; 22106476c0d2SJohn Dyson vm_object_t object; 22116476c0d2SJohn Dyson int error = 0; 22126476c0d2SJohn Dyson 22136476c0d2SJohn Dyson retry: 22146476c0d2SJohn Dyson if ((object = vp->v_object) == NULL) { 22156476c0d2SJohn Dyson if (vp->v_type == VREG) { 22166476c0d2SJohn Dyson if ((error = VOP_GETATTR(vp, &vat, cred, p)) != 0) 22176476c0d2SJohn Dyson goto retn; 22186476c0d2SJohn Dyson (void) vnode_pager_alloc(vp, 22196476c0d2SJohn Dyson OFF_TO_IDX(round_page(vat.va_size)), 0, 0); 22206476c0d2SJohn Dyson } else { 22216476c0d2SJohn Dyson /* 22226476c0d2SJohn Dyson * This simply allocates the biggest object possible 22236476c0d2SJohn Dyson * for a VBLK vnode. This should be fixed, but doesn't 22246476c0d2SJohn Dyson * cause any problems (yet). 22256476c0d2SJohn Dyson */ 22266476c0d2SJohn Dyson (void) vnode_pager_alloc(vp, INT_MAX, 0, 0); 22276476c0d2SJohn Dyson } 22286476c0d2SJohn Dyson vp->v_object->flags |= OBJ_VFS_REF; 22296476c0d2SJohn Dyson } else { 22306476c0d2SJohn Dyson if (object->flags & OBJ_DEAD) { 22316476c0d2SJohn Dyson if (waslocked) 2232996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 22336476c0d2SJohn Dyson tsleep(object, PVM, "vodead", 0); 22346476c0d2SJohn Dyson if (waslocked) 2235996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 22366476c0d2SJohn Dyson goto retry; 22376476c0d2SJohn Dyson } 22386476c0d2SJohn Dyson if ((object->flags & OBJ_VFS_REF) == 0) { 22396476c0d2SJohn Dyson object->flags |= OBJ_VFS_REF; 22406476c0d2SJohn Dyson vm_object_reference(object); 22416476c0d2SJohn Dyson } 22426476c0d2SJohn Dyson } 22436476c0d2SJohn Dyson if (vp->v_object) 22446476c0d2SJohn Dyson vp->v_flag |= VVMIO; 22456476c0d2SJohn Dyson 22466476c0d2SJohn Dyson retn: 22476476c0d2SJohn Dyson return error; 22486476c0d2SJohn Dyson } 2249b15a966eSPoul-Henning Kamp 2250b15a966eSPoul-Henning Kamp void 2251b15a966eSPoul-Henning Kamp vtouch(vp) 2252b15a966eSPoul-Henning Kamp struct vnode *vp; 2253b15a966eSPoul-Henning Kamp { 2254b15a966eSPoul-Henning Kamp simple_lock(&vp->v_interlock); 2255b15a966eSPoul-Henning Kamp if (vp->v_usecount) { 2256b15a966eSPoul-Henning Kamp simple_unlock(&vp->v_interlock); 2257b15a966eSPoul-Henning Kamp return; 2258b15a966eSPoul-Henning Kamp } 2259b15a966eSPoul-Henning Kamp if (simple_lock_try(&vnode_free_list_slock)) { 22608670684aSPoul-Henning Kamp if (vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) { 2261b15a966eSPoul-Henning Kamp TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 2262b15a966eSPoul-Henning Kamp TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 22638670684aSPoul-Henning Kamp } 2264b15a966eSPoul-Henning Kamp simple_unlock(&vnode_free_list_slock); 2265b15a966eSPoul-Henning Kamp } 2266b15a966eSPoul-Henning Kamp simple_unlock(&vp->v_interlock); 2267b15a966eSPoul-Henning Kamp } 2268