]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/fs/pseudofs/pseudofs.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / fs / pseudofs / pseudofs.c
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
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, 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 *
69 pfs_alloc_node(struct pfs_info *pi, const char *name, pfs_type_t type)
70 {
71         struct pfs_node *pn;
72
73         KASSERT(strlen(name) < PFS_NAMELEN,
74             ("%s(): node name is too long", __func__));
75
76         pn = malloc(sizeof *pn,
77             M_PFSNODES, M_WAITOK|M_ZERO);
78         mtx_init(&pn->pn_mutex, "pfs_node", NULL, MTX_DEF | MTX_DUPOK);
79         strlcpy(pn->pn_name, name, sizeof pn->pn_name);
80         pn->pn_type = type;
81         pn->pn_info = pi;
82         return (pn);
83 }
84
85 /*
86  * Add a node to a directory
87  */
88 static void
89 pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
90 {
91 #ifdef INVARIANTS
92         struct pfs_node *iter;
93 #endif
94
95         KASSERT(parent != NULL,
96             ("%s(): parent is NULL", __func__));
97         KASSERT(pn->pn_parent == NULL,
98             ("%s(): node already has a parent", __func__));
99         KASSERT(parent->pn_info != NULL,
100             ("%s(): parent has no pn_info", __func__));
101         KASSERT(parent->pn_type == pfstype_dir ||
102             parent->pn_type == pfstype_procdir ||
103             parent->pn_type == pfstype_root,
104             ("%s(): parent is not a directory", __func__));
105
106 #ifdef INVARIANTS
107         /* XXX no locking! */
108         if (pn->pn_type == pfstype_procdir)
109                 for (iter = parent; iter != NULL; iter = iter->pn_parent)
110                         KASSERT(iter->pn_type != pfstype_procdir,
111                             ("%s(): nested process directories", __func__));
112         for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
113                 KASSERT(strcmp(pn->pn_name, iter->pn_name) != 0,
114                     ("%s(): homonymous siblings", __func__));
115                 if (pn->pn_type == pfstype_procdir)
116                         KASSERT(iter->pn_type != pfstype_procdir,
117                             ("%s(): sibling process directories", __func__));
118         }
119 #endif
120
121         pn->pn_parent = parent;
122         pfs_fileno_alloc(pn);
123
124         pfs_lock(parent);
125         pn->pn_next = parent->pn_nodes;
126         if ((parent->pn_flags & PFS_PROCDEP) != 0)
127                 pn->pn_flags |= PFS_PROCDEP;
128         parent->pn_nodes = pn;
129         pfs_unlock(parent);
130 }
131
132 /*
133  * Detach a node from its aprent
134  */
135 static void
136 pfs_detach_node(struct pfs_node *pn)
137 {
138         struct pfs_node *parent = pn->pn_parent;
139         struct pfs_node **iter;
140
141         KASSERT(parent != NULL, ("%s(): node has no parent", __func__));
142         KASSERT(parent->pn_info == pn->pn_info,
143             ("%s(): parent has different pn_info", __func__));
144
145         pfs_lock(parent);
146         iter = &parent->pn_nodes;
147         while (*iter != NULL) {
148                 if (*iter == pn) {
149                         *iter = pn->pn_next;
150                         break;
151                 }
152                 iter = &(*iter)->pn_next;
153         }
154         pn->pn_parent = NULL;
155         pfs_unlock(parent);
156 }
157
158 /*
159  * Add . and .. to a directory
160  */
161 static void
162 pfs_fixup_dir(struct pfs_node *parent)
163 {
164         struct pfs_node *pn;
165
166         pn = pfs_alloc_node(parent->pn_info, ".", pfstype_this);
167         pfs_add_node(parent, pn);
168         pn = pfs_alloc_node(parent->pn_info, "..", pfstype_parent);
169         pfs_add_node(parent, pn);
170 }
171
172 /*
173  * Create a directory
174  */
175 struct pfs_node *
176 pfs_create_dir(struct pfs_node *parent, const char *name,
177                pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
178                int flags)
179 {
180         struct pfs_node *pn;
181
182         pn = pfs_alloc_node(parent->pn_info, name,
183             (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir);
184         pn->pn_attr = attr;
185         pn->pn_vis = vis;
186         pn->pn_destroy = destroy;
187         pn->pn_flags = flags;
188         pfs_add_node(parent, pn);
189         pfs_fixup_dir(pn);
190
191         return (pn);
192 }
193
194 /*
195  * Create a file
196  */
197 struct pfs_node *
198 pfs_create_file(struct pfs_node *parent, const char *name, pfs_fill_t fill,
199                 pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
200                 int flags)
201 {
202         struct pfs_node *pn;
203
204         pn = pfs_alloc_node(parent->pn_info, name, pfstype_file);
205         pn->pn_fill = fill;
206         pn->pn_attr = attr;
207         pn->pn_vis = vis;
208         pn->pn_destroy = destroy;
209         pn->pn_flags = flags;
210         pfs_add_node(parent, pn);
211
212         return (pn);
213 }
214
215 /*
216  * Create a symlink
217  */
218 struct pfs_node *
219 pfs_create_link(struct pfs_node *parent, const char *name, pfs_fill_t fill,
220                 pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
221                 int flags)
222 {
223         struct pfs_node *pn;
224
225         pn = pfs_alloc_node(parent->pn_info, name, pfstype_symlink);
226         pn->pn_fill = fill;
227         pn->pn_attr = attr;
228         pn->pn_vis = vis;
229         pn->pn_destroy = destroy;
230         pn->pn_flags = flags;
231         pfs_add_node(parent, pn);
232
233         return (pn);
234 }
235
236 /*
237  * Locate a node by name
238  */
239 struct pfs_node *
240 pfs_find_node(struct pfs_node *parent, const char *name)
241 {
242         struct pfs_node *pn;
243
244         pfs_lock(parent);
245         for (pn = parent->pn_nodes; pn != NULL; pn = pn->pn_next)
246                 if (strcmp(pn->pn_name, name) == 0)
247                         break;
248         pfs_unlock(parent);
249         return (pn);
250 }
251
252 /*
253  * Destroy a node and all its descendants.  If the node to be destroyed
254  * has a parent, the parent's mutex must be held.
255  */
256 int
257 pfs_destroy(struct pfs_node *pn)
258 {
259         struct pfs_node *iter;
260
261         KASSERT(pn != NULL,
262             ("%s(): node is NULL", __func__));
263         KASSERT(pn->pn_info != NULL,
264             ("%s(): node has no pn_info", __func__));
265
266         if (pn->pn_parent)
267                 pfs_detach_node(pn);
268
269         /* destroy children */
270         if (pn->pn_type == pfstype_dir ||
271             pn->pn_type == pfstype_procdir ||
272             pn->pn_type == pfstype_root) {
273                 pfs_lock(pn);
274                 while (pn->pn_nodes != NULL) {
275                         iter = pn->pn_nodes;
276                         pn->pn_nodes = iter->pn_next;
277                         iter->pn_parent = NULL;
278                         pfs_unlock(pn);
279                         pfs_destroy(iter);
280                         pfs_lock(pn);
281                 }
282                 pfs_unlock(pn);
283         }
284
285         /* revoke vnodes and fileno */
286         pfs_purge(pn);
287
288         /* callback to free any private resources */
289         if (pn->pn_destroy != NULL)
290                 pn_destroy(pn);
291
292         /* destroy the node */
293         pfs_fileno_free(pn);
294         mtx_destroy(&pn->pn_mutex);
295         free(pn, M_PFSNODES);
296
297         return (0);
298 }
299
300 /*
301  * Mount a pseudofs instance
302  */
303 int
304 pfs_mount(struct pfs_info *pi, struct mount *mp)
305 {
306         struct statfs *sbp;
307
308         if (mp->mnt_flag & MNT_UPDATE)
309                 return (EOPNOTSUPP);
310
311         MNT_ILOCK(mp);
312         mp->mnt_flag |= MNT_LOCAL;
313         MNT_IUNLOCK(mp);
314         mp->mnt_data = pi;
315         vfs_getnewfsid(mp);
316
317         sbp = &mp->mnt_stat;
318         vfs_mountedfrom(mp, pi->pi_name);
319         sbp->f_bsize = PAGE_SIZE;
320         sbp->f_iosize = PAGE_SIZE;
321         sbp->f_blocks = 1;
322         sbp->f_bfree = 0;
323         sbp->f_bavail = 0;
324         sbp->f_files = 1;
325         sbp->f_ffree = 0;
326
327         return (0);
328 }
329
330 /*
331  * Compatibility shim for old mount(2) system call
332  */
333 int
334 pfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
335 {
336         int error;
337
338         error = kernel_mount(ma, flags);
339         return (error);
340 }
341
342 /*
343  * Unmount a pseudofs instance
344  */
345 int
346 pfs_unmount(struct mount *mp, int mntflags)
347 {
348         int error;
349
350         error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0,
351             curthread);
352         return (error);
353 }
354
355 /*
356  * Return a root vnode
357  */
358 int
359 pfs_root(struct mount *mp, int flags, struct vnode **vpp)
360 {
361         struct pfs_info *pi;
362
363         pi = (struct pfs_info *)mp->mnt_data;
364         return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID));
365 }
366
367 /*
368  * Return filesystem stats
369  */
370 int
371 pfs_statfs(struct mount *mp, struct statfs *sbp)
372 {
373         /* no-op:  always called with mp->mnt_stat */
374         return (0);
375 }
376
377 /*
378  * Initialize a pseudofs instance
379  */
380 int
381 pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
382 {
383         struct pfs_node *root;
384         int error;
385
386         mtx_assert(&Giant, MA_OWNED);
387
388         pfs_fileno_init(pi);
389
390         /* set up the root diretory */
391         root = pfs_alloc_node(pi, "/", pfstype_root);
392         pi->pi_root = root;
393         pfs_fileno_alloc(root);
394         pfs_fixup_dir(root);
395
396         /* construct file hierarchy */
397         error = (pi->pi_init)(pi, vfc);
398         if (error) {
399                 pfs_destroy(root);
400                 pi->pi_root = NULL;
401                 return (error);
402         }
403
404         if (bootverbose)
405                 printf("%s registered\n", pi->pi_name);
406         return (0);
407 }
408
409 /*
410  * Destroy a pseudofs instance
411  */
412 int
413 pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
414 {
415         int error;
416
417         mtx_assert(&Giant, MA_OWNED);
418
419         pfs_destroy(pi->pi_root);
420         pi->pi_root = NULL;
421         pfs_fileno_uninit(pi);
422         if (bootverbose)
423                 printf("%s unregistered\n", pi->pi_name);
424         error = (pi->pi_uninit)(pi, vfc);
425         return (error);
426 }
427
428 /*
429  * Handle load / unload events
430  */
431 static int
432 pfs_modevent(module_t mod, int evt, void *arg)
433 {
434         switch (evt) {
435         case MOD_LOAD:
436                 pfs_vncache_load();
437                 break;
438         case MOD_UNLOAD:
439         case MOD_SHUTDOWN:
440                 pfs_vncache_unload();
441                 break;
442         default:
443                 return EOPNOTSUPP;
444                 break;
445         }
446         return 0;
447 }
448
449 /*
450  * Module declaration
451  */
452 static moduledata_t pseudofs_data = {
453         "pseudofs",
454         pfs_modevent,
455         NULL
456 };
457 DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
458 MODULE_VERSION(pseudofs, 1);