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/kern/vfs_init.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 /*      $NetBSD: vfs_init.c,v 1.59 2022/11/18 00:10:03 riastradh Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Copyright (c) 1989, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * This code is derived from software contributed
   38  * to Berkeley by John Heidemann of the UCLA Ficus project.
   39  *
   40  * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice, this list of conditions and the following disclaimer.
   47  * 2. Redistributions in binary form must reproduce the above copyright
   48  *    notice, this list of conditions and the following disclaimer in the
   49  *    documentation and/or other materials provided with the distribution.
   50  * 3. Neither the name of the University nor the names of its contributors
   51  *    may be used to endorse or promote products derived from this software
   52  *    without specific prior written permission.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   64  * SUCH DAMAGE.
   65  *
   66  *      @(#)vfs_init.c  8.5 (Berkeley) 5/11/95
   67  */
   68 
   69 #include <sys/cdefs.h>
   70 __KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.59 2022/11/18 00:10:03 riastradh Exp $");
   71 
   72 #include <sys/param.h>
   73 #include <sys/mount.h>
   74 #include <sys/time.h>
   75 #include <sys/vnode.h>
   76 #include <sys/stat.h>
   77 #include <sys/namei.h>
   78 #include <sys/ucred.h>
   79 #include <sys/buf.h>
   80 #include <sys/errno.h>
   81 #include <sys/kmem.h>
   82 #include <sys/systm.h>
   83 #include <sys/module.h>
   84 #include <sys/dirhash.h>
   85 #include <sys/sysctl.h>
   86 #include <sys/kauth.h>
   87 
   88 #include <miscfs/deadfs/deadfs.h>
   89 #include <miscfs/fifofs/fifo.h>
   90 #include <miscfs/specfs/specdev.h>
   91 
   92 /*
   93  * Sigh, such primitive tools are these...
   94  */
   95 #if 0
   96 #define DODEBUG(A) A
   97 #else
   98 #define DODEBUG(A)
   99 #endif
  100 
  101 pool_cache_t pnbuf_cache;
  102 
  103 /*
  104  * These vnodeopv_descs are listed here because they are not
  105  * associated with any particular file system, and thus cannot
  106  * be initialized by vfs_attach().
  107  */
  108 const struct vnodeopv_desc * const vfs_special_vnodeopv_descs[] = {
  109         &dead_vnodeop_opv_desc,
  110         &fifo_vnodeop_opv_desc,
  111         &spec_vnodeop_opv_desc,
  112         NULL,
  113 };
  114 
  115 struct vfs_list_head vfs_list =                 /* vfs list */
  116     LIST_HEAD_INITIALIZER(vfs_list);
  117 
  118 static kauth_listener_t mount_listener;
  119 
  120 /*
  121  * This code doesn't work if the defn is **vnodop_defns with cc.
  122  * The problem is because of the compiler sometimes putting in an
  123  * extra level of indirection for arrays.  It's an interesting
  124  * "feature" of C.
  125  */
  126 typedef int (*PFI)(void *);
  127 
  128 /*
  129  * A miscellaneous routine.
  130  * A generic "default" routine that just returns an error.
  131  */
  132 /*ARGSUSED*/
  133 int
  134 vn_default_error(void *v)
  135 {
  136 
  137         return (EOPNOTSUPP);
  138 }
  139 
  140 static struct sysctllog *vfs_sysctllog;
  141 
  142 /*
  143  * Top level filesystem related information gathering.
  144  */
  145 static void
  146 sysctl_vfs_setup(void)
  147 {
  148 
  149         sysctl_createv(&vfs_sysctllog, 0, NULL, NULL,
  150                        CTLFLAG_PERMANENT,
  151                        CTLTYPE_NODE, "generic",
  152                        SYSCTL_DESCR("Non-specific vfs related information"),
  153                        NULL, 0, NULL, 0,
  154                        CTL_VFS, VFS_GENERIC, CTL_EOL);
  155         sysctl_createv(&vfs_sysctllog, 0, NULL, NULL,
  156                        CTLFLAG_PERMANENT,
  157                        CTLTYPE_STRING, "fstypes",
  158                        SYSCTL_DESCR("List of file systems present"),
  159                        sysctl_vfs_generic_fstypes, 0, NULL, 0,
  160                        CTL_VFS, VFS_GENERIC, CTL_CREATE, CTL_EOL);
  161         sysctl_createv(&vfs_sysctllog, 0, NULL, NULL,
  162                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  163                        CTLTYPE_INT, "magiclinks",
  164                        SYSCTL_DESCR("Whether \"magic\" symlinks are expanded"),
  165                        NULL, 0, &vfs_magiclinks, 0,
  166                        CTL_VFS, VFS_GENERIC, VFS_MAGICLINKS, CTL_EOL);
  167         sysctl_createv(&vfs_sysctllog, 0, NULL, NULL,
  168                         CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  169                         CTLTYPE_INT, "timestamp_precision",
  170                         SYSCTL_DESCR("File timestamp precision"),
  171                         NULL, 0, &vfs_timestamp_precision, 0,
  172                         CTL_VFS, VFS_GENERIC, VFS_TIMESTAMP_PRECISION,
  173                         CTL_EOL);
  174 }
  175 
  176 
  177 /*
  178  * vfs_init.c
  179  *
  180  * Allocate and fill in operations vectors.
  181  *
  182  * An undocumented feature of this approach to defining operations is that
  183  * there can be multiple entries in vfs_opv_descs for the same operations
  184  * vector. This allows third parties to extend the set of operations
  185  * supported by another layer in a binary compatibile way. For example,
  186  * assume that NFS needed to be modified to support Ficus. NFS has an entry
  187  * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
  188  * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
  189  * listing those new operations Ficus adds to NFS, all without modifying the
  190  * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
  191  * that is a(whole)nother story.) This is a feature.
  192  */
  193 
  194 /*
  195  * Init the vector, if it needs it.
  196  * Also handle backwards compatibility.
  197  */
  198 static void
  199 vfs_opv_init_explicit(const struct vnodeopv_desc *vfs_opv_desc)
  200 {
  201         int (**opv_desc_vector)(void *);
  202         const struct vnodeopv_entry_desc *opve_descp;
  203 
  204         opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p);
  205 
  206         for (opve_descp = vfs_opv_desc->opv_desc_ops;
  207              opve_descp->opve_op;
  208              opve_descp++) {
  209                 /*
  210                  * Sanity check:  is this operation listed
  211                  * in the list of operations?  We check this
  212                  * by seeing if its offset is zero.  Since
  213                  * the default routine should always be listed
  214                  * first, it should be the only one with a zero
  215                  * offset.  Any other operation with a zero
  216                  * offset is probably not listed in
  217                  * vfs_op_descs, and so is probably an error.
  218                  *
  219                  * A panic here means the layer programmer
  220                  * has committed the all-too common bug
  221                  * of adding a new operation to the layer's
  222                  * list of vnode operations but
  223                  * not adding the operation to the system-wide
  224                  * list of supported operations.
  225                  */
  226                 if (opve_descp->opve_op->vdesc_offset == 0 &&
  227                     opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
  228                         printf("operation %s not listed in %s.\n",
  229                             opve_descp->opve_op->vdesc_name, "vfs_op_descs");
  230                         panic ("vfs_opv_init: bad operation");
  231                 }
  232 
  233                 /*
  234                  * Fill in this entry.
  235                  */
  236                 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
  237                     opve_descp->opve_impl;
  238         }
  239 }
  240 
  241 static void
  242 vfs_opv_init_default(const struct vnodeopv_desc *vfs_opv_desc)
  243 {
  244         int j;
  245         int (**opv_desc_vector)(void *);
  246 
  247         opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p);
  248 
  249         /*
  250          * Force every operations vector to have a default routine.
  251          */
  252         if (opv_desc_vector[VOFFSET(vop_default)] == NULL)
  253                 panic("vfs_opv_init: operation vector without default routine.");
  254 
  255         for (j = 0; j < VNODE_OPS_COUNT; j++)
  256                 if (opv_desc_vector[j] == NULL)
  257                         opv_desc_vector[j] =
  258                             opv_desc_vector[VOFFSET(vop_default)];
  259 }
  260 
  261 void
  262 vfs_opv_init(const struct vnodeopv_desc * const *vopvdpp)
  263 {
  264         int (**opv_desc_vector)(void *);
  265         int i;
  266 
  267         /*
  268          * Allocate the vectors.
  269          */
  270         for (i = 0; vopvdpp[i] != NULL; i++) {
  271                 opv_desc_vector =
  272                     kmem_alloc(VNODE_OPS_COUNT * sizeof(PFI), KM_SLEEP);
  273                 memset(opv_desc_vector, 0, VNODE_OPS_COUNT * sizeof(PFI));
  274                 *(vopvdpp[i]->opv_desc_vector_p) = opv_desc_vector;
  275                 DODEBUG(printf("vector at %p allocated\n",
  276                     opv_desc_vector_p));
  277         }
  278 
  279         /*
  280          * ...and fill them in.
  281          */
  282         for (i = 0; vopvdpp[i] != NULL; i++)
  283                 vfs_opv_init_explicit(vopvdpp[i]);
  284 
  285         /*
  286          * Finally, go back and replace unfilled routines
  287          * with their default.
  288          */
  289         for (i = 0; vopvdpp[i] != NULL; i++)
  290                 vfs_opv_init_default(vopvdpp[i]);
  291 }
  292 
  293 void
  294 vfs_opv_free(const struct vnodeopv_desc * const *vopvdpp)
  295 {
  296         int i;
  297 
  298         /*
  299          * Free the vectors allocated in vfs_opv_init().
  300          */
  301         for (i = 0; vopvdpp[i] != NULL; i++) {
  302                 kmem_free(*(vopvdpp[i]->opv_desc_vector_p),
  303                     VNODE_OPS_COUNT * sizeof(PFI));
  304                 *(vopvdpp[i]->opv_desc_vector_p) = NULL;
  305         }
  306 }
  307 
  308 #ifdef DEBUG
  309 static void
  310 vfs_op_check(void)
  311 {
  312         int i;
  313 
  314         DODEBUG(printf("Vnode_interface_init.\n"));
  315 
  316         /*
  317          * Check offset of each op.
  318          */
  319         for (i = 0; vfs_op_descs[i]; i++) {
  320                 if (vfs_op_descs[i]->vdesc_offset != i)
  321                         panic("vfs_op_check: vfs_op_desc[] offset mismatch");
  322         }
  323 
  324         if (i != VNODE_OPS_COUNT) {
  325                 panic("vfs_op_check: vnode ops count mismatch (%d != %d)",
  326                         i, VNODE_OPS_COUNT);
  327         }
  328 
  329         DODEBUG(printf ("vfs_opv_numops=%d\n", VNODE_OPS_COUNT));
  330 }
  331 #endif /* DEBUG */
  332 
  333 /*
  334  * Common routine to check if an unprivileged mount is allowed.
  335  *
  336  * We export just this part (i.e., without the access control) so that if a
  337  * secmodel wants to implement finer grained user mounts it can do so without
  338  * copying too much code. More elaborate policies (i.e., specific users allowed
  339  * to also create devices and/or introduce set-id binaries, or export
  340  * file-systems) will require a different implementation.
  341  *
  342  * This routine is intended to be called from listener context, and as such
  343  * does not take credentials as an argument.
  344  */
  345 int
  346 usermount_common_policy(struct mount *mp, u_long flags)
  347 {
  348 
  349         /* No exporting if unprivileged. */
  350         if (flags & MNT_EXPORTED)
  351                 return EPERM;
  352 
  353         /* Must have 'nosuid' and 'nodev'. */
  354         if ((flags & MNT_NODEV) == 0 || (flags & MNT_NOSUID) == 0)
  355                 return EPERM;
  356 
  357         /* Retain 'noexec'. */
  358         if ((mp->mnt_flag & MNT_NOEXEC) && (flags & MNT_NOEXEC) == 0)
  359                 return EPERM;
  360 
  361         return 0;
  362 }
  363 
  364 static int
  365 mount_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
  366     void *arg0, void *arg1, void *arg2, void *arg3)
  367 {
  368         int result;
  369         enum kauth_system_req req;
  370 
  371         result = KAUTH_RESULT_DEFER;
  372         req = (enum kauth_system_req)(uintptr_t)(uintptr_t)arg0;
  373 
  374         if (action != KAUTH_SYSTEM_MOUNT)
  375                 return result;
  376 
  377         if (req == KAUTH_REQ_SYSTEM_MOUNT_GET)
  378                 result = KAUTH_RESULT_ALLOW;
  379         else if (req == KAUTH_REQ_SYSTEM_MOUNT_DEVICE) {
  380                 vnode_t *devvp = arg2;
  381                 accmode_t accmode = (accmode_t)(unsigned long)arg3;
  382                 int error;
  383 
  384                 error = VOP_ACCESS(devvp, accmode, cred);
  385                 if (!error)
  386                         result = KAUTH_RESULT_ALLOW;
  387         }
  388 
  389         return result;
  390 }
  391 
  392 /*
  393  * Initialize the vnode structures and initialize each file system type.
  394  */
  395 void
  396 vfsinit(void)
  397 {
  398 
  399         /*
  400          * Attach sysctl nodes
  401          */
  402         sysctl_vfs_setup();
  403 
  404         /*
  405          * Initialize the namei pathname buffer pool and cache.
  406          */
  407         pnbuf_cache = pool_cache_init(MAXPATHLEN, 0, 0, 0, "pnbufpl",
  408             NULL, IPL_NONE, NULL, NULL, NULL);
  409         KASSERT(pnbuf_cache != NULL);
  410 
  411         /*
  412          * Initialize the vnode table
  413          */
  414         vntblinit();
  415 
  416         /*
  417          * Initialize the vnode name cache
  418          */
  419         nchinit();
  420 
  421 #ifdef DEBUG
  422         /*
  423          * Check the list of vnode operations.
  424          */
  425         vfs_op_check();
  426 #endif
  427 
  428         /*
  429          * Initialize the special vnode operations.
  430          */
  431         vfs_opv_init(vfs_special_vnodeopv_descs);
  432 
  433         /*
  434          * Initialise generic dirhash.
  435          */
  436         dirhash_init();
  437 
  438         /*
  439          * Initialise VFS hooks.
  440          */
  441         vfs_hooks_init();
  442 
  443         mount_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
  444             mount_listener_cb, NULL);
  445 
  446         /*
  447          * Establish each file system which was statically
  448          * included in the kernel.
  449          */
  450         module_init_class(MODULE_CLASS_VFS);
  451 
  452         /*
  453          * Initialize EVFILT_FS for kqueue.
  454          */
  455         vfs_evfilt_fs_init();
  456 }
  457 
  458 /*
  459  * Drop a reference to a file system type.
  460  */
  461 void
  462 vfs_delref(struct vfsops *vfs)
  463 {
  464 
  465         mutex_enter(&vfs_list_lock);
  466         vfs->vfs_refcount--;
  467         mutex_exit(&vfs_list_lock);
  468 }
  469 
  470 /*
  471  * Establish a file system and initialize it.
  472  */
  473 int
  474 vfs_attach(struct vfsops *vfs)
  475 {
  476         struct vfsops *v;
  477         int error = 0;
  478 
  479         mutex_enter(&vfs_list_lock);
  480 
  481         /*
  482          * Make sure this file system doesn't already exist.
  483          */
  484         LIST_FOREACH(v, &vfs_list, vfs_list) {
  485                 if (strcmp(vfs->vfs_name, v->vfs_name) == 0) {
  486                         error = EEXIST;
  487                         goto out;
  488                 }
  489         }
  490 
  491         /*
  492          * Initialize the vnode operations for this file system.
  493          */
  494         vfs_opv_init(vfs->vfs_opv_descs);
  495 
  496         /*
  497          * Now initialize the file system itself.
  498          */
  499         (*vfs->vfs_init)();
  500 
  501         /*
  502          * ...and link it into the kernel's list.
  503          */
  504         LIST_INSERT_HEAD(&vfs_list, vfs, vfs_list);
  505 
  506         /*
  507          * Sanity: make sure the reference count is 0.
  508          */
  509         vfs->vfs_refcount = 0;
  510  out:
  511         mutex_exit(&vfs_list_lock);
  512         return (error);
  513 }
  514 
  515 /*
  516  * Remove a file system from the kernel.
  517  */
  518 int
  519 vfs_detach(struct vfsops *vfs)
  520 {
  521         struct vfsops *v;
  522         int error = 0;
  523 
  524         mutex_enter(&vfs_list_lock);
  525 
  526         /*
  527          * Make sure no one is using the filesystem.
  528          */
  529         if (vfs->vfs_refcount != 0) {
  530                 error = EBUSY;
  531                 goto out;
  532         }
  533 
  534         /*
  535          * ...and remove it from the kernel's list.
  536          */
  537         LIST_FOREACH(v, &vfs_list, vfs_list) {
  538                 if (v == vfs) {
  539                         LIST_REMOVE(v, vfs_list);
  540                         break;
  541                 }
  542         }
  543 
  544         if (v == NULL) {
  545                 error = ESRCH;
  546                 goto out;
  547         }
  548 
  549         /*
  550          * Now run the file system-specific cleanups.
  551          */
  552         (*vfs->vfs_done)();
  553 
  554         /*
  555          * Free the vnode operations vector.
  556          */
  557         vfs_opv_free(vfs->vfs_opv_descs);
  558  out:
  559         mutex_exit(&vfs_list_lock);
  560         return (error);
  561 }
  562 
  563 void
  564 vfs_reinit(void)
  565 {
  566         struct vfsops *vfs;
  567 
  568         mutex_enter(&vfs_list_lock);
  569         LIST_FOREACH(vfs, &vfs_list, vfs_list) {
  570                 if (vfs->vfs_reinit) {
  571                         vfs->vfs_refcount++;
  572                         mutex_exit(&vfs_list_lock);
  573                         (*vfs->vfs_reinit)();
  574                         mutex_enter(&vfs_list_lock);
  575                         vfs->vfs_refcount--;
  576                 }
  577         }
  578         mutex_exit(&vfs_list_lock);
  579 }

Cache object: ea703520a64c3f64306a052ea5ab1f34


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