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 * 38df8bae1dSRodney W. Grimes * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94 3998d93822SBruce Evans * $Id: vfs_subr.c,v 1.44 1995/11/29 11:28:00 phk Exp $ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes /* 43df8bae1dSRodney W. Grimes * External virtual filesystem routines 44df8bae1dSRodney W. Grimes */ 45df8bae1dSRodney W. Grimes 46df8bae1dSRodney W. Grimes #include <sys/param.h> 47df8bae1dSRodney W. Grimes #include <sys/systm.h> 48986f4ce7SBruce Evans #include <sys/kernel.h> 496acceb40SBruce Evans #include <sys/file.h> 50df8bae1dSRodney W. Grimes #include <sys/proc.h> 51df8bae1dSRodney W. Grimes #include <sys/mount.h> 52df8bae1dSRodney W. Grimes #include <sys/time.h> 53df8bae1dSRodney W. Grimes #include <sys/vnode.h> 54df8bae1dSRodney W. Grimes #include <sys/stat.h> 55df8bae1dSRodney W. Grimes #include <sys/namei.h> 56df8bae1dSRodney W. Grimes #include <sys/ucred.h> 57df8bae1dSRodney W. Grimes #include <sys/buf.h> 58df8bae1dSRodney W. Grimes #include <sys/errno.h> 59df8bae1dSRodney W. Grimes #include <sys/malloc.h> 60df8bae1dSRodney W. Grimes #include <sys/domain.h> 61df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <vm/vm.h> 64df8bae1dSRodney W. Grimes #include <sys/sysctl.h> 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 67df8bae1dSRodney W. Grimes 6898d93822SBruce Evans #ifdef DDB 6998d93822SBruce Evans extern void printlockedvnodes __P((void)); 7098d93822SBruce Evans #endif 7198d93822SBruce Evans extern void vclean __P((struct vnode *vp, int flags)); 7298d93822SBruce Evans extern void vfs_unmountroot __P((struct mount *rootfs)); 7398d93822SBruce Evans 74df8bae1dSRodney W. Grimes enum vtype iftovt_tab[16] = { 75df8bae1dSRodney W. Grimes VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 76df8bae1dSRodney W. Grimes VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 77df8bae1dSRodney W. Grimes }; 78df8bae1dSRodney W. Grimes int vttoif_tab[9] = { 79df8bae1dSRodney W. Grimes 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 80df8bae1dSRodney W. Grimes S_IFSOCK, S_IFIFO, S_IFMT, 81df8bae1dSRodney W. Grimes }; 82df8bae1dSRodney W. Grimes 83df8bae1dSRodney W. Grimes /* 84df8bae1dSRodney W. Grimes * Insq/Remq for the vnode usage lists. 85df8bae1dSRodney W. Grimes */ 86df8bae1dSRodney W. Grimes #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) 87df8bae1dSRodney W. Grimes #define bufremvn(bp) { \ 88df8bae1dSRodney W. Grimes LIST_REMOVE(bp, b_vnbufs); \ 89df8bae1dSRodney W. Grimes (bp)->b_vnbufs.le_next = NOLIST; \ 90df8bae1dSRodney W. Grimes } 91df8bae1dSRodney W. Grimes 92df8bae1dSRodney W. Grimes TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ 93fbd6e6c9SPoul-Henning Kamp u_long freevnodes = 0; 94fbd6e6c9SPoul-Henning Kamp 95df8bae1dSRodney W. Grimes struct mntlist mountlist; /* mounted filesystem list */ 96df8bae1dSRodney W. Grimes 970d94caffSDavid Greenman int desiredvnodes; 982d0b1d70SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, ""); 990d94caffSDavid Greenman 10098d93822SBruce Evans static void vfs_free_addrlist __P((struct netexport *nep)); 10198d93822SBruce Evans static int vfs_free_netcred __P((struct radix_node *rn, void *w)); 10298d93822SBruce Evans static int vfs_hang_addrlist __P((struct mount *mp, struct netexport *nep, 10398d93822SBruce Evans struct export_args *argp)); 10498d93822SBruce Evans 105df8bae1dSRodney W. Grimes /* 106df8bae1dSRodney W. Grimes * Initialize the vnode management data structures. 107df8bae1dSRodney W. Grimes */ 10826f9a767SRodney W. Grimes void 109df8bae1dSRodney W. Grimes vntblinit() 110df8bae1dSRodney W. Grimes { 1110d94caffSDavid Greenman desiredvnodes = maxproc + vm_object_cache_max; 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes TAILQ_INIT(&vnode_free_list); 114628641f8SDavid Greenman CIRCLEQ_INIT(&mountlist); 115df8bae1dSRodney W. Grimes } 116df8bae1dSRodney W. Grimes 117df8bae1dSRodney W. Grimes /* 118df8bae1dSRodney W. Grimes * Lock a filesystem. 119df8bae1dSRodney W. Grimes * Used to prevent access to it while mounting and unmounting. 120df8bae1dSRodney W. Grimes */ 12126f9a767SRodney W. Grimes int 122df8bae1dSRodney W. Grimes vfs_lock(mp) 123df8bae1dSRodney W. Grimes register struct mount *mp; 124df8bae1dSRodney W. Grimes { 125df8bae1dSRodney W. Grimes 126df8bae1dSRodney W. Grimes while (mp->mnt_flag & MNT_MLOCK) { 127df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_MWAIT; 12882478919SDavid Greenman (void) tsleep((caddr_t) mp, PVFS, "vfslck", 0); 129df8bae1dSRodney W. Grimes } 130df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_MLOCK; 131df8bae1dSRodney W. Grimes return (0); 132df8bae1dSRodney W. Grimes } 133df8bae1dSRodney W. Grimes 134df8bae1dSRodney W. Grimes /* 135df8bae1dSRodney W. Grimes * Unlock a locked filesystem. 136df8bae1dSRodney W. Grimes * Panic if filesystem is not locked. 137df8bae1dSRodney W. Grimes */ 138df8bae1dSRodney W. Grimes void 139df8bae1dSRodney W. Grimes vfs_unlock(mp) 140df8bae1dSRodney W. Grimes register struct mount *mp; 141df8bae1dSRodney W. Grimes { 142df8bae1dSRodney W. Grimes 143df8bae1dSRodney W. Grimes if ((mp->mnt_flag & MNT_MLOCK) == 0) 144df8bae1dSRodney W. Grimes panic("vfs_unlock: not locked"); 145df8bae1dSRodney W. Grimes mp->mnt_flag &= ~MNT_MLOCK; 146df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_MWAIT) { 147df8bae1dSRodney W. Grimes mp->mnt_flag &= ~MNT_MWAIT; 148df8bae1dSRodney W. Grimes wakeup((caddr_t) mp); 149df8bae1dSRodney W. Grimes } 150df8bae1dSRodney W. Grimes } 151df8bae1dSRodney W. Grimes 152df8bae1dSRodney W. Grimes /* 153df8bae1dSRodney W. Grimes * Mark a mount point as busy. 154df8bae1dSRodney W. Grimes * Used to synchronize access and to delay unmounting. 155df8bae1dSRodney W. Grimes */ 15626f9a767SRodney W. Grimes int 157df8bae1dSRodney W. Grimes vfs_busy(mp) 158df8bae1dSRodney W. Grimes register struct mount *mp; 159df8bae1dSRodney W. Grimes { 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes while (mp->mnt_flag & MNT_MPBUSY) { 162df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_MPWANT; 16382478919SDavid Greenman (void) tsleep((caddr_t) &mp->mnt_flag, PVFS, "vfsbsy", 0); 164df8bae1dSRodney W. Grimes } 165df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_UNMOUNT) 166df8bae1dSRodney W. Grimes return (1); 167df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_MPBUSY; 168df8bae1dSRodney W. Grimes return (0); 169df8bae1dSRodney W. Grimes } 170df8bae1dSRodney W. Grimes 171df8bae1dSRodney W. Grimes /* 172df8bae1dSRodney W. Grimes * Free a busy filesystem. 173df8bae1dSRodney W. Grimes * Panic if filesystem is not busy. 174df8bae1dSRodney W. Grimes */ 17526f9a767SRodney W. Grimes void 176df8bae1dSRodney W. Grimes vfs_unbusy(mp) 177df8bae1dSRodney W. Grimes register struct mount *mp; 178df8bae1dSRodney W. Grimes { 179df8bae1dSRodney W. Grimes 180df8bae1dSRodney W. Grimes if ((mp->mnt_flag & MNT_MPBUSY) == 0) 181df8bae1dSRodney W. Grimes panic("vfs_unbusy: not busy"); 182df8bae1dSRodney W. Grimes mp->mnt_flag &= ~MNT_MPBUSY; 183df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_MPWANT) { 184df8bae1dSRodney W. Grimes mp->mnt_flag &= ~MNT_MPWANT; 185df8bae1dSRodney W. Grimes wakeup((caddr_t) &mp->mnt_flag); 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes } 188df8bae1dSRodney W. Grimes 189e0e9c421SDavid Greenman void 1904b2af45fSPoul-Henning Kamp vfs_unmountroot(struct mount *rootfs) 191e0e9c421SDavid Greenman { 192e0e9c421SDavid Greenman struct mount *mp = rootfs; 193e0e9c421SDavid Greenman int error; 194e0e9c421SDavid Greenman 195e0e9c421SDavid Greenman if (vfs_busy(mp)) { 196e0e9c421SDavid Greenman printf("failed to unmount root\n"); 197e0e9c421SDavid Greenman return; 198e0e9c421SDavid Greenman } 199e0e9c421SDavid Greenman mp->mnt_flag |= MNT_UNMOUNT; 200bb56ec4aSPoul-Henning Kamp if ((error = vfs_lock(mp))) { 201e0e9c421SDavid Greenman printf("lock of root filesystem failed (%d)\n", error); 202e0e9c421SDavid Greenman return; 203e0e9c421SDavid Greenman } 204e0e9c421SDavid Greenman vnode_pager_umount(mp); /* release cached vnodes */ 205e0e9c421SDavid Greenman cache_purgevfs(mp); /* remove cache entries for this file sys */ 206e0e9c421SDavid Greenman 207bb56ec4aSPoul-Henning Kamp if ((error = VFS_SYNC(mp, MNT_WAIT, initproc->p_ucred, initproc))) 208e0e9c421SDavid Greenman printf("sync of root filesystem failed (%d)\n", error); 209e0e9c421SDavid Greenman 210bb56ec4aSPoul-Henning Kamp if ((error = VFS_UNMOUNT(mp, MNT_FORCE, initproc))) { 2114f5a3fefSDavid Greenman printf("unmount of root filesystem failed ("); 2124f5a3fefSDavid Greenman if (error == EBUSY) 2134f5a3fefSDavid Greenman printf("BUSY)\n"); 2144f5a3fefSDavid Greenman else 2154f5a3fefSDavid Greenman printf("%d)\n", error); 2164f5a3fefSDavid Greenman } 217e0e9c421SDavid Greenman mp->mnt_flag &= ~MNT_UNMOUNT; 218e0e9c421SDavid Greenman vfs_unbusy(mp); 219e0e9c421SDavid Greenman } 220e0e9c421SDavid Greenman 221e0e9c421SDavid Greenman /* 222e0e9c421SDavid Greenman * Unmount all filesystems. Should only be called by halt(). 223e0e9c421SDavid Greenman */ 224e0e9c421SDavid Greenman void 225e0e9c421SDavid Greenman vfs_unmountall() 226e0e9c421SDavid Greenman { 227628641f8SDavid Greenman struct mount *mp, *nmp, *rootfs = NULL; 228e0e9c421SDavid Greenman int error; 229e0e9c421SDavid Greenman 230e0e9c421SDavid Greenman /* unmount all but rootfs */ 231628641f8SDavid Greenman for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { 232628641f8SDavid Greenman nmp = mp->mnt_list.cqe_prev; 233e0e9c421SDavid Greenman 234e0e9c421SDavid Greenman if (mp->mnt_flag & MNT_ROOTFS) { 235e0e9c421SDavid Greenman rootfs = mp; 236e0e9c421SDavid Greenman continue; 237e0e9c421SDavid Greenman } 238e0e9c421SDavid Greenman error = dounmount(mp, MNT_FORCE, initproc); 239e0e9c421SDavid Greenman if (error) { 2404f5a3fefSDavid Greenman printf("unmount of %s failed (", mp->mnt_stat.f_mntonname); 2414f5a3fefSDavid Greenman if (error == EBUSY) 2424f5a3fefSDavid Greenman printf("BUSY)\n"); 2434f5a3fefSDavid Greenman else 2444f5a3fefSDavid Greenman printf("%d)\n", error); 245e0e9c421SDavid Greenman } 246e0e9c421SDavid Greenman } 247e0e9c421SDavid Greenman 248e0e9c421SDavid Greenman /* and finally... */ 249e0e9c421SDavid Greenman if (rootfs) { 250e0e9c421SDavid Greenman vfs_unmountroot(rootfs); 251e0e9c421SDavid Greenman } else { 252e0e9c421SDavid Greenman printf("no root filesystem\n"); 253e0e9c421SDavid Greenman } 254e0e9c421SDavid Greenman } 255e0e9c421SDavid Greenman 256df8bae1dSRodney W. Grimes /* 257df8bae1dSRodney W. Grimes * Lookup a mount point by filesystem identifier. 258df8bae1dSRodney W. Grimes */ 259df8bae1dSRodney W. Grimes struct mount * 260df8bae1dSRodney W. Grimes getvfs(fsid) 261df8bae1dSRodney W. Grimes fsid_t *fsid; 262df8bae1dSRodney W. Grimes { 263df8bae1dSRodney W. Grimes register struct mount *mp; 264df8bae1dSRodney W. Grimes 265628641f8SDavid Greenman for (mp = mountlist.cqh_first; mp != (void *)&mountlist; 266628641f8SDavid Greenman mp = mp->mnt_list.cqe_next) { 267df8bae1dSRodney W. Grimes if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 268df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) 269df8bae1dSRodney W. Grimes return (mp); 270df8bae1dSRodney W. Grimes } 271df8bae1dSRodney W. Grimes return ((struct mount *) 0); 272df8bae1dSRodney W. Grimes } 273df8bae1dSRodney W. Grimes 274df8bae1dSRodney W. Grimes /* 275df8bae1dSRodney W. Grimes * Get a new unique fsid 276df8bae1dSRodney W. Grimes */ 277df8bae1dSRodney W. Grimes void 278df8bae1dSRodney W. Grimes getnewfsid(mp, mtype) 279df8bae1dSRodney W. Grimes struct mount *mp; 280df8bae1dSRodney W. Grimes int mtype; 281df8bae1dSRodney W. Grimes { 282df8bae1dSRodney W. Grimes static u_short xxxfs_mntid; 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes fsid_t tfsid; 285df8bae1dSRodney W. Grimes 286df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0); 287df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[1] = mtype; 288df8bae1dSRodney W. Grimes if (xxxfs_mntid == 0) 289df8bae1dSRodney W. Grimes ++xxxfs_mntid; 290df8bae1dSRodney W. Grimes tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); 291df8bae1dSRodney W. Grimes tfsid.val[1] = mtype; 292628641f8SDavid Greenman if (mountlist.cqh_first != (void *)&mountlist) { 293df8bae1dSRodney W. Grimes while (getvfs(&tfsid)) { 294df8bae1dSRodney W. Grimes tfsid.val[0]++; 295df8bae1dSRodney W. Grimes xxxfs_mntid++; 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes } 298df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 299df8bae1dSRodney W. Grimes } 300df8bae1dSRodney W. Grimes 301df8bae1dSRodney W. Grimes /* 302df8bae1dSRodney W. Grimes * Set vnode attributes to VNOVAL 303df8bae1dSRodney W. Grimes */ 30426f9a767SRodney W. Grimes void 30526f9a767SRodney W. Grimes vattr_null(vap) 306df8bae1dSRodney W. Grimes register struct vattr *vap; 307df8bae1dSRodney W. Grimes { 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes vap->va_type = VNON; 31026f9a767SRodney W. Grimes vap->va_size = VNOVAL; 31126f9a767SRodney W. Grimes vap->va_bytes = VNOVAL; 312df8bae1dSRodney W. Grimes vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 313df8bae1dSRodney W. Grimes vap->va_fsid = vap->va_fileid = 314df8bae1dSRodney W. Grimes vap->va_blocksize = vap->va_rdev = 315df8bae1dSRodney W. Grimes vap->va_atime.ts_sec = vap->va_atime.ts_nsec = 316df8bae1dSRodney W. Grimes vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = 317df8bae1dSRodney W. Grimes vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec = 318df8bae1dSRodney W. Grimes vap->va_flags = vap->va_gen = VNOVAL; 319df8bae1dSRodney W. Grimes vap->va_vaflags = 0; 320df8bae1dSRodney W. Grimes } 321df8bae1dSRodney W. Grimes 322df8bae1dSRodney W. Grimes /* 323df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 324df8bae1dSRodney W. Grimes */ 325f57e6547SBruce Evans extern vop_t **dead_vnodeop_p; 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes /* 328df8bae1dSRodney W. Grimes * Return the next vnode from the free list. 329df8bae1dSRodney W. Grimes */ 33026f9a767SRodney W. Grimes int 331df8bae1dSRodney W. Grimes getnewvnode(tag, mp, vops, vpp) 332df8bae1dSRodney W. Grimes enum vtagtype tag; 333df8bae1dSRodney W. Grimes struct mount *mp; 334f57e6547SBruce Evans vop_t **vops; 335df8bae1dSRodney W. Grimes struct vnode **vpp; 336df8bae1dSRodney W. Grimes { 337df8bae1dSRodney W. Grimes register struct vnode *vp; 338df8bae1dSRodney W. Grimes 339fbd6e6c9SPoul-Henning Kamp vp = vnode_free_list.tqh_first; 340fbd6e6c9SPoul-Henning Kamp /* 341fbd6e6c9SPoul-Henning Kamp * we allocate a new vnode if 342fbd6e6c9SPoul-Henning Kamp * 1. we don't have any free 343fbd6e6c9SPoul-Henning Kamp * Pretty obvious, we actually used to panic, but that 344fbd6e6c9SPoul-Henning Kamp * is a silly thing to do. 345fbd6e6c9SPoul-Henning Kamp * 2. we havn't filled our pool yet 346fbd6e6c9SPoul-Henning Kamp * We don't want to trash the incore (VM-)vnodecache. 34715f1b096SDavid Greenman * 3. if less that 1/4th of our vnodes are free. 348fbd6e6c9SPoul-Henning Kamp * We don't want to trash the namei cache either. 349fbd6e6c9SPoul-Henning Kamp */ 35015f1b096SDavid Greenman if (freevnodes < (numvnodes >> 2) || 351fbd6e6c9SPoul-Henning Kamp numvnodes < desiredvnodes || 352f8a0b2ddSDavid Greenman vp == NULL) { 353df8bae1dSRodney W. Grimes vp = (struct vnode *) malloc((u_long) sizeof *vp, 354df8bae1dSRodney W. Grimes M_VNODE, M_WAITOK); 355df8bae1dSRodney W. Grimes bzero((char *) vp, sizeof *vp); 356df8bae1dSRodney W. Grimes numvnodes++; 357df8bae1dSRodney W. Grimes } else { 358fbd6e6c9SPoul-Henning Kamp TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 359fbd6e6c9SPoul-Henning Kamp freevnodes--; 360fbd6e6c9SPoul-Henning Kamp 361df8bae1dSRodney W. Grimes if (vp->v_usecount) 362df8bae1dSRodney W. Grimes panic("free vnode isn't"); 3630d94caffSDavid Greenman 364df8bae1dSRodney W. Grimes /* see comment on why 0xdeadb is set at end of vgone (below) */ 365df8bae1dSRodney W. Grimes vp->v_freelist.tqe_prev = (struct vnode **) 0xdeadb; 366df8bae1dSRodney W. Grimes vp->v_lease = NULL; 367df8bae1dSRodney W. Grimes if (vp->v_type != VBAD) 368df8bae1dSRodney W. Grimes vgone(vp); 369df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 370797f2d22SPoul-Henning Kamp { 371797f2d22SPoul-Henning Kamp int s; 3720d94caffSDavid Greenman 373df8bae1dSRodney W. Grimes if (vp->v_data) 374df8bae1dSRodney W. Grimes panic("cleaned vnode isn't"); 375df8bae1dSRodney W. Grimes s = splbio(); 376df8bae1dSRodney W. Grimes if (vp->v_numoutput) 377df8bae1dSRodney W. Grimes panic("Clean vnode has pending I/O's"); 378df8bae1dSRodney W. Grimes splx(s); 379797f2d22SPoul-Henning Kamp } 380df8bae1dSRodney W. Grimes #endif 381df8bae1dSRodney W. Grimes vp->v_flag = 0; 382df8bae1dSRodney W. Grimes vp->v_lastr = 0; 383df8bae1dSRodney W. Grimes vp->v_ralen = 0; 384df8bae1dSRodney W. Grimes vp->v_maxra = 0; 385df8bae1dSRodney W. Grimes vp->v_lastw = 0; 386df8bae1dSRodney W. Grimes vp->v_lasta = 0; 387df8bae1dSRodney W. Grimes vp->v_cstart = 0; 388df8bae1dSRodney W. Grimes vp->v_clen = 0; 389df8bae1dSRodney W. Grimes vp->v_socket = 0; 390e0c02154SDavid Greenman vp->v_writecount = 0; /* XXX */ 391df8bae1dSRodney W. Grimes } 392f9ceb7c7SDavid Greenman vp->v_type = VNON; 3937500ed1dSDavid Greenman cache_purge(vp); 394df8bae1dSRodney W. Grimes vp->v_tag = tag; 395df8bae1dSRodney W. Grimes vp->v_op = vops; 396df8bae1dSRodney W. Grimes insmntque(vp, mp); 397df8bae1dSRodney W. Grimes *vpp = vp; 398df8bae1dSRodney W. Grimes vp->v_usecount = 1; 399df8bae1dSRodney W. Grimes vp->v_data = 0; 400df8bae1dSRodney W. Grimes return (0); 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes 403df8bae1dSRodney W. Grimes /* 404df8bae1dSRodney W. Grimes * Move a vnode from one mount queue to another. 405df8bae1dSRodney W. Grimes */ 40626f9a767SRodney W. Grimes void 407df8bae1dSRodney W. Grimes insmntque(vp, mp) 408df8bae1dSRodney W. Grimes register struct vnode *vp; 409df8bae1dSRodney W. Grimes register struct mount *mp; 410df8bae1dSRodney W. Grimes { 411df8bae1dSRodney W. Grimes 412df8bae1dSRodney W. Grimes /* 413df8bae1dSRodney W. Grimes * Delete from old mount point vnode list, if on one. 414df8bae1dSRodney W. Grimes */ 415df8bae1dSRodney W. Grimes if (vp->v_mount != NULL) 416df8bae1dSRodney W. Grimes LIST_REMOVE(vp, v_mntvnodes); 417df8bae1dSRodney W. Grimes /* 418df8bae1dSRodney W. Grimes * Insert into list of vnodes for the new mount point, if available. 419df8bae1dSRodney W. Grimes */ 420df8bae1dSRodney W. Grimes if ((vp->v_mount = mp) == NULL) 421df8bae1dSRodney W. Grimes return; 422df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes 425df8bae1dSRodney W. Grimes /* 426df8bae1dSRodney W. Grimes * Update outstanding I/O count and do wakeup if requested. 427df8bae1dSRodney W. Grimes */ 42826f9a767SRodney W. Grimes void 429df8bae1dSRodney W. Grimes vwakeup(bp) 430df8bae1dSRodney W. Grimes register struct buf *bp; 431df8bae1dSRodney W. Grimes { 432df8bae1dSRodney W. Grimes register struct vnode *vp; 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes bp->b_flags &= ~B_WRITEINPROG; 435bb56ec4aSPoul-Henning Kamp if ((vp = bp->b_vp)) { 436df8bae1dSRodney W. Grimes vp->v_numoutput--; 437df8bae1dSRodney W. Grimes if (vp->v_numoutput < 0) 438df8bae1dSRodney W. Grimes panic("vwakeup: neg numoutput"); 439a3a8bb29SDavid Greenman if ((vp->v_numoutput == 0) && (vp->v_flag & VBWAIT)) { 440df8bae1dSRodney W. Grimes vp->v_flag &= ~VBWAIT; 441df8bae1dSRodney W. Grimes wakeup((caddr_t) &vp->v_numoutput); 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes 446df8bae1dSRodney W. Grimes /* 447df8bae1dSRodney W. Grimes * Flush out and invalidate all buffers associated with a vnode. 448df8bae1dSRodney W. Grimes * Called with the underlying object locked. 449df8bae1dSRodney W. Grimes */ 450df8bae1dSRodney W. Grimes int 451df8bae1dSRodney W. Grimes vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 452df8bae1dSRodney W. Grimes register struct vnode *vp; 453df8bae1dSRodney W. Grimes int flags; 454df8bae1dSRodney W. Grimes struct ucred *cred; 455df8bae1dSRodney W. Grimes struct proc *p; 456df8bae1dSRodney W. Grimes int slpflag, slptimeo; 457df8bae1dSRodney W. Grimes { 458df8bae1dSRodney W. Grimes register struct buf *bp; 459df8bae1dSRodney W. Grimes struct buf *nbp, *blist; 460df8bae1dSRodney W. Grimes int s, error; 4611cdeb653SDavid Greenman vm_object_t object; 462df8bae1dSRodney W. Grimes 463df8bae1dSRodney W. Grimes if (flags & V_SAVE) { 464bb56ec4aSPoul-Henning Kamp if ((error = VOP_FSYNC(vp, cred, MNT_WAIT, p))) 465df8bae1dSRodney W. Grimes return (error); 466df8bae1dSRodney W. Grimes if (vp->v_dirtyblkhd.lh_first != NULL) 467df8bae1dSRodney W. Grimes panic("vinvalbuf: dirty bufs"); 468df8bae1dSRodney W. Grimes } 469df8bae1dSRodney W. Grimes for (;;) { 4701cdeb653SDavid Greenman if ((blist = vp->v_cleanblkhd.lh_first) && (flags & V_SAVEMETA)) 471df8bae1dSRodney W. Grimes while (blist && blist->b_lblkno < 0) 472df8bae1dSRodney W. Grimes blist = blist->b_vnbufs.le_next; 473df8bae1dSRodney W. Grimes if (!blist && (blist = vp->v_dirtyblkhd.lh_first) && 474df8bae1dSRodney W. Grimes (flags & V_SAVEMETA)) 475df8bae1dSRodney W. Grimes while (blist && blist->b_lblkno < 0) 476df8bae1dSRodney W. Grimes blist = blist->b_vnbufs.le_next; 477df8bae1dSRodney W. Grimes if (!blist) 478df8bae1dSRodney W. Grimes break; 479df8bae1dSRodney W. Grimes 480df8bae1dSRodney W. Grimes for (bp = blist; bp; bp = nbp) { 481df8bae1dSRodney W. Grimes nbp = bp->b_vnbufs.le_next; 4821cdeb653SDavid Greenman if ((flags & V_SAVEMETA) && bp->b_lblkno < 0) 483df8bae1dSRodney W. Grimes continue; 484df8bae1dSRodney W. Grimes s = splbio(); 485df8bae1dSRodney W. Grimes if (bp->b_flags & B_BUSY) { 486df8bae1dSRodney W. Grimes bp->b_flags |= B_WANTED; 487df8bae1dSRodney W. Grimes error = tsleep((caddr_t) bp, 488df8bae1dSRodney W. Grimes slpflag | (PRIBIO + 1), "vinvalbuf", 489df8bae1dSRodney W. Grimes slptimeo); 490df8bae1dSRodney W. Grimes splx(s); 491df8bae1dSRodney W. Grimes if (error) 492df8bae1dSRodney W. Grimes return (error); 493df8bae1dSRodney W. Grimes break; 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes bremfree(bp); 496df8bae1dSRodney W. Grimes bp->b_flags |= B_BUSY; 497df8bae1dSRodney W. Grimes splx(s); 498df8bae1dSRodney W. Grimes /* 4990d94caffSDavid Greenman * XXX Since there are no node locks for NFS, I 5000d94caffSDavid Greenman * believe there is a slight chance that a delayed 5010d94caffSDavid Greenman * write will occur while sleeping just above, so 5020d94caffSDavid Greenman * check for it. 503df8bae1dSRodney W. Grimes */ 504df8bae1dSRodney W. Grimes if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) { 505df8bae1dSRodney W. Grimes (void) VOP_BWRITE(bp); 506df8bae1dSRodney W. Grimes break; 507df8bae1dSRodney W. Grimes } 508213fd1b6SDavid Greenman bp->b_flags |= (B_INVAL|B_NOCACHE|B_RELBUF); 509df8bae1dSRodney W. Grimes brelse(bp); 510df8bae1dSRodney W. Grimes } 511df8bae1dSRodney W. Grimes } 5121cdeb653SDavid Greenman 5130d94caffSDavid Greenman s = splbio(); 5140d94caffSDavid Greenman while (vp->v_numoutput > 0) { 5150d94caffSDavid Greenman vp->v_flag |= VBWAIT; 5160d94caffSDavid Greenman tsleep(&vp->v_numoutput, PVM, "vnvlbv", 0); 5170d94caffSDavid Greenman } 5180d94caffSDavid Greenman splx(s); 5190d94caffSDavid Greenman 520ff769afcSDavid Greenman /* 521ff769afcSDavid Greenman * Destroy the copy in the VM cache, too. 522ff769afcSDavid Greenman */ 523aa2cabb9SDavid Greenman object = vp->v_object; 52462b71ed6SDavid Greenman if (object != NULL) { 525b9461930SDavid Greenman vm_object_page_remove(object, 0, object->size, 526b9461930SDavid Greenman (flags & V_SAVE) ? TRUE : FALSE); 5271cdeb653SDavid Greenman } 528df8bae1dSRodney W. Grimes if (!(flags & V_SAVEMETA) && 529df8bae1dSRodney W. Grimes (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first)) 530df8bae1dSRodney W. Grimes panic("vinvalbuf: flush failed"); 531df8bae1dSRodney W. Grimes return (0); 532df8bae1dSRodney W. Grimes } 533df8bae1dSRodney W. Grimes 534df8bae1dSRodney W. Grimes /* 535df8bae1dSRodney W. Grimes * Associate a buffer with a vnode. 536df8bae1dSRodney W. Grimes */ 53726f9a767SRodney W. Grimes void 538df8bae1dSRodney W. Grimes bgetvp(vp, bp) 539df8bae1dSRodney W. Grimes register struct vnode *vp; 540df8bae1dSRodney W. Grimes register struct buf *bp; 541df8bae1dSRodney W. Grimes { 542602d2b48SDavid Greenman int s; 543df8bae1dSRodney W. Grimes 544df8bae1dSRodney W. Grimes if (bp->b_vp) 545df8bae1dSRodney W. Grimes panic("bgetvp: not free"); 546df8bae1dSRodney W. Grimes VHOLD(vp); 547df8bae1dSRodney W. Grimes bp->b_vp = vp; 548df8bae1dSRodney W. Grimes if (vp->v_type == VBLK || vp->v_type == VCHR) 549df8bae1dSRodney W. Grimes bp->b_dev = vp->v_rdev; 550df8bae1dSRodney W. Grimes else 551df8bae1dSRodney W. Grimes bp->b_dev = NODEV; 552df8bae1dSRodney W. Grimes /* 553df8bae1dSRodney W. Grimes * Insert onto list for new vnode. 554df8bae1dSRodney W. Grimes */ 555602d2b48SDavid Greenman s = splbio(); 556df8bae1dSRodney W. Grimes bufinsvn(bp, &vp->v_cleanblkhd); 557602d2b48SDavid Greenman splx(s); 558df8bae1dSRodney W. Grimes } 559df8bae1dSRodney W. Grimes 560df8bae1dSRodney W. Grimes /* 561df8bae1dSRodney W. Grimes * Disassociate a buffer from a vnode. 562df8bae1dSRodney W. Grimes */ 56326f9a767SRodney W. Grimes void 564df8bae1dSRodney W. Grimes brelvp(bp) 565df8bae1dSRodney W. Grimes register struct buf *bp; 566df8bae1dSRodney W. Grimes { 567df8bae1dSRodney W. Grimes struct vnode *vp; 568602d2b48SDavid Greenman int s; 569df8bae1dSRodney W. Grimes 570df8bae1dSRodney W. Grimes if (bp->b_vp == (struct vnode *) 0) 571df8bae1dSRodney W. Grimes panic("brelvp: NULL"); 572df8bae1dSRodney W. Grimes /* 573df8bae1dSRodney W. Grimes * Delete from old vnode list, if on one. 574df8bae1dSRodney W. Grimes */ 575602d2b48SDavid Greenman s = splbio(); 576df8bae1dSRodney W. Grimes if (bp->b_vnbufs.le_next != NOLIST) 577df8bae1dSRodney W. Grimes bufremvn(bp); 578602d2b48SDavid Greenman splx(s); 579602d2b48SDavid Greenman 580df8bae1dSRodney W. Grimes vp = bp->b_vp; 581df8bae1dSRodney W. Grimes bp->b_vp = (struct vnode *) 0; 582df8bae1dSRodney W. Grimes HOLDRELE(vp); 583df8bae1dSRodney W. Grimes } 584df8bae1dSRodney W. Grimes 585df8bae1dSRodney W. Grimes /* 5860d94caffSDavid Greenman * Associate a p-buffer with a vnode. 5870d94caffSDavid Greenman */ 5880d94caffSDavid Greenman void 5890d94caffSDavid Greenman pbgetvp(vp, bp) 5900d94caffSDavid Greenman register struct vnode *vp; 5910d94caffSDavid Greenman register struct buf *bp; 5920d94caffSDavid Greenman { 5930d94caffSDavid Greenman if (bp->b_vp) 5940d94caffSDavid Greenman panic("pbgetvp: not free"); 5950d94caffSDavid Greenman VHOLD(vp); 5960d94caffSDavid Greenman bp->b_vp = vp; 5970d94caffSDavid Greenman if (vp->v_type == VBLK || vp->v_type == VCHR) 5980d94caffSDavid Greenman bp->b_dev = vp->v_rdev; 5990d94caffSDavid Greenman else 6000d94caffSDavid Greenman bp->b_dev = NODEV; 6010d94caffSDavid Greenman } 6020d94caffSDavid Greenman 6030d94caffSDavid Greenman /* 6040d94caffSDavid Greenman * Disassociate a p-buffer from a vnode. 6050d94caffSDavid Greenman */ 6060d94caffSDavid Greenman void 6070d94caffSDavid Greenman pbrelvp(bp) 6080d94caffSDavid Greenman register struct buf *bp; 6090d94caffSDavid Greenman { 6100d94caffSDavid Greenman struct vnode *vp; 6110d94caffSDavid Greenman 6120d94caffSDavid Greenman if (bp->b_vp == (struct vnode *) 0) 6130d94caffSDavid Greenman panic("brelvp: NULL"); 6140d94caffSDavid Greenman 6150d94caffSDavid Greenman vp = bp->b_vp; 6160d94caffSDavid Greenman bp->b_vp = (struct vnode *) 0; 6170d94caffSDavid Greenman HOLDRELE(vp); 6180d94caffSDavid Greenman } 6190d94caffSDavid Greenman 6200d94caffSDavid Greenman /* 621df8bae1dSRodney W. Grimes * Reassign a buffer from one vnode to another. 622df8bae1dSRodney W. Grimes * Used to assign file specific control information 623df8bae1dSRodney W. Grimes * (indirect blocks) to the vnode to which they belong. 624df8bae1dSRodney W. Grimes */ 62526f9a767SRodney W. Grimes void 626df8bae1dSRodney W. Grimes reassignbuf(bp, newvp) 627df8bae1dSRodney W. Grimes register struct buf *bp; 628df8bae1dSRodney W. Grimes register struct vnode *newvp; 629df8bae1dSRodney W. Grimes { 630df8bae1dSRodney W. Grimes register struct buflists *listheadp; 631df8bae1dSRodney W. Grimes 632df8bae1dSRodney W. Grimes if (newvp == NULL) { 633df8bae1dSRodney W. Grimes printf("reassignbuf: NULL"); 634df8bae1dSRodney W. Grimes return; 635df8bae1dSRodney W. Grimes } 636df8bae1dSRodney W. Grimes /* 637df8bae1dSRodney W. Grimes * Delete from old vnode list, if on one. 638df8bae1dSRodney W. Grimes */ 639df8bae1dSRodney W. Grimes if (bp->b_vnbufs.le_next != NOLIST) 640df8bae1dSRodney W. Grimes bufremvn(bp); 641df8bae1dSRodney W. Grimes /* 6420d94caffSDavid Greenman * If dirty, put on list of dirty buffers; otherwise insert onto list 6430d94caffSDavid Greenman * of clean buffers. 644df8bae1dSRodney W. Grimes */ 6450d94caffSDavid Greenman if (bp->b_flags & B_DELWRI) { 6460d94caffSDavid Greenman struct buf *tbp; 6470d94caffSDavid Greenman 6480d94caffSDavid Greenman tbp = newvp->v_dirtyblkhd.lh_first; 6490d94caffSDavid Greenman if (!tbp || (tbp->b_lblkno > bp->b_lblkno)) { 6500d94caffSDavid Greenman bufinsvn(bp, &newvp->v_dirtyblkhd); 6510d94caffSDavid Greenman } else { 6520d94caffSDavid Greenman while (tbp->b_vnbufs.le_next && (tbp->b_vnbufs.le_next->b_lblkno < bp->b_lblkno)) { 6530d94caffSDavid Greenman tbp = tbp->b_vnbufs.le_next; 6540d94caffSDavid Greenman } 6550d94caffSDavid Greenman LIST_INSERT_AFTER(tbp, bp, b_vnbufs); 6560d94caffSDavid Greenman } 6570d94caffSDavid Greenman } else { 658df8bae1dSRodney W. Grimes listheadp = &newvp->v_cleanblkhd; 659df8bae1dSRodney W. Grimes bufinsvn(bp, listheadp); 660df8bae1dSRodney W. Grimes } 6610d94caffSDavid Greenman } 662df8bae1dSRodney W. Grimes 663df8bae1dSRodney W. Grimes /* 664df8bae1dSRodney W. Grimes * Create a vnode for a block device. 665df8bae1dSRodney W. Grimes * Used for root filesystem, argdev, and swap areas. 666df8bae1dSRodney W. Grimes * Also used for memory file system special devices. 667df8bae1dSRodney W. Grimes */ 66826f9a767SRodney W. Grimes int 669df8bae1dSRodney W. Grimes bdevvp(dev, vpp) 670df8bae1dSRodney W. Grimes dev_t dev; 671df8bae1dSRodney W. Grimes struct vnode **vpp; 672df8bae1dSRodney W. Grimes { 673df8bae1dSRodney W. Grimes register struct vnode *vp; 674df8bae1dSRodney W. Grimes struct vnode *nvp; 675df8bae1dSRodney W. Grimes int error; 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes if (dev == NODEV) 678df8bae1dSRodney W. Grimes return (0); 679df8bae1dSRodney W. Grimes error = getnewvnode(VT_NON, (struct mount *) 0, spec_vnodeop_p, &nvp); 680df8bae1dSRodney W. Grimes if (error) { 681df8bae1dSRodney W. Grimes *vpp = 0; 682df8bae1dSRodney W. Grimes return (error); 683df8bae1dSRodney W. Grimes } 684df8bae1dSRodney W. Grimes vp = nvp; 685df8bae1dSRodney W. Grimes vp->v_type = VBLK; 686bb56ec4aSPoul-Henning Kamp if ((nvp = checkalias(vp, dev, (struct mount *) 0))) { 687df8bae1dSRodney W. Grimes vput(vp); 688df8bae1dSRodney W. Grimes vp = nvp; 689df8bae1dSRodney W. Grimes } 690df8bae1dSRodney W. Grimes *vpp = vp; 691df8bae1dSRodney W. Grimes return (0); 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes 694df8bae1dSRodney W. Grimes /* 695df8bae1dSRodney W. Grimes * Check to see if the new vnode represents a special device 696df8bae1dSRodney W. Grimes * for which we already have a vnode (either because of 697df8bae1dSRodney W. Grimes * bdevvp() or because of a different vnode representing 698df8bae1dSRodney W. Grimes * the same block device). If such an alias exists, deallocate 699df8bae1dSRodney W. Grimes * the existing contents and return the aliased vnode. The 700df8bae1dSRodney W. Grimes * caller is responsible for filling it with its new contents. 701df8bae1dSRodney W. Grimes */ 702df8bae1dSRodney W. Grimes struct vnode * 703df8bae1dSRodney W. Grimes checkalias(nvp, nvp_rdev, mp) 704df8bae1dSRodney W. Grimes register struct vnode *nvp; 705df8bae1dSRodney W. Grimes dev_t nvp_rdev; 706df8bae1dSRodney W. Grimes struct mount *mp; 707df8bae1dSRodney W. Grimes { 708df8bae1dSRodney W. Grimes register struct vnode *vp; 709df8bae1dSRodney W. Grimes struct vnode **vpp; 710df8bae1dSRodney W. Grimes 711df8bae1dSRodney W. Grimes if (nvp->v_type != VBLK && nvp->v_type != VCHR) 712df8bae1dSRodney W. Grimes return (NULLVP); 713df8bae1dSRodney W. Grimes 714df8bae1dSRodney W. Grimes vpp = &speclisth[SPECHASH(nvp_rdev)]; 715df8bae1dSRodney W. Grimes loop: 716df8bae1dSRodney W. Grimes for (vp = *vpp; vp; vp = vp->v_specnext) { 717df8bae1dSRodney W. Grimes if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 718df8bae1dSRodney W. Grimes continue; 719df8bae1dSRodney W. Grimes /* 720df8bae1dSRodney W. Grimes * Alias, but not in use, so flush it out. 721df8bae1dSRodney W. Grimes */ 722df8bae1dSRodney W. Grimes if (vp->v_usecount == 0) { 723df8bae1dSRodney W. Grimes vgone(vp); 724df8bae1dSRodney W. Grimes goto loop; 725df8bae1dSRodney W. Grimes } 726df8bae1dSRodney W. Grimes if (vget(vp, 1)) 727df8bae1dSRodney W. Grimes goto loop; 728df8bae1dSRodney W. Grimes break; 729df8bae1dSRodney W. Grimes } 730df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_tag != VT_NON) { 731df8bae1dSRodney W. Grimes MALLOC(nvp->v_specinfo, struct specinfo *, 732df8bae1dSRodney W. Grimes sizeof(struct specinfo), M_VNODE, M_WAITOK); 733df8bae1dSRodney W. Grimes nvp->v_rdev = nvp_rdev; 734df8bae1dSRodney W. Grimes nvp->v_hashchain = vpp; 735df8bae1dSRodney W. Grimes nvp->v_specnext = *vpp; 736df8bae1dSRodney W. Grimes nvp->v_specflags = 0; 737df8bae1dSRodney W. Grimes *vpp = nvp; 738df8bae1dSRodney W. Grimes if (vp != NULL) { 739df8bae1dSRodney W. Grimes nvp->v_flag |= VALIASED; 740df8bae1dSRodney W. Grimes vp->v_flag |= VALIASED; 741df8bae1dSRodney W. Grimes vput(vp); 742df8bae1dSRodney W. Grimes } 743df8bae1dSRodney W. Grimes return (NULLVP); 744df8bae1dSRodney W. Grimes } 745df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 746df8bae1dSRodney W. Grimes vclean(vp, 0); 747df8bae1dSRodney W. Grimes vp->v_op = nvp->v_op; 748df8bae1dSRodney W. Grimes vp->v_tag = nvp->v_tag; 749df8bae1dSRodney W. Grimes nvp->v_type = VNON; 750df8bae1dSRodney W. Grimes insmntque(vp, mp); 751df8bae1dSRodney W. Grimes return (vp); 752df8bae1dSRodney W. Grimes } 753df8bae1dSRodney W. Grimes 754df8bae1dSRodney W. Grimes /* 755df8bae1dSRodney W. Grimes * Grab a particular vnode from the free list, increment its 756df8bae1dSRodney W. Grimes * reference count and lock it. The vnode lock bit is set the 757df8bae1dSRodney W. Grimes * vnode is being eliminated in vgone. The process is awakened 758df8bae1dSRodney W. Grimes * when the transition is completed, and an error returned to 759df8bae1dSRodney W. Grimes * indicate that the vnode is no longer usable (possibly having 760df8bae1dSRodney W. Grimes * been changed to a new file system type). 761df8bae1dSRodney W. Grimes */ 76226f9a767SRodney W. Grimes int 763df8bae1dSRodney W. Grimes vget(vp, lockflag) 764df8bae1dSRodney W. Grimes register struct vnode *vp; 765df8bae1dSRodney W. Grimes int lockflag; 766df8bae1dSRodney W. Grimes { 767df8bae1dSRodney W. Grimes 768df8bae1dSRodney W. Grimes /* 7690d94caffSDavid Greenman * If the vnode is in the process of being cleaned out for another 7700d94caffSDavid Greenman * use, we wait for the cleaning to finish and then return failure. 7710d94caffSDavid Greenman * Cleaning is determined either by checking that the VXLOCK flag is 7720d94caffSDavid Greenman * set, or that the use count is zero with the back pointer set to 7730d94caffSDavid Greenman * show that it has been removed from the free list by getnewvnode. 7740d94caffSDavid Greenman * The VXLOCK flag may not have been set yet because vclean is blocked 7750d94caffSDavid Greenman * in the VOP_LOCK call waiting for the VOP_INACTIVE to complete. 776df8bae1dSRodney W. Grimes */ 777df8bae1dSRodney W. Grimes if ((vp->v_flag & VXLOCK) || 778df8bae1dSRodney W. Grimes (vp->v_usecount == 0 && 779df8bae1dSRodney W. Grimes vp->v_freelist.tqe_prev == (struct vnode **) 0xdeadb)) { 780df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 78182478919SDavid Greenman (void) tsleep((caddr_t) vp, PINOD, "vget", 0); 782df8bae1dSRodney W. Grimes return (1); 783df8bae1dSRodney W. Grimes } 784fbd6e6c9SPoul-Henning Kamp if (vp->v_usecount == 0) { 785df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 786fbd6e6c9SPoul-Henning Kamp freevnodes--; 787fbd6e6c9SPoul-Henning Kamp } 788df8bae1dSRodney W. Grimes vp->v_usecount++; 789df8bae1dSRodney W. Grimes if (lockflag) 790df8bae1dSRodney W. Grimes VOP_LOCK(vp); 791df8bae1dSRodney W. Grimes return (0); 792df8bae1dSRodney W. Grimes } 793df8bae1dSRodney W. Grimes 794df8bae1dSRodney W. Grimes /* 795df8bae1dSRodney W. Grimes * Vnode reference, just increment the count 796df8bae1dSRodney W. Grimes */ 79726f9a767SRodney W. Grimes void 79826f9a767SRodney W. Grimes vref(vp) 799df8bae1dSRodney W. Grimes struct vnode *vp; 800df8bae1dSRodney W. Grimes { 801df8bae1dSRodney W. Grimes 802df8bae1dSRodney W. Grimes if (vp->v_usecount <= 0) 803df8bae1dSRodney W. Grimes panic("vref used where vget required"); 804df8bae1dSRodney W. Grimes vp->v_usecount++; 805df8bae1dSRodney W. Grimes } 806df8bae1dSRodney W. Grimes 807df8bae1dSRodney W. Grimes /* 808df8bae1dSRodney W. Grimes * vput(), just unlock and vrele() 809df8bae1dSRodney W. Grimes */ 81026f9a767SRodney W. Grimes void 81126f9a767SRodney W. Grimes vput(vp) 812df8bae1dSRodney W. Grimes register struct vnode *vp; 813df8bae1dSRodney W. Grimes { 814df8bae1dSRodney W. Grimes 815df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 816df8bae1dSRodney W. Grimes vrele(vp); 817df8bae1dSRodney W. Grimes } 818df8bae1dSRodney W. Grimes 819df8bae1dSRodney W. Grimes /* 820df8bae1dSRodney W. Grimes * Vnode release. 821df8bae1dSRodney W. Grimes * If count drops to zero, call inactive routine and return to freelist. 822df8bae1dSRodney W. Grimes */ 82326f9a767SRodney W. Grimes void 82426f9a767SRodney W. Grimes vrele(vp) 825df8bae1dSRodney W. Grimes register struct vnode *vp; 826df8bae1dSRodney W. Grimes { 827df8bae1dSRodney W. Grimes 828df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 829df8bae1dSRodney W. Grimes if (vp == NULL) 830df8bae1dSRodney W. Grimes panic("vrele: null vp"); 831df8bae1dSRodney W. Grimes #endif 832df8bae1dSRodney W. Grimes vp->v_usecount--; 833df8bae1dSRodney W. Grimes if (vp->v_usecount > 0) 834df8bae1dSRodney W. Grimes return; 835df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 836e0dca2b9SDavid Greenman if (vp->v_usecount < 0 /* || vp->v_writecount < 0 */ ) { 837e0dca2b9SDavid Greenman vprint("vrele: negative ref count", vp); 838e0dca2b9SDavid Greenman panic("vrele: negative reference cnt"); 839df8bae1dSRodney W. Grimes } 840df8bae1dSRodney W. Grimes #endif 841acc835fdSDavid Greenman if (vp->v_flag & VAGE) { 842acc835fdSDavid Greenman TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 843acc835fdSDavid Greenman vp->v_flag &= ~VAGE; 844acc835fdSDavid Greenman } else { 845df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); 846acc835fdSDavid Greenman } 847fbd6e6c9SPoul-Henning Kamp freevnodes++; 848acc835fdSDavid Greenman 849df8bae1dSRodney W. Grimes VOP_INACTIVE(vp); 850df8bae1dSRodney W. Grimes } 851df8bae1dSRodney W. Grimes 852430179f0SBruce Evans #ifdef DIAGNOSTIC 853df8bae1dSRodney W. Grimes /* 854df8bae1dSRodney W. Grimes * Page or buffer structure gets a reference. 855df8bae1dSRodney W. Grimes */ 85626f9a767SRodney W. Grimes void 85726f9a767SRodney W. Grimes vhold(vp) 858df8bae1dSRodney W. Grimes register struct vnode *vp; 859df8bae1dSRodney W. Grimes { 860df8bae1dSRodney W. Grimes 861df8bae1dSRodney W. Grimes vp->v_holdcnt++; 862df8bae1dSRodney W. Grimes } 863df8bae1dSRodney W. Grimes 864df8bae1dSRodney W. Grimes /* 865df8bae1dSRodney W. Grimes * Page or buffer structure frees a reference. 866df8bae1dSRodney W. Grimes */ 86726f9a767SRodney W. Grimes void 86826f9a767SRodney W. Grimes holdrele(vp) 869df8bae1dSRodney W. Grimes register struct vnode *vp; 870df8bae1dSRodney W. Grimes { 871df8bae1dSRodney W. Grimes 872df8bae1dSRodney W. Grimes if (vp->v_holdcnt <= 0) 873df8bae1dSRodney W. Grimes panic("holdrele: holdcnt"); 874df8bae1dSRodney W. Grimes vp->v_holdcnt--; 875df8bae1dSRodney W. Grimes } 876430179f0SBruce Evans #endif /* DIAGNOSTIC */ 877df8bae1dSRodney W. Grimes 878df8bae1dSRodney W. Grimes /* 879df8bae1dSRodney W. Grimes * Remove any vnodes in the vnode table belonging to mount point mp. 880df8bae1dSRodney W. Grimes * 881df8bae1dSRodney W. Grimes * If MNT_NOFORCE is specified, there should not be any active ones, 882df8bae1dSRodney W. Grimes * return error if any are found (nb: this is a user error, not a 883df8bae1dSRodney W. Grimes * system error). If MNT_FORCE is specified, detach any active vnodes 884df8bae1dSRodney W. Grimes * that are found. 885df8bae1dSRodney W. Grimes */ 886df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 887df8bae1dSRodney W. Grimes int busyprt = 0; /* print out busy vnodes */ 888395e6735SPoul-Henning Kamp SYSCTL_INT(_debug, 1, busyprt, CTLFLAG_RW, &busyprt, 0, ""); 889df8bae1dSRodney W. Grimes #endif 890df8bae1dSRodney W. Grimes 89126f9a767SRodney W. Grimes int 892df8bae1dSRodney W. Grimes vflush(mp, skipvp, flags) 893df8bae1dSRodney W. Grimes struct mount *mp; 894df8bae1dSRodney W. Grimes struct vnode *skipvp; 895df8bae1dSRodney W. Grimes int flags; 896df8bae1dSRodney W. Grimes { 897df8bae1dSRodney W. Grimes register struct vnode *vp, *nvp; 898df8bae1dSRodney W. Grimes int busy = 0; 899df8bae1dSRodney W. Grimes 900df8bae1dSRodney W. Grimes if ((mp->mnt_flag & MNT_MPBUSY) == 0) 901df8bae1dSRodney W. Grimes panic("vflush: not busy"); 902df8bae1dSRodney W. Grimes loop: 903df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 9043d2a8cf3SDavid Greenman /* 9053d2a8cf3SDavid Greenman * Make sure this vnode wasn't reclaimed in getnewvnode(). 9063d2a8cf3SDavid Greenman * Start over if it has (it won't be on the list anymore). 9073d2a8cf3SDavid Greenman */ 908df8bae1dSRodney W. Grimes if (vp->v_mount != mp) 909df8bae1dSRodney W. Grimes goto loop; 910df8bae1dSRodney W. Grimes nvp = vp->v_mntvnodes.le_next; 911df8bae1dSRodney W. Grimes /* 912df8bae1dSRodney W. Grimes * Skip over a selected vnode. 913df8bae1dSRodney W. Grimes */ 914df8bae1dSRodney W. Grimes if (vp == skipvp) 915df8bae1dSRodney W. Grimes continue; 916df8bae1dSRodney W. Grimes /* 917df8bae1dSRodney W. Grimes * Skip over a vnodes marked VSYSTEM. 918df8bae1dSRodney W. Grimes */ 919df8bae1dSRodney W. Grimes if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 920df8bae1dSRodney W. Grimes continue; 921df8bae1dSRodney W. Grimes /* 9220d94caffSDavid Greenman * If WRITECLOSE is set, only flush out regular file vnodes 9230d94caffSDavid Greenman * open for writing. 924df8bae1dSRodney W. Grimes */ 925df8bae1dSRodney W. Grimes if ((flags & WRITECLOSE) && 926df8bae1dSRodney W. Grimes (vp->v_writecount == 0 || vp->v_type != VREG)) 927df8bae1dSRodney W. Grimes continue; 928df8bae1dSRodney W. Grimes /* 9290d94caffSDavid Greenman * With v_usecount == 0, all we need to do is clear out the 9300d94caffSDavid Greenman * vnode data structures and we are done. 931df8bae1dSRodney W. Grimes */ 932df8bae1dSRodney W. Grimes if (vp->v_usecount == 0) { 933df8bae1dSRodney W. Grimes vgone(vp); 934df8bae1dSRodney W. Grimes continue; 935df8bae1dSRodney W. Grimes } 936df8bae1dSRodney W. Grimes /* 9370d94caffSDavid Greenman * If FORCECLOSE is set, forcibly close the vnode. For block 9380d94caffSDavid Greenman * or character devices, revert to an anonymous device. For 9390d94caffSDavid Greenman * all other files, just kill them. 940df8bae1dSRodney W. Grimes */ 941df8bae1dSRodney W. Grimes if (flags & FORCECLOSE) { 942df8bae1dSRodney W. Grimes if (vp->v_type != VBLK && vp->v_type != VCHR) { 943df8bae1dSRodney W. Grimes vgone(vp); 944df8bae1dSRodney W. Grimes } else { 945df8bae1dSRodney W. Grimes vclean(vp, 0); 946df8bae1dSRodney W. Grimes vp->v_op = spec_vnodeop_p; 947df8bae1dSRodney W. Grimes insmntque(vp, (struct mount *) 0); 948df8bae1dSRodney W. Grimes } 949df8bae1dSRodney W. Grimes continue; 950df8bae1dSRodney W. Grimes } 951df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 952df8bae1dSRodney W. Grimes if (busyprt) 953df8bae1dSRodney W. Grimes vprint("vflush: busy vnode", vp); 954df8bae1dSRodney W. Grimes #endif 955df8bae1dSRodney W. Grimes busy++; 956df8bae1dSRodney W. Grimes } 957df8bae1dSRodney W. Grimes if (busy) 958df8bae1dSRodney W. Grimes return (EBUSY); 959df8bae1dSRodney W. Grimes return (0); 960df8bae1dSRodney W. Grimes } 961df8bae1dSRodney W. Grimes 962df8bae1dSRodney W. Grimes /* 963df8bae1dSRodney W. Grimes * Disassociate the underlying file system from a vnode. 964df8bae1dSRodney W. Grimes */ 965df8bae1dSRodney W. Grimes void 9664b2af45fSPoul-Henning Kamp vclean(struct vnode *vp, int flags) 967df8bae1dSRodney W. Grimes { 968df8bae1dSRodney W. Grimes int active; 969df8bae1dSRodney W. Grimes 970df8bae1dSRodney W. Grimes /* 9710d94caffSDavid Greenman * Check to see if the vnode is in use. If so we have to reference it 9720d94caffSDavid Greenman * before we clean it out so that its count cannot fall to zero and 9730d94caffSDavid Greenman * generate a race against ourselves to recycle it. 974df8bae1dSRodney W. Grimes */ 975bb56ec4aSPoul-Henning Kamp if ((active = vp->v_usecount)) 976df8bae1dSRodney W. Grimes VREF(vp); 977df8bae1dSRodney W. Grimes /* 9780d94caffSDavid Greenman * Even if the count is zero, the VOP_INACTIVE routine may still have 9790d94caffSDavid Greenman * the object locked while it cleans it out. The VOP_LOCK ensures that 9800d94caffSDavid Greenman * the VOP_INACTIVE routine is done with its work. For active vnodes, 9810d94caffSDavid Greenman * it ensures that no other activity can occur while the underlying 9820d94caffSDavid Greenman * object is being cleaned out. 983df8bae1dSRodney W. Grimes */ 984df8bae1dSRodney W. Grimes VOP_LOCK(vp); 985df8bae1dSRodney W. Grimes /* 9860d94caffSDavid Greenman * Prevent the vnode from being recycled or brought into use while we 9870d94caffSDavid Greenman * clean it out. 988df8bae1dSRodney W. Grimes */ 989df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) 990df8bae1dSRodney W. Grimes panic("vclean: deadlock"); 991df8bae1dSRodney W. Grimes vp->v_flag |= VXLOCK; 992df8bae1dSRodney W. Grimes /* 993df8bae1dSRodney W. Grimes * Clean out any buffers associated with the vnode. 994df8bae1dSRodney W. Grimes */ 995df8bae1dSRodney W. Grimes if (flags & DOCLOSE) 996df8bae1dSRodney W. Grimes vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0); 997df8bae1dSRodney W. Grimes /* 9980d94caffSDavid Greenman * Any other processes trying to obtain this lock must first wait for 9990d94caffSDavid Greenman * VXLOCK to clear, then call the new lock operation. 1000df8bae1dSRodney W. Grimes */ 1001df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 1002df8bae1dSRodney W. Grimes /* 10030d94caffSDavid Greenman * If purging an active vnode, it must be closed and deactivated 10040d94caffSDavid Greenman * before being reclaimed. 1005df8bae1dSRodney W. Grimes */ 1006df8bae1dSRodney W. Grimes if (active) { 1007df8bae1dSRodney W. Grimes if (flags & DOCLOSE) 10086acceb40SBruce Evans VOP_CLOSE(vp, FNONBLOCK, NOCRED, NULL); 1009df8bae1dSRodney W. Grimes VOP_INACTIVE(vp); 1010df8bae1dSRodney W. Grimes } 1011df8bae1dSRodney W. Grimes /* 1012df8bae1dSRodney W. Grimes * Reclaim the vnode. 1013df8bae1dSRodney W. Grimes */ 1014df8bae1dSRodney W. Grimes if (VOP_RECLAIM(vp)) 1015df8bae1dSRodney W. Grimes panic("vclean: cannot reclaim"); 1016df8bae1dSRodney W. Grimes if (active) 1017df8bae1dSRodney W. Grimes vrele(vp); 1018df8bae1dSRodney W. Grimes 1019df8bae1dSRodney W. Grimes /* 1020df8bae1dSRodney W. Grimes * Done with purge, notify sleepers of the grim news. 1021df8bae1dSRodney W. Grimes */ 1022df8bae1dSRodney W. Grimes vp->v_op = dead_vnodeop_p; 1023df8bae1dSRodney W. Grimes vp->v_tag = VT_NON; 1024df8bae1dSRodney W. Grimes vp->v_flag &= ~VXLOCK; 1025df8bae1dSRodney W. Grimes if (vp->v_flag & VXWANT) { 1026df8bae1dSRodney W. Grimes vp->v_flag &= ~VXWANT; 1027df8bae1dSRodney W. Grimes wakeup((caddr_t) vp); 1028df8bae1dSRodney W. Grimes } 1029df8bae1dSRodney W. Grimes } 1030df8bae1dSRodney W. Grimes 1031df8bae1dSRodney W. Grimes /* 1032df8bae1dSRodney W. Grimes * Eliminate all activity associated with the requested vnode 1033df8bae1dSRodney W. Grimes * and with all vnodes aliased to the requested vnode. 1034df8bae1dSRodney W. Grimes */ 103526f9a767SRodney W. Grimes void 103626f9a767SRodney W. Grimes vgoneall(vp) 1037df8bae1dSRodney W. Grimes register struct vnode *vp; 1038df8bae1dSRodney W. Grimes { 1039df8bae1dSRodney W. Grimes register struct vnode *vq; 1040df8bae1dSRodney W. Grimes 1041df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1042df8bae1dSRodney W. Grimes /* 10430d94caffSDavid Greenman * If a vgone (or vclean) is already in progress, wait until 10440d94caffSDavid Greenman * it is done and return. 1045df8bae1dSRodney W. Grimes */ 1046df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) { 1047df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 104882478919SDavid Greenman (void) tsleep((caddr_t) vp, PINOD, "vgall", 0); 1049df8bae1dSRodney W. Grimes return; 1050df8bae1dSRodney W. Grimes } 1051df8bae1dSRodney W. Grimes /* 10520d94caffSDavid Greenman * Ensure that vp will not be vgone'd while we are eliminating 10530d94caffSDavid Greenman * its aliases. 1054df8bae1dSRodney W. Grimes */ 1055df8bae1dSRodney W. Grimes vp->v_flag |= VXLOCK; 1056df8bae1dSRodney W. Grimes while (vp->v_flag & VALIASED) { 1057df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1058df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1059df8bae1dSRodney W. Grimes vq->v_type != vp->v_type || vp == vq) 1060df8bae1dSRodney W. Grimes continue; 1061df8bae1dSRodney W. Grimes vgone(vq); 1062df8bae1dSRodney W. Grimes break; 1063df8bae1dSRodney W. Grimes } 1064df8bae1dSRodney W. Grimes } 1065df8bae1dSRodney W. Grimes /* 10660d94caffSDavid Greenman * Remove the lock so that vgone below will really eliminate 10670d94caffSDavid Greenman * the vnode after which time vgone will awaken any sleepers. 1068df8bae1dSRodney W. Grimes */ 1069df8bae1dSRodney W. Grimes vp->v_flag &= ~VXLOCK; 1070df8bae1dSRodney W. Grimes } 1071df8bae1dSRodney W. Grimes vgone(vp); 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes 1074df8bae1dSRodney W. Grimes /* 1075df8bae1dSRodney W. Grimes * Eliminate all activity associated with a vnode 1076df8bae1dSRodney W. Grimes * in preparation for reuse. 1077df8bae1dSRodney W. Grimes */ 107826f9a767SRodney W. Grimes void 107926f9a767SRodney W. Grimes vgone(vp) 1080df8bae1dSRodney W. Grimes register struct vnode *vp; 1081df8bae1dSRodney W. Grimes { 1082df8bae1dSRodney W. Grimes register struct vnode *vq; 1083df8bae1dSRodney W. Grimes struct vnode *vx; 1084df8bae1dSRodney W. Grimes 1085df8bae1dSRodney W. Grimes /* 10860d94caffSDavid Greenman * If a vgone (or vclean) is already in progress, wait until it is 10870d94caffSDavid Greenman * done and return. 1088df8bae1dSRodney W. Grimes */ 1089df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) { 1090df8bae1dSRodney W. Grimes vp->v_flag |= VXWANT; 109182478919SDavid Greenman (void) tsleep((caddr_t) vp, PINOD, "vgone", 0); 1092df8bae1dSRodney W. Grimes return; 1093df8bae1dSRodney W. Grimes } 1094df8bae1dSRodney W. Grimes /* 1095df8bae1dSRodney W. Grimes * Clean out the filesystem specific data. 1096df8bae1dSRodney W. Grimes */ 1097df8bae1dSRodney W. Grimes vclean(vp, DOCLOSE); 1098df8bae1dSRodney W. Grimes /* 1099df8bae1dSRodney W. Grimes * Delete from old mount point vnode list, if on one. 1100df8bae1dSRodney W. Grimes */ 1101df8bae1dSRodney W. Grimes if (vp->v_mount != NULL) { 1102df8bae1dSRodney W. Grimes LIST_REMOVE(vp, v_mntvnodes); 1103df8bae1dSRodney W. Grimes vp->v_mount = NULL; 1104df8bae1dSRodney W. Grimes } 1105df8bae1dSRodney W. Grimes /* 1106df8bae1dSRodney W. Grimes * If special device, remove it from special device alias list. 1107df8bae1dSRodney W. Grimes */ 1108df8bae1dSRodney W. Grimes if (vp->v_type == VBLK || vp->v_type == VCHR) { 1109df8bae1dSRodney W. Grimes if (*vp->v_hashchain == vp) { 1110df8bae1dSRodney W. Grimes *vp->v_hashchain = vp->v_specnext; 1111df8bae1dSRodney W. Grimes } else { 1112df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1113df8bae1dSRodney W. Grimes if (vq->v_specnext != vp) 1114df8bae1dSRodney W. Grimes continue; 1115df8bae1dSRodney W. Grimes vq->v_specnext = vp->v_specnext; 1116df8bae1dSRodney W. Grimes break; 1117df8bae1dSRodney W. Grimes } 1118df8bae1dSRodney W. Grimes if (vq == NULL) 1119df8bae1dSRodney W. Grimes panic("missing bdev"); 1120df8bae1dSRodney W. Grimes } 1121df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1122df8bae1dSRodney W. Grimes vx = NULL; 1123df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1124df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1125df8bae1dSRodney W. Grimes vq->v_type != vp->v_type) 1126df8bae1dSRodney W. Grimes continue; 1127df8bae1dSRodney W. Grimes if (vx) 1128df8bae1dSRodney W. Grimes break; 1129df8bae1dSRodney W. Grimes vx = vq; 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes if (vx == NULL) 1132df8bae1dSRodney W. Grimes panic("missing alias"); 1133df8bae1dSRodney W. Grimes if (vq == NULL) 1134df8bae1dSRodney W. Grimes vx->v_flag &= ~VALIASED; 1135df8bae1dSRodney W. Grimes vp->v_flag &= ~VALIASED; 1136df8bae1dSRodney W. Grimes } 1137df8bae1dSRodney W. Grimes FREE(vp->v_specinfo, M_VNODE); 1138df8bae1dSRodney W. Grimes vp->v_specinfo = NULL; 1139df8bae1dSRodney W. Grimes } 1140df8bae1dSRodney W. Grimes /* 11410d94caffSDavid Greenman * If it is on the freelist and not already at the head, move it to 11420d94caffSDavid Greenman * the head of the list. The test of the back pointer and the 11430d94caffSDavid Greenman * reference count of zero is because it will be removed from the free 11440d94caffSDavid Greenman * list by getnewvnode, but will not have its reference count 11450d94caffSDavid Greenman * incremented until after calling vgone. If the reference count were 11460d94caffSDavid Greenman * incremented first, vgone would (incorrectly) try to close the 11470d94caffSDavid Greenman * previous instance of the underlying object. So, the back pointer is 11480d94caffSDavid Greenman * explicitly set to `0xdeadb' in getnewvnode after removing it from 11490d94caffSDavid Greenman * the freelist to ensure that we do not try to move it here. 1150df8bae1dSRodney W. Grimes */ 1151df8bae1dSRodney W. Grimes if (vp->v_usecount == 0 && 1152df8bae1dSRodney W. Grimes vp->v_freelist.tqe_prev != (struct vnode **) 0xdeadb && 1153df8bae1dSRodney W. Grimes vnode_free_list.tqh_first != vp) { 1154df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); 1155df8bae1dSRodney W. Grimes TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); 1156df8bae1dSRodney W. Grimes } 1157df8bae1dSRodney W. Grimes vp->v_type = VBAD; 1158df8bae1dSRodney W. Grimes } 1159df8bae1dSRodney W. Grimes 1160df8bae1dSRodney W. Grimes /* 1161df8bae1dSRodney W. Grimes * Lookup a vnode by device number. 1162df8bae1dSRodney W. Grimes */ 116326f9a767SRodney W. Grimes int 1164df8bae1dSRodney W. Grimes vfinddev(dev, type, vpp) 1165df8bae1dSRodney W. Grimes dev_t dev; 1166df8bae1dSRodney W. Grimes enum vtype type; 1167df8bae1dSRodney W. Grimes struct vnode **vpp; 1168df8bae1dSRodney W. Grimes { 1169df8bae1dSRodney W. Grimes register struct vnode *vp; 1170df8bae1dSRodney W. Grimes 1171df8bae1dSRodney W. Grimes for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 1172df8bae1dSRodney W. Grimes if (dev != vp->v_rdev || type != vp->v_type) 1173df8bae1dSRodney W. Grimes continue; 1174df8bae1dSRodney W. Grimes *vpp = vp; 1175df8bae1dSRodney W. Grimes return (1); 1176df8bae1dSRodney W. Grimes } 1177df8bae1dSRodney W. Grimes return (0); 1178df8bae1dSRodney W. Grimes } 1179df8bae1dSRodney W. Grimes 1180df8bae1dSRodney W. Grimes /* 1181df8bae1dSRodney W. Grimes * Calculate the total number of references to a special device. 1182df8bae1dSRodney W. Grimes */ 118326f9a767SRodney W. Grimes int 1184df8bae1dSRodney W. Grimes vcount(vp) 1185df8bae1dSRodney W. Grimes register struct vnode *vp; 1186df8bae1dSRodney W. Grimes { 1187df8bae1dSRodney W. Grimes register struct vnode *vq, *vnext; 1188df8bae1dSRodney W. Grimes int count; 1189df8bae1dSRodney W. Grimes 1190df8bae1dSRodney W. Grimes loop: 1191df8bae1dSRodney W. Grimes if ((vp->v_flag & VALIASED) == 0) 1192df8bae1dSRodney W. Grimes return (vp->v_usecount); 1193df8bae1dSRodney W. Grimes for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) { 1194df8bae1dSRodney W. Grimes vnext = vq->v_specnext; 1195df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 1196df8bae1dSRodney W. Grimes continue; 1197df8bae1dSRodney W. Grimes /* 1198df8bae1dSRodney W. Grimes * Alias, but not in use, so flush it out. 1199df8bae1dSRodney W. Grimes */ 1200df8bae1dSRodney W. Grimes if (vq->v_usecount == 0 && vq != vp) { 1201df8bae1dSRodney W. Grimes vgone(vq); 1202df8bae1dSRodney W. Grimes goto loop; 1203df8bae1dSRodney W. Grimes } 1204df8bae1dSRodney W. Grimes count += vq->v_usecount; 1205df8bae1dSRodney W. Grimes } 1206df8bae1dSRodney W. Grimes return (count); 1207df8bae1dSRodney W. Grimes } 1208df8bae1dSRodney W. Grimes 1209df8bae1dSRodney W. Grimes /* 1210df8bae1dSRodney W. Grimes * Print out a description of a vnode. 1211df8bae1dSRodney W. Grimes */ 1212df8bae1dSRodney W. Grimes static char *typename[] = 1213df8bae1dSRodney W. Grimes {"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD"}; 1214df8bae1dSRodney W. Grimes 121526f9a767SRodney W. Grimes void 1216df8bae1dSRodney W. Grimes vprint(label, vp) 1217df8bae1dSRodney W. Grimes char *label; 1218df8bae1dSRodney W. Grimes register struct vnode *vp; 1219df8bae1dSRodney W. Grimes { 1220df8bae1dSRodney W. Grimes char buf[64]; 1221df8bae1dSRodney W. Grimes 1222df8bae1dSRodney W. Grimes if (label != NULL) 1223df8bae1dSRodney W. Grimes printf("%s: ", label); 1224bb56ec4aSPoul-Henning Kamp printf("type %s, usecount %d, writecount %d, refcount %ld,", 1225df8bae1dSRodney W. Grimes typename[vp->v_type], vp->v_usecount, vp->v_writecount, 1226df8bae1dSRodney W. Grimes vp->v_holdcnt); 1227df8bae1dSRodney W. Grimes buf[0] = '\0'; 1228df8bae1dSRodney W. Grimes if (vp->v_flag & VROOT) 1229df8bae1dSRodney W. Grimes strcat(buf, "|VROOT"); 1230df8bae1dSRodney W. Grimes if (vp->v_flag & VTEXT) 1231df8bae1dSRodney W. Grimes strcat(buf, "|VTEXT"); 1232df8bae1dSRodney W. Grimes if (vp->v_flag & VSYSTEM) 1233df8bae1dSRodney W. Grimes strcat(buf, "|VSYSTEM"); 1234df8bae1dSRodney W. Grimes if (vp->v_flag & VXLOCK) 1235df8bae1dSRodney W. Grimes strcat(buf, "|VXLOCK"); 1236df8bae1dSRodney W. Grimes if (vp->v_flag & VXWANT) 1237df8bae1dSRodney W. Grimes strcat(buf, "|VXWANT"); 1238df8bae1dSRodney W. Grimes if (vp->v_flag & VBWAIT) 1239df8bae1dSRodney W. Grimes strcat(buf, "|VBWAIT"); 1240df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) 1241df8bae1dSRodney W. Grimes strcat(buf, "|VALIASED"); 1242df8bae1dSRodney W. Grimes if (buf[0] != '\0') 1243df8bae1dSRodney W. Grimes printf(" flags (%s)", &buf[1]); 1244df8bae1dSRodney W. Grimes if (vp->v_data == NULL) { 1245df8bae1dSRodney W. Grimes printf("\n"); 1246df8bae1dSRodney W. Grimes } else { 1247df8bae1dSRodney W. Grimes printf("\n\t"); 1248df8bae1dSRodney W. Grimes VOP_PRINT(vp); 1249df8bae1dSRodney W. Grimes } 1250df8bae1dSRodney W. Grimes } 1251df8bae1dSRodney W. Grimes 12521a477b0cSDavid Greenman #ifdef DDB 1253df8bae1dSRodney W. Grimes /* 1254df8bae1dSRodney W. Grimes * List all of the locked vnodes in the system. 1255df8bae1dSRodney W. Grimes * Called when debugging the kernel. 1256df8bae1dSRodney W. Grimes */ 125726f9a767SRodney W. Grimes void 12584b2af45fSPoul-Henning Kamp printlockedvnodes(void) 1259df8bae1dSRodney W. Grimes { 1260df8bae1dSRodney W. Grimes register struct mount *mp; 1261df8bae1dSRodney W. Grimes register struct vnode *vp; 1262df8bae1dSRodney W. Grimes 1263df8bae1dSRodney W. Grimes printf("Locked vnodes\n"); 1264628641f8SDavid Greenman for (mp = mountlist.cqh_first; mp != (void *)&mountlist; 1265628641f8SDavid Greenman mp = mp->mnt_list.cqe_next) { 1266df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; 1267df8bae1dSRodney W. Grimes vp != NULL; 1268df8bae1dSRodney W. Grimes vp = vp->v_mntvnodes.le_next) 1269df8bae1dSRodney W. Grimes if (VOP_ISLOCKED(vp)) 1270df8bae1dSRodney W. Grimes vprint((char *) 0, vp); 1271df8bae1dSRodney W. Grimes } 1272df8bae1dSRodney W. Grimes } 1273df8bae1dSRodney W. Grimes #endif 1274df8bae1dSRodney W. Grimes 1275df8bae1dSRodney W. Grimes int kinfo_vdebug = 1; 1276df8bae1dSRodney W. Grimes int kinfo_vgetfailed; 12770d94caffSDavid Greenman 1278df8bae1dSRodney W. Grimes #define KINFO_VNODESLOP 10 1279df8bae1dSRodney W. Grimes /* 1280df8bae1dSRodney W. Grimes * Dump vnode list (via sysctl). 1281df8bae1dSRodney W. Grimes * Copyout address of vnode followed by vnode. 1282df8bae1dSRodney W. Grimes */ 1283df8bae1dSRodney W. Grimes /* ARGSUSED */ 12844b2af45fSPoul-Henning Kamp static int 12854b2af45fSPoul-Henning Kamp sysctl_vnode SYSCTL_HANDLER_ARGS 1286df8bae1dSRodney W. Grimes { 1287df8bae1dSRodney W. Grimes register struct mount *mp, *nmp; 1288df8bae1dSRodney W. Grimes struct vnode *vp; 1289df8bae1dSRodney W. Grimes int error; 1290df8bae1dSRodney W. Grimes 1291df8bae1dSRodney W. Grimes #define VPTRSZ sizeof (struct vnode *) 1292df8bae1dSRodney W. Grimes #define VNODESZ sizeof (struct vnode) 12934b2af45fSPoul-Henning Kamp 12944b2af45fSPoul-Henning Kamp req->lock = 0; 12952d0b1d70SPoul-Henning Kamp if (!req->oldptr) /* Make an estimate */ 12964b2af45fSPoul-Henning Kamp return (SYSCTL_OUT(req, 0, 12974b2af45fSPoul-Henning Kamp (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ))); 1298df8bae1dSRodney W. Grimes 1299628641f8SDavid Greenman for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 1300628641f8SDavid Greenman nmp = mp->mnt_list.cqe_next; 1301df8bae1dSRodney W. Grimes if (vfs_busy(mp)) 1302df8bae1dSRodney W. Grimes continue; 1303df8bae1dSRodney W. Grimes again: 1304df8bae1dSRodney W. Grimes for (vp = mp->mnt_vnodelist.lh_first; 1305df8bae1dSRodney W. Grimes vp != NULL; 1306df8bae1dSRodney W. Grimes vp = vp->v_mntvnodes.le_next) { 1307df8bae1dSRodney W. Grimes /* 13080d94caffSDavid Greenman * Check that the vp is still associated with this 13090d94caffSDavid Greenman * filesystem. RACE: could have been recycled onto 13100d94caffSDavid Greenman * the same filesystem. 1311df8bae1dSRodney W. Grimes */ 1312df8bae1dSRodney W. Grimes if (vp->v_mount != mp) { 1313df8bae1dSRodney W. Grimes if (kinfo_vdebug) 1314df8bae1dSRodney W. Grimes printf("kinfo: vp changed\n"); 1315df8bae1dSRodney W. Grimes goto again; 1316df8bae1dSRodney W. Grimes } 13174b2af45fSPoul-Henning Kamp if ((error = SYSCTL_OUT(req, &vp, VPTRSZ)) || 13184b2af45fSPoul-Henning Kamp (error = SYSCTL_OUT(req, vp, VNODESZ))) { 1319e887950aSBruce Evans vfs_unbusy(mp); 1320df8bae1dSRodney W. Grimes return (error); 1321e887950aSBruce Evans } 1322df8bae1dSRodney W. Grimes } 1323df8bae1dSRodney W. Grimes vfs_unbusy(mp); 1324df8bae1dSRodney W. Grimes } 1325df8bae1dSRodney W. Grimes 1326df8bae1dSRodney W. Grimes return (0); 1327df8bae1dSRodney W. Grimes } 1328df8bae1dSRodney W. Grimes 13294b2af45fSPoul-Henning Kamp SYSCTL_NODE(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD, 13304b2af45fSPoul-Henning Kamp sysctl_vnode, ""); 13314b2af45fSPoul-Henning Kamp 13324b2af45fSPoul-Henning Kamp 1333df8bae1dSRodney W. Grimes /* 1334df8bae1dSRodney W. Grimes * Check to see if a filesystem is mounted on a block device. 1335df8bae1dSRodney W. Grimes */ 1336df8bae1dSRodney W. Grimes int 1337df8bae1dSRodney W. Grimes vfs_mountedon(vp) 1338df8bae1dSRodney W. Grimes register struct vnode *vp; 1339df8bae1dSRodney W. Grimes { 1340df8bae1dSRodney W. Grimes register struct vnode *vq; 1341df8bae1dSRodney W. Grimes 1342df8bae1dSRodney W. Grimes if (vp->v_specflags & SI_MOUNTEDON) 1343df8bae1dSRodney W. Grimes return (EBUSY); 1344df8bae1dSRodney W. Grimes if (vp->v_flag & VALIASED) { 1345df8bae1dSRodney W. Grimes for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 1346df8bae1dSRodney W. Grimes if (vq->v_rdev != vp->v_rdev || 1347df8bae1dSRodney W. Grimes vq->v_type != vp->v_type) 1348df8bae1dSRodney W. Grimes continue; 1349df8bae1dSRodney W. Grimes if (vq->v_specflags & SI_MOUNTEDON) 1350df8bae1dSRodney W. Grimes return (EBUSY); 1351df8bae1dSRodney W. Grimes } 1352df8bae1dSRodney W. Grimes } 1353df8bae1dSRodney W. Grimes return (0); 1354df8bae1dSRodney W. Grimes } 1355df8bae1dSRodney W. Grimes 1356df8bae1dSRodney W. Grimes /* 1357df8bae1dSRodney W. Grimes * Build hash lists of net addresses and hang them off the mount point. 1358df8bae1dSRodney W. Grimes * Called by ufs_mount() to set up the lists of export addresses. 1359df8bae1dSRodney W. Grimes */ 1360df8bae1dSRodney W. Grimes static int 13614b2af45fSPoul-Henning Kamp vfs_hang_addrlist(struct mount *mp, struct netexport *nep, 13624b2af45fSPoul-Henning Kamp struct export_args *argp) 1363df8bae1dSRodney W. Grimes { 1364df8bae1dSRodney W. Grimes register struct netcred *np; 1365df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1366df8bae1dSRodney W. Grimes register int i; 1367df8bae1dSRodney W. Grimes struct radix_node *rn; 1368df8bae1dSRodney W. Grimes struct sockaddr *saddr, *smask = 0; 1369df8bae1dSRodney W. Grimes struct domain *dom; 1370df8bae1dSRodney W. Grimes int error; 1371df8bae1dSRodney W. Grimes 1372df8bae1dSRodney W. Grimes if (argp->ex_addrlen == 0) { 1373df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_DEFEXPORTED) 1374df8bae1dSRodney W. Grimes return (EPERM); 1375df8bae1dSRodney W. Grimes np = &nep->ne_defexported; 1376df8bae1dSRodney W. Grimes np->netc_exflags = argp->ex_flags; 1377df8bae1dSRodney W. Grimes np->netc_anon = argp->ex_anon; 1378df8bae1dSRodney W. Grimes np->netc_anon.cr_ref = 1; 1379df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_DEFEXPORTED; 1380df8bae1dSRodney W. Grimes return (0); 1381df8bae1dSRodney W. Grimes } 1382df8bae1dSRodney W. Grimes i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 1383df8bae1dSRodney W. Grimes np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK); 1384df8bae1dSRodney W. Grimes bzero((caddr_t) np, i); 1385df8bae1dSRodney W. Grimes saddr = (struct sockaddr *) (np + 1); 1386bb56ec4aSPoul-Henning Kamp if ((error = copyin(argp->ex_addr, (caddr_t) saddr, argp->ex_addrlen))) 1387df8bae1dSRodney W. Grimes goto out; 1388df8bae1dSRodney W. Grimes if (saddr->sa_len > argp->ex_addrlen) 1389df8bae1dSRodney W. Grimes saddr->sa_len = argp->ex_addrlen; 1390df8bae1dSRodney W. Grimes if (argp->ex_masklen) { 1391df8bae1dSRodney W. Grimes smask = (struct sockaddr *) ((caddr_t) saddr + argp->ex_addrlen); 1392df8bae1dSRodney W. Grimes error = copyin(argp->ex_addr, (caddr_t) smask, argp->ex_masklen); 1393df8bae1dSRodney W. Grimes if (error) 1394df8bae1dSRodney W. Grimes goto out; 1395df8bae1dSRodney W. Grimes if (smask->sa_len > argp->ex_masklen) 1396df8bae1dSRodney W. Grimes smask->sa_len = argp->ex_masklen; 1397df8bae1dSRodney W. Grimes } 1398df8bae1dSRodney W. Grimes i = saddr->sa_family; 1399df8bae1dSRodney W. Grimes if ((rnh = nep->ne_rtable[i]) == 0) { 1400df8bae1dSRodney W. Grimes /* 14010d94caffSDavid Greenman * Seems silly to initialize every AF when most are not used, 14020d94caffSDavid Greenman * do so on demand here 1403df8bae1dSRodney W. Grimes */ 1404df8bae1dSRodney W. Grimes for (dom = domains; dom; dom = dom->dom_next) 1405df8bae1dSRodney W. Grimes if (dom->dom_family == i && dom->dom_rtattach) { 1406df8bae1dSRodney W. Grimes dom->dom_rtattach((void **) &nep->ne_rtable[i], 1407df8bae1dSRodney W. Grimes dom->dom_rtoffset); 1408df8bae1dSRodney W. Grimes break; 1409df8bae1dSRodney W. Grimes } 1410df8bae1dSRodney W. Grimes if ((rnh = nep->ne_rtable[i]) == 0) { 1411df8bae1dSRodney W. Grimes error = ENOBUFS; 1412df8bae1dSRodney W. Grimes goto out; 1413df8bae1dSRodney W. Grimes } 1414df8bae1dSRodney W. Grimes } 1415df8bae1dSRodney W. Grimes rn = (*rnh->rnh_addaddr) ((caddr_t) saddr, (caddr_t) smask, rnh, 1416df8bae1dSRodney W. Grimes np->netc_rnodes); 1417df8bae1dSRodney W. Grimes if (rn == 0 || np != (struct netcred *) rn) { /* already exists */ 1418df8bae1dSRodney W. Grimes error = EPERM; 1419df8bae1dSRodney W. Grimes goto out; 1420df8bae1dSRodney W. Grimes } 1421df8bae1dSRodney W. Grimes np->netc_exflags = argp->ex_flags; 1422df8bae1dSRodney W. Grimes np->netc_anon = argp->ex_anon; 1423df8bae1dSRodney W. Grimes np->netc_anon.cr_ref = 1; 1424df8bae1dSRodney W. Grimes return (0); 1425df8bae1dSRodney W. Grimes out: 1426df8bae1dSRodney W. Grimes free(np, M_NETADDR); 1427df8bae1dSRodney W. Grimes return (error); 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes 1430df8bae1dSRodney W. Grimes /* ARGSUSED */ 1431df8bae1dSRodney W. Grimes static int 14324b2af45fSPoul-Henning Kamp vfs_free_netcred(struct radix_node *rn, void *w) 1433df8bae1dSRodney W. Grimes { 1434df8bae1dSRodney W. Grimes register struct radix_node_head *rnh = (struct radix_node_head *) w; 1435df8bae1dSRodney W. Grimes 1436df8bae1dSRodney W. Grimes (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh); 1437df8bae1dSRodney W. Grimes free((caddr_t) rn, M_NETADDR); 1438df8bae1dSRodney W. Grimes return (0); 1439df8bae1dSRodney W. Grimes } 1440df8bae1dSRodney W. Grimes 1441df8bae1dSRodney W. Grimes /* 1442df8bae1dSRodney W. Grimes * Free the net address hash lists that are hanging off the mount points. 1443df8bae1dSRodney W. Grimes */ 1444df8bae1dSRodney W. Grimes static void 14454b2af45fSPoul-Henning Kamp vfs_free_addrlist(struct netexport *nep) 1446df8bae1dSRodney W. Grimes { 1447df8bae1dSRodney W. Grimes register int i; 1448df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1449df8bae1dSRodney W. Grimes 1450df8bae1dSRodney W. Grimes for (i = 0; i <= AF_MAX; i++) 1451bb56ec4aSPoul-Henning Kamp if ((rnh = nep->ne_rtable[i])) { 1452df8bae1dSRodney W. Grimes (*rnh->rnh_walktree) (rnh, vfs_free_netcred, 1453df8bae1dSRodney W. Grimes (caddr_t) rnh); 1454df8bae1dSRodney W. Grimes free((caddr_t) rnh, M_RTABLE); 1455df8bae1dSRodney W. Grimes nep->ne_rtable[i] = 0; 1456df8bae1dSRodney W. Grimes } 1457df8bae1dSRodney W. Grimes } 1458df8bae1dSRodney W. Grimes 1459df8bae1dSRodney W. Grimes int 1460df8bae1dSRodney W. Grimes vfs_export(mp, nep, argp) 1461df8bae1dSRodney W. Grimes struct mount *mp; 1462df8bae1dSRodney W. Grimes struct netexport *nep; 1463df8bae1dSRodney W. Grimes struct export_args *argp; 1464df8bae1dSRodney W. Grimes { 1465df8bae1dSRodney W. Grimes int error; 1466df8bae1dSRodney W. Grimes 1467df8bae1dSRodney W. Grimes if (argp->ex_flags & MNT_DELEXPORT) { 1468df8bae1dSRodney W. Grimes vfs_free_addrlist(nep); 1469df8bae1dSRodney W. Grimes mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 1470df8bae1dSRodney W. Grimes } 1471df8bae1dSRodney W. Grimes if (argp->ex_flags & MNT_EXPORTED) { 1472bb56ec4aSPoul-Henning Kamp if ((error = vfs_hang_addrlist(mp, nep, argp))) 1473df8bae1dSRodney W. Grimes return (error); 1474df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_EXPORTED; 1475df8bae1dSRodney W. Grimes } 1476df8bae1dSRodney W. Grimes return (0); 1477df8bae1dSRodney W. Grimes } 1478df8bae1dSRodney W. Grimes 1479df8bae1dSRodney W. Grimes struct netcred * 1480df8bae1dSRodney W. Grimes vfs_export_lookup(mp, nep, nam) 1481df8bae1dSRodney W. Grimes register struct mount *mp; 1482df8bae1dSRodney W. Grimes struct netexport *nep; 1483df8bae1dSRodney W. Grimes struct mbuf *nam; 1484df8bae1dSRodney W. Grimes { 1485df8bae1dSRodney W. Grimes register struct netcred *np; 1486df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1487df8bae1dSRodney W. Grimes struct sockaddr *saddr; 1488df8bae1dSRodney W. Grimes 1489df8bae1dSRodney W. Grimes np = NULL; 1490df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_EXPORTED) { 1491df8bae1dSRodney W. Grimes /* 1492df8bae1dSRodney W. Grimes * Lookup in the export list first. 1493df8bae1dSRodney W. Grimes */ 1494df8bae1dSRodney W. Grimes if (nam != NULL) { 1495df8bae1dSRodney W. Grimes saddr = mtod(nam, struct sockaddr *); 1496df8bae1dSRodney W. Grimes rnh = nep->ne_rtable[saddr->sa_family]; 1497df8bae1dSRodney W. Grimes if (rnh != NULL) { 1498df8bae1dSRodney W. Grimes np = (struct netcred *) 1499df8bae1dSRodney W. Grimes (*rnh->rnh_matchaddr) ((caddr_t) saddr, 1500df8bae1dSRodney W. Grimes rnh); 1501df8bae1dSRodney W. Grimes if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 1502df8bae1dSRodney W. Grimes np = NULL; 1503df8bae1dSRodney W. Grimes } 1504df8bae1dSRodney W. Grimes } 1505df8bae1dSRodney W. Grimes /* 1506df8bae1dSRodney W. Grimes * If no address match, use the default if it exists. 1507df8bae1dSRodney W. Grimes */ 1508df8bae1dSRodney W. Grimes if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 1509df8bae1dSRodney W. Grimes np = &nep->ne_defexported; 1510df8bae1dSRodney W. Grimes } 1511df8bae1dSRodney W. Grimes return (np); 1512df8bae1dSRodney W. Grimes } 151361f5d510SDavid Greenman 151461f5d510SDavid Greenman 151561f5d510SDavid Greenman /* 151661f5d510SDavid Greenman * perform msync on all vnodes under a mount point 151761f5d510SDavid Greenman * the mount point must be locked. 151861f5d510SDavid Greenman */ 151961f5d510SDavid Greenman void 152061f5d510SDavid Greenman vfs_msync(struct mount *mp, int flags) { 152161f5d510SDavid Greenman struct vnode *vp; 152261f5d510SDavid Greenman loop: 152361f5d510SDavid Greenman for (vp = mp->mnt_vnodelist.lh_first; 152461f5d510SDavid Greenman vp != NULL; 152561f5d510SDavid Greenman vp = vp->v_mntvnodes.le_next) { 152661f5d510SDavid Greenman 152761f5d510SDavid Greenman if (vp->v_mount != mp) 152861f5d510SDavid Greenman goto loop; 152961f5d510SDavid Greenman if (VOP_ISLOCKED(vp) && (flags != MNT_WAIT)) 153061f5d510SDavid Greenman continue; 1531aa2cabb9SDavid Greenman if (vp->v_object && 15325e527f65SJohn Dyson (((vm_object_t) vp->v_object)->flags & OBJ_MIGHTBEDIRTY)) { 153324a1cce3SDavid Greenman vm_object_page_clean(vp->v_object, 0, 0, TRUE, TRUE); 153461f5d510SDavid Greenman } 153561f5d510SDavid Greenman } 153661f5d510SDavid Greenman } 1537