xref: /freebsd/sys/fs/pseudofs/pseudofs.c (revision 388596dffca78599f7cb7da894f4c6766ddcd3db)
19733a808SDag-Erling Smørgrav /*-
29733a808SDag-Erling Smørgrav  * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
39733a808SDag-Erling Smørgrav  * All rights reserved.
49733a808SDag-Erling Smørgrav  *
59733a808SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
69733a808SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
79733a808SDag-Erling Smørgrav  * are met:
89733a808SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
99733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
109733a808SDag-Erling Smørgrav  *    in this position and unchanged.
119733a808SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
129733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
139733a808SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
149733a808SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
159733a808SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
169733a808SDag-Erling Smørgrav  *
179733a808SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189733a808SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199733a808SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209733a808SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219733a808SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229733a808SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239733a808SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249733a808SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259733a808SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269733a808SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279733a808SDag-Erling Smørgrav  */
289733a808SDag-Erling Smørgrav 
29de52d21aSDag-Erling Smørgrav #include <sys/cdefs.h>
30de52d21aSDag-Erling Smørgrav __FBSDID("$FreeBSD$");
31de52d21aSDag-Erling Smørgrav 
32de52d21aSDag-Erling Smørgrav #include "opt_pseudofs.h"
33de52d21aSDag-Erling Smørgrav 
349733a808SDag-Erling Smørgrav #include <sys/param.h>
359733a808SDag-Erling Smørgrav #include <sys/kernel.h>
369733a808SDag-Erling Smørgrav #include <sys/systm.h>
377106ca0dSJohn Baldwin #include <sys/lock.h>
389733a808SDag-Erling Smørgrav #include <sys/malloc.h>
399733a808SDag-Erling Smørgrav #include <sys/module.h>
409733a808SDag-Erling Smørgrav #include <sys/mount.h>
4149fa664fSDag-Erling Smørgrav #include <sys/mutex.h>
429733a808SDag-Erling Smørgrav #include <sys/proc.h>
439733a808SDag-Erling Smørgrav #include <sys/sbuf.h>
449733a808SDag-Erling Smørgrav #include <sys/sysctl.h>
459733a808SDag-Erling Smørgrav #include <sys/vnode.h>
469733a808SDag-Erling Smørgrav 
479733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs.h>
489733a808SDag-Erling Smørgrav #include <fs/pseudofs/pseudofs_internal.h>
499733a808SDag-Erling Smørgrav 
5033802b9eSDag-Erling Smørgrav static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
5133802b9eSDag-Erling Smørgrav 
529733a808SDag-Erling Smørgrav SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW, 0,
539733a808SDag-Erling Smørgrav     "pseudofs");
549733a808SDag-Erling Smørgrav 
55388596dfSDag-Erling Smørgrav int pfs_trace;
56388596dfSDag-Erling Smørgrav SYSCTL_INT(_vfs_pfs, OID_AUTO, trace, CTLFLAG_RW, &pfs_trace, 0,
57388596dfSDag-Erling Smørgrav     "enable tracing of pseudofs vnode operations");
58388596dfSDag-Erling Smørgrav 
5941aa8697SDag-Erling Smørgrav #if PFS_FSNAMELEN != MFSNAMELEN
6041aa8697SDag-Erling Smørgrav #error "PFS_FSNAMELEN is not equal to MFSNAMELEN"
6141aa8697SDag-Erling Smørgrav #endif
6241aa8697SDag-Erling Smørgrav 
639733a808SDag-Erling Smørgrav /*
64388596dfSDag-Erling Smørgrav  * Allocate and initialize a node
65388596dfSDag-Erling Smørgrav  */
66388596dfSDag-Erling Smørgrav static struct pfs_node *
67388596dfSDag-Erling Smørgrav pfs_alloc_node(struct pfs_info *pi, const char *name, pfs_type_t type)
68388596dfSDag-Erling Smørgrav {
69388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
70388596dfSDag-Erling Smørgrav 
71388596dfSDag-Erling Smørgrav 	KASSERT(strlen(name) < PFS_NAMELEN,
72388596dfSDag-Erling Smørgrav 	    ("%s(): node name is too long", __func__));
73388596dfSDag-Erling Smørgrav 
74388596dfSDag-Erling Smørgrav 	MALLOC(pn, struct pfs_node *, sizeof *pn,
75388596dfSDag-Erling Smørgrav 	    M_PFSNODES, M_WAITOK|M_ZERO);
76388596dfSDag-Erling Smørgrav 	mtx_init(&pn->pn_mutex, "pfs_node", NULL, MTX_DEF | MTX_DUPOK);
77388596dfSDag-Erling Smørgrav 	strlcpy(pn->pn_name, name, sizeof pn->pn_name);
78388596dfSDag-Erling Smørgrav 	pn->pn_type = type;
79388596dfSDag-Erling Smørgrav 	pn->pn_info = pi;
80388596dfSDag-Erling Smørgrav 	return (pn);
81388596dfSDag-Erling Smørgrav }
82388596dfSDag-Erling Smørgrav 
83388596dfSDag-Erling Smørgrav /*
8433802b9eSDag-Erling Smørgrav  * Add a node to a directory
8533802b9eSDag-Erling Smørgrav  */
86388596dfSDag-Erling Smørgrav static void
87388596dfSDag-Erling Smørgrav pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
8833802b9eSDag-Erling Smørgrav {
89388596dfSDag-Erling Smørgrav #ifdef INVARIANTS
90388596dfSDag-Erling Smørgrav 	struct pfs_node *iter;
91388596dfSDag-Erling Smørgrav #endif
92388596dfSDag-Erling Smørgrav 
9333802b9eSDag-Erling Smørgrav 	KASSERT(parent != NULL,
946e551fb6SDavid E. O'Brien 	    ("%s(): parent is NULL", __func__));
95388596dfSDag-Erling Smørgrav 	KASSERT(pn->pn_parent == NULL,
96388596dfSDag-Erling Smørgrav 	    ("%s(): node already has a parent", __func__));
9733802b9eSDag-Erling Smørgrav 	KASSERT(parent->pn_info != NULL,
986e551fb6SDavid E. O'Brien 	    ("%s(): parent has no pn_info", __func__));
9933802b9eSDag-Erling Smørgrav 	KASSERT(parent->pn_type == pfstype_dir ||
10033802b9eSDag-Erling Smørgrav 	    parent->pn_type == pfstype_procdir ||
10133802b9eSDag-Erling Smørgrav 	    parent->pn_type == pfstype_root,
1026e551fb6SDavid E. O'Brien 	    ("%s(): parent is not a directory", __func__));
10333802b9eSDag-Erling Smørgrav 
104388596dfSDag-Erling Smørgrav #ifdef INVARIANTS
105388596dfSDag-Erling Smørgrav 	/* XXX no locking! */
106388596dfSDag-Erling Smørgrav 	if (pn->pn_type == pfstype_procdir)
107388596dfSDag-Erling Smørgrav 		for (iter = parent; iter != NULL; iter = iter->pn_parent)
108388596dfSDag-Erling Smørgrav 			KASSERT(iter->pn_type != pfstype_procdir,
109388596dfSDag-Erling Smørgrav 			    ("%s(): nested process directories", __func__));
110388596dfSDag-Erling Smørgrav 	for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
111388596dfSDag-Erling Smørgrav 		KASSERT(strcmp(pn->pn_name, iter->pn_name) != 0,
112388596dfSDag-Erling Smørgrav 		    ("%s(): homonymous siblings", __func__));
113388596dfSDag-Erling Smørgrav 		if (pn->pn_type == pfstype_procdir)
114388596dfSDag-Erling Smørgrav 			KASSERT(iter->pn_type != pfstype_procdir,
115388596dfSDag-Erling Smørgrav 			    ("%s(): sibling process directories", __func__));
116388596dfSDag-Erling Smørgrav 	}
117388596dfSDag-Erling Smørgrav #endif
11833802b9eSDag-Erling Smørgrav 
119388596dfSDag-Erling Smørgrav 	pn->pn_parent = parent;
120388596dfSDag-Erling Smørgrav 	pfs_fileno_alloc(pn);
121388596dfSDag-Erling Smørgrav 
122388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
123388596dfSDag-Erling Smørgrav 	pn->pn_next = parent->pn_nodes;
12406be2aaaSNate Lawson 	if ((parent->pn_flags & PFS_PROCDEP) != 0)
125388596dfSDag-Erling Smørgrav 		pn->pn_flags |= PFS_PROCDEP;
126388596dfSDag-Erling Smørgrav 	parent->pn_nodes = pn;
127388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
128388596dfSDag-Erling Smørgrav }
12933802b9eSDag-Erling Smørgrav 
130388596dfSDag-Erling Smørgrav /*
131388596dfSDag-Erling Smørgrav  * Detach a node from its aprent
132388596dfSDag-Erling Smørgrav  */
133388596dfSDag-Erling Smørgrav static void
134388596dfSDag-Erling Smørgrav pfs_detach_node(struct pfs_node *pn)
135388596dfSDag-Erling Smørgrav {
136388596dfSDag-Erling Smørgrav 	struct pfs_node *parent = pn->pn_parent;
137388596dfSDag-Erling Smørgrav 	struct pfs_node **iter;
138388596dfSDag-Erling Smørgrav 
139388596dfSDag-Erling Smørgrav 	KASSERT(parent != NULL, ("%s(): node has no parent", __func__));
140388596dfSDag-Erling Smørgrav 	KASSERT(parent->pn_info == pn->pn_info,
141388596dfSDag-Erling Smørgrav 	    ("%s(): parent has different pn_info", __func__));
142388596dfSDag-Erling Smørgrav 
143388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
144388596dfSDag-Erling Smørgrav 	iter = &parent->pn_nodes;
145388596dfSDag-Erling Smørgrav 	while (*iter != NULL) {
146388596dfSDag-Erling Smørgrav 		if (*iter == pn) {
147388596dfSDag-Erling Smørgrav 			*iter = pn->pn_next;
148388596dfSDag-Erling Smørgrav 			break;
149388596dfSDag-Erling Smørgrav 		}
150388596dfSDag-Erling Smørgrav 		iter = &(*iter)->pn_next;
151388596dfSDag-Erling Smørgrav 	}
152388596dfSDag-Erling Smørgrav 	pn->pn_parent = NULL;
153388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
15433802b9eSDag-Erling Smørgrav }
15533802b9eSDag-Erling Smørgrav 
15633802b9eSDag-Erling Smørgrav /*
15733802b9eSDag-Erling Smørgrav  * Add . and .. to a directory
15833802b9eSDag-Erling Smørgrav  */
159388596dfSDag-Erling Smørgrav static void
160388596dfSDag-Erling Smørgrav pfs_fixup_dir(struct pfs_node *parent)
16133802b9eSDag-Erling Smørgrav {
162388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
16333802b9eSDag-Erling Smørgrav 
164388596dfSDag-Erling Smørgrav 	pn = pfs_alloc_node(parent->pn_info, ".", pfstype_this);
165388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
166388596dfSDag-Erling Smørgrav 	pn = pfs_alloc_node(parent->pn_info, "..", pfstype_parent);
167388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
16833802b9eSDag-Erling Smørgrav }
16933802b9eSDag-Erling Smørgrav 
17033802b9eSDag-Erling Smørgrav /*
17133802b9eSDag-Erling Smørgrav  * Create a directory
17233802b9eSDag-Erling Smørgrav  */
17333802b9eSDag-Erling Smørgrav struct pfs_node	*
174b331ec01SDag-Erling Smørgrav pfs_create_dir(struct pfs_node *parent, const char *name,
175771709ebSDag-Erling Smørgrav 	       pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
176771709ebSDag-Erling Smørgrav 	       int flags)
17733802b9eSDag-Erling Smørgrav {
178388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
17933802b9eSDag-Erling Smørgrav 
180388596dfSDag-Erling Smørgrav 	pn = pfs_alloc_node(parent->pn_info, name,
181388596dfSDag-Erling Smørgrav 	    (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir);
182388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
183388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
184388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
185388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
186388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
187388596dfSDag-Erling Smørgrav 	pfs_fixup_dir(pn);
18833802b9eSDag-Erling Smørgrav 
189388596dfSDag-Erling Smørgrav 	return (pn);
19033802b9eSDag-Erling Smørgrav }
19133802b9eSDag-Erling Smørgrav 
19233802b9eSDag-Erling Smørgrav /*
19333802b9eSDag-Erling Smørgrav  * Create a file
19433802b9eSDag-Erling Smørgrav  */
19533802b9eSDag-Erling Smørgrav struct pfs_node	*
196b331ec01SDag-Erling Smørgrav pfs_create_file(struct pfs_node *parent, const char *name, pfs_fill_t fill,
197771709ebSDag-Erling Smørgrav 		pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
198771709ebSDag-Erling Smørgrav 		int flags)
19933802b9eSDag-Erling Smørgrav {
200388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
20133802b9eSDag-Erling Smørgrav 
202388596dfSDag-Erling Smørgrav 	pn = pfs_alloc_node(parent->pn_info, name, pfstype_file);
203388596dfSDag-Erling Smørgrav 	pn->pn_fill = fill;
204388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
205388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
206388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
207388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
208388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
20933802b9eSDag-Erling Smørgrav 
210388596dfSDag-Erling Smørgrav 	return (pn);
21133802b9eSDag-Erling Smørgrav }
21233802b9eSDag-Erling Smørgrav 
21333802b9eSDag-Erling Smørgrav /*
21433802b9eSDag-Erling Smørgrav  * Create a symlink
21533802b9eSDag-Erling Smørgrav  */
21633802b9eSDag-Erling Smørgrav struct pfs_node	*
217b331ec01SDag-Erling Smørgrav pfs_create_link(struct pfs_node *parent, const char *name, pfs_fill_t fill,
218771709ebSDag-Erling Smørgrav 		pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
219771709ebSDag-Erling Smørgrav 		int flags)
22033802b9eSDag-Erling Smørgrav {
221388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
22233802b9eSDag-Erling Smørgrav 
223388596dfSDag-Erling Smørgrav 	pn = pfs_alloc_node(parent->pn_info, name, pfstype_symlink);
224388596dfSDag-Erling Smørgrav 	pn->pn_fill = fill;
225388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
226388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
227388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
228388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
229388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
230388596dfSDag-Erling Smørgrav 
231388596dfSDag-Erling Smørgrav 	return (pn);
23233802b9eSDag-Erling Smørgrav }
23333802b9eSDag-Erling Smørgrav 
23433802b9eSDag-Erling Smørgrav /*
235b331ec01SDag-Erling Smørgrav  * Locate a node by name
236b331ec01SDag-Erling Smørgrav  */
237b331ec01SDag-Erling Smørgrav struct pfs_node *
238b331ec01SDag-Erling Smørgrav pfs_find_node(struct pfs_node *parent, const char *name)
239b331ec01SDag-Erling Smørgrav {
240388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
241b331ec01SDag-Erling Smørgrav 
242388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
243388596dfSDag-Erling Smørgrav 	for (pn = parent->pn_nodes; pn != NULL; pn = pn->pn_next)
244388596dfSDag-Erling Smørgrav 		if (strcmp(pn->pn_name, name) == 0)
245f61bc4eaSDag-Erling Smørgrav 			break;
246388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
247388596dfSDag-Erling Smørgrav 	return (pn);
248b331ec01SDag-Erling Smørgrav }
249b331ec01SDag-Erling Smørgrav 
250b331ec01SDag-Erling Smørgrav /*
251388596dfSDag-Erling Smørgrav  * Destroy a node and all its descendants.  If the node to be destroyed
252388596dfSDag-Erling Smørgrav  * has a parent, the parent's mutex must be held.
25333802b9eSDag-Erling Smørgrav  */
25433802b9eSDag-Erling Smørgrav int
255388596dfSDag-Erling Smørgrav pfs_destroy(struct pfs_node *pn)
25633802b9eSDag-Erling Smørgrav {
257388596dfSDag-Erling Smørgrav 	struct pfs_node *iter;
25833802b9eSDag-Erling Smørgrav 
259388596dfSDag-Erling Smørgrav 	KASSERT(pn != NULL,
2606e551fb6SDavid E. O'Brien 	    ("%s(): node is NULL", __func__));
261388596dfSDag-Erling Smørgrav 	KASSERT(pn->pn_info != NULL,
2626e551fb6SDavid E. O'Brien 	    ("%s(): node has no pn_info", __func__));
26333802b9eSDag-Erling Smørgrav 
264388596dfSDag-Erling Smørgrav 	if (pn->pn_parent)
265388596dfSDag-Erling Smørgrav 		pfs_detach_node(pn);
26633802b9eSDag-Erling Smørgrav 
267388596dfSDag-Erling Smørgrav 	/* destroy children */
268388596dfSDag-Erling Smørgrav 	if (pn->pn_type == pfstype_dir ||
269388596dfSDag-Erling Smørgrav 	    pn->pn_type == pfstype_procdir ||
270388596dfSDag-Erling Smørgrav 	    pn->pn_type == pfstype_root) {
271388596dfSDag-Erling Smørgrav 		pfs_lock(pn);
272388596dfSDag-Erling Smørgrav 		while (pn->pn_nodes != NULL) {
273388596dfSDag-Erling Smørgrav 			iter = pn->pn_nodes;
274388596dfSDag-Erling Smørgrav 			pn->pn_nodes = iter->pn_next;
275388596dfSDag-Erling Smørgrav 			iter->pn_parent = NULL;
276388596dfSDag-Erling Smørgrav 			pfs_unlock(pn);
277388596dfSDag-Erling Smørgrav 			pfs_destroy(iter);
278388596dfSDag-Erling Smørgrav 			pfs_lock(pn);
27933802b9eSDag-Erling Smørgrav 		}
280388596dfSDag-Erling Smørgrav 		pfs_unlock(pn);
28133802b9eSDag-Erling Smørgrav 	}
282388596dfSDag-Erling Smørgrav 
283388596dfSDag-Erling Smørgrav 	/* revoke vnodes and fileno */
284388596dfSDag-Erling Smørgrav 	pfs_purge(pn);
28533802b9eSDag-Erling Smørgrav 
286771709ebSDag-Erling Smørgrav 	/* callback to free any private resources */
287388596dfSDag-Erling Smørgrav 	if (pn->pn_destroy != NULL)
288388596dfSDag-Erling Smørgrav 		pn_destroy(pn);
289771709ebSDag-Erling Smørgrav 
290388596dfSDag-Erling Smørgrav 	/* destroy the node */
291388596dfSDag-Erling Smørgrav 	pfs_fileno_free(pn);
292388596dfSDag-Erling Smørgrav 	mtx_destroy(&pn->pn_mutex);
293388596dfSDag-Erling Smørgrav 	FREE(pn, M_PFSNODES);
29433802b9eSDag-Erling Smørgrav 
29533802b9eSDag-Erling Smørgrav 	return (0);
29633802b9eSDag-Erling Smørgrav }
29733802b9eSDag-Erling Smørgrav 
29833802b9eSDag-Erling Smørgrav /*
2999733a808SDag-Erling Smørgrav  * Mount a pseudofs instance
3009733a808SDag-Erling Smørgrav  */
3019733a808SDag-Erling Smørgrav int
3025e8c582aSPoul-Henning Kamp pfs_mount(struct pfs_info *pi, struct mount *mp, struct thread *td)
3039733a808SDag-Erling Smørgrav {
3049733a808SDag-Erling Smørgrav 	struct statfs *sbp;
3059733a808SDag-Erling Smørgrav 
3069733a808SDag-Erling Smørgrav 	if (mp->mnt_flag & MNT_UPDATE)
3079733a808SDag-Erling Smørgrav 		return (EOPNOTSUPP);
3089733a808SDag-Erling Smørgrav 
30915bad11fSDag-Erling Smørgrav 	MNT_ILOCK(mp);
3109733a808SDag-Erling Smørgrav 	mp->mnt_flag |= MNT_LOCAL;
31115bad11fSDag-Erling Smørgrav 	mp->mnt_kern_flag |= MNTK_MPSAFE;
31215bad11fSDag-Erling Smørgrav 	MNT_IUNLOCK(mp);
3139733a808SDag-Erling Smørgrav 	mp->mnt_data = (qaddr_t)pi;
3149733a808SDag-Erling Smørgrav 	vfs_getnewfsid(mp);
3159733a808SDag-Erling Smørgrav 
3169733a808SDag-Erling Smørgrav 	sbp = &mp->mnt_stat;
317def91cf2SPoul-Henning Kamp 	vfs_mountedfrom(mp, pi->pi_name);
3189733a808SDag-Erling Smørgrav 	sbp->f_bsize = PAGE_SIZE;
3199733a808SDag-Erling Smørgrav 	sbp->f_iosize = PAGE_SIZE;
3209733a808SDag-Erling Smørgrav 	sbp->f_blocks = 1;
3219733a808SDag-Erling Smørgrav 	sbp->f_bfree = 0;
3229733a808SDag-Erling Smørgrav 	sbp->f_bavail = 0;
3239733a808SDag-Erling Smørgrav 	sbp->f_files = 1;
3249733a808SDag-Erling Smørgrav 	sbp->f_ffree = 0;
3259733a808SDag-Erling Smørgrav 
3269733a808SDag-Erling Smørgrav 	return (0);
3279733a808SDag-Erling Smørgrav }
3289733a808SDag-Erling Smørgrav 
3299733a808SDag-Erling Smørgrav /*
330388596dfSDag-Erling Smørgrav  * Compatibility shim for old mount(2) system call
331c9ad8a67SKelly Yancey  */
332c9ad8a67SKelly Yancey int
333c9ad8a67SKelly Yancey pfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
334c9ad8a67SKelly Yancey {
335388596dfSDag-Erling Smørgrav 	int error;
336388596dfSDag-Erling Smørgrav 
337388596dfSDag-Erling Smørgrav 	error = kernel_mount(ma, flags);
338388596dfSDag-Erling Smørgrav 	return (error);
339c9ad8a67SKelly Yancey }
340c9ad8a67SKelly Yancey 
341c9ad8a67SKelly Yancey /*
3429733a808SDag-Erling Smørgrav  * Unmount a pseudofs instance
3439733a808SDag-Erling Smørgrav  */
3449733a808SDag-Erling Smørgrav int
345b40ce416SJulian Elischer pfs_unmount(struct mount *mp, int mntflags, struct thread *td)
3469733a808SDag-Erling Smørgrav {
3479733a808SDag-Erling Smørgrav 	int error;
3489733a808SDag-Erling Smørgrav 
349f257b7a5SAlfred Perlstein 	error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0, td);
3509733a808SDag-Erling Smørgrav 	return (error);
3519733a808SDag-Erling Smørgrav }
3529733a808SDag-Erling Smørgrav 
3539733a808SDag-Erling Smørgrav /*
3549733a808SDag-Erling Smørgrav  * Return a root vnode
3559733a808SDag-Erling Smørgrav  */
3569733a808SDag-Erling Smørgrav int
357d9b2d9f7SJeff Roberson pfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
3589733a808SDag-Erling Smørgrav {
3599733a808SDag-Erling Smørgrav 	struct pfs_info *pi;
3609733a808SDag-Erling Smørgrav 
3619733a808SDag-Erling Smørgrav 	pi = (struct pfs_info *)mp->mnt_data;
362388596dfSDag-Erling Smørgrav 	return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID));
3639733a808SDag-Erling Smørgrav }
3649733a808SDag-Erling Smørgrav 
3659733a808SDag-Erling Smørgrav /*
3669733a808SDag-Erling Smørgrav  * Return filesystem stats
3679733a808SDag-Erling Smørgrav  */
3689733a808SDag-Erling Smørgrav int
369b40ce416SJulian Elischer pfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
3709733a808SDag-Erling Smørgrav {
371def91cf2SPoul-Henning Kamp 	/* no-op:  always called with mp->mnt_stat */
3729733a808SDag-Erling Smørgrav 	return (0);
3739733a808SDag-Erling Smørgrav }
3749733a808SDag-Erling Smørgrav 
3759733a808SDag-Erling Smørgrav /*
3769733a808SDag-Erling Smørgrav  * Initialize a pseudofs instance
3779733a808SDag-Erling Smørgrav  */
3789733a808SDag-Erling Smørgrav int
3799733a808SDag-Erling Smørgrav pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
3809733a808SDag-Erling Smørgrav {
38133802b9eSDag-Erling Smørgrav 	struct pfs_node *root;
38233802b9eSDag-Erling Smørgrav 	int error;
38333802b9eSDag-Erling Smørgrav 
384f61bc4eaSDag-Erling Smørgrav 	mtx_assert(&Giant, MA_OWNED);
38533802b9eSDag-Erling Smørgrav 
386388596dfSDag-Erling Smørgrav 	pfs_fileno_init(pi);
387388596dfSDag-Erling Smørgrav 
38833802b9eSDag-Erling Smørgrav 	/* set up the root diretory */
389388596dfSDag-Erling Smørgrav 	root = pfs_alloc_node(pi, "/", pfstype_root);
39033802b9eSDag-Erling Smørgrav 	pi->pi_root = root;
391388596dfSDag-Erling Smørgrav 	pfs_fileno_alloc(root);
392388596dfSDag-Erling Smørgrav 	pfs_fixup_dir(root);
39333802b9eSDag-Erling Smørgrav 
39433802b9eSDag-Erling Smørgrav 	/* construct file hierarchy */
39533802b9eSDag-Erling Smørgrav 	error = (pi->pi_init)(pi, vfc);
39633802b9eSDag-Erling Smørgrav 	if (error) {
39733802b9eSDag-Erling Smørgrav 		pfs_destroy(root);
39833802b9eSDag-Erling Smørgrav 		pi->pi_root = NULL;
39933802b9eSDag-Erling Smørgrav 		return (error);
40033802b9eSDag-Erling Smørgrav 	}
40133802b9eSDag-Erling Smørgrav 
402b7004390SDag-Erling Smørgrav 	if (bootverbose)
4039733a808SDag-Erling Smørgrav 		printf("%s registered\n", pi->pi_name);
4049733a808SDag-Erling Smørgrav 	return (0);
4059733a808SDag-Erling Smørgrav }
4069733a808SDag-Erling Smørgrav 
4079733a808SDag-Erling Smørgrav /*
4089733a808SDag-Erling Smørgrav  * Destroy a pseudofs instance
4099733a808SDag-Erling Smørgrav  */
4109733a808SDag-Erling Smørgrav int
4119733a808SDag-Erling Smørgrav pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
4129733a808SDag-Erling Smørgrav {
41333802b9eSDag-Erling Smørgrav 	int error;
41433802b9eSDag-Erling Smørgrav 
415f61bc4eaSDag-Erling Smørgrav 	mtx_assert(&Giant, MA_OWNED);
416f61bc4eaSDag-Erling Smørgrav 
41733802b9eSDag-Erling Smørgrav 	pfs_destroy(pi->pi_root);
41833802b9eSDag-Erling Smørgrav 	pi->pi_root = NULL;
41915bad11fSDag-Erling Smørgrav 	pfs_fileno_uninit(pi);
420b7004390SDag-Erling Smørgrav 	if (bootverbose)
4219733a808SDag-Erling Smørgrav 		printf("%s unregistered\n", pi->pi_name);
42233802b9eSDag-Erling Smørgrav 	error = (pi->pi_uninit)(pi, vfc);
42333802b9eSDag-Erling Smørgrav 	return (error);
4249733a808SDag-Erling Smørgrav }
4259733a808SDag-Erling Smørgrav 
4269733a808SDag-Erling Smørgrav /*
4279733a808SDag-Erling Smørgrav  * Handle load / unload events
4289733a808SDag-Erling Smørgrav  */
4299733a808SDag-Erling Smørgrav static int
4309733a808SDag-Erling Smørgrav pfs_modevent(module_t mod, int evt, void *arg)
4319733a808SDag-Erling Smørgrav {
4329733a808SDag-Erling Smørgrav 	switch (evt) {
4339733a808SDag-Erling Smørgrav 	case MOD_LOAD:
4349733a808SDag-Erling Smørgrav 		pfs_vncache_load();
4359733a808SDag-Erling Smørgrav 		break;
4369733a808SDag-Erling Smørgrav 	case MOD_UNLOAD:
4379733a808SDag-Erling Smørgrav 	case MOD_SHUTDOWN:
4389733a808SDag-Erling Smørgrav 		pfs_vncache_unload();
4399733a808SDag-Erling Smørgrav 		break;
4409733a808SDag-Erling Smørgrav 	default:
4413e019deaSPoul-Henning Kamp 		return EOPNOTSUPP;
4429733a808SDag-Erling Smørgrav 		break;
4439733a808SDag-Erling Smørgrav 	}
4449733a808SDag-Erling Smørgrav 	return 0;
4459733a808SDag-Erling Smørgrav }
4469733a808SDag-Erling Smørgrav 
4479733a808SDag-Erling Smørgrav /*
4489733a808SDag-Erling Smørgrav  * Module declaration
4499733a808SDag-Erling Smørgrav  */
4509733a808SDag-Erling Smørgrav static moduledata_t pseudofs_data = {
4519733a808SDag-Erling Smørgrav 	"pseudofs",
4529733a808SDag-Erling Smørgrav 	pfs_modevent,
4539733a808SDag-Erling Smørgrav 	NULL
4549733a808SDag-Erling Smørgrav };
4559733a808SDag-Erling Smørgrav DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
45698c7e22cSDag-Erling Smørgrav MODULE_VERSION(pseudofs, 1);
457