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/kern_module.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-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1997 Doug Rabson
    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  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/systm.h>
   35 #include <sys/eventhandler.h>
   36 #include <sys/malloc.h>
   37 #include <sys/sysproto.h>
   38 #include <sys/sysent.h>
   39 #include <sys/proc.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/reboot.h>
   43 #include <sys/sx.h>
   44 #include <sys/module.h>
   45 #include <sys/linker.h>
   46 
   47 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
   48 
   49 struct module {
   50         TAILQ_ENTRY(module)     link;   /* chain together all modules */
   51         TAILQ_ENTRY(module)     flink;  /* all modules in a file */
   52         struct linker_file      *file;  /* file which contains this module */
   53         int                     refs;   /* reference count */
   54         int                     id;     /* unique id number */
   55         char                    *name;  /* module name */
   56         modeventhand_t          handler;        /* event handler */
   57         void                    *arg;   /* argument for handler */
   58         modspecific_t           data;   /* module specific data */
   59 };
   60 
   61 #define MOD_EVENT(mod, type)    (mod)->handler((mod), (type), (mod)->arg)
   62 
   63 static TAILQ_HEAD(modulelist, module) modules;
   64 struct sx modules_sx;
   65 static int nextid = 1;
   66 static void module_shutdown(void *, int);
   67 
   68 static int
   69 modevent_nop(module_t mod, int what, void *arg)
   70 {
   71 
   72         switch(what) {
   73         case MOD_LOAD:
   74                 return (0);
   75         case MOD_UNLOAD:
   76                 return (EBUSY);
   77         default:
   78                 return (EOPNOTSUPP);
   79         }
   80 }
   81 
   82 static void
   83 module_init(void *arg)
   84 {
   85 
   86         sx_init(&modules_sx, "module subsystem sx lock");
   87         TAILQ_INIT(&modules);
   88         EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
   89             SHUTDOWN_PRI_DEFAULT);
   90 }
   91 
   92 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL);
   93 
   94 static void
   95 module_shutdown(void *arg1, int arg2)
   96 {
   97         module_t mod;
   98 
   99         if (arg2 & RB_NOSYNC)
  100                 return;
  101         mtx_lock(&Giant);
  102         MOD_SLOCK;
  103         TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link)
  104                 MOD_EVENT(mod, MOD_SHUTDOWN);
  105         MOD_SUNLOCK;
  106         mtx_unlock(&Giant);
  107 }
  108 
  109 void
  110 module_register_init(const void *arg)
  111 {
  112         const moduledata_t *data = (const moduledata_t *)arg;
  113         int error;
  114         module_t mod;
  115 
  116         mtx_lock(&Giant);
  117         MOD_SLOCK;
  118         mod = module_lookupbyname(data->name);
  119         if (mod == NULL)
  120                 panic("module_register_init: module named %s not found\n",
  121                     data->name);
  122         MOD_SUNLOCK;
  123         error = MOD_EVENT(mod, MOD_LOAD);
  124         if (error) {
  125                 MOD_EVENT(mod, MOD_UNLOAD);
  126                 MOD_XLOCK;
  127                 module_release(mod);
  128                 MOD_XUNLOCK;
  129                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
  130                     " %d\n", data->name, (void *)data->evhand, data->priv,
  131                     error); 
  132         } else {
  133                 MOD_XLOCK;
  134                 if (mod->file) {
  135                         /*
  136                          * Once a module is successfully loaded, move
  137                          * it to the head of the module list for this
  138                          * linker file.  This resorts the list so that
  139                          * when the kernel linker iterates over the
  140                          * modules to unload them, it will unload them
  141                          * in the reverse order they were loaded.
  142                          */
  143                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  144                         TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
  145                 }
  146                 MOD_XUNLOCK;
  147         }
  148         mtx_unlock(&Giant);
  149 }
  150 
  151 int
  152 module_register(const moduledata_t *data, linker_file_t container)
  153 {
  154         size_t namelen;
  155         module_t newmod;
  156 
  157         MOD_XLOCK;
  158         newmod = module_lookupbyname(data->name);
  159         if (newmod != NULL) {
  160                 MOD_XUNLOCK;
  161                 printf("%s: cannot register %s from %s; already loaded from %s\n",
  162                     __func__, data->name, container->filename, newmod->file->filename);
  163                 return (EEXIST);
  164         }
  165         namelen = strlen(data->name) + 1;
  166         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  167         newmod->refs = 1;
  168         newmod->id = nextid++;
  169         newmod->name = (char *)(newmod + 1);
  170         strcpy(newmod->name, data->name);
  171         newmod->handler = data->evhand ? data->evhand : modevent_nop;
  172         newmod->arg = data->priv;
  173         bzero(&newmod->data, sizeof(newmod->data));
  174         TAILQ_INSERT_TAIL(&modules, newmod, link);
  175 
  176         if (container)
  177                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
  178         newmod->file = container;
  179         MOD_XUNLOCK;
  180         return (0);
  181 }
  182 
  183 void
  184 module_reference(module_t mod)
  185 {
  186 
  187         MOD_XLOCK_ASSERT;
  188 
  189         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
  190         mod->refs++;
  191 }
  192 
  193 void
  194 module_release(module_t mod)
  195 {
  196 
  197         MOD_XLOCK_ASSERT;
  198 
  199         if (mod->refs <= 0)
  200                 panic("module_release: bad reference count");
  201 
  202         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
  203 
  204         mod->refs--;
  205         if (mod->refs == 0) {
  206                 TAILQ_REMOVE(&modules, mod, link);
  207                 if (mod->file)
  208                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  209                 free(mod, M_MODULE);
  210         }
  211 }
  212 
  213 module_t
  214 module_lookupbyname(const char *name)
  215 {
  216         module_t mod;
  217         int err;
  218 
  219         MOD_LOCK_ASSERT;
  220 
  221         TAILQ_FOREACH(mod, &modules, link) {
  222                 err = strcmp(mod->name, name);
  223                 if (err == 0)
  224                         return (mod);
  225         }
  226         return (NULL);
  227 }
  228 
  229 module_t
  230 module_lookupbyid(int modid)
  231 {
  232         module_t mod;
  233 
  234         MOD_LOCK_ASSERT;
  235 
  236         TAILQ_FOREACH(mod, &modules, link)
  237                 if (mod->id == modid)
  238                         return(mod);
  239         return (NULL);
  240 }
  241 
  242 int
  243 module_quiesce(module_t mod)
  244 {
  245         int error;
  246 
  247         mtx_lock(&Giant);
  248         error = MOD_EVENT(mod, MOD_QUIESCE);
  249         mtx_unlock(&Giant);
  250         if (error == EOPNOTSUPP || error == EINVAL)
  251                 error = 0;
  252         return (error);
  253 }
  254 
  255 int
  256 module_unload(module_t mod)
  257 {
  258         int error;
  259 
  260         mtx_lock(&Giant);
  261         error = MOD_EVENT(mod, MOD_UNLOAD);
  262         mtx_unlock(&Giant);
  263         return (error);
  264 }
  265 
  266 int
  267 module_getid(module_t mod)
  268 {
  269 
  270         MOD_LOCK_ASSERT;
  271         return (mod->id);
  272 }
  273 
  274 module_t
  275 module_getfnext(module_t mod)
  276 {
  277 
  278         MOD_LOCK_ASSERT;
  279         return (TAILQ_NEXT(mod, flink));
  280 }
  281 
  282 const char *
  283 module_getname(module_t mod)
  284 {
  285 
  286         MOD_LOCK_ASSERT;
  287         return (mod->name);
  288 }
  289 
  290 void
  291 module_setspecific(module_t mod, modspecific_t *datap)
  292 {
  293 
  294         MOD_XLOCK_ASSERT;
  295         mod->data = *datap;
  296 }
  297 
  298 linker_file_t
  299 module_file(module_t mod)
  300 {
  301 
  302         return (mod->file);
  303 }
  304 
  305 /*
  306  * Syscalls.
  307  */
  308 int
  309 sys_modnext(struct thread *td, struct modnext_args *uap)
  310 {
  311         module_t mod;
  312         int error = 0;
  313 
  314         td->td_retval[0] = -1;
  315 
  316         MOD_SLOCK;
  317         if (uap->modid == 0) {
  318                 mod = TAILQ_FIRST(&modules);
  319                 if (mod)
  320                         td->td_retval[0] = mod->id;
  321                 else
  322                         error = ENOENT;
  323                 goto done2;
  324         }
  325         mod = module_lookupbyid(uap->modid);
  326         if (mod == NULL) {
  327                 error = ENOENT;
  328                 goto done2;
  329         }
  330         if (TAILQ_NEXT(mod, link))
  331                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
  332         else
  333                 td->td_retval[0] = 0;
  334 done2:
  335         MOD_SUNLOCK;
  336         return (error);
  337 }
  338 
  339 int
  340 sys_modfnext(struct thread *td, struct modfnext_args *uap)
  341 {
  342         module_t mod;
  343         int error;
  344 
  345         td->td_retval[0] = -1;
  346 
  347         MOD_SLOCK;
  348         mod = module_lookupbyid(uap->modid);
  349         if (mod == NULL) {
  350                 error = ENOENT;
  351         } else {
  352                 error = 0;
  353                 if (TAILQ_NEXT(mod, flink))
  354                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
  355                 else
  356                         td->td_retval[0] = 0;
  357         }
  358         MOD_SUNLOCK;
  359         return (error);
  360 }
  361 
  362 struct module_stat_v1 {
  363         int     version;                /* set to sizeof(struct module_stat) */
  364         char    name[MAXMODNAMEV1V2];
  365         int     refs;
  366         int     id;
  367 };
  368 
  369 struct module_stat_v2 {
  370         int     version;                /* set to sizeof(struct module_stat) */
  371         char    name[MAXMODNAMEV1V2];
  372         int     refs;
  373         int     id;
  374         modspecific_t   data;
  375 };
  376 
  377 int
  378 sys_modstat(struct thread *td, struct modstat_args *uap)
  379 {
  380         module_t mod;
  381         modspecific_t data;
  382         int error = 0;
  383         int id, namelen, refs, version;
  384         struct module_stat *stat;
  385         struct module_stat_v2 *stat_v2;
  386         char *name;
  387         bool is_v1v2;
  388 
  389         MOD_SLOCK;
  390         mod = module_lookupbyid(uap->modid);
  391         if (mod == NULL) {
  392                 MOD_SUNLOCK;
  393                 return (ENOENT);
  394         }
  395         id = mod->id;
  396         refs = mod->refs;
  397         name = mod->name;
  398         data = mod->data;
  399         MOD_SUNLOCK;
  400         stat = uap->stat;
  401 
  402         /*
  403          * Check the version of the user's structure.
  404          */
  405         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  406                 return (error);
  407         is_v1v2 = (version == sizeof(struct module_stat_v1) ||
  408             version == sizeof(struct module_stat_v2));
  409         if (!is_v1v2 && version != sizeof(struct module_stat))
  410                 return (EINVAL);
  411         namelen = strlen(mod->name) + 1;
  412         if (is_v1v2 && namelen > MAXMODNAMEV1V2)
  413                 namelen = MAXMODNAMEV1V2;
  414         else if (namelen > MAXMODNAMEV3)
  415                 namelen = MAXMODNAMEV3;
  416         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  417                 return (error);
  418 
  419         /* Extending MAXMODNAME gives an offset change for v3. */
  420         if (is_v1v2) {
  421                 stat_v2 = (struct module_stat_v2 *)stat;
  422                 if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0)
  423                         return (error);
  424                 if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0)
  425                         return (error);
  426         } else {
  427                 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  428                         return (error);
  429                 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  430                         return (error);
  431         }
  432 
  433         /*
  434          * >v1 stat includes module data.
  435          */
  436         if (version == sizeof(struct module_stat_v2)) {
  437                 if ((error = copyout(&data, &stat_v2->data,
  438                     sizeof(data))) != 0)
  439                         return (error);
  440         } else if (version == sizeof(struct module_stat)) {
  441                 if ((error = copyout(&data, &stat->data, 
  442                     sizeof(data))) != 0)
  443                         return (error);
  444         }
  445         td->td_retval[0] = 0;
  446         return (error);
  447 }
  448 
  449 int
  450 sys_modfind(struct thread *td, struct modfind_args *uap)
  451 {
  452         int error = 0;
  453         char name[MAXMODNAMEV3];
  454         module_t mod;
  455 
  456         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  457                 return (error);
  458 
  459         MOD_SLOCK;
  460         mod = module_lookupbyname(name);
  461         if (mod == NULL)
  462                 error = ENOENT;
  463         else
  464                 td->td_retval[0] = module_getid(mod);
  465         MOD_SUNLOCK;
  466         return (error);
  467 }
  468 
  469 MODULE_VERSION(kernel, __FreeBSD_version);
  470 
  471 #ifdef COMPAT_FREEBSD32
  472 #include <sys/mount.h>
  473 #include <sys/socket.h>
  474 #include <compat/freebsd32/freebsd32_util.h>
  475 #include <compat/freebsd32/freebsd32.h>
  476 #include <compat/freebsd32/freebsd32_proto.h>
  477 
  478 typedef union modspecific32 {
  479         int             intval;
  480         uint32_t        uintval;
  481         int             longval;
  482         uint32_t        ulongval;
  483 } modspecific32_t;
  484 
  485 struct module_stat32_v2 {
  486         int             version;
  487         char            name[MAXMODNAMEV1V2];
  488         int             refs;
  489         int             id;
  490         modspecific32_t data;
  491 };
  492 
  493 struct module_stat32 {
  494         int             version;
  495         char            name[MAXMODNAME];
  496         int             refs;
  497         int             id;
  498         modspecific32_t data;
  499 };
  500 
  501 int
  502 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  503 {
  504         module_t mod;
  505         modspecific32_t data32;
  506         int error = 0;
  507         int id, namelen, refs, version;
  508         struct module_stat32 *stat32;
  509         struct module_stat32_v2 *stat32_v2;
  510         char *name;
  511         bool is_v1v2;
  512 
  513         MOD_SLOCK;
  514         mod = module_lookupbyid(uap->modid);
  515         if (mod == NULL) {
  516                 MOD_SUNLOCK;
  517                 return (ENOENT);
  518         }
  519 
  520         id = mod->id;
  521         refs = mod->refs;
  522         name = mod->name;
  523         CP(mod->data, data32, intval);
  524         CP(mod->data, data32, uintval);
  525         CP(mod->data, data32, longval);
  526         CP(mod->data, data32, ulongval);
  527         MOD_SUNLOCK;
  528         stat32 = uap->stat;
  529 
  530         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  531                 return (error);
  532         is_v1v2 = (version == sizeof(struct module_stat_v1) ||
  533             version == sizeof(struct module_stat32_v2));
  534         if (!is_v1v2 && version != sizeof(struct module_stat32))
  535                 return (EINVAL);
  536         namelen = strlen(mod->name) + 1;
  537         if (is_v1v2 && namelen > MAXMODNAMEV1V2)
  538                 namelen = MAXMODNAMEV1V2;
  539         else if (namelen > MAXMODNAMEV3)
  540                 namelen = MAXMODNAMEV3;
  541         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  542                 return (error);
  543 
  544         /* Extending MAXMODNAME gives an offset change for v3. */
  545         if (is_v1v2) {
  546                 stat32_v2 = (struct module_stat32_v2 *)stat32;
  547                 if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0)
  548                         return (error);
  549                 if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0)
  550                         return (error);
  551         } else {
  552                 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  553                         return (error);
  554                 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  555                         return (error);
  556         }
  557 
  558         /*
  559          * >v1 stat includes module data.
  560          */
  561         if (version == sizeof(struct module_stat32_v2)) {
  562                 if ((error = copyout(&data32, &stat32_v2->data,
  563                     sizeof(data32))) != 0)
  564                         return (error);
  565         } else if (version == sizeof(struct module_stat32)) {
  566                 if ((error = copyout(&data32, &stat32->data,
  567                     sizeof(data32))) != 0)
  568                         return (error);
  569         }
  570         td->td_retval[0] = 0;
  571         return (error);
  572 }
  573 #endif

Cache object: 2557d0c662ad9b95178dd70467fba06b


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