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

Cache object: 1a98ea5dfb59f317235ffc677e66e3cd


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