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 <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/5.3/sys/kern/kern_module.c 136588 2004-10-16 08:43:07Z cvs2svn $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/systm.h>
   33 #include <sys/eventhandler.h>
   34 #include <sys/malloc.h>
   35 #include <sys/sysproto.h>
   36 #include <sys/sysent.h>
   37 #include <sys/proc.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/reboot.h>
   41 #include <sys/sx.h>
   42 #include <sys/module.h>
   43 #include <sys/linker.h>
   44 
   45 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
   46 
   47 typedef TAILQ_HEAD(, module) modulelist_t;
   48 struct module {
   49         TAILQ_ENTRY(module)     link;   /* chain together all modules */
   50         TAILQ_ENTRY(module)     flink;  /* all modules in a file */
   51         struct linker_file      *file;  /* file which contains this module */
   52         int                     refs;   /* reference count */
   53         int                     id;     /* unique id number */
   54         char                    *name;  /* module name */
   55         modeventhand_t          handler;        /* event handler */
   56         void                    *arg;   /* argument for handler */
   57         modspecific_t           data;   /* module specific data */
   58 };
   59 
   60 #define MOD_EVENT(mod, type)    (mod)->handler((mod), (type), (mod)->arg)
   61 
   62 static modulelist_t modules;
   63 struct sx modules_sx;
   64 static int nextid = 1;
   65 static void module_shutdown(void *, int);
   66 
   67 static int
   68 modevent_nop(module_t mod, int what, void *arg)
   69 {
   70 
   71         switch(what) {
   72         case MOD_LOAD:
   73                 return (0);
   74         case MOD_UNLOAD:
   75                 return (EBUSY);
   76         default:
   77                 return (EOPNOTSUPP);
   78         }
   79 }
   80 
   81 static void
   82 module_init(void *arg)
   83 {
   84 
   85         sx_init(&modules_sx, "module subsystem sx lock");
   86         TAILQ_INIT(&modules);
   87         EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
   88             SHUTDOWN_PRI_DEFAULT);
   89 }
   90 
   91 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
   92 
   93 static void
   94 module_shutdown(void *arg1, int arg2)
   95 {
   96         module_t mod;
   97 
   98         if (arg2 & RB_NOSYNC)
   99                 return;
  100         MOD_SLOCK;
  101         TAILQ_FOREACH(mod, &modules, link)
  102                 MOD_EVENT(mod, MOD_SHUTDOWN);
  103         MOD_SUNLOCK;
  104 }
  105 
  106 void
  107 module_register_init(const void *arg)
  108 {
  109         const moduledata_t *data = (const moduledata_t *)arg;
  110         int error;
  111         module_t mod;
  112 
  113         MOD_SLOCK;
  114         mod = module_lookupbyname(data->name);
  115         if (mod == NULL)
  116                 panic("module_register_init: module named %s not found\n",
  117                     data->name);
  118         MOD_SUNLOCK;
  119         error = MOD_EVENT(mod, MOD_LOAD);
  120         if (error) {
  121                 MOD_EVENT(mod, MOD_UNLOAD);
  122                 MOD_XLOCK;
  123                 module_release(mod);
  124                 MOD_XUNLOCK;
  125                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
  126                     " %d\n", data->name, (void *)data->evhand, data->priv,
  127                     error); 
  128         }
  129 }
  130 
  131 int
  132 module_register(const moduledata_t *data, linker_file_t container)
  133 {
  134         size_t namelen;
  135         module_t newmod;
  136 
  137         MOD_SLOCK;
  138         newmod = module_lookupbyname(data->name);
  139         if (newmod != NULL) {
  140                 MOD_SUNLOCK;
  141                 printf("module_register: module %s already exists!\n",
  142                     data->name);
  143                 return (EEXIST);
  144         }
  145         MOD_SUNLOCK;
  146         namelen = strlen(data->name) + 1;
  147         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  148         if (newmod == NULL)
  149                 return (ENOMEM);
  150         MOD_XLOCK;
  151         newmod->refs = 1;
  152         newmod->id = nextid++;
  153         newmod->name = (char *)(newmod + 1);
  154         strcpy(newmod->name, data->name);
  155         newmod->handler = data->evhand ? data->evhand : modevent_nop;
  156         newmod->arg = data->priv;
  157         bzero(&newmod->data, sizeof(newmod->data));
  158         TAILQ_INSERT_TAIL(&modules, newmod, link);
  159 
  160         if (container)
  161                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
  162         newmod->file = container;
  163         MOD_XUNLOCK;
  164         return (0);
  165 }
  166 
  167 void
  168 module_reference(module_t mod)
  169 {
  170 
  171         MOD_XLOCK_ASSERT;
  172 
  173         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
  174         mod->refs++;
  175 }
  176 
  177 void
  178 module_release(module_t mod)
  179 {
  180 
  181         MOD_XLOCK_ASSERT;
  182 
  183         if (mod->refs <= 0)
  184                 panic("module_release: bad reference count");
  185 
  186         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
  187         
  188         mod->refs--;
  189         if (mod->refs == 0) {
  190                 TAILQ_REMOVE(&modules, mod, link);
  191                 if (mod->file)
  192                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
  193                 MOD_XUNLOCK;
  194                 free(mod, M_MODULE);
  195                 MOD_XLOCK;
  196         }
  197 }
  198 
  199 module_t
  200 module_lookupbyname(const char *name)
  201 {
  202         module_t mod;
  203         int err;
  204 
  205         MOD_LOCK_ASSERT;
  206 
  207         TAILQ_FOREACH(mod, &modules, link) {
  208                 err = strcmp(mod->name, name);
  209                 if (err == 0)
  210                         return (mod);
  211         }
  212         return (NULL);
  213 }
  214 
  215 module_t
  216 module_lookupbyid(int modid)
  217 {
  218         module_t mod;
  219 
  220         MOD_LOCK_ASSERT;
  221 
  222         TAILQ_FOREACH(mod, &modules, link)
  223                 if (mod->id == modid)
  224                         return(mod);
  225         return (NULL);
  226 }
  227 
  228 int
  229 module_unload(module_t mod, int flags)
  230 {
  231         int error;
  232 
  233         error = MOD_EVENT(mod, MOD_QUIESCE);
  234         if (error == EOPNOTSUPP || error == EINVAL)
  235                 error = 0;
  236         if (flags == LINKER_UNLOAD_NORMAL && error != 0)
  237                 return (error);
  238         return (MOD_EVENT(mod, MOD_UNLOAD));
  239 }
  240 
  241 int
  242 module_getid(module_t mod)
  243 {
  244 
  245         MOD_LOCK_ASSERT;
  246         return (mod->id);
  247 }
  248 
  249 module_t
  250 module_getfnext(module_t mod)
  251 {
  252 
  253         MOD_LOCK_ASSERT;
  254         return (TAILQ_NEXT(mod, flink));
  255 }
  256 
  257 void
  258 module_setspecific(module_t mod, modspecific_t *datap)
  259 {
  260 
  261         MOD_XLOCK_ASSERT;
  262         mod->data = *datap;
  263 }
  264 
  265 /*
  266  * Syscalls.
  267  */
  268 /*
  269  * MPSAFE
  270  */
  271 int
  272 modnext(struct thread *td, struct modnext_args *uap)
  273 {
  274         module_t mod;
  275         int error = 0;
  276 
  277         td->td_retval[0] = -1;
  278 
  279         MOD_SLOCK;
  280         if (uap->modid == 0) {
  281                 mod = TAILQ_FIRST(&modules);
  282                 if (mod)
  283                         td->td_retval[0] = mod->id;
  284                 else
  285                         error = ENOENT;
  286                 goto done2;
  287         }
  288         mod = module_lookupbyid(uap->modid);
  289         if (mod == NULL) {
  290                 error = ENOENT;
  291                 goto done2;
  292         }
  293         if (TAILQ_NEXT(mod, link))
  294                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
  295         else
  296                 td->td_retval[0] = 0;
  297 done2:
  298         MOD_SUNLOCK;
  299         return (error);
  300 }
  301 
  302 /*
  303  * MPSAFE
  304  */
  305 int
  306 modfnext(struct thread *td, struct modfnext_args *uap)
  307 {
  308         module_t mod;
  309         int error;
  310 
  311         td->td_retval[0] = -1;
  312 
  313         MOD_SLOCK;
  314         mod = module_lookupbyid(uap->modid);
  315         if (mod == NULL) {
  316                 error = ENOENT;
  317         } else {
  318                 error = 0;
  319                 if (TAILQ_NEXT(mod, flink))
  320                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
  321                 else
  322                         td->td_retval[0] = 0;
  323         }
  324         MOD_SUNLOCK;
  325         return (error);
  326 }
  327 
  328 struct module_stat_v1 {
  329         int     version;                /* set to sizeof(struct module_stat) */
  330         char    name[MAXMODNAME];
  331         int     refs;
  332         int     id;
  333 };
  334 
  335 /*
  336  * MPSAFE
  337  */
  338 int
  339 modstat(struct thread *td, struct modstat_args *uap)
  340 {
  341         module_t mod;
  342         modspecific_t data;
  343         int error = 0;
  344         int id, namelen, refs, version;
  345         struct module_stat *stat;
  346         char *name;
  347 
  348         MOD_SLOCK;
  349         mod = module_lookupbyid(uap->modid);
  350         if (mod == NULL) {
  351                 MOD_SUNLOCK;
  352                 return (ENOENT);
  353         }
  354         id = mod->id;
  355         refs = mod->refs;
  356         name = mod->name;
  357         data = mod->data;
  358         MOD_SUNLOCK;
  359         stat = uap->stat;
  360 
  361         /*
  362          * Check the version of the user's structure.
  363          */
  364         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
  365                 return (error);
  366         if (version != sizeof(struct module_stat_v1)
  367             && version != sizeof(struct module_stat))
  368                 return (EINVAL);
  369         namelen = strlen(mod->name) + 1;
  370         if (namelen > MAXMODNAME)
  371                 namelen = MAXMODNAME;
  372         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
  373                 return (error);
  374 
  375         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
  376                 return (error);
  377         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
  378                 return (error);
  379 
  380         /*
  381          * >v1 stat includes module data.
  382          */
  383         if (version == sizeof(struct module_stat))
  384                 if ((error = copyout(&data, &stat->data, 
  385                     sizeof(data))) != 0)
  386                         return (error);
  387         td->td_retval[0] = 0;
  388         return (error);
  389 }
  390 
  391 /*
  392  * MPSAFE
  393  */
  394 int
  395 modfind(struct thread *td, struct modfind_args *uap)
  396 {
  397         int error = 0;
  398         char name[MAXMODNAME];
  399         module_t mod;
  400 
  401         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
  402                 return (error);
  403 
  404         MOD_SLOCK;
  405         mod = module_lookupbyname(name);
  406         if (mod == NULL)
  407                 error = ENOENT;
  408         else
  409                 td->td_retval[0] = module_getid(mod);
  410         MOD_SUNLOCK;
  411         return (error);
  412 }

Cache object: 5b50c090428b2c1f6531c5c66c229cda


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