1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2001 Dag-Erling Smørgrav
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 #include "opt_pseudofs.h"
33
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/mount.h>
41 #include <sys/mutex.h>
42 #include <sys/proc.h>
43 #include <sys/sbuf.h>
44 #include <sys/sysctl.h>
45 #include <sys/vnode.h>
46
47 #include <fs/pseudofs/pseudofs.h>
48 #include <fs/pseudofs/pseudofs_internal.h>
49
50 static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
51
52 SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
53 "pseudofs");
54
55 #ifdef PSEUDOFS_TRACE
56 int pfs_trace;
57 SYSCTL_INT(_vfs_pfs, OID_AUTO, trace, CTLFLAG_RW, &pfs_trace, 0,
58 "enable tracing of pseudofs vnode operations");
59 #endif
60
61 #if PFS_FSNAMELEN != MFSNAMELEN
62 #error "PFS_FSNAMELEN is not equal to MFSNAMELEN"
63 #endif
64
65 /*
66 * Allocate and initialize a node
67 */
68 static struct pfs_node *
pfs_alloc_node_flags(struct pfs_info * pi,const char * name,pfs_type_t type,int flags)69 pfs_alloc_node_flags(struct pfs_info *pi, const char *name, pfs_type_t type, int flags)
70 {
71 struct pfs_node *pn;
72 int malloc_flags;
73 size_t len;
74
75 len = strlen(name);
76 KASSERT(len < PFS_NAMELEN,
77 ("%s(): node name is too long", __func__));
78 if (flags & PFS_NOWAIT)
79 malloc_flags = M_NOWAIT | M_ZERO;
80 else
81 malloc_flags = M_WAITOK | M_ZERO;
82 pn = malloc(sizeof(*pn) + len + 1, M_PFSNODES, malloc_flags);
83 if (pn == NULL)
84 return (NULL);
85 mtx_init(&pn->pn_mutex, "pfs_node", NULL, MTX_DEF | MTX_DUPOK);
86 memcpy(pn->pn_name, name, len);
87 pn->pn_type = type;
88 pn->pn_info = pi;
89 return (pn);
90 }
91
92 static struct pfs_node *
pfs_alloc_node(struct pfs_info * pi,const char * name,pfs_type_t type)93 pfs_alloc_node(struct pfs_info *pi, const char *name, pfs_type_t type)
94 {
95 return (pfs_alloc_node_flags(pi, name, type, 0));
96 }
97
98 /*
99 * Add a node to a directory
100 */
101 static int
pfs_add_node(struct pfs_node * parent,struct pfs_node * pn)102 pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
103 {
104 struct pfs_node *iter;
105
106 KASSERT(parent != NULL,
107 ("%s(): parent is NULL", __func__));
108 KASSERT(pn->pn_parent == NULL,
109 ("%s(): node already has a parent", __func__));
110 KASSERT(parent->pn_info != NULL,
111 ("%s(): parent has no pn_info", __func__));
112 KASSERT(parent->pn_type == pfstype_dir ||
113 parent->pn_type == pfstype_procdir ||
114 parent->pn_type == pfstype_root,
115 ("%s(): parent is not a directory", __func__));
116
117 #ifdef INVARIANTS
118 /* XXX no locking! */
119 if (pn->pn_type == pfstype_procdir)
120 for (iter = parent; iter != NULL; iter = iter->pn_parent)
121 KASSERT(iter->pn_type != pfstype_procdir,
122 ("%s(): nested process directories", __func__));
123 for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
124 if (pn->pn_type == pfstype_procdir)
125 KASSERT(iter->pn_type != pfstype_procdir,
126 ("%s(): sibling process directories", __func__));
127 }
128 #endif
129
130 pn->pn_parent = parent;
131 pfs_fileno_alloc(pn);
132 pfs_lock(parent);
133 for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
134 if (strcmp(pn->pn_name, iter->pn_name) != 0)
135 continue;
136 printf("pfs_add_node: homonymous siblings: '%s/%s' type %d\n",
137 parent->pn_name, pn->pn_name, pn->pn_type);
138 /* Do not detach, because we are not yet attached. */
139 pn->pn_parent = NULL;
140 pfs_unlock(parent);
141 return (EEXIST);
142 }
143
144
145 if ((parent->pn_flags & PFS_PROCDEP) != 0)
146 pn->pn_flags |= PFS_PROCDEP;
147 if (parent->pn_nodes == NULL) {
148 KASSERT(parent->pn_last_node == NULL,
149 ("%s(): pn_last_node not NULL", __func__));
150 parent->pn_nodes = pn;
151 parent->pn_last_node = pn;
152 } else {
153 KASSERT(parent->pn_last_node != NULL,
154 ("%s(): pn_last_node is NULL", __func__));
155 KASSERT(parent->pn_last_node->pn_next == NULL,
156 ("%s(): pn_last_node->pn_next not NULL", __func__));
157 parent->pn_last_node->pn_next = pn;
158 parent->pn_last_node = pn;
159 }
160 pfs_unlock(parent);
161 return (0);
162 }
163
164 /*
165 * Detach a node from its parent
166 */
167 static void
pfs_detach_node(struct pfs_node * pn)168 pfs_detach_node(struct pfs_node *pn)
169 {
170 struct pfs_node *node, *parent = pn->pn_parent;
171 struct pfs_node **iter;
172
173 KASSERT(parent != NULL, ("%s(): node has no parent", __func__));
174 KASSERT(parent->pn_info == pn->pn_info,
175 ("%s(): parent has different pn_info", __func__));
176
177 pfs_lock(parent);
178 if (pn == parent->pn_last_node) {
179 if (pn == pn->pn_nodes) {
180 parent->pn_last_node = NULL;
181 } else {
182 for (node = parent->pn_nodes;
183 node->pn_next != pn; node = node->pn_next)
184 continue;
185 parent->pn_last_node = node;
186 }
187 }
188 iter = &parent->pn_nodes;
189 while (*iter != NULL) {
190 if (*iter == pn) {
191 *iter = pn->pn_next;
192 break;
193 }
194 iter = &(*iter)->pn_next;
195 }
196 pn->pn_parent = NULL;
197 pfs_unlock(parent);
198 }
199
200 /*
201 * Add . and .. to a directory
202 */
203 static int
pfs_fixup_dir_flags(struct pfs_node * parent,int flags)204 pfs_fixup_dir_flags(struct pfs_node *parent, int flags)
205 {
206 struct pfs_node *dot, *dotdot;
207 int rc;
208
209 dot = pfs_alloc_node_flags(parent->pn_info, ".", pfstype_this, flags);
210 if (dot == NULL)
211 return (ENOMEM);
212 dotdot = pfs_alloc_node_flags(parent->pn_info, "..", pfstype_parent, flags);
213 if (dotdot == NULL) {
214 pfs_destroy(dot);
215 return (ENOMEM);
216 }
217 rc = pfs_add_node(parent, dot);
218 if (rc == 0)
219 rc = pfs_add_node(parent, dotdot);
220 if (rc != 0) {
221 pfs_destroy(dot);
222 pfs_destroy(dotdot);
223 }
224 return (rc);
225 }
226
227 static void
pfs_fixup_dir(struct pfs_node * parent)228 pfs_fixup_dir(struct pfs_node *parent)
229 {
230
231 pfs_fixup_dir_flags(parent, 0);
232 }
233
234 /*
235 * Create a directory
236 */
237 int
pfs_create_dir(struct pfs_node * parent,struct pfs_node ** opn,const char * name,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)238 pfs_create_dir(struct pfs_node *parent, struct pfs_node **opn,
239 const char *name, pfs_attr_t attr, pfs_vis_t vis,
240 pfs_destroy_t destroy, int flags)
241 {
242 struct pfs_node *pdir, *pn;
243 int rc;
244
245 /* Preserve in case the caller is reusing the one pointer for both. */
246 pdir = parent;
247 if (opn != NULL)
248 *opn = NULL;
249 pn = pfs_alloc_node_flags(pdir->pn_info, name,
250 (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir, flags);
251 if (pn == NULL)
252 return (ENOMEM);
253 pn->pn_attr = attr;
254 pn->pn_vis = vis;
255 pn->pn_destroy = destroy;
256 pn->pn_flags = flags;
257 rc = pfs_add_node(pdir, pn);
258 if (rc == 0)
259 rc = pfs_fixup_dir_flags(pn, flags);
260 if (rc != 0) {
261 pfs_destroy(pn);
262 pn = NULL;
263 } else if (opn != NULL) {
264 *opn = pn;
265 }
266
267 return (rc);
268 }
269
270 /*
271 * Create a file
272 */
273 int
pfs_create_file(struct pfs_node * parent,struct pfs_node ** opn,const char * name,pfs_fill_t fill,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)274 pfs_create_file(struct pfs_node *parent, struct pfs_node **opn,
275 const char *name, pfs_fill_t fill, pfs_attr_t attr,
276 pfs_vis_t vis, pfs_destroy_t destroy, int flags)
277 {
278 struct pfs_node *pn;
279 int rc;
280
281 if (opn != NULL)
282 *opn = NULL;
283 pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_file, flags);
284 if (pn == NULL)
285 return (ENOMEM);
286
287 pn->pn_fill = fill;
288 pn->pn_attr = attr;
289 pn->pn_vis = vis;
290 pn->pn_destroy = destroy;
291 pn->pn_flags = flags;
292 if ((rc = pfs_add_node(parent, pn)) != 0) {
293 pfs_destroy(pn);
294 pn = NULL;
295 } else if (opn != NULL) {
296 *opn = pn;
297 }
298
299 return (rc);
300 }
301
302 /*
303 * Create a symlink
304 */
305 int
pfs_create_link(struct pfs_node * parent,struct pfs_node ** opn,const char * name,pfs_fill_t fill,pfs_attr_t attr,pfs_vis_t vis,pfs_destroy_t destroy,int flags)306 pfs_create_link(struct pfs_node *parent, struct pfs_node **opn,
307 const char *name, pfs_fill_t fill, pfs_attr_t attr,
308 pfs_vis_t vis, pfs_destroy_t destroy, int flags)
309 {
310 struct pfs_node *pn;
311 int rc;
312
313 if (opn != NULL)
314 *opn = NULL;
315 pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_symlink, flags);
316 if (pn == NULL)
317 return (ENOMEM);
318
319 pn->pn_fill = fill;
320 pn->pn_attr = attr;
321 pn->pn_vis = vis;
322 pn->pn_destroy = destroy;
323 pn->pn_flags = flags;
324 if ((rc = pfs_add_node(parent, pn)) != 0) {
325 pfs_destroy(pn);
326 pn = NULL;
327 } else if (opn != NULL) {
328 *opn = pn;
329 }
330
331 return (rc);
332 }
333
334 /*
335 * Locate a node by name
336 */
337 struct pfs_node *
pfs_find_node(struct pfs_node * parent,const char * name)338 pfs_find_node(struct pfs_node *parent, const char *name)
339 {
340 struct pfs_node *pn;
341
342 pfs_lock(parent);
343 for (pn = parent->pn_nodes; pn != NULL; pn = pn->pn_next)
344 if (strcmp(pn->pn_name, name) == 0)
345 break;
346 pfs_unlock(parent);
347 return (pn);
348 }
349
350 /*
351 * Destroy a node and all its descendants. If the node to be destroyed
352 * has a parent, the parent's mutex must be held.
353 */
354 int
pfs_destroy(struct pfs_node * pn)355 pfs_destroy(struct pfs_node *pn)
356 {
357 struct pfs_node *iter;
358
359 KASSERT(pn != NULL,
360 ("%s(): node is NULL", __func__));
361 KASSERT(pn->pn_info != NULL,
362 ("%s(): node has no pn_info", __func__));
363
364 if (pn->pn_parent)
365 pfs_detach_node(pn);
366
367 /* destroy children */
368 if (pn->pn_type == pfstype_dir ||
369 pn->pn_type == pfstype_procdir ||
370 pn->pn_type == pfstype_root) {
371 pfs_lock(pn);
372 while (pn->pn_nodes != NULL) {
373 iter = pn->pn_nodes;
374 pn->pn_nodes = iter->pn_next;
375 iter->pn_parent = NULL;
376 pfs_unlock(pn);
377 pfs_destroy(iter);
378 pfs_lock(pn);
379 }
380 pfs_unlock(pn);
381 }
382
383 /* revoke vnodes and fileno */
384 pfs_purge(pn);
385
386 /* callback to free any private resources */
387 if (pn->pn_destroy != NULL)
388 pn_destroy(pn);
389
390 /* destroy the node */
391 pfs_fileno_free(pn);
392 mtx_destroy(&pn->pn_mutex);
393 free(pn, M_PFSNODES);
394
395 return (0);
396 }
397
398 /*
399 * Mount a pseudofs instance
400 */
401 int
pfs_mount(struct pfs_info * pi,struct mount * mp)402 pfs_mount(struct pfs_info *pi, struct mount *mp)
403 {
404 struct statfs *sbp;
405
406 if (mp->mnt_flag & MNT_UPDATE)
407 return (EOPNOTSUPP);
408
409 MNT_ILOCK(mp);
410 mp->mnt_flag |= MNT_LOCAL;
411 mp->mnt_kern_flag |= MNTK_NOMSYNC;
412 MNT_IUNLOCK(mp);
413 mp->mnt_data = pi;
414 vfs_getnewfsid(mp);
415
416 sbp = &mp->mnt_stat;
417 vfs_mountedfrom(mp, pi->pi_name);
418 sbp->f_bsize = PAGE_SIZE;
419 sbp->f_iosize = PAGE_SIZE;
420 sbp->f_blocks = 2;
421 sbp->f_bfree = 2;
422 sbp->f_bavail = 2;
423 sbp->f_files = 0;
424 sbp->f_ffree = 0;
425
426 return (0);
427 }
428
429 /*
430 * Compatibility shim for old mount(2) system call
431 */
432 int
pfs_cmount(struct mntarg * ma,void * data,uint64_t flags)433 pfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
434 {
435 int error;
436
437 error = kernel_mount(ma, flags);
438 return (error);
439 }
440
441 /*
442 * Unmount a pseudofs instance
443 */
444 int
pfs_unmount(struct mount * mp,int mntflags)445 pfs_unmount(struct mount *mp, int mntflags)
446 {
447 int error;
448
449 error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0,
450 curthread);
451 return (error);
452 }
453
454 /*
455 * Return a root vnode
456 */
457 int
pfs_root(struct mount * mp,int flags,struct vnode ** vpp)458 pfs_root(struct mount *mp, int flags, struct vnode **vpp)
459 {
460 struct pfs_info *pi;
461
462 pi = (struct pfs_info *)mp->mnt_data;
463 return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID));
464 }
465
466 /*
467 * Return filesystem stats
468 */
469 int
pfs_statfs(struct mount * mp,struct statfs * sbp)470 pfs_statfs(struct mount *mp, struct statfs *sbp)
471 {
472 /* no-op: always called with mp->mnt_stat */
473 return (0);
474 }
475
476 /*
477 * Initialize a pseudofs instance
478 */
479 int
pfs_init(struct pfs_info * pi,struct vfsconf * vfc)480 pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
481 {
482 struct pfs_node *root;
483 int error;
484
485 pfs_fileno_init(pi);
486
487 /* set up the root directory */
488 root = pfs_alloc_node(pi, "/", pfstype_root);
489 pi->pi_root = root;
490 pfs_fileno_alloc(root);
491 pfs_fixup_dir(root);
492
493 /* construct file hierarchy */
494 error = (pi->pi_init)(pi, vfc);
495 if (error) {
496 pfs_destroy(root);
497 pi->pi_root = NULL;
498 pfs_fileno_uninit(pi);
499 return (error);
500 }
501
502 if (bootverbose)
503 printf("%s registered\n", pi->pi_name);
504 return (0);
505 }
506
507 /*
508 * Destroy a pseudofs instance
509 */
510 int
pfs_uninit(struct pfs_info * pi,struct vfsconf * vfc)511 pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
512 {
513 int error;
514
515 pfs_destroy(pi->pi_root);
516 pi->pi_root = NULL;
517 pfs_fileno_uninit(pi);
518 if (bootverbose)
519 printf("%s unregistered\n", pi->pi_name);
520 error = (pi->pi_uninit)(pi, vfc);
521 return (error);
522 }
523
524 /*
525 * Handle load / unload events
526 */
527 static int
pfs_modevent(module_t mod,int evt,void * arg)528 pfs_modevent(module_t mod, int evt, void *arg)
529 {
530 switch (evt) {
531 case MOD_LOAD:
532 pfs_vncache_load();
533 break;
534 case MOD_UNLOAD:
535 case MOD_SHUTDOWN:
536 pfs_vncache_unload();
537 break;
538 default:
539 return EOPNOTSUPP;
540 break;
541 }
542 return 0;
543 }
544
545 /*
546 * Module declaration
547 */
548 static moduledata_t pseudofs_data = {
549 "pseudofs",
550 pfs_modevent,
551 NULL
552 };
553 DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
554 MODULE_VERSION(pseudofs, 1);
555