xref: /freebsd/sys/fs/pseudofs/pseudofs.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
1 /*-
2  * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *	$FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/mount.h>
38 #include <sys/mutex.h>
39 #include <sys/proc.h>
40 #include <sys/sbuf.h>
41 #include <sys/sysctl.h>
42 #include <sys/vnode.h>
43 
44 #include <fs/pseudofs/pseudofs.h>
45 #include <fs/pseudofs/pseudofs_internal.h>
46 
47 static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
48 
49 SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW, 0,
50     "pseudofs");
51 
52 /*
53  * Add a node to a directory
54  */
55 static int
56 _pfs_add_node(struct pfs_node *parent, struct pfs_node *node)
57 {
58 	KASSERT(parent != NULL,
59 	    (__FUNCTION__ "(): parent is NULL"));
60 	KASSERT(parent->pn_info != NULL,
61 	    (__FUNCTION__ "(): parent has no pn_info"));
62 	KASSERT(parent->pn_type == pfstype_dir ||
63 	    parent->pn_type == pfstype_procdir ||
64 	    parent->pn_type == pfstype_root,
65 	    (__FUNCTION__ "(): parent is not a directory"));
66 
67 	/* XXX should check for duplicate names etc. */
68 
69 	mtx_lock(&parent->pn_info->pi_mutex);
70 	node->pn_info = parent->pn_info;
71 	node->pn_parent = parent;
72 	node->pn_next = parent->pn_nodes;
73 	parent->pn_nodes = node;
74 	mtx_unlock(&parent->pn_info->pi_mutex);
75 
76 	return (0);
77 }
78 
79 /*
80  * Add . and .. to a directory
81  */
82 static int
83 _pfs_fixup_dir(struct pfs_node *parent)
84 {
85 	struct pfs_node *dir;
86 
87 	MALLOC(dir, struct pfs_node *, sizeof *dir,
88 	    M_PFSNODES, M_WAITOK|M_ZERO);
89 	dir->pn_name[0] = '.';
90 	dir->pn_type = pfstype_this;
91 
92 	if (_pfs_add_node(parent, dir) != 0) {
93 		FREE(dir, M_PFSNODES);
94 		return (-1);
95 	}
96 
97 	MALLOC(dir, struct pfs_node *, sizeof *dir,
98 	    M_PFSNODES, M_WAITOK|M_ZERO);
99 	dir->pn_name[0] = dir->pn_name[1] = '.';
100 	dir->pn_type = pfstype_parent;
101 
102 	if (_pfs_add_node(parent, dir) != 0) {
103 		FREE(dir, M_PFSNODES);
104 		return (-1);
105 	}
106 
107 	return (0);
108 }
109 
110 /*
111  * Create a directory
112  */
113 struct pfs_node	*
114 pfs_create_dir(struct pfs_node *parent, char *name,
115 	       pfs_attr_t attr, pfs_vis_t vis, int flags)
116 {
117 	struct pfs_node *dir;
118 
119 	KASSERT(strlen(name) < PFS_NAMELEN,
120 	    (__FUNCTION__ "(): node name is too long"));
121 
122 	MALLOC(dir, struct pfs_node *, sizeof *dir,
123 	    M_PFSNODES, M_WAITOK|M_ZERO);
124 	strcpy(dir->pn_name, name);
125 	dir->pn_type = (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir;
126 	dir->pn_attr = attr;
127 	dir->pn_vis = vis;
128 	dir->pn_flags = flags & ~PFS_PROCDEP;
129 
130 	if (_pfs_add_node(parent, dir) != 0) {
131 		FREE(dir, M_PFSNODES);
132 		return (NULL);
133 	}
134 
135 	if (_pfs_fixup_dir(dir) != 0) {
136 		pfs_destroy(dir);
137 		return (NULL);
138 	}
139 
140 	return (dir);
141 }
142 
143 /*
144  * Create a file
145  */
146 struct pfs_node	*
147 pfs_create_file(struct pfs_node *parent, char *name, pfs_fill_t fill,
148                 pfs_attr_t attr, pfs_vis_t vis, int flags)
149 {
150 	struct pfs_node *node;
151 
152 	KASSERT(strlen(name) < PFS_NAMELEN,
153 	    (__FUNCTION__ "(): node name is too long"));
154 
155 	MALLOC(node, struct pfs_node *, sizeof *node,
156 	    M_PFSNODES, M_WAITOK|M_ZERO);
157 	strcpy(node->pn_name, name);
158 	node->pn_type = pfstype_file;
159 	node->pn_func = fill;
160 	node->pn_attr = attr;
161 	node->pn_vis = vis;
162 	node->pn_flags = flags;
163 
164 	if (_pfs_add_node(parent, node) != 0) {
165 		FREE(node, M_PFSNODES);
166 		return (NULL);
167 	}
168 
169 	return (node);
170 }
171 
172 /*
173  * Create a symlink
174  */
175 struct pfs_node	*
176 pfs_create_link(struct pfs_node *parent, char *name, pfs_fill_t fill,
177                 pfs_attr_t attr, pfs_vis_t vis, int flags)
178 {
179 	struct pfs_node *node;
180 
181 	node = pfs_create_file(parent, name, fill, attr, vis, flags);
182 	if (node == NULL)
183 		return (NULL);
184 	node->pn_type = pfstype_symlink;
185 	return (node);
186 }
187 
188 /*
189  * Destroy a node or a tree of nodes
190  */
191 int
192 pfs_destroy(struct pfs_node *node)
193 {
194 	struct pfs_node *parent, *rover;
195 
196 	KASSERT(node != NULL,
197 	    (__FUNCTION__ "(): node is NULL"));
198 	KASSERT(node->pn_info != NULL,
199 	    (__FUNCTION__ "(): node has no pn_info"));
200 
201 	/* destroy children */
202 	if (node->pn_type == pfstype_dir ||
203 	    node->pn_type == pfstype_procdir ||
204 	    node->pn_type == pfstype_root)
205 		while (node->pn_nodes != NULL)
206 			pfs_destroy(node->pn_nodes);
207 
208 	/* unlink from parent */
209 	if ((parent = node->pn_parent) != NULL) {
210 		KASSERT(parent->pn_info == node->pn_info,
211 		    (__FUNCTION__ "(): parent has different pn_info"));
212 		mtx_lock(&node->pn_info->pi_mutex);
213 		if (parent->pn_nodes == node) {
214 			parent->pn_nodes = node->pn_next;
215 		} else {
216 			rover = parent->pn_nodes;
217 			while (rover->pn_next != NULL) {
218 				if (rover->pn_next == node) {
219 					rover->pn_next = node->pn_next;
220 					break;
221 				}
222 				rover = rover->pn_next;
223 			}
224 		}
225 		mtx_unlock(&node->pn_info->pi_mutex);
226 	}
227 
228 	/* revoke vnodes and release memory */
229 	pfs_disable(node);
230 	FREE(node, M_PFSNODES);
231 
232 	return (0);
233 }
234 
235 /*
236  * Mount a pseudofs instance
237  */
238 int
239 pfs_mount(struct pfs_info *pi, struct mount *mp, char *path, caddr_t data,
240 	  struct nameidata *ndp, struct thread *td)
241 {
242 	struct statfs *sbp;
243 
244 	if (mp->mnt_flag & MNT_UPDATE)
245 		return (EOPNOTSUPP);
246 
247 	mp->mnt_flag |= MNT_LOCAL;
248 	mp->mnt_data = (qaddr_t)pi;
249 	vfs_getnewfsid(mp);
250 
251 	sbp = &mp->mnt_stat;
252 	bcopy(pi->pi_name, sbp->f_mntfromname, sizeof pi->pi_name);
253 	sbp->f_bsize = PAGE_SIZE;
254 	sbp->f_iosize = PAGE_SIZE;
255 	sbp->f_blocks = 1;
256 	sbp->f_bfree = 0;
257 	sbp->f_bavail = 0;
258 	sbp->f_files = 1;
259 	sbp->f_ffree = 0;
260 
261 	return (0);
262 }
263 
264 /*
265  * Unmount a pseudofs instance
266  */
267 int
268 pfs_unmount(struct mount *mp, int mntflags, struct thread *td)
269 {
270 	struct pfs_info *pi;
271 	int error;
272 
273 	pi = (struct pfs_info *)mp->mnt_data;
274 
275 	/* XXX do stuff with pi... */
276 
277 	error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0);
278 	return (error);
279 }
280 
281 /*
282  * Return a root vnode
283  */
284 int
285 pfs_root(struct mount *mp, struct vnode **vpp)
286 {
287 	struct pfs_info *pi;
288 
289 	pi = (struct pfs_info *)mp->mnt_data;
290 	return pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID);
291 }
292 
293 /*
294  * Return filesystem stats
295  */
296 int
297 pfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
298 {
299 	bcopy(&mp->mnt_stat, sbp, sizeof *sbp);
300 	return (0);
301 }
302 
303 /*
304  * Initialize a pseudofs instance
305  */
306 int
307 pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
308 {
309 	struct pfs_node *root;
310 	int error;
311 
312 	mtx_init(&pi->pi_mutex, "pseudofs", MTX_DEF);
313 
314 	/* set up the root diretory */
315 	MALLOC(root, struct pfs_node *, sizeof *root,
316 	    M_PFSNODES, M_WAITOK|M_ZERO);
317 	root->pn_type = pfstype_root;
318 	root->pn_name[0] = '/';
319 	root->pn_info = pi;
320 	if (_pfs_fixup_dir(root) != 0) {
321 		FREE(root, M_PFSNODES);
322 		return (ENODEV); /* XXX not really the right errno */
323 	}
324 	pi->pi_root = root;
325 
326 	/* construct file hierarchy */
327 	error = (pi->pi_init)(pi, vfc);
328 	if (error) {
329 		pfs_destroy(root);
330 		pi->pi_root = NULL;
331 		mtx_destroy(&pi->pi_mutex);
332 		return (error);
333 	}
334 
335 	pfs_fileno_init(pi);
336 	if (bootverbose)
337 		printf("%s registered\n", pi->pi_name);
338 	return (0);
339 }
340 
341 /*
342  * Destroy a pseudofs instance
343  */
344 int
345 pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
346 {
347 	int error;
348 
349 	pfs_fileno_uninit(pi);
350 	pfs_destroy(pi->pi_root);
351 	pi->pi_root = NULL;
352 	mtx_destroy(&pi->pi_mutex);
353 	if (bootverbose)
354 		printf("%s unregistered\n", pi->pi_name);
355 	error = (pi->pi_uninit)(pi, vfc);
356 	return (error);
357 }
358 
359 /*
360  * Handle load / unload events
361  */
362 static int
363 pfs_modevent(module_t mod, int evt, void *arg)
364 {
365 	switch (evt) {
366 	case MOD_LOAD:
367 		pfs_fileno_load();
368 		pfs_vncache_load();
369 		break;
370 	case MOD_UNLOAD:
371 	case MOD_SHUTDOWN:
372 		pfs_vncache_unload();
373 		pfs_fileno_unload();
374 		break;
375 	default:
376 		printf("pseudofs: unexpected event type %d\n", evt);
377 		break;
378 	}
379 	return 0;
380 }
381 
382 /*
383  * Module declaration
384  */
385 static moduledata_t pseudofs_data = {
386 	"pseudofs",
387 	pfs_modevent,
388 	NULL
389 };
390 DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
391 MODULE_VERSION(pseudofs, 3);
392