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$");
   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 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[MAXMODNAME];
  365         int     refs;
  366         int     id;
  367 };
  368 
  369 int
  370 sys_modstat(struct thread *td, struct modstat_args *uap)
  371 {
  372         module_t mod;
  373         modspecific_t data;
  374         int error = 0;
  375         int id, namelen, refs, version;
  376         struct module_stat *stat;
  377         char *name;
  378 
  379         MOD_SLOCK;
  380         mod = module_lookupbyid(uap->modid);
  381         if (mod == NULL) {
  382                 MOD_SUNLOCK;
  383                 return (ENOENT);
  384         }
  385         id = mod->id;
  386         refs = mod->refs;
  387         name = mod->name;
  388         data = mod->data;
  389         MOD_SUNLOCK;
  390         stat = uap->stat;
  391 
  392         /*
  393          * Check the version of the user's structure.
  394          */
  395         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  396                 return (error);
  397         if (version != sizeof(struct module_stat_v1)
  398             && version != sizeof(struct module_stat))
  399                 return (EINVAL);
  400         namelen = strlen(mod->name) + 1;
  401         if (namelen > MAXMODNAME)
  402                 namelen = MAXMODNAME;
  403         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  404                 return (error);
  405 
  406         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  407                 return (error);
  408         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  409                 return (error);
  410 
  411         /*
  412          * >v1 stat includes module data.
  413          */
  414         if (version == sizeof(struct module_stat))
  415                 if ((error = copyout(&data, &stat->data, 
  416                     sizeof(data))) != 0)
  417                         return (error);
  418         td->td_retval[0] = 0;
  419         return (error);
  420 }
  421 
  422 int
  423 sys_modfind(struct thread *td, struct modfind_args *uap)
  424 {
  425         int error = 0;
  426         char name[MAXMODNAME];
  427         module_t mod;
  428 
  429         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  430                 return (error);
  431 
  432         MOD_SLOCK;
  433         mod = module_lookupbyname(name);
  434         if (mod == NULL)
  435                 error = ENOENT;
  436         else
  437                 td->td_retval[0] = module_getid(mod);
  438         MOD_SUNLOCK;
  439         return (error);
  440 }
  441 
  442 MODULE_VERSION(kernel, __FreeBSD_version);
  443 
  444 #ifdef COMPAT_FREEBSD32
  445 #include <sys/mount.h>
  446 #include <sys/socket.h>
  447 #include <compat/freebsd32/freebsd32_util.h>
  448 #include <compat/freebsd32/freebsd32.h>
  449 #include <compat/freebsd32/freebsd32_proto.h>
  450 
  451 typedef union modspecific32 {
  452         int             intval;
  453         uint32_t        uintval;
  454         int             longval;
  455         uint32_t        ulongval;
  456 } modspecific32_t;
  457 
  458 struct module_stat32 {
  459         int             version;
  460         char            name[MAXMODNAME];
  461         int             refs;
  462         int             id;
  463         modspecific32_t data;
  464 };
  465 
  466 int
  467 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  468 {
  469         module_t mod;
  470         modspecific32_t data32;
  471         int error = 0;
  472         int id, namelen, refs, version;
  473         struct module_stat32 *stat32;
  474         char *name;
  475 
  476         MOD_SLOCK;
  477         mod = module_lookupbyid(uap->modid);
  478         if (mod == NULL) {
  479                 MOD_SUNLOCK;
  480                 return (ENOENT);
  481         }
  482 
  483         id = mod->id;
  484         refs = mod->refs;
  485         name = mod->name;
  486         CP(mod->data, data32, intval);
  487         CP(mod->data, data32, uintval);
  488         CP(mod->data, data32, longval);
  489         CP(mod->data, data32, ulongval);
  490         MOD_SUNLOCK;
  491         stat32 = uap->stat;
  492 
  493         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  494                 return (error);
  495         if (version != sizeof(struct module_stat_v1)
  496             && version != sizeof(struct module_stat32))
  497                 return (EINVAL);
  498         namelen = strlen(mod->name) + 1;
  499         if (namelen > MAXMODNAME)
  500                 namelen = MAXMODNAME;
  501         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  502                 return (error);
  503 
  504         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  505                 return (error);
  506         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  507                 return (error);
  508 
  509         /*
  510          * >v1 stat includes module data.
  511          */
  512         if (version == sizeof(struct module_stat32))
  513                 if ((error = copyout(&data32, &stat32->data,
  514                     sizeof(data32))) != 0)
  515                         return (error);
  516         td->td_retval[0] = 0;
  517         return (error);
  518 }
  519 #endif

Cache object: c20f1e8546ea25dd129e11d060380ae2


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