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/7.3/sys/kern/kern_module.c 187554 2009-01-21 18:35:48Z jhb $");
   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 typedef TAILQ_HEAD(, module) modulelist_t;
   50 struct module {
   51         TAILQ_ENTRY(module)     link;   /* chain together all modules */
   52         TAILQ_ENTRY(module)     flink;  /* all modules in a file */
   53         struct linker_file      *file;  /* file which contains this module */
   54         int                     refs;   /* reference count */
   55         int                     id;     /* unique id number */
   56         char                    *name;  /* module name */
   57         modeventhand_t          handler;        /* event handler */
   58         void                    *arg;   /* argument for handler */
   59         modspecific_t           data;   /* module specific data */
   60 };
   61 
   62 #define MOD_EVENT(mod, type)    (mod)->handler((mod), (type), (mod)->arg)
   63 
   64 static modulelist_t modules;
   65 struct sx modules_sx;
   66 static int nextid = 1;
   67 static void module_shutdown(void *, int);
   68 
   69 static int
   70 modevent_nop(module_t mod, int what, void *arg)
   71 {
   72 
   73         switch(what) {
   74         case MOD_LOAD:
   75                 return (0);
   76         case MOD_UNLOAD:
   77                 return (EBUSY);
   78         default:
   79                 return (EOPNOTSUPP);
   80         }
   81 }
   82 
   83 static void
   84 module_init(void *arg)
   85 {
   86 
   87         sx_init(&modules_sx, "module subsystem sx lock");
   88         TAILQ_INIT(&modules);
   89         EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
   90             SHUTDOWN_PRI_DEFAULT);
   91 }
   92 
   93 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
   94 
   95 static void
   96 module_shutdown(void *arg1, int arg2)
   97 {
   98         module_t mod;
   99 
  100         if (arg2 & RB_NOSYNC)
  101                 return;
  102         mtx_lock(&Giant);
  103         MOD_SLOCK;
  104         TAILQ_FOREACH(mod, &modules, link)
  105                 MOD_EVENT(mod, MOD_SHUTDOWN);
  106         MOD_SUNLOCK;
  107         mtx_unlock(&Giant);
  108 }
  109 
  110 void
  111 module_register_init(const void *arg)
  112 {
  113         const moduledata_t *data = (const moduledata_t *)arg;
  114         int error;
  115         module_t mod;
  116 
  117         mtx_lock(&Giant);
  118         MOD_SLOCK;
  119         mod = module_lookupbyname(data->name);
  120         if (mod == NULL)
  121                 panic("module_register_init: module named %s not found\n",
  122                     data->name);
  123         MOD_SUNLOCK;
  124         error = MOD_EVENT(mod, MOD_LOAD);
  125         if (error) {
  126                 MOD_EVENT(mod, MOD_UNLOAD);
  127                 MOD_XLOCK;
  128                 module_release(mod);
  129                 MOD_XUNLOCK;
  130                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
  131                     " %d\n", data->name, (void *)data->evhand, data->priv,
  132                     error); 
  133         } else {
  134                 MOD_XLOCK;
  135                 if (mod->file) {
  136                         /*
  137                          * Once a module is succesfully loaded, move
  138                          * it to the head of the module list for this
  139                          * linker file.  This resorts the list so that
  140                          * when the kernel linker iterates over the
  141                          * modules to unload them, it will unload them
  142                          * in the reverse order they were loaded.
  143                          */
  144                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  145                         TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
  146                 }
  147                 MOD_XUNLOCK;
  148         }
  149         mtx_unlock(&Giant);
  150 }
  151 
  152 int
  153 module_register(const moduledata_t *data, linker_file_t container)
  154 {
  155         size_t namelen;
  156         module_t newmod;
  157 
  158         MOD_XLOCK;
  159         newmod = module_lookupbyname(data->name);
  160         if (newmod != NULL) {
  161                 MOD_XUNLOCK;
  162                 printf("module_register: module %s already exists!\n",
  163                     data->name);
  164                 return (EEXIST);
  165         }
  166         namelen = strlen(data->name) + 1;
  167         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  168         if (newmod == NULL) {
  169                 MOD_XUNLOCK;
  170                 return (ENOMEM);
  171         }
  172         newmod->refs = 1;
  173         newmod->id = nextid++;
  174         newmod->name = (char *)(newmod + 1);
  175         strcpy(newmod->name, data->name);
  176         newmod->handler = data->evhand ? data->evhand : modevent_nop;
  177         newmod->arg = data->priv;
  178         bzero(&newmod->data, sizeof(newmod->data));
  179         TAILQ_INSERT_TAIL(&modules, newmod, link);
  180 
  181         if (container)
  182                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
  183         newmod->file = container;
  184         MOD_XUNLOCK;
  185         return (0);
  186 }
  187 
  188 void
  189 module_reference(module_t mod)
  190 {
  191 
  192         MOD_XLOCK_ASSERT;
  193 
  194         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
  195         mod->refs++;
  196 }
  197 
  198 void
  199 module_release(module_t mod)
  200 {
  201 
  202         MOD_XLOCK_ASSERT;
  203 
  204         if (mod->refs <= 0)
  205                 panic("module_release: bad reference count");
  206 
  207         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
  208         
  209         mod->refs--;
  210         if (mod->refs == 0) {
  211                 TAILQ_REMOVE(&modules, mod, link);
  212                 if (mod->file)
  213                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  214                 free(mod, M_MODULE);
  215         }
  216 }
  217 
  218 module_t
  219 module_lookupbyname(const char *name)
  220 {
  221         module_t mod;
  222         int err;
  223 
  224         MOD_LOCK_ASSERT;
  225 
  226         TAILQ_FOREACH(mod, &modules, link) {
  227                 err = strcmp(mod->name, name);
  228                 if (err == 0)
  229                         return (mod);
  230         }
  231         return (NULL);
  232 }
  233 
  234 module_t
  235 module_lookupbyid(int modid)
  236 {
  237         module_t mod;
  238 
  239         MOD_LOCK_ASSERT;
  240 
  241         TAILQ_FOREACH(mod, &modules, link)
  242                 if (mod->id == modid)
  243                         return(mod);
  244         return (NULL);
  245 }
  246 
  247 int
  248 module_quiesce(module_t mod)
  249 {
  250         int error;
  251 
  252         mtx_lock(&Giant);
  253         error = MOD_EVENT(mod, MOD_QUIESCE);
  254         mtx_unlock(&Giant);
  255         if (error == EOPNOTSUPP || error == EINVAL)
  256                 error = 0;
  257         return (error);
  258 }
  259 
  260 int
  261 module_unload(module_t mod)
  262 {
  263         int error;
  264 
  265         mtx_lock(&Giant);
  266         error = MOD_EVENT(mod, MOD_UNLOAD);
  267         mtx_unlock(&Giant);
  268         return (error);
  269 }
  270 
  271 int
  272 module_getid(module_t mod)
  273 {
  274 
  275         MOD_LOCK_ASSERT;
  276         return (mod->id);
  277 }
  278 
  279 module_t
  280 module_getfnext(module_t mod)
  281 {
  282 
  283         MOD_LOCK_ASSERT;
  284         return (TAILQ_NEXT(mod, flink));
  285 }
  286 
  287 const char *
  288 module_getname(module_t mod)
  289 {
  290 
  291         MOD_LOCK_ASSERT;
  292         return (mod->name);
  293 }
  294 
  295 void
  296 module_setspecific(module_t mod, modspecific_t *datap)
  297 {
  298 
  299         MOD_XLOCK_ASSERT;
  300         mod->data = *datap;
  301 }
  302 
  303 linker_file_t
  304 module_file(module_t mod)
  305 {
  306 
  307         return (mod->file);
  308 }
  309 
  310 /*
  311  * Syscalls.
  312  */
  313 int
  314 modnext(struct thread *td, struct modnext_args *uap)
  315 {
  316         module_t mod;
  317         int error = 0;
  318 
  319         td->td_retval[0] = -1;
  320 
  321         MOD_SLOCK;
  322         if (uap->modid == 0) {
  323                 mod = TAILQ_FIRST(&modules);
  324                 if (mod)
  325                         td->td_retval[0] = mod->id;
  326                 else
  327                         error = ENOENT;
  328                 goto done2;
  329         }
  330         mod = module_lookupbyid(uap->modid);
  331         if (mod == NULL) {
  332                 error = ENOENT;
  333                 goto done2;
  334         }
  335         if (TAILQ_NEXT(mod, link))
  336                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
  337         else
  338                 td->td_retval[0] = 0;
  339 done2:
  340         MOD_SUNLOCK;
  341         return (error);
  342 }
  343 
  344 int
  345 modfnext(struct thread *td, struct modfnext_args *uap)
  346 {
  347         module_t mod;
  348         int error;
  349 
  350         td->td_retval[0] = -1;
  351 
  352         MOD_SLOCK;
  353         mod = module_lookupbyid(uap->modid);
  354         if (mod == NULL) {
  355                 error = ENOENT;
  356         } else {
  357                 error = 0;
  358                 if (TAILQ_NEXT(mod, flink))
  359                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
  360                 else
  361                         td->td_retval[0] = 0;
  362         }
  363         MOD_SUNLOCK;
  364         return (error);
  365 }
  366 
  367 struct module_stat_v1 {
  368         int     version;                /* set to sizeof(struct module_stat) */
  369         char    name[MAXMODNAME];
  370         int     refs;
  371         int     id;
  372 };
  373 
  374 int
  375 modstat(struct thread *td, struct modstat_args *uap)
  376 {
  377         module_t mod;
  378         modspecific_t data;
  379         int error = 0;
  380         int id, namelen, refs, version;
  381         struct module_stat *stat;
  382         char *name;
  383 
  384         MOD_SLOCK;
  385         mod = module_lookupbyid(uap->modid);
  386         if (mod == NULL) {
  387                 MOD_SUNLOCK;
  388                 return (ENOENT);
  389         }
  390         id = mod->id;
  391         refs = mod->refs;
  392         name = mod->name;
  393         data = mod->data;
  394         MOD_SUNLOCK;
  395         stat = uap->stat;
  396 
  397         /*
  398          * Check the version of the user's structure.
  399          */
  400         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  401                 return (error);
  402         if (version != sizeof(struct module_stat_v1)
  403             && version != sizeof(struct module_stat))
  404                 return (EINVAL);
  405         namelen = strlen(mod->name) + 1;
  406         if (namelen > MAXMODNAME)
  407                 namelen = MAXMODNAME;
  408         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  409                 return (error);
  410 
  411         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  412                 return (error);
  413         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  414                 return (error);
  415 
  416         /*
  417          * >v1 stat includes module data.
  418          */
  419         if (version == sizeof(struct module_stat))
  420                 if ((error = copyout(&data, &stat->data, 
  421                     sizeof(data))) != 0)
  422                         return (error);
  423         td->td_retval[0] = 0;
  424         return (error);
  425 }
  426 
  427 int
  428 modfind(struct thread *td, struct modfind_args *uap)
  429 {
  430         int error = 0;
  431         char name[MAXMODNAME];
  432         module_t mod;
  433 
  434         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  435                 return (error);
  436 
  437         MOD_SLOCK;
  438         mod = module_lookupbyname(name);
  439         if (mod == NULL)
  440                 error = ENOENT;
  441         else
  442                 td->td_retval[0] = module_getid(mod);
  443         MOD_SUNLOCK;
  444         return (error);
  445 }
  446 
  447 #ifdef COMPAT_IA32
  448 #include <sys/mount.h>
  449 #include <sys/socket.h>
  450 #include <compat/freebsd32/freebsd32_util.h>
  451 #include <compat/freebsd32/freebsd32.h>
  452 #include <compat/freebsd32/freebsd32_proto.h>
  453 
  454 typedef union modspecific32 {
  455         int             intval;
  456         u_int32_t       uintval;
  457         int             longval;
  458         u_int32_t       ulongval;
  459 } modspecific32_t;
  460 
  461 struct module_stat32 {
  462         int             version;
  463         char            name[MAXMODNAME];
  464         int             refs;
  465         int             id;
  466         modspecific32_t data;
  467 };
  468 
  469 int
  470 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  471 {
  472         module_t mod;
  473         modspecific32_t data32;
  474         int error = 0;
  475         int id, namelen, refs, version;
  476         struct module_stat32 *stat32;
  477         char *name;
  478 
  479         MOD_SLOCK;
  480         mod = module_lookupbyid(uap->modid);
  481         if (mod == NULL) {
  482                 MOD_SUNLOCK;
  483                 return (ENOENT);
  484         }
  485 
  486         id = mod->id;
  487         refs = mod->refs;
  488         name = mod->name;
  489         CP(mod->data, data32, intval);
  490         CP(mod->data, data32, uintval);
  491         CP(mod->data, data32, longval);
  492         CP(mod->data, data32, ulongval);
  493         MOD_SUNLOCK;
  494         stat32 = uap->stat;
  495 
  496         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  497                 return (error);
  498         if (version != sizeof(struct module_stat_v1)
  499             && version != sizeof(struct module_stat32))
  500                 return (EINVAL);
  501         namelen = strlen(mod->name) + 1;
  502         if (namelen > MAXMODNAME)
  503                 namelen = MAXMODNAME;
  504         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  505                 return (error);
  506 
  507         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  508                 return (error);
  509         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  510                 return (error);
  511 
  512         /*
  513          * >v1 stat includes module data.
  514          */
  515         if (version == sizeof(struct module_stat32))
  516                 if ((error = copyout(&data32, &stat32->data,
  517                     sizeof(data32))) != 0)
  518                         return (error);
  519         td->td_retval[0] = 0;
  520         return (error);
  521 }
  522 #endif

Cache object: 29b507314c43b8c2f45055793a85b0f2


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