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  * 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         pfs_fileno_init(pi);
  387 
  388         /* set up the root directory */
  389         root = pfs_alloc_node(pi, "/", pfstype_root);
  390         pi->pi_root = root;
  391         pfs_fileno_alloc(root);
  392         pfs_fixup_dir(root);
  393 
  394         /* construct file hierarchy */
  395         error = (pi->pi_init)(pi, vfc);
  396         if (error) {
  397                 pfs_destroy(root);
  398                 pi->pi_root = NULL;
  399                 return (error);
  400         }
  401 
  402         if (bootverbose)
  403                 printf("%s registered\n", pi->pi_name);
  404         return (0);
  405 }
  406 
  407 /*
  408  * Destroy a pseudofs instance
  409  */
  410 int
  411 pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
  412 {
  413         int error;
  414 
  415         pfs_destroy(pi->pi_root);
  416         pi->pi_root = NULL;
  417         pfs_fileno_uninit(pi);
  418         if (bootverbose)
  419                 printf("%s unregistered\n", pi->pi_name);
  420         error = (pi->pi_uninit)(pi, vfc);
  421         return (error);
  422 }
  423 
  424 /*
  425  * Handle load / unload events
  426  */
  427 static int
  428 pfs_modevent(module_t mod, int evt, void *arg)
  429 {
  430         switch (evt) {
  431         case MOD_LOAD:
  432                 pfs_vncache_load();
  433                 break;
  434         case MOD_UNLOAD:
  435         case MOD_SHUTDOWN:
  436                 pfs_vncache_unload();
  437                 break;
  438         default:
  439                 return EOPNOTSUPP;
  440                 break;
  441         }
  442         return 0;
  443 }
  444 
  445 /*
  446  * Module declaration
  447  */
  448 static moduledata_t pseudofs_data = {
  449         "pseudofs",
  450         pfs_modevent,
  451         NULL
  452 };
  453 DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
  454 MODULE_VERSION(pseudofs, 1);

Cache object: c59257a6688f745baf7e93901a82dc2f


[ 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.