xref: /freebsd/sys/fs/pseudofs/pseudofs.c (revision e738085b94631f90e21a49852538ac95974baf44)
19733a808SDag-Erling Smørgrav /*-
2d63027b6SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3d63027b6SPedro F. Giffuni  *
4*e738085bSDag-Erling Smørgrav  * Copyright (c) 2001 Dag-Erling Smørgrav
59733a808SDag-Erling Smørgrav  * All rights reserved.
69733a808SDag-Erling Smørgrav  *
79733a808SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
89733a808SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
99733a808SDag-Erling Smørgrav  * are met:
109733a808SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
119733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
129733a808SDag-Erling Smørgrav  *    in this position and unchanged.
139733a808SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
149733a808SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
159733a808SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
169733a808SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
179733a808SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
189733a808SDag-Erling Smørgrav  *
199733a808SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
209733a808SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
219733a808SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
229733a808SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
239733a808SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249733a808SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
259733a808SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
269733a808SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
279733a808SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
289733a808SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299733a808SDag-Erling Smørgrav  */
309733a808SDag-Erling Smørgrav 
31de52d21aSDag-Erling Smørgrav #include <sys/cdefs.h>
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 
52d3d10ed2SPawel Biernacki SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
539733a808SDag-Erling Smørgrav     "pseudofs");
549733a808SDag-Erling Smørgrav 
5563cc3320SDmitry Chagin #ifdef PSEUDOFS_TRACE
56388596dfSDag-Erling Smørgrav int pfs_trace;
57388596dfSDag-Erling Smørgrav SYSCTL_INT(_vfs_pfs, OID_AUTO, trace, CTLFLAG_RW, &pfs_trace, 0,
58388596dfSDag-Erling Smørgrav     "enable tracing of pseudofs vnode operations");
5963cc3320SDmitry Chagin #endif
60388596dfSDag-Erling Smørgrav 
6141aa8697SDag-Erling Smørgrav #if PFS_FSNAMELEN != MFSNAMELEN
6241aa8697SDag-Erling Smørgrav #error "PFS_FSNAMELEN is not equal to MFSNAMELEN"
6341aa8697SDag-Erling Smørgrav #endif
6441aa8697SDag-Erling Smørgrav 
659733a808SDag-Erling Smørgrav /*
66388596dfSDag-Erling Smørgrav  * Allocate and initialize a node
67388596dfSDag-Erling Smørgrav  */
68388596dfSDag-Erling Smørgrav static struct pfs_node *
pfs_alloc_node_flags(struct pfs_info * pi,const char * name,pfs_type_t type,int flags)6981167243SMatt Macy pfs_alloc_node_flags(struct pfs_info *pi, const char *name, pfs_type_t type, int flags)
70388596dfSDag-Erling Smørgrav {
71388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
7281167243SMatt Macy 	int malloc_flags;
737f723243SDmitry Chagin 	size_t len;
74388596dfSDag-Erling Smørgrav 
757f723243SDmitry Chagin 	len = strlen(name);
767f723243SDmitry Chagin 	KASSERT(len < PFS_NAMELEN,
77388596dfSDag-Erling Smørgrav 	    ("%s(): node name is too long", __func__));
7881167243SMatt Macy 	if (flags & PFS_NOWAIT)
7981167243SMatt Macy 		malloc_flags = M_NOWAIT | M_ZERO;
8081167243SMatt Macy 	else
8181167243SMatt Macy 		malloc_flags = M_WAITOK | M_ZERO;
827f723243SDmitry Chagin 	pn = malloc(sizeof(*pn) + len + 1, M_PFSNODES, malloc_flags);
8381167243SMatt Macy 	if (pn == NULL)
8481167243SMatt Macy 		return (NULL);
85388596dfSDag-Erling Smørgrav 	mtx_init(&pn->pn_mutex, "pfs_node", NULL, MTX_DEF | MTX_DUPOK);
867f723243SDmitry Chagin 	memcpy(pn->pn_name, name, len);
87388596dfSDag-Erling Smørgrav 	pn->pn_type = type;
88388596dfSDag-Erling Smørgrav 	pn->pn_info = pi;
89388596dfSDag-Erling Smørgrav 	return (pn);
90388596dfSDag-Erling Smørgrav }
91388596dfSDag-Erling Smørgrav 
9281167243SMatt Macy static struct pfs_node *
pfs_alloc_node(struct pfs_info * pi,const char * name,pfs_type_t type)9381167243SMatt Macy pfs_alloc_node(struct pfs_info *pi, const char *name, pfs_type_t type)
9481167243SMatt Macy {
9581167243SMatt Macy 	return (pfs_alloc_node_flags(pi, name, type, 0));
9681167243SMatt Macy }
9781167243SMatt Macy 
98388596dfSDag-Erling Smørgrav /*
9933802b9eSDag-Erling Smørgrav  * Add a node to a directory
10033802b9eSDag-Erling Smørgrav  */
101388596dfSDag-Erling Smørgrav static void
pfs_add_node(struct pfs_node * parent,struct pfs_node * pn)102388596dfSDag-Erling Smørgrav pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
10333802b9eSDag-Erling Smørgrav {
104388596dfSDag-Erling Smørgrav #ifdef INVARIANTS
105388596dfSDag-Erling Smørgrav 	struct pfs_node *iter;
106388596dfSDag-Erling Smørgrav #endif
107388596dfSDag-Erling Smørgrav 
10833802b9eSDag-Erling Smørgrav 	KASSERT(parent != NULL,
1096e551fb6SDavid E. O'Brien 	    ("%s(): parent is NULL", __func__));
110388596dfSDag-Erling Smørgrav 	KASSERT(pn->pn_parent == NULL,
111388596dfSDag-Erling Smørgrav 	    ("%s(): node already has a parent", __func__));
11233802b9eSDag-Erling Smørgrav 	KASSERT(parent->pn_info != NULL,
1136e551fb6SDavid E. O'Brien 	    ("%s(): parent has no pn_info", __func__));
11433802b9eSDag-Erling Smørgrav 	KASSERT(parent->pn_type == pfstype_dir ||
11533802b9eSDag-Erling Smørgrav 	    parent->pn_type == pfstype_procdir ||
11633802b9eSDag-Erling Smørgrav 	    parent->pn_type == pfstype_root,
1176e551fb6SDavid E. O'Brien 	    ("%s(): parent is not a directory", __func__));
11833802b9eSDag-Erling Smørgrav 
119388596dfSDag-Erling Smørgrav #ifdef INVARIANTS
120388596dfSDag-Erling Smørgrav 	/* XXX no locking! */
121388596dfSDag-Erling Smørgrav 	if (pn->pn_type == pfstype_procdir)
122388596dfSDag-Erling Smørgrav 		for (iter = parent; iter != NULL; iter = iter->pn_parent)
123388596dfSDag-Erling Smørgrav 			KASSERT(iter->pn_type != pfstype_procdir,
124388596dfSDag-Erling Smørgrav 			    ("%s(): nested process directories", __func__));
125388596dfSDag-Erling Smørgrav 	for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
126388596dfSDag-Erling Smørgrav 		KASSERT(strcmp(pn->pn_name, iter->pn_name) != 0,
127388596dfSDag-Erling Smørgrav 		    ("%s(): homonymous siblings", __func__));
128388596dfSDag-Erling Smørgrav 		if (pn->pn_type == pfstype_procdir)
129388596dfSDag-Erling Smørgrav 			KASSERT(iter->pn_type != pfstype_procdir,
130388596dfSDag-Erling Smørgrav 			    ("%s(): sibling process directories", __func__));
131388596dfSDag-Erling Smørgrav 	}
132388596dfSDag-Erling Smørgrav #endif
13333802b9eSDag-Erling Smørgrav 
134388596dfSDag-Erling Smørgrav 	pn->pn_parent = parent;
135388596dfSDag-Erling Smørgrav 	pfs_fileno_alloc(pn);
136388596dfSDag-Erling Smørgrav 
137388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
13806be2aaaSNate Lawson 	if ((parent->pn_flags & PFS_PROCDEP) != 0)
139388596dfSDag-Erling Smørgrav 		pn->pn_flags |= PFS_PROCDEP;
140cf389852SEdward Tomasz Napierala 	if (parent->pn_nodes == NULL) {
141cf389852SEdward Tomasz Napierala 		KASSERT(parent->pn_last_node == NULL,
142cf389852SEdward Tomasz Napierala 		    ("%s(): pn_last_node not NULL", __func__));
143388596dfSDag-Erling Smørgrav 		parent->pn_nodes = pn;
144cf389852SEdward Tomasz Napierala 		parent->pn_last_node = pn;
145cf389852SEdward Tomasz Napierala 	} else {
146cf389852SEdward Tomasz Napierala 		KASSERT(parent->pn_last_node != NULL,
147cf389852SEdward Tomasz Napierala 		    ("%s(): pn_last_node is NULL", __func__));
148cf389852SEdward Tomasz Napierala 		KASSERT(parent->pn_last_node->pn_next == NULL,
149cf389852SEdward Tomasz Napierala 		    ("%s(): pn_last_node->pn_next not NULL", __func__));
150cf389852SEdward Tomasz Napierala 		parent->pn_last_node->pn_next = pn;
151cf389852SEdward Tomasz Napierala 		parent->pn_last_node = pn;
152cf389852SEdward Tomasz Napierala 	}
153388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
154388596dfSDag-Erling Smørgrav }
15533802b9eSDag-Erling Smørgrav 
156388596dfSDag-Erling Smørgrav /*
157388596dfSDag-Erling Smørgrav  * Detach a node from its aprent
158388596dfSDag-Erling Smørgrav  */
159388596dfSDag-Erling Smørgrav static void
pfs_detach_node(struct pfs_node * pn)160388596dfSDag-Erling Smørgrav pfs_detach_node(struct pfs_node *pn)
161388596dfSDag-Erling Smørgrav {
162cf389852SEdward Tomasz Napierala 	struct pfs_node *node, *parent = pn->pn_parent;
163388596dfSDag-Erling Smørgrav 	struct pfs_node **iter;
164388596dfSDag-Erling Smørgrav 
165388596dfSDag-Erling Smørgrav 	KASSERT(parent != NULL, ("%s(): node has no parent", __func__));
166388596dfSDag-Erling Smørgrav 	KASSERT(parent->pn_info == pn->pn_info,
167388596dfSDag-Erling Smørgrav 	    ("%s(): parent has different pn_info", __func__));
168388596dfSDag-Erling Smørgrav 
169388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
170cf389852SEdward Tomasz Napierala 	if (pn == parent->pn_last_node) {
171cf389852SEdward Tomasz Napierala 		if (pn == pn->pn_nodes) {
172cf389852SEdward Tomasz Napierala 			parent->pn_last_node = NULL;
173cf389852SEdward Tomasz Napierala 		} else {
174cf389852SEdward Tomasz Napierala 			for (node = parent->pn_nodes;
175cf389852SEdward Tomasz Napierala 			    node->pn_next != pn; node = node->pn_next)
176cf389852SEdward Tomasz Napierala 				continue;
177cf389852SEdward Tomasz Napierala 			parent->pn_last_node = node;
178cf389852SEdward Tomasz Napierala 		}
179cf389852SEdward Tomasz Napierala 	}
180388596dfSDag-Erling Smørgrav 	iter = &parent->pn_nodes;
181388596dfSDag-Erling Smørgrav 	while (*iter != NULL) {
182388596dfSDag-Erling Smørgrav 		if (*iter == pn) {
183388596dfSDag-Erling Smørgrav 			*iter = pn->pn_next;
184388596dfSDag-Erling Smørgrav 			break;
185388596dfSDag-Erling Smørgrav 		}
186388596dfSDag-Erling Smørgrav 		iter = &(*iter)->pn_next;
187388596dfSDag-Erling Smørgrav 	}
188388596dfSDag-Erling Smørgrav 	pn->pn_parent = NULL;
189388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
19033802b9eSDag-Erling Smørgrav }
19133802b9eSDag-Erling Smørgrav 
19233802b9eSDag-Erling Smørgrav /*
19333802b9eSDag-Erling Smørgrav  * Add . and .. to a directory
19433802b9eSDag-Erling Smørgrav  */
19581167243SMatt Macy static int
pfs_fixup_dir_flags(struct pfs_node * parent,int flags)19681167243SMatt Macy pfs_fixup_dir_flags(struct pfs_node *parent, int flags)
19781167243SMatt Macy {
19881167243SMatt Macy 	struct pfs_node *dot, *dotdot;
19981167243SMatt Macy 
20081167243SMatt Macy 	dot = pfs_alloc_node_flags(parent->pn_info, ".", pfstype_this, flags);
20181167243SMatt Macy 	if (dot == NULL)
20281167243SMatt Macy 		return (ENOMEM);
20381167243SMatt Macy 	dotdot = pfs_alloc_node_flags(parent->pn_info, "..", pfstype_parent, flags);
20481167243SMatt Macy 	if (dotdot == NULL) {
20581167243SMatt Macy 		pfs_destroy(dot);
20681167243SMatt Macy 		return (ENOMEM);
20781167243SMatt Macy 	}
20881167243SMatt Macy 	pfs_add_node(parent, dot);
20981167243SMatt Macy 	pfs_add_node(parent, dotdot);
21081167243SMatt Macy 	return (0);
21181167243SMatt Macy }
21281167243SMatt Macy 
213388596dfSDag-Erling Smørgrav static void
pfs_fixup_dir(struct pfs_node * parent)214388596dfSDag-Erling Smørgrav pfs_fixup_dir(struct pfs_node *parent)
21533802b9eSDag-Erling Smørgrav {
21633802b9eSDag-Erling Smørgrav 
21781167243SMatt Macy 	pfs_fixup_dir_flags(parent, 0);
21833802b9eSDag-Erling Smørgrav }
21933802b9eSDag-Erling Smørgrav 
22033802b9eSDag-Erling Smørgrav /*
22133802b9eSDag-Erling Smørgrav  * Create a directory
22233802b9eSDag-Erling Smørgrav  */
22333802b9eSDag-Erling Smørgrav struct pfs_node	*
pfs_create_dir(struct pfs_node * parent,const char * name,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)224b331ec01SDag-Erling Smørgrav pfs_create_dir(struct pfs_node *parent, const char *name,
225771709ebSDag-Erling Smørgrav 	       pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
226771709ebSDag-Erling Smørgrav 	       int flags)
22733802b9eSDag-Erling Smørgrav {
228388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
22981167243SMatt Macy 	int rc;
23033802b9eSDag-Erling Smørgrav 
23181167243SMatt Macy 	pn = pfs_alloc_node_flags(parent->pn_info, name,
23281167243SMatt Macy 			 (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir, flags);
23381167243SMatt Macy 	if (pn == NULL)
23481167243SMatt Macy 		return (NULL);
235388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
236388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
237388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
238388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
239388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
24081167243SMatt Macy 	rc = pfs_fixup_dir_flags(pn, flags);
24181167243SMatt Macy 	if (rc) {
24281167243SMatt Macy 		pfs_destroy(pn);
24381167243SMatt Macy 		return (NULL);
24481167243SMatt Macy 	}
245388596dfSDag-Erling Smørgrav 	return (pn);
24633802b9eSDag-Erling Smørgrav }
24733802b9eSDag-Erling Smørgrav 
24833802b9eSDag-Erling Smørgrav /*
24933802b9eSDag-Erling Smørgrav  * Create a file
25033802b9eSDag-Erling Smørgrav  */
25133802b9eSDag-Erling Smørgrav struct pfs_node	*
pfs_create_file(struct pfs_node * parent,const char * name,pfs_fill_t fill,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)252b331ec01SDag-Erling Smørgrav pfs_create_file(struct pfs_node *parent, const char *name, pfs_fill_t fill,
253771709ebSDag-Erling Smørgrav 		pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
254771709ebSDag-Erling Smørgrav 		int flags)
25533802b9eSDag-Erling Smørgrav {
256388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
25733802b9eSDag-Erling Smørgrav 
25881167243SMatt Macy 	pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_file, flags);
25981167243SMatt Macy 	if (pn == NULL)
26081167243SMatt Macy 		return (NULL);
261388596dfSDag-Erling Smørgrav 	pn->pn_fill = fill;
262388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
263388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
264388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
265388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
266388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
26733802b9eSDag-Erling Smørgrav 
268388596dfSDag-Erling Smørgrav 	return (pn);
26933802b9eSDag-Erling Smørgrav }
27033802b9eSDag-Erling Smørgrav 
27133802b9eSDag-Erling Smørgrav /*
27233802b9eSDag-Erling Smørgrav  * Create a symlink
27333802b9eSDag-Erling Smørgrav  */
27433802b9eSDag-Erling Smørgrav struct pfs_node	*
pfs_create_link(struct pfs_node * parent,const char * name,pfs_fill_t fill,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)275b331ec01SDag-Erling Smørgrav pfs_create_link(struct pfs_node *parent, const char *name, pfs_fill_t fill,
276771709ebSDag-Erling Smørgrav 		pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
277771709ebSDag-Erling Smørgrav 		int flags)
27833802b9eSDag-Erling Smørgrav {
279388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
28033802b9eSDag-Erling Smørgrav 
28181167243SMatt Macy 	pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_symlink, flags);
28281167243SMatt Macy 	if (pn == NULL)
28381167243SMatt Macy 		return (NULL);
284388596dfSDag-Erling Smørgrav 	pn->pn_fill = fill;
285388596dfSDag-Erling Smørgrav 	pn->pn_attr = attr;
286388596dfSDag-Erling Smørgrav 	pn->pn_vis = vis;
287388596dfSDag-Erling Smørgrav 	pn->pn_destroy = destroy;
288388596dfSDag-Erling Smørgrav 	pn->pn_flags = flags;
289388596dfSDag-Erling Smørgrav 	pfs_add_node(parent, pn);
290388596dfSDag-Erling Smørgrav 
291388596dfSDag-Erling Smørgrav 	return (pn);
29233802b9eSDag-Erling Smørgrav }
29333802b9eSDag-Erling Smørgrav 
29433802b9eSDag-Erling Smørgrav /*
295b331ec01SDag-Erling Smørgrav  * Locate a node by name
296b331ec01SDag-Erling Smørgrav  */
297b331ec01SDag-Erling Smørgrav struct pfs_node *
pfs_find_node(struct pfs_node * parent,const char * name)298b331ec01SDag-Erling Smørgrav pfs_find_node(struct pfs_node *parent, const char *name)
299b331ec01SDag-Erling Smørgrav {
300388596dfSDag-Erling Smørgrav 	struct pfs_node *pn;
301b331ec01SDag-Erling Smørgrav 
302388596dfSDag-Erling Smørgrav 	pfs_lock(parent);
303388596dfSDag-Erling Smørgrav 	for (pn = parent->pn_nodes; pn != NULL; pn = pn->pn_next)
304388596dfSDag-Erling Smørgrav 		if (strcmp(pn->pn_name, name) == 0)
305f61bc4eaSDag-Erling Smørgrav 			break;
306388596dfSDag-Erling Smørgrav 	pfs_unlock(parent);
307388596dfSDag-Erling Smørgrav 	return (pn);
308b331ec01SDag-Erling Smørgrav }
309b331ec01SDag-Erling Smørgrav 
310b331ec01SDag-Erling Smørgrav /*
311388596dfSDag-Erling Smørgrav  * Destroy a node and all its descendants.  If the node to be destroyed
312388596dfSDag-Erling Smørgrav  * has a parent, the parent's mutex must be held.
31333802b9eSDag-Erling Smørgrav  */
31433802b9eSDag-Erling Smørgrav int
pfs_destroy(struct pfs_node * pn)315388596dfSDag-Erling Smørgrav pfs_destroy(struct pfs_node *pn)
31633802b9eSDag-Erling Smørgrav {
317388596dfSDag-Erling Smørgrav 	struct pfs_node *iter;
31833802b9eSDag-Erling Smørgrav 
319388596dfSDag-Erling Smørgrav 	KASSERT(pn != NULL,
3206e551fb6SDavid E. O'Brien 	    ("%s(): node is NULL", __func__));
321388596dfSDag-Erling Smørgrav 	KASSERT(pn->pn_info != NULL,
3226e551fb6SDavid E. O'Brien 	    ("%s(): node has no pn_info", __func__));
32333802b9eSDag-Erling Smørgrav 
324388596dfSDag-Erling Smørgrav 	if (pn->pn_parent)
325388596dfSDag-Erling Smørgrav 		pfs_detach_node(pn);
32633802b9eSDag-Erling Smørgrav 
327388596dfSDag-Erling Smørgrav 	/* destroy children */
328388596dfSDag-Erling Smørgrav 	if (pn->pn_type == pfstype_dir ||
329388596dfSDag-Erling Smørgrav 	    pn->pn_type == pfstype_procdir ||
330388596dfSDag-Erling Smørgrav 	    pn->pn_type == pfstype_root) {
331388596dfSDag-Erling Smørgrav 		pfs_lock(pn);
332388596dfSDag-Erling Smørgrav 		while (pn->pn_nodes != NULL) {
333388596dfSDag-Erling Smørgrav 			iter = pn->pn_nodes;
334388596dfSDag-Erling Smørgrav 			pn->pn_nodes = iter->pn_next;
335388596dfSDag-Erling Smørgrav 			iter->pn_parent = NULL;
336388596dfSDag-Erling Smørgrav 			pfs_unlock(pn);
337388596dfSDag-Erling Smørgrav 			pfs_destroy(iter);
338388596dfSDag-Erling Smørgrav 			pfs_lock(pn);
33933802b9eSDag-Erling Smørgrav 		}
340388596dfSDag-Erling Smørgrav 		pfs_unlock(pn);
34133802b9eSDag-Erling Smørgrav 	}
342388596dfSDag-Erling Smørgrav 
343388596dfSDag-Erling Smørgrav 	/* revoke vnodes and fileno */
344388596dfSDag-Erling Smørgrav 	pfs_purge(pn);
34533802b9eSDag-Erling Smørgrav 
346771709ebSDag-Erling Smørgrav 	/* callback to free any private resources */
347388596dfSDag-Erling Smørgrav 	if (pn->pn_destroy != NULL)
348388596dfSDag-Erling Smørgrav 		pn_destroy(pn);
349771709ebSDag-Erling Smørgrav 
350388596dfSDag-Erling Smørgrav 	/* destroy the node */
351388596dfSDag-Erling Smørgrav 	pfs_fileno_free(pn);
352388596dfSDag-Erling Smørgrav 	mtx_destroy(&pn->pn_mutex);
3531ede983cSDag-Erling Smørgrav 	free(pn, M_PFSNODES);
35433802b9eSDag-Erling Smørgrav 
35533802b9eSDag-Erling Smørgrav 	return (0);
35633802b9eSDag-Erling Smørgrav }
35733802b9eSDag-Erling Smørgrav 
35833802b9eSDag-Erling Smørgrav /*
3599733a808SDag-Erling Smørgrav  * Mount a pseudofs instance
3609733a808SDag-Erling Smørgrav  */
3619733a808SDag-Erling Smørgrav int
pfs_mount(struct pfs_info * pi,struct mount * mp)362dfd233edSAttilio Rao pfs_mount(struct pfs_info *pi, struct mount *mp)
3639733a808SDag-Erling Smørgrav {
3649733a808SDag-Erling Smørgrav 	struct statfs *sbp;
3659733a808SDag-Erling Smørgrav 
3669733a808SDag-Erling Smørgrav 	if (mp->mnt_flag & MNT_UPDATE)
3679733a808SDag-Erling Smørgrav 		return (EOPNOTSUPP);
3689733a808SDag-Erling Smørgrav 
36915bad11fSDag-Erling Smørgrav 	MNT_ILOCK(mp);
3709733a808SDag-Erling Smørgrav 	mp->mnt_flag |= MNT_LOCAL;
37148c426f2SMateusz Guzik 	mp->mnt_kern_flag |= MNTK_NOMSYNC;
37215bad11fSDag-Erling Smørgrav 	MNT_IUNLOCK(mp);
37377465d93SAlfred Perlstein 	mp->mnt_data = pi;
3749733a808SDag-Erling Smørgrav 	vfs_getnewfsid(mp);
3759733a808SDag-Erling Smørgrav 
3769733a808SDag-Erling Smørgrav 	sbp = &mp->mnt_stat;
377def91cf2SPoul-Henning Kamp 	vfs_mountedfrom(mp, pi->pi_name);
3789733a808SDag-Erling Smørgrav 	sbp->f_bsize = PAGE_SIZE;
3799733a808SDag-Erling Smørgrav 	sbp->f_iosize = PAGE_SIZE;
38088a795e8SStefan Eßer 	sbp->f_blocks = 2;
38188a795e8SStefan Eßer 	sbp->f_bfree = 2;
38288a795e8SStefan Eßer 	sbp->f_bavail = 2;
38388a795e8SStefan Eßer 	sbp->f_files = 0;
3849733a808SDag-Erling Smørgrav 	sbp->f_ffree = 0;
3859733a808SDag-Erling Smørgrav 
3869733a808SDag-Erling Smørgrav 	return (0);
3879733a808SDag-Erling Smørgrav }
3889733a808SDag-Erling Smørgrav 
3899733a808SDag-Erling Smørgrav /*
390388596dfSDag-Erling Smørgrav  * Compatibility shim for old mount(2) system call
391c9ad8a67SKelly Yancey  */
392c9ad8a67SKelly Yancey int
pfs_cmount(struct mntarg * ma,void * data,uint64_t flags)393cc672d35SKirk McKusick pfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
394c9ad8a67SKelly Yancey {
395388596dfSDag-Erling Smørgrav 	int error;
396388596dfSDag-Erling Smørgrav 
397388596dfSDag-Erling Smørgrav 	error = kernel_mount(ma, flags);
398388596dfSDag-Erling Smørgrav 	return (error);
399c9ad8a67SKelly Yancey }
400c9ad8a67SKelly Yancey 
401c9ad8a67SKelly Yancey /*
4029733a808SDag-Erling Smørgrav  * Unmount a pseudofs instance
4039733a808SDag-Erling Smørgrav  */
4049733a808SDag-Erling Smørgrav int
pfs_unmount(struct mount * mp,int mntflags)405dfd233edSAttilio Rao pfs_unmount(struct mount *mp, int mntflags)
4069733a808SDag-Erling Smørgrav {
4079733a808SDag-Erling Smørgrav 	int error;
4089733a808SDag-Erling Smørgrav 
409dfd233edSAttilio Rao 	error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0,
410dfd233edSAttilio Rao 	    curthread);
4119733a808SDag-Erling Smørgrav 	return (error);
4129733a808SDag-Erling Smørgrav }
4139733a808SDag-Erling Smørgrav 
4149733a808SDag-Erling Smørgrav /*
4159733a808SDag-Erling Smørgrav  * Return a root vnode
4169733a808SDag-Erling Smørgrav  */
4179733a808SDag-Erling Smørgrav int
pfs_root(struct mount * mp,int flags,struct vnode ** vpp)418dfd233edSAttilio Rao pfs_root(struct mount *mp, int flags, struct vnode **vpp)
4199733a808SDag-Erling Smørgrav {
4209733a808SDag-Erling Smørgrav 	struct pfs_info *pi;
4219733a808SDag-Erling Smørgrav 
4229733a808SDag-Erling Smørgrav 	pi = (struct pfs_info *)mp->mnt_data;
423388596dfSDag-Erling Smørgrav 	return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID));
4249733a808SDag-Erling Smørgrav }
4259733a808SDag-Erling Smørgrav 
4269733a808SDag-Erling Smørgrav /*
4279733a808SDag-Erling Smørgrav  * Return filesystem stats
4289733a808SDag-Erling Smørgrav  */
4299733a808SDag-Erling Smørgrav int
pfs_statfs(struct mount * mp,struct statfs * sbp)430dfd233edSAttilio Rao pfs_statfs(struct mount *mp, struct statfs *sbp)
4319733a808SDag-Erling Smørgrav {
432def91cf2SPoul-Henning Kamp 	/* no-op:  always called with mp->mnt_stat */
4339733a808SDag-Erling Smørgrav 	return (0);
4349733a808SDag-Erling Smørgrav }
4359733a808SDag-Erling Smørgrav 
4369733a808SDag-Erling Smørgrav /*
4379733a808SDag-Erling Smørgrav  * Initialize a pseudofs instance
4389733a808SDag-Erling Smørgrav  */
4399733a808SDag-Erling Smørgrav int
pfs_init(struct pfs_info * pi,struct vfsconf * vfc)4409733a808SDag-Erling Smørgrav pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
4419733a808SDag-Erling Smørgrav {
44233802b9eSDag-Erling Smørgrav 	struct pfs_node *root;
44333802b9eSDag-Erling Smørgrav 	int error;
44433802b9eSDag-Erling Smørgrav 
445388596dfSDag-Erling Smørgrav 	pfs_fileno_init(pi);
446388596dfSDag-Erling Smørgrav 
4476828ba63SKonstantin Belousov 	/* set up the root directory */
448388596dfSDag-Erling Smørgrav 	root = pfs_alloc_node(pi, "/", pfstype_root);
44933802b9eSDag-Erling Smørgrav 	pi->pi_root = root;
450388596dfSDag-Erling Smørgrav 	pfs_fileno_alloc(root);
451388596dfSDag-Erling Smørgrav 	pfs_fixup_dir(root);
45233802b9eSDag-Erling Smørgrav 
45333802b9eSDag-Erling Smørgrav 	/* construct file hierarchy */
45433802b9eSDag-Erling Smørgrav 	error = (pi->pi_init)(pi, vfc);
45533802b9eSDag-Erling Smørgrav 	if (error) {
45633802b9eSDag-Erling Smørgrav 		pfs_destroy(root);
45733802b9eSDag-Erling Smørgrav 		pi->pi_root = NULL;
45833802b9eSDag-Erling Smørgrav 		return (error);
45933802b9eSDag-Erling Smørgrav 	}
46033802b9eSDag-Erling Smørgrav 
461b7004390SDag-Erling Smørgrav 	if (bootverbose)
4629733a808SDag-Erling Smørgrav 		printf("%s registered\n", pi->pi_name);
4639733a808SDag-Erling Smørgrav 	return (0);
4649733a808SDag-Erling Smørgrav }
4659733a808SDag-Erling Smørgrav 
4669733a808SDag-Erling Smørgrav /*
4679733a808SDag-Erling Smørgrav  * Destroy a pseudofs instance
4689733a808SDag-Erling Smørgrav  */
4699733a808SDag-Erling Smørgrav int
pfs_uninit(struct pfs_info * pi,struct vfsconf * vfc)4709733a808SDag-Erling Smørgrav pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
4719733a808SDag-Erling Smørgrav {
47233802b9eSDag-Erling Smørgrav 	int error;
47333802b9eSDag-Erling Smørgrav 
47433802b9eSDag-Erling Smørgrav 	pfs_destroy(pi->pi_root);
47533802b9eSDag-Erling Smørgrav 	pi->pi_root = NULL;
47615bad11fSDag-Erling Smørgrav 	pfs_fileno_uninit(pi);
477b7004390SDag-Erling Smørgrav 	if (bootverbose)
4789733a808SDag-Erling Smørgrav 		printf("%s unregistered\n", pi->pi_name);
47933802b9eSDag-Erling Smørgrav 	error = (pi->pi_uninit)(pi, vfc);
48033802b9eSDag-Erling Smørgrav 	return (error);
4819733a808SDag-Erling Smørgrav }
4829733a808SDag-Erling Smørgrav 
4839733a808SDag-Erling Smørgrav /*
4849733a808SDag-Erling Smørgrav  * Handle load / unload events
4859733a808SDag-Erling Smørgrav  */
4869733a808SDag-Erling Smørgrav static int
pfs_modevent(module_t mod,int evt,void * arg)4879733a808SDag-Erling Smørgrav pfs_modevent(module_t mod, int evt, void *arg)
4889733a808SDag-Erling Smørgrav {
4899733a808SDag-Erling Smørgrav 	switch (evt) {
4909733a808SDag-Erling Smørgrav 	case MOD_LOAD:
4919733a808SDag-Erling Smørgrav 		pfs_vncache_load();
4929733a808SDag-Erling Smørgrav 		break;
4939733a808SDag-Erling Smørgrav 	case MOD_UNLOAD:
4949733a808SDag-Erling Smørgrav 	case MOD_SHUTDOWN:
4959733a808SDag-Erling Smørgrav 		pfs_vncache_unload();
4969733a808SDag-Erling Smørgrav 		break;
4979733a808SDag-Erling Smørgrav 	default:
4983e019deaSPoul-Henning Kamp 		return EOPNOTSUPP;
4999733a808SDag-Erling Smørgrav 		break;
5009733a808SDag-Erling Smørgrav 	}
5019733a808SDag-Erling Smørgrav 	return 0;
5029733a808SDag-Erling Smørgrav }
5039733a808SDag-Erling Smørgrav 
5049733a808SDag-Erling Smørgrav /*
5059733a808SDag-Erling Smørgrav  * Module declaration
5069733a808SDag-Erling Smørgrav  */
5079733a808SDag-Erling Smørgrav static moduledata_t pseudofs_data = {
5089733a808SDag-Erling Smørgrav 	"pseudofs",
5099733a808SDag-Erling Smørgrav 	pfs_modevent,
5109733a808SDag-Erling Smørgrav 	NULL
5119733a808SDag-Erling Smørgrav };
5129733a808SDag-Erling Smørgrav DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
51398c7e22cSDag-Erling Smørgrav MODULE_VERSION(pseudofs, 1);
514