The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/pseudofs/pseudofs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ddcad9d5b363ace000885828a792e966


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.