xref: /freebsd/sys/kern/vfs_export.c (revision f6b4c2855516a0b37302035aaf5815c94003d83e)
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