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  * Copyright (c) 1997 Doug Rabson
    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  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include "opt_compat.h"
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/9.1/sys/kern/kern_module.c 225617 2011-09-16 13:58:51Z kmacy $");
   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, 0);
   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 succesfully 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("module_register: module %s already exists!\n",
  162                     data->name);
  163                 return (EEXIST);
  164         }
  165         namelen = strlen(data->name) + 1;
  166         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  167         if (newmod == NULL) {
  168                 MOD_XUNLOCK;
  169                 return (ENOMEM);
  170         }
  171         newmod->refs = 1;
  172         newmod->id = nextid++;
  173         newmod->name = (char *)(newmod + 1);
  174         strcpy(newmod->name, data->name);
  175         newmod->handler = data->evhand ? data->evhand : modevent_nop;
  176         newmod->arg = data->priv;
  177         bzero(&newmod->data, sizeof(newmod->data));
  178         TAILQ_INSERT_TAIL(&modules, newmod, link);
  179 
  180         if (container)
  181                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
  182         newmod->file = container;
  183         MOD_XUNLOCK;
  184         return (0);
  185 }
  186 
  187 void
  188 module_reference(module_t mod)
  189 {
  190 
  191         MOD_XLOCK_ASSERT;
  192 
  193         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
  194         mod->refs++;
  195 }
  196 
  197 void
  198 module_release(module_t mod)
  199 {
  200 
  201         MOD_XLOCK_ASSERT;
  202 
  203         if (mod->refs <= 0)
  204                 panic("module_release: bad reference count");
  205 
  206         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
  207         
  208         mod->refs--;
  209         if (mod->refs == 0) {
  210                 TAILQ_REMOVE(&modules, mod, link);
  211                 if (mod->file)
  212                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  213                 free(mod, M_MODULE);
  214         }
  215 }
  216 
  217 module_t
  218 module_lookupbyname(const char *name)
  219 {
  220         module_t mod;
  221         int err;
  222 
  223         MOD_LOCK_ASSERT;
  224 
  225         TAILQ_FOREACH(mod, &modules, link) {
  226                 err = strcmp(mod->name, name);
  227                 if (err == 0)
  228                         return (mod);
  229         }
  230         return (NULL);
  231 }
  232 
  233 module_t
  234 module_lookupbyid(int modid)
  235 {
  236         module_t mod;
  237 
  238         MOD_LOCK_ASSERT;
  239 
  240         TAILQ_FOREACH(mod, &modules, link)
  241                 if (mod->id == modid)
  242                         return(mod);
  243         return (NULL);
  244 }
  245 
  246 int
  247 module_quiesce(module_t mod)
  248 {
  249         int error;
  250 
  251         mtx_lock(&Giant);
  252         error = MOD_EVENT(mod, MOD_QUIESCE);
  253         mtx_unlock(&Giant);
  254         if (error == EOPNOTSUPP || error == EINVAL)
  255                 error = 0;
  256         return (error);
  257 }
  258 
  259 int
  260 module_unload(module_t mod)
  261 {
  262         int error;
  263 
  264         mtx_lock(&Giant);
  265         error = MOD_EVENT(mod, MOD_UNLOAD);
  266         mtx_unlock(&Giant);
  267         return (error);
  268 }
  269 
  270 int
  271 module_getid(module_t mod)
  272 {
  273 
  274         MOD_LOCK_ASSERT;
  275         return (mod->id);
  276 }
  277 
  278 module_t
  279 module_getfnext(module_t mod)
  280 {
  281 
  282         MOD_LOCK_ASSERT;
  283         return (TAILQ_NEXT(mod, flink));
  284 }
  285 
  286 const char *
  287 module_getname(module_t mod)
  288 {
  289 
  290         MOD_LOCK_ASSERT;
  291         return (mod->name);
  292 }
  293 
  294 void
  295 module_setspecific(module_t mod, modspecific_t *datap)
  296 {
  297 
  298         MOD_XLOCK_ASSERT;
  299         mod->data = *datap;
  300 }
  301 
  302 linker_file_t
  303 module_file(module_t mod)
  304 {
  305 
  306         return (mod->file);
  307 }
  308 
  309 /*
  310  * Syscalls.
  311  */
  312 int
  313 sys_modnext(struct thread *td, struct modnext_args *uap)
  314 {
  315         module_t mod;
  316         int error = 0;
  317 
  318         td->td_retval[0] = -1;
  319 
  320         MOD_SLOCK;
  321         if (uap->modid == 0) {
  322                 mod = TAILQ_FIRST(&modules);
  323                 if (mod)
  324                         td->td_retval[0] = mod->id;
  325                 else
  326                         error = ENOENT;
  327                 goto done2;
  328         }
  329         mod = module_lookupbyid(uap->modid);
  330         if (mod == NULL) {
  331                 error = ENOENT;
  332                 goto done2;
  333         }
  334         if (TAILQ_NEXT(mod, link))
  335                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
  336         else
  337                 td->td_retval[0] = 0;
  338 done2:
  339         MOD_SUNLOCK;
  340         return (error);
  341 }
  342 
  343 int
  344 sys_modfnext(struct thread *td, struct modfnext_args *uap)
  345 {
  346         module_t mod;
  347         int error;
  348 
  349         td->td_retval[0] = -1;
  350 
  351         MOD_SLOCK;
  352         mod = module_lookupbyid(uap->modid);
  353         if (mod == NULL) {
  354                 error = ENOENT;
  355         } else {
  356                 error = 0;
  357                 if (TAILQ_NEXT(mod, flink))
  358                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
  359                 else
  360                         td->td_retval[0] = 0;
  361         }
  362         MOD_SUNLOCK;
  363         return (error);
  364 }
  365 
  366 struct module_stat_v1 {
  367         int     version;                /* set to sizeof(struct module_stat) */
  368         char    name[MAXMODNAME];
  369         int     refs;
  370         int     id;
  371 };
  372 
  373 int
  374 sys_modstat(struct thread *td, struct modstat_args *uap)
  375 {
  376         module_t mod;
  377         modspecific_t data;
  378         int error = 0;
  379         int id, namelen, refs, version;
  380         struct module_stat *stat;
  381         char *name;
  382 
  383         MOD_SLOCK;
  384         mod = module_lookupbyid(uap->modid);
  385         if (mod == NULL) {
  386                 MOD_SUNLOCK;
  387                 return (ENOENT);
  388         }
  389         id = mod->id;
  390         refs = mod->refs;
  391         name = mod->name;
  392         data = mod->data;
  393         MOD_SUNLOCK;
  394         stat = uap->stat;
  395 
  396         /*
  397          * Check the version of the user's structure.
  398          */
  399         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  400                 return (error);
  401         if (version != sizeof(struct module_stat_v1)
  402             && version != sizeof(struct module_stat))
  403                 return (EINVAL);
  404         namelen = strlen(mod->name) + 1;
  405         if (namelen > MAXMODNAME)
  406                 namelen = MAXMODNAME;
  407         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  408                 return (error);
  409 
  410         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  411                 return (error);
  412         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  413                 return (error);
  414 
  415         /*
  416          * >v1 stat includes module data.
  417          */
  418         if (version == sizeof(struct module_stat))
  419                 if ((error = copyout(&data, &stat->data, 
  420                     sizeof(data))) != 0)
  421                         return (error);
  422         td->td_retval[0] = 0;
  423         return (error);
  424 }
  425 
  426 int
  427 sys_modfind(struct thread *td, struct modfind_args *uap)
  428 {
  429         int error = 0;
  430         char name[MAXMODNAME];
  431         module_t mod;
  432 
  433         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  434                 return (error);
  435 
  436         MOD_SLOCK;
  437         mod = module_lookupbyname(name);
  438         if (mod == NULL)
  439                 error = ENOENT;
  440         else
  441                 td->td_retval[0] = module_getid(mod);
  442         MOD_SUNLOCK;
  443         return (error);
  444 }
  445 
  446 MODULE_VERSION(kernel, __FreeBSD_version);
  447 
  448 #ifdef COMPAT_FREEBSD32
  449 #include <sys/mount.h>
  450 #include <sys/socket.h>
  451 #include <compat/freebsd32/freebsd32_util.h>
  452 #include <compat/freebsd32/freebsd32.h>
  453 #include <compat/freebsd32/freebsd32_proto.h>
  454 
  455 typedef union modspecific32 {
  456         int             intval;
  457         uint32_t        uintval;
  458         int             longval;
  459         uint32_t        ulongval;
  460 } modspecific32_t;
  461 
  462 struct module_stat32 {
  463         int             version;
  464         char            name[MAXMODNAME];
  465         int             refs;
  466         int             id;
  467         modspecific32_t data;
  468 };
  469 
  470 int
  471 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  472 {
  473         module_t mod;
  474         modspecific32_t data32;
  475         int error = 0;
  476         int id, namelen, refs, version;
  477         struct module_stat32 *stat32;
  478         char *name;
  479 
  480         MOD_SLOCK;
  481         mod = module_lookupbyid(uap->modid);
  482         if (mod == NULL) {
  483                 MOD_SUNLOCK;
  484                 return (ENOENT);
  485         }
  486 
  487         id = mod->id;
  488         refs = mod->refs;
  489         name = mod->name;
  490         CP(mod->data, data32, intval);
  491         CP(mod->data, data32, uintval);
  492         CP(mod->data, data32, longval);
  493         CP(mod->data, data32, ulongval);
  494         MOD_SUNLOCK;
  495         stat32 = uap->stat;
  496 
  497         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  498                 return (error);
  499         if (version != sizeof(struct module_stat_v1)
  500             && version != sizeof(struct module_stat32))
  501                 return (EINVAL);
  502         namelen = strlen(mod->name) + 1;
  503         if (namelen > MAXMODNAME)
  504                 namelen = MAXMODNAME;
  505         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  506                 return (error);
  507 
  508         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  509                 return (error);
  510         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  511                 return (error);
  512 
  513         /*
  514          * >v1 stat includes module data.
  515          */
  516         if (version == sizeof(struct module_stat32))
  517                 if ((error = copyout(&data32, &stat32->data,
  518                     sizeof(data32))) != 0)
  519                         return (error);
  520         td->td_retval[0] = 0;
  521         return (error);
  522 }
  523 #endif

Cache object: 801da027012ae22dabc6c1e71c15c0ca


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