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 /*
    2  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
    3  * 
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Matthew Dillon <dillon@backplane.com>
    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  * 
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of The DragonFly Project nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific, prior written permission.
   20  * 
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *
   35  * Copyright (c) 1989, 1993
   36  *      The Regents of the University of California.  All rights reserved.
   37  *
   38  * This code is derived from software contributed
   39  * to Berkeley by John Heidemann of the UCLA Ficus project.
   40  *
   41  * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  * 3. Neither the name of the University nor the names of its contributors
   52  *    may be used to endorse or promote products derived from this software
   53  *    without specific prior written permission.
   54  *
   55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   65  * SUCH DAMAGE.
   66  *
   67  *      @(#)vfs_init.c  8.3 (Berkeley) 1/4/94
   68  * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $
   69  * $DragonFly: src/sys/kern/vfs_init.c,v 1.15 2008/06/01 19:27:35 dillon Exp $
   70  */
   71 /*
   72  * Manage vnode VOP operations vectors
   73  */
   74 #include <sys/param.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/mount.h>
   78 #include <sys/sysctl.h>
   79 #include <sys/vnode.h>
   80 #include <sys/malloc.h>
   81 #include <sys/objcache.h>
   82 
   83 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
   84 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
   85 
   86 /*
   87  * Zone for namei
   88  */
   89 struct objcache *namei_oc;
   90 
   91 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
   92 static void vfs_calc_vnodeops(struct vop_ops *ops);
   93 
   94 
   95 /*
   96  * Add a vnode operations (vnops) vector to the global list.
   97  */
   98 void
   99 vfs_nadd_vnodeops_sysinit(void *data)
  100 {
  101         struct vop_ops *ops = data;
  102 
  103         vfs_add_vnodeops(NULL, ops, NULL);      /* mount, template, newcopy */
  104 }
  105 
  106 /*
  107  * Unlink previously added vnode operations vector.
  108  */
  109 void
  110 vfs_nrm_vnodeops_sysinit(void *data)
  111 {
  112         struct vop_ops *ops = data;
  113 
  114         vfs_rm_vnodeops(NULL, ops, NULL);
  115 }
  116 
  117 void
  118 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
  119                  struct vop_ops **ops_pp)
  120 {
  121         struct vop_ops *ops;
  122 
  123         if (ops_pp) {
  124                 KKASSERT(*ops_pp == NULL);
  125                 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
  126                 ops = *ops_pp;
  127                 bcopy(template, ops, sizeof(*ops));
  128         } else {
  129                 ops = template;
  130         }
  131 
  132         vfs_calc_vnodeops(ops);
  133         ops->head.vv_mount = mp;
  134 
  135         if (mp) {
  136                 if (mp->mnt_vn_coherency_ops)
  137                         mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
  138                 else if (mp->mnt_vn_journal_ops)
  139                         mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
  140                 else
  141                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
  142         }
  143 }
  144 
  145 /*
  146  * Remove a previously installed operations vector.
  147  *
  148  * NOTE: Either template or ops_pp may be NULL, but not both.
  149  */
  150 void
  151 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
  152                 struct vop_ops **ops_pp)
  153 {
  154         struct vop_ops *ops;
  155 
  156         if (ops_pp) {
  157                 ops = *ops_pp;
  158                 *ops_pp = NULL;
  159         } else {
  160                 ops = template;
  161         }
  162         if (ops == NULL)
  163                 return;
  164         KKASSERT(mp == ops->head.vv_mount);
  165         if (mp) {
  166                 if (mp->mnt_vn_coherency_ops)
  167                         mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
  168                 else if (mp->mnt_vn_journal_ops)
  169                         mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
  170                 else
  171                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
  172         }
  173         if (ops_pp)
  174                 kfree(ops, M_VNODEOP);
  175 }
  176 
  177 /*
  178  * Calculate the VFS operations vector array.  This function basically
  179  * replaces any NULL entry with the default entry.
  180  */
  181 static void
  182 vfs_calc_vnodeops(struct vop_ops *ops)
  183 {
  184         int off;
  185 
  186         for (off = __offsetof(struct vop_ops, vop_ops_first_field);
  187              off <= __offsetof(struct vop_ops, vop_ops_last_field);
  188              off += sizeof(void *)
  189         ) {
  190                 if (*(void **)((char *)ops + off) == NULL)
  191                     *(void **)((char *)ops + off) = ops->vop_default;
  192         }
  193 }
  194 
  195 /*
  196  * Routines having to do with the management of the vnode table.
  197  */
  198 struct vattr va_null;
  199 
  200 /*
  201  * Initialize the vnode structures and initialize each file system type.
  202  */
  203 /* ARGSUSED*/
  204 static void
  205 vfsinit(void *dummy)
  206 {
  207         TAILQ_INIT(&vnodeopv_list);
  208         namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
  209 
  210         /*
  211          * Initialize the vnode table
  212          */
  213         vfs_subr_init();
  214         vfs_mount_init();
  215         vfs_lock_init();
  216 
  217         /*
  218          * Initialize the vnode name cache
  219          */
  220         nchinit();
  221 
  222         /*
  223          * Initialize each file system type.
  224          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
  225          */
  226         vattr_null(&va_null);
  227 }
  228 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
  229 
  230 /*
  231  * vfsconf related functions/data.
  232  */
  233 
  234 /* highest defined filesystem type */
  235 static int vfsconf_maxtypenum = VFS_GENERIC + 1; 
  236 
  237 /* head of list of filesystem types */
  238 static STAILQ_HEAD(, vfsconf) vfsconf_list = 
  239         STAILQ_HEAD_INITIALIZER(vfsconf_list);
  240 
  241 struct vfsconf *
  242 vfsconf_find_by_name(const char *name) 
  243 {
  244         struct vfsconf *vfsp;
  245 
  246         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
  247                 if (strcmp(name, vfsp->vfc_name) == 0)
  248                         break;
  249         }
  250         return vfsp;
  251 }
  252 
  253 struct vfsconf *
  254 vfsconf_find_by_typenum(int typenum) 
  255 {
  256         struct vfsconf *vfsp;
  257 
  258         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
  259                 if (typenum == vfsp->vfc_typenum)
  260                         break;
  261         }
  262         return vfsp;
  263 }
  264 
  265 static void
  266 vfsconf_add(struct vfsconf *vfc)
  267 {
  268         vfc->vfc_typenum = vfsconf_maxtypenum++;
  269         STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next);
  270 }
  271 
  272 static void
  273 vfsconf_remove(struct vfsconf *vfc)
  274 {
  275         int maxtypenum;
  276 
  277         STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next); 
  278 
  279         maxtypenum = VFS_GENERIC;
  280         STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) {
  281                 if (maxtypenum < vfc->vfc_typenum)
  282                         maxtypenum = vfc->vfc_typenum;
  283         }
  284         vfsconf_maxtypenum = maxtypenum + 1;
  285 }
  286 
  287 int
  288 vfsconf_get_maxtypenum(void)
  289 {
  290         return vfsconf_maxtypenum;
  291 }
  292 
  293 /*
  294  * Iterate over all vfsconf entries. Break out of the iterator
  295  * by returning != 0.
  296  */
  297 int
  298 vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data)
  299 {
  300         int error;
  301         struct vfsconf *vfsp;
  302 
  303         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
  304                 error = iter(vfsp, data);
  305                 if (error)
  306                         return (error);
  307         }
  308         return (0);
  309 }
  310 
  311 /*
  312  * Register a VFS.
  313  *
  314  * After doing general initialisation, this function will
  315  * call the filesystem specific initialisation vector op,
  316  * i.e. vfsops->vfs_init().
  317  */
  318 int
  319 vfs_register(struct vfsconf *vfc)
  320 {
  321         struct sysctl_oid *oidp;
  322         struct vfsops *vfsops = NULL;
  323 
  324         if (vfsconf_find_by_name(vfc->vfc_name) != NULL)
  325                 return EEXIST;
  326 
  327         vfsconf_add(vfc);
  328 
  329         /*
  330          * If this filesystem has a sysctl node under vfs
  331          * (i.e. vfs.xxfs), then change the oid number of that node to 
  332          * match the filesystem's type number.  This allows user code
  333          * which uses the type number to read sysctl variables defined
  334          * by the filesystem to continue working. Since the oids are
  335          * in a sorted list, we need to make sure the order is
  336          * preserved by re-registering the oid after modifying its
  337          * number.
  338          */
  339         SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
  340                 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
  341                         sysctl_unregister_oid(oidp);
  342                         oidp->oid_number = vfc->vfc_typenum;
  343                         sysctl_register_oid(oidp);
  344                 }
  345         
  346         /*
  347          * Initialise unused fields in the file system's vfsops vector.
  348          *
  349          * NOTE the file system should provide the mount and unmount ops
  350          * at the least.  In order for unmount to succeed, we also need
  351          * the file system to provide us with vfsops->vfs_root otherwise
  352          * the unmount(2) operation will not succeed.
  353          */
  354         vfsops = vfc->vfc_vfsops;
  355         KKASSERT(vfc->vfc_vfsops != NULL);
  356         KKASSERT(vfsops->vfs_mount != NULL);
  357         KKASSERT(vfsops->vfs_root != NULL);
  358         KKASSERT(vfsops->vfs_unmount != NULL);
  359 
  360         if (vfsops->vfs_root == NULL) {
  361                 /* return file system's root vnode */
  362                 vfsops->vfs_root = vfs_stdroot;
  363         }
  364         if (vfsops->vfs_start == NULL) {
  365                 /* 
  366                  * Make file system operational before first use.  This
  367                  * routine is called at mount-time for initialising MFS,
  368                  * not used by other file systems.
  369                  */
  370                 vfsops->vfs_start = vfs_stdstart;
  371         }
  372         if (vfsops->vfs_quotactl == NULL) {
  373                 /* quota control */
  374                 vfsops->vfs_quotactl = vfs_stdquotactl;
  375         }
  376         if (vfsops->vfs_statfs == NULL) {
  377                 /* return file system's status */
  378                 vfsops->vfs_statfs = vfs_stdstatfs;
  379         }
  380         if (vfsops->vfs_statvfs == NULL) {
  381                 /* return file system's status */
  382                 vfsops->vfs_statvfs = vfs_stdstatvfs;
  383         }
  384         if (vfsops->vfs_sync == NULL) {
  385                 /*
  386                  * Flush dirty buffers.  File systems can use vfs_stdsync()
  387                  * by explicitly setting it in the vfsops->vfs_sync vector
  388                  * entry.
  389                  */
  390                 vfsops->vfs_sync = vfs_stdnosync;
  391         }
  392         if (vfsops->vfs_vget == NULL) {
  393                 /* convert an inode number to a vnode */
  394                 vfsops->vfs_vget = vfs_stdvget;
  395         }
  396         if (vfsops->vfs_fhtovp == NULL) {
  397                 /* turn an NFS file handle into a vnode */
  398                 vfsops->vfs_fhtovp = vfs_stdfhtovp;
  399         }
  400         if (vfsops->vfs_checkexp == NULL) {
  401                 /* check if file system is exported */
  402                 vfsops->vfs_checkexp = vfs_stdcheckexp;
  403         }
  404         if (vfsops->vfs_vptofh == NULL) {
  405                 /* turn a vnode into an NFS file handle */
  406                 vfsops->vfs_vptofh = vfs_stdvptofh;
  407         }
  408         if (vfsops->vfs_init == NULL) {
  409                 /* file system specific initialisation */
  410                 vfsops->vfs_init = vfs_stdinit;
  411         }
  412         if (vfsops->vfs_uninit == NULL) {
  413                 /* file system specific uninitialisation */
  414                 vfsops->vfs_uninit = vfs_stduninit;
  415         }
  416         if (vfsops->vfs_extattrctl == NULL) {
  417                 /* extended attribute control */
  418                 vfsops->vfs_extattrctl = vfs_stdextattrctl;
  419         }
  420 
  421         if (vfsops->vfs_ncpgen_set == NULL) {
  422                 /* namecache generation number */
  423                 vfsops->vfs_ncpgen_set = vfs_stdncpgen_set;
  424         }
  425 
  426         if (vfsops->vfs_ncpgen_test == NULL) {
  427                 /* check namecache generation */
  428                 vfsops->vfs_ncpgen_test = vfs_stdncpgen_test;
  429         }
  430 
  431         /* VFS quota uid and gid accounting */
  432         if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) {
  433                 vfsops->vfs_acinit = vfs_stdac_init;
  434         }
  435         if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) {
  436                 vfsops->vfs_acdone = vfs_stdac_done;
  437         }
  438 
  439         /*
  440          * Call init function for this VFS...
  441          */
  442         vfs_init(vfc);
  443         return 0;
  444 }
  445 
  446 
  447 /*
  448  * Remove previously registered VFS.
  449  *
  450  * After doing general de-registration like removing sysctl
  451  * nodes etc, it will call the filesystem specific vector
  452  * op, i.e. vfsops->vfs_uninit().
  453  * 
  454  */
  455 int
  456 vfs_unregister(struct vfsconf *vfc)
  457 {
  458         struct vfsconf *vfsp;
  459         int error;
  460 
  461         vfsp = vfsconf_find_by_name(vfc->vfc_name);
  462 
  463         if (vfsp == NULL)
  464                 return EINVAL;
  465 
  466         if (vfsp->vfc_refcount != 0)
  467                 return EBUSY;
  468 
  469         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
  470                 error = vfs_uninit(vfc, vfsp);
  471                 if (error)
  472                         return (error);
  473         }
  474 
  475         vfsconf_remove(vfsp);
  476         return 0;
  477 }
  478 
  479 int
  480 vfs_modevent(module_t mod, int type, void *data)
  481 {
  482         struct vfsconf *vfc;
  483         int error = 0;
  484 
  485         vfc = (struct vfsconf *)data;
  486 
  487         switch (type) {
  488         case MOD_LOAD:
  489                 if (vfc)
  490                         error = vfs_register(vfc);
  491                 break;
  492 
  493         case MOD_UNLOAD:
  494                 if (vfc)
  495                         error = vfs_unregister(vfc);
  496                 break;
  497         default:        /* including MOD_SHUTDOWN */
  498                 break;
  499         }
  500         return (error);
  501 }

Cache object: acfef049ba77b9ff97e645c1f6cfe3c6


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