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

Cache object: 59de0c66aeca26b4120a0bb504ce0d5f


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