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/6.4/sys/kern/kern_module.c 174796 2007-12-19 23:03:02Z 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         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_XLOCK;
  140         newmod = module_lookupbyname(data->name);
  141         if (newmod != NULL) {
  142                 MOD_XUNLOCK;
  143                 printf("module_register: module %s already exists!\n",
  144                     data->name);
  145                 return (EEXIST);
  146         }
  147         namelen = strlen(data->name) + 1;
  148         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
  149         if (newmod == NULL) {
  150                 MOD_XUNLOCK;
  151                 return (ENOMEM);
  152         }
  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 <sys/socket.h>
  419 #include <compat/freebsd32/freebsd32_util.h>
  420 #include <compat/freebsd32/freebsd32.h>
  421 #include <compat/freebsd32/freebsd32_proto.h>
  422 
  423 typedef union modspecific32 {
  424         int             intval;
  425         u_int32_t       uintval;
  426         int             longval;
  427         u_int32_t       ulongval;
  428 } modspecific32_t;
  429 
  430 struct module_stat32 {
  431         int             version;
  432         char            name[MAXMODNAME];
  433         int             refs;
  434         int             id;
  435         modspecific32_t data;
  436 };
  437 
  438 /*
  439  * MPSAFE
  440  */
  441 int
  442 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
  443 {
  444         module_t mod;
  445         modspecific32_t data32;
  446         int error = 0;
  447         int id, namelen, refs, version;
  448         struct module_stat32 *stat32;
  449         char *name;
  450 
  451         MOD_SLOCK;
  452         mod = module_lookupbyid(uap->modid);
  453         if (mod == NULL) {
  454                 MOD_SUNLOCK;
  455                 return (ENOENT);
  456         }
  457 
  458         id = mod->id;
  459         refs = mod->refs;
  460         name = mod->name;
  461         CP(mod->data, data32, intval);
  462         CP(mod->data, data32, uintval);
  463         CP(mod->data, data32, longval);
  464         CP(mod->data, data32, ulongval);
  465         MOD_SUNLOCK;
  466         stat32 = uap->stat;
  467 
  468         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
  469                 return (error);
  470         if (version != sizeof(struct module_stat_v1)
  471             && version != sizeof(struct module_stat32))
  472                 return (EINVAL);
  473         namelen = strlen(mod->name) + 1;
  474         if (namelen > MAXMODNAME)
  475                 namelen = MAXMODNAME;
  476         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
  477                 return (error);
  478 
  479         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
  480                 return (error);
  481         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
  482                 return (error);
  483 
  484         /*
  485          * >v1 stat includes module data.
  486          */
  487         if (version == sizeof(struct module_stat32))
  488                 if ((error = copyout(&data32, &stat32->data,
  489                     sizeof(data32))) != 0)
  490                         return (error);
  491         td->td_retval[0] = 0;
  492         return (error);
  493 }
  494 #endif

Cache object: 641da86c561ee96f908e8866d8317d81


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