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 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         }
  134         mtx_unlock(&Giant);
  135 }
  136 
  137 int
  138 module_register(const moduledata_t *data, linker_file_t container)
  139 {
  140         size_t namelen;
  141         module_t newmod;
  142 
  143         MOD_XLOCK;
  144         newmod = module_lookupbyname(data->name);
  145         if (newmod != NULL) {
  146                 MOD_XUNLOCK;
  147                 printf("module_register: module %s already exists!\n",
  148                     data->name);
  149                 return (EEXIST);
  150         }
  151         namelen = strlen(data->name) + 1;
  152         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  153         if (newmod == NULL) {
  154                 MOD_XUNLOCK;
  155                 return (ENOMEM);
  156         }
  157         newmod->refs = 1;
  158         newmod->id = nextid++;
  159         newmod->name = (char *)(newmod + 1);
  160         strcpy(newmod->name, data->name);
  161         newmod->handler = data->evhand ? data->evhand : modevent_nop;
  162         newmod->arg = data->priv;
  163         bzero(&newmod->data, sizeof(newmod->data));
  164         TAILQ_INSERT_TAIL(&modules, newmod, link);
  165 
  166         if (container)
  167                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
  168         newmod->file = container;
  169         MOD_XUNLOCK;
  170         return (0);
  171 }
  172 
  173 void
  174 module_reference(module_t mod)
  175 {
  176 
  177         MOD_XLOCK_ASSERT;
  178 
  179         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
  180         mod->refs++;
  181 }
  182 
  183 void
  184 module_release(module_t mod)
  185 {
  186 
  187         MOD_XLOCK_ASSERT;
  188 
  189         if (mod->refs <= 0)
  190                 panic("module_release: bad reference count");
  191 
  192         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
  193         
  194         mod->refs--;
  195         if (mod->refs == 0) {
  196                 TAILQ_REMOVE(&modules, mod, link);
  197                 if (mod->file)
  198                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  199                 MOD_XUNLOCK;
  200                 free(mod, M_MODULE);
  201                 MOD_XLOCK;
  202         }
  203 }
  204 
  205 module_t
  206 module_lookupbyname(const char *name)
  207 {
  208         module_t mod;
  209         int err;
  210 
  211         MOD_LOCK_ASSERT;
  212 
  213         TAILQ_FOREACH(mod, &modules, link) {
  214                 err = strcmp(mod->name, name);
  215                 if (err == 0)
  216                         return (mod);
  217         }
  218         return (NULL);
  219 }
  220 
  221 module_t
  222 module_lookupbyid(int modid)
  223 {
  224         module_t mod;
  225 
  226         MOD_LOCK_ASSERT;
  227 
  228         TAILQ_FOREACH(mod, &modules, link)
  229                 if (mod->id == modid)
  230                         return(mod);
  231         return (NULL);
  232 }
  233 
  234 int
  235 module_unload(module_t mod, int flags)
  236 {
  237         int error;
  238 
  239         mtx_lock(&Giant);
  240         error = MOD_EVENT(mod, MOD_QUIESCE);
  241         if (error == EOPNOTSUPP || error == EINVAL)
  242                 error = 0;
  243         if (error == 0 || flags == LINKER_UNLOAD_FORCE)
  244                 error = MOD_EVENT(mod, MOD_UNLOAD);
  245         mtx_unlock(&Giant);
  246         return (error);
  247 }
  248 
  249 int
  250 module_getid(module_t mod)
  251 {
  252 
  253         MOD_LOCK_ASSERT;
  254         return (mod->id);
  255 }
  256 
  257 module_t
  258 module_getfnext(module_t mod)
  259 {
  260 
  261         MOD_LOCK_ASSERT;
  262         return (TAILQ_NEXT(mod, flink));
  263 }
  264 
  265 void
  266 module_setspecific(module_t mod, modspecific_t *datap)
  267 {
  268 
  269         MOD_XLOCK_ASSERT;
  270         mod->data = *datap;
  271 }
  272 
  273 linker_file_t
  274 module_file(module_t mod)
  275 {
  276 
  277         return (mod->file);
  278 }
  279 
  280 /*
  281  * Syscalls.
  282  */
  283 int
  284 modnext(struct thread *td, struct modnext_args *uap)
  285 {
  286         module_t mod;
  287         int error = 0;
  288 
  289         td->td_retval[0] = -1;
  290 
  291         MOD_SLOCK;
  292         if (uap->modid == 0) {
  293                 mod = TAILQ_FIRST(&modules);
  294                 if (mod)
  295                         td->td_retval[0] = mod->id;
  296                 else
  297                         error = ENOENT;
  298                 goto done2;
  299         }
  300         mod = module_lookupbyid(uap->modid);
  301         if (mod == NULL) {
  302                 error = ENOENT;
  303                 goto done2;
  304         }
  305         if (TAILQ_NEXT(mod, link))
  306                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
  307         else
  308                 td->td_retval[0] = 0;
  309 done2:
  310         MOD_SUNLOCK;
  311         return (error);
  312 }
  313 
  314 int
  315 modfnext(struct thread *td, struct modfnext_args *uap)
  316 {
  317         module_t mod;
  318         int error;
  319 
  320         td->td_retval[0] = -1;
  321 
  322         MOD_SLOCK;
  323         mod = module_lookupbyid(uap->modid);
  324         if (mod == NULL) {
  325                 error = ENOENT;
  326         } else {
  327                 error = 0;
  328                 if (TAILQ_NEXT(mod, flink))
  329                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
  330                 else
  331                         td->td_retval[0] = 0;
  332         }
  333         MOD_SUNLOCK;
  334         return (error);
  335 }
  336 
  337 struct module_stat_v1 {
  338         int     version;                /* set to sizeof(struct module_stat) */
  339         char    name[MAXMODNAME];
  340         int     refs;
  341         int     id;
  342 };
  343 
  344 int
  345 modstat(struct thread *td, struct modstat_args *uap)
  346 {
  347         module_t mod;
  348         modspecific_t data;
  349         int error = 0;
  350         int id, namelen, refs, version;
  351         struct module_stat *stat;
  352         char *name;
  353 
  354         MOD_SLOCK;
  355         mod = module_lookupbyid(uap->modid);
  356         if (mod == NULL) {
  357                 MOD_SUNLOCK;
  358                 return (ENOENT);
  359         }
  360         id = mod->id;
  361         refs = mod->refs;
  362         name = mod->name;
  363         data = mod->data;
  364         MOD_SUNLOCK;
  365         stat = uap->stat;
  366 
  367         /*
  368          * Check the version of the user's structure.
  369          */
  370         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  371                 return (error);
  372         if (version != sizeof(struct module_stat_v1)
  373             && version != sizeof(struct module_stat))
  374                 return (EINVAL);
  375         namelen = strlen(mod->name) + 1;
  376         if (namelen > MAXMODNAME)
  377                 namelen = MAXMODNAME;
  378         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  379                 return (error);
  380 
  381         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  382                 return (error);
  383         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  384                 return (error);
  385 
  386         /*
  387          * >v1 stat includes module data.
  388          */
  389         if (version == sizeof(struct module_stat))
  390                 if ((error = copyout(&data, &stat->data, 
  391                     sizeof(data))) != 0)
  392                         return (error);
  393         td->td_retval[0] = 0;
  394         return (error);
  395 }
  396 
  397 int
  398 modfind(struct thread *td, struct modfind_args *uap)
  399 {
  400         int error = 0;
  401         char name[MAXMODNAME];
  402         module_t mod;
  403 
  404         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  405                 return (error);
  406 
  407         MOD_SLOCK;
  408         mod = module_lookupbyname(name);
  409         if (mod == NULL)
  410                 error = ENOENT;
  411         else
  412                 td->td_retval[0] = module_getid(mod);
  413         MOD_SUNLOCK;
  414         return (error);
  415 }
  416 
  417 #ifdef COMPAT_IA32
  418 #include <sys/mount.h>
  419 #include <sys/socket.h>
  420 #include <compat/freebsd32/freebsd32_util.h>
  421 #include <compat/freebsd32/freebsd32.h>
  422 #include <compat/freebsd32/freebsd32_proto.h>
  423 
  424 typedef union modspecific32 {
  425         int             intval;
  426         u_int32_t       uintval;
  427         int             longval;
  428         u_int32_t       ulongval;
  429 } modspecific32_t;
  430 
  431 struct module_stat32 {
  432         int             version;
  433         char            name[MAXMODNAME];
  434         int             refs;
  435         int             id;
  436         modspecific32_t data;
  437 };
  438 
  439 int
  440 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  441 {
  442         module_t mod;
  443         modspecific32_t data32;
  444         int error = 0;
  445         int id, namelen, refs, version;
  446         struct module_stat32 *stat32;
  447         char *name;
  448 
  449         MOD_SLOCK;
  450         mod = module_lookupbyid(uap->modid);
  451         if (mod == NULL) {
  452                 MOD_SUNLOCK;
  453                 return (ENOENT);
  454         }
  455 
  456         id = mod->id;
  457         refs = mod->refs;
  458         name = mod->name;
  459         CP(mod->data, data32, intval);
  460         CP(mod->data, data32, uintval);
  461         CP(mod->data, data32, longval);
  462         CP(mod->data, data32, ulongval);
  463         MOD_SUNLOCK;
  464         stat32 = uap->stat;
  465 
  466         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  467                 return (error);
  468         if (version != sizeof(struct module_stat_v1)
  469             && version != sizeof(struct module_stat32))
  470                 return (EINVAL);
  471         namelen = strlen(mod->name) + 1;
  472         if (namelen > MAXMODNAME)
  473                 namelen = MAXMODNAME;
  474         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  475                 return (error);
  476 
  477         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  478                 return (error);
  479         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  480                 return (error);
  481 
  482         /*
  483          * >v1 stat includes module data.
  484          */
  485         if (version == sizeof(struct module_stat32))
  486                 if ((error = copyout(&data32, &stat32->data,
  487                     sizeof(data32))) != 0)
  488                         return (error);
  489         td->td_retval[0] = 0;
  490         return (error);
  491 }
  492 #endif

Cache object: 163132d642bf3674b74ff346758aa659


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