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

Cache object: 10f599831e21befc8405d9becc95dbae


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