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 int pfs_trace;
   56 SYSCTL_INT(_vfs_pfs, OID_AUTO, trace, CTLFLAG_RW, &pfs_trace, 0,
   57     "enable tracing of pseudofs vnode operations");
   58 
   59 #if PFS_FSNAMELEN != MFSNAMELEN
   60 #error "PFS_FSNAMELEN is not equal to MFSNAMELEN"
   61 #endif
   62 
   63 /*
   64  * Allocate and initialize a node
   65  */
   66 static struct pfs_node *
   67 pfs_alloc_node(struct pfs_info *pi, const char *name, pfs_type_t type)
   68 {
   69         struct pfs_node *pn;
   70 
   71         KASSERT(strlen(name) < PFS_NAMELEN,
   72             ("%s(): node name is too long", __func__));
   73 
   74         MALLOC(pn, struct pfs_node *, sizeof *pn,
   75             M_PFSNODES, M_WAITOK|M_ZERO);
   76         mtx_init(&pn->pn_mutex, "pfs_node", NULL, MTX_DEF | MTX_DUPOK);
   77         strlcpy(pn->pn_name, name, sizeof pn->pn_name);
   78         pn->pn_type = type;
   79         pn->pn_info = pi;
   80         return (pn);
   81 }
   82 
   83 /*
   84  * Add a node to a directory
   85  */
   86 static void
   87 pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
   88 {
   89 #ifdef INVARIANTS
   90         struct pfs_node *iter;
   91 #endif
   92 
   93         KASSERT(parent != NULL,
   94             ("%s(): parent is NULL", __func__));
   95         KASSERT(pn->pn_parent == NULL,
   96             ("%s(): node already has a parent", __func__));
   97         KASSERT(parent->pn_info != NULL,
   98             ("%s(): parent has no pn_info", __func__));
   99         KASSERT(parent->pn_type == pfstype_dir ||
  100             parent->pn_type == pfstype_procdir ||
  101             parent->pn_type == pfstype_root,
  102             ("%s(): parent is not a directory", __func__));
  103 
  104 #ifdef INVARIANTS
  105         /* XXX no locking! */
  106         if (pn->pn_type == pfstype_procdir)
  107                 for (iter = parent; iter != NULL; iter = iter->pn_parent)
  108                         KASSERT(iter->pn_type != pfstype_procdir,
  109                             ("%s(): nested process directories", __func__));
  110         for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
  111                 KASSERT(strcmp(pn->pn_name, iter->pn_name) != 0,
  112                     ("%s(): homonymous siblings", __func__));
  113                 if (pn->pn_type == pfstype_procdir)
  114                         KASSERT(iter->pn_type != pfstype_procdir,
  115                             ("%s(): sibling process directories", __func__));
  116         }
  117 #endif
  118 
  119         pn->pn_parent = parent;
  120         pfs_fileno_alloc(pn);
  121 
  122         pfs_lock(parent);
  123         pn->pn_next = parent->pn_nodes;
  124         if ((parent->pn_flags & PFS_PROCDEP) != 0)
  125                 pn->pn_flags |= PFS_PROCDEP;
  126         parent->pn_nodes = pn;
  127         pfs_unlock(parent);
  128 }
  129 
  130 /*
  131  * Detach a node from its aprent
  132  */
  133 static void
  134 pfs_detach_node(struct pfs_node *pn)
  135 {
  136         struct pfs_node *parent = pn->pn_parent;
  137         struct pfs_node **iter;
  138 
  139         KASSERT(parent != NULL, ("%s(): node has no parent", __func__));
  140         KASSERT(parent->pn_info == pn->pn_info,
  141             ("%s(): parent has different pn_info", __func__));
  142 
  143         pfs_lock(parent);
  144         iter = &parent->pn_nodes;
  145         while (*iter != NULL) {
  146                 if (*iter == pn) {
  147                         *iter = pn->pn_next;
  148                         break;
  149                 }
  150                 iter = &(*iter)->pn_next;
  151         }
  152         pn->pn_parent = NULL;
  153         pfs_unlock(parent);
  154 }
  155 
  156 /*
  157  * Add . and .. to a directory
  158  */
  159 static void
  160 pfs_fixup_dir(struct pfs_node *parent)
  161 {
  162         struct pfs_node *pn;
  163 
  164         pn = pfs_alloc_node(parent->pn_info, ".", pfstype_this);
  165         pfs_add_node(parent, pn);
  166         pn = pfs_alloc_node(parent->pn_info, "..", pfstype_parent);
  167         pfs_add_node(parent, pn);
  168 }
  169 
  170 /*
  171  * Create a directory
  172  */
  173 struct pfs_node *
  174 pfs_create_dir(struct pfs_node *parent, const char *name,
  175                pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
  176                int flags)
  177 {
  178         struct pfs_node *pn;
  179 
  180         pn = pfs_alloc_node(parent->pn_info, name,
  181             (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir);
  182         pn->pn_attr = attr;
  183         pn->pn_vis = vis;
  184         pn->pn_destroy = destroy;
  185         pn->pn_flags = flags;
  186         pfs_add_node(parent, pn);
  187         pfs_fixup_dir(pn);
  188 
  189         return (pn);
  190 }
  191 
  192 /*
  193  * Create a file
  194  */
  195 struct pfs_node *
  196 pfs_create_file(struct pfs_node *parent, const char *name, pfs_fill_t fill,
  197                 pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
  198                 int flags)
  199 {
  200         struct pfs_node *pn;
  201 
  202         pn = pfs_alloc_node(parent->pn_info, name, pfstype_file);
  203         pn->pn_fill = fill;
  204         pn->pn_attr = attr;
  205         pn->pn_vis = vis;
  206         pn->pn_destroy = destroy;
  207         pn->pn_flags = flags;
  208         pfs_add_node(parent, pn);
  209 
  210         return (pn);
  211 }
  212 
  213 /*
  214  * Create a symlink
  215  */
  216 struct pfs_node *
  217 pfs_create_link(struct pfs_node *parent, const char *name, pfs_fill_t fill,
  218                 pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
  219                 int flags)
  220 {
  221         struct pfs_node *pn;
  222 
  223         pn = pfs_alloc_node(parent->pn_info, name, pfstype_symlink);
  224         pn->pn_fill = fill;
  225         pn->pn_attr = attr;
  226         pn->pn_vis = vis;
  227         pn->pn_destroy = destroy;
  228         pn->pn_flags = flags;
  229         pfs_add_node(parent, pn);
  230 
  231         return (pn);
  232 }
  233 
  234 /*
  235  * Locate a node by name
  236  */
  237 struct pfs_node *
  238 pfs_find_node(struct pfs_node *parent, const char *name)
  239 {
  240         struct pfs_node *pn;
  241 
  242         pfs_lock(parent);
  243         for (pn = parent->pn_nodes; pn != NULL; pn = pn->pn_next)
  244                 if (strcmp(pn->pn_name, name) == 0)
  245                         break;
  246         pfs_unlock(parent);
  247         return (pn);
  248 }
  249 
  250 /*
  251  * Destroy a node and all its descendants.  If the node to be destroyed
  252  * has a parent, the parent's mutex must be held.
  253  */
  254 int
  255 pfs_destroy(struct pfs_node *pn)
  256 {
  257         struct pfs_node *iter;
  258 
  259         KASSERT(pn != NULL,
  260             ("%s(): node is NULL", __func__));
  261         KASSERT(pn->pn_info != NULL,
  262             ("%s(): node has no pn_info", __func__));
  263 
  264         if (pn->pn_parent)
  265                 pfs_detach_node(pn);
  266 
  267         /* destroy children */
  268         if (pn->pn_type == pfstype_dir ||
  269             pn->pn_type == pfstype_procdir ||
  270             pn->pn_type == pfstype_root) {
  271                 pfs_lock(pn);
  272                 while (pn->pn_nodes != NULL) {
  273                         iter = pn->pn_nodes;
  274                         pn->pn_nodes = iter->pn_next;
  275                         iter->pn_parent = NULL;
  276                         pfs_unlock(pn);
  277                         pfs_destroy(iter);
  278                         pfs_lock(pn);
  279                 }
  280                 pfs_unlock(pn);
  281         }
  282 
  283         /* revoke vnodes and fileno */
  284         pfs_purge(pn);
  285 
  286         /* callback to free any private resources */
  287         if (pn->pn_destroy != NULL)
  288                 pn_destroy(pn);
  289 
  290         /* destroy the node */
  291         pfs_fileno_free(pn);
  292         mtx_destroy(&pn->pn_mutex);
  293         FREE(pn, M_PFSNODES);
  294 
  295         return (0);
  296 }
  297 
  298 /*
  299  * Mount a pseudofs instance
  300  */
  301 int
  302 pfs_mount(struct pfs_info *pi, struct mount *mp, struct thread *td)
  303 {
  304         struct statfs *sbp;
  305 
  306         if (mp->mnt_flag & MNT_UPDATE)
  307                 return (EOPNOTSUPP);
  308 
  309         MNT_ILOCK(mp);
  310         mp->mnt_flag |= MNT_LOCAL;
  311         mp->mnt_kern_flag |= MNTK_MPSAFE;
  312         MNT_IUNLOCK(mp);
  313         mp->mnt_data = (qaddr_t)pi;
  314         vfs_getnewfsid(mp);
  315 
  316         sbp = &mp->mnt_stat;
  317         vfs_mountedfrom(mp, pi->pi_name);
  318         sbp->f_bsize = PAGE_SIZE;
  319         sbp->f_iosize = PAGE_SIZE;
  320         sbp->f_blocks = 1;
  321         sbp->f_bfree = 0;
  322         sbp->f_bavail = 0;
  323         sbp->f_files = 1;
  324         sbp->f_ffree = 0;
  325 
  326         return (0);
  327 }
  328 
  329 /*
  330  * Compatibility shim for old mount(2) system call
  331  */
  332 int
  333 pfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
  334 {
  335         int error;
  336 
  337         error = kernel_mount(ma, flags);
  338         return (error);
  339 }
  340 
  341 /*
  342  * Unmount a pseudofs instance
  343  */
  344 int
  345 pfs_unmount(struct mount *mp, int mntflags, struct thread *td)
  346 {
  347         int error;
  348 
  349         error = vflush(mp, 0, (mntflags & MNT_FORCE) ?  FORCECLOSE : 0, td);
  350         return (error);
  351 }
  352 
  353 /*
  354  * Return a root vnode
  355  */
  356 int
  357 pfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
  358 {
  359         struct pfs_info *pi;
  360 
  361         pi = (struct pfs_info *)mp->mnt_data;
  362         return (pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID));
  363 }
  364 
  365 /*
  366  * Return filesystem stats
  367  */
  368 int
  369 pfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
  370 {
  371         /* no-op:  always called with mp->mnt_stat */
  372         return (0);
  373 }
  374 
  375 /*
  376  * Initialize a pseudofs instance
  377  */
  378 int
  379 pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
  380 {
  381         struct pfs_node *root;
  382         int error;
  383 
  384         mtx_assert(&Giant, MA_OWNED);
  385 
  386         pfs_fileno_init(pi);
  387 
  388         /* set up the root diretory */
  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         mtx_assert(&Giant, MA_OWNED);
  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: 200ff7fee6ca48ddf3311df8b574e914


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