kern_module.c revision 92547
125537Sdfr/*- 225537Sdfr * Copyright (c) 1997 Doug Rabson 325537Sdfr * All rights reserved. 425537Sdfr * 525537Sdfr * Redistribution and use in source and binary forms, with or without 625537Sdfr * modification, are permitted provided that the following conditions 725537Sdfr * are met: 825537Sdfr * 1. Redistributions of source code must retain the above copyright 925537Sdfr * notice, this list of conditions and the following disclaimer. 1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1125537Sdfr * notice, this list of conditions and the following disclaimer in the 1225537Sdfr * documentation and/or other materials provided with the distribution. 1325537Sdfr * 1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725537Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425537Sdfr * SUCH DAMAGE. 2525537Sdfr * 2650477Speter * $FreeBSD: head/sys/kern/kern_module.c 92547 2002-03-18 07:45:30Z arr $ 2725537Sdfr */ 2825537Sdfr 2925537Sdfr#include <sys/param.h> 3025537Sdfr#include <sys/kernel.h> 3125537Sdfr#include <sys/systm.h> 3250107Smsmith#include <sys/eventhandler.h> 3325537Sdfr#include <sys/malloc.h> 3425537Sdfr#include <sys/sysproto.h> 3525537Sdfr#include <sys/sysent.h> 3630994Sphk#include <sys/proc.h> 3782749Sdillon#include <sys/lock.h> 3882749Sdillon#include <sys/mutex.h> 3992547Sarr#include <sys/sx.h> 4092547Sarr#include <sys/module.h> 4192547Sarr#include <sys/linker.h> 4225537Sdfr 4369774Sphkstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 4425537Sdfr 4560938Sjaketypedef TAILQ_HEAD(, module) modulelist_t; 4625537Sdfrstruct module { 4790963Sarr TAILQ_ENTRY(module) link; /* chain together all modules */ 4890963Sarr TAILQ_ENTRY(module) flink; /* all modules in a file */ 4990963Sarr struct linker_file *file; /* file which contains this module */ 5090963Sarr int refs; /* reference count */ 5190963Sarr int id; /* unique id number */ 5290963Sarr char *name; /* module name */ 5390963Sarr modeventhand_t handler; /* event handler */ 5490963Sarr void *arg; /* argument for handler */ 5590963Sarr modspecific_t data; /* module specific data */ 5625537Sdfr}; 5725537Sdfr 5890963Sarr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 5925537Sdfr 6025537Sdfrstatic modulelist_t modules; 6192547Sarrstruct sx modules_sx; 6225537Sdfrstatic int nextid = 1; 6390963Sarrstatic void module_shutdown(void *, int); 6425537Sdfr 6552991Speterstatic int 6690963Sarrmodevent_nop(module_t mod, int what, void *arg) 6752991Speter{ 6890980Sarr return (0); 6952991Speter} 7052991Speter 7125537Sdfrstatic void 7290963Sarrmodule_init(void *arg) 7325537Sdfr{ 7490963Sarr 7592547Sarr sx_init(&modules_sx, "module subsystem sx lock"); 7690963Sarr TAILQ_INIT(&modules); 7790963Sarr EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL, 7890963Sarr SHUTDOWN_PRI_DEFAULT); 7925537Sdfr} 8025537Sdfr 8190963SarrSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0) 8225537Sdfr 8325537Sdfrstatic void 8490963Sarrmodule_shutdown(void *arg1, int arg2) 8525537Sdfr{ 8690963Sarr module_t mod; 8725537Sdfr 8892547Sarr MOD_SLOCK; 8990963Sarr TAILQ_FOREACH(mod, &modules, link) 9090963Sarr MOD_EVENT(mod, MOD_SHUTDOWN); 9192547Sarr MOD_SUNLOCK; 9225537Sdfr} 9325537Sdfr 9425537Sdfrvoid 9543387Sdillonmodule_register_init(const void *arg) 9625537Sdfr{ 9790963Sarr const moduledata_t *data = (const moduledata_t *)arg; 9890963Sarr int error; 9990963Sarr module_t mod; 10025537Sdfr 10192547Sarr MOD_SLOCK; 10290963Sarr mod = module_lookupbyname(data->name); 10390963Sarr if (mod == NULL) 10491067Sarr panic("module_register_init: module named %s not found\n", 10590963Sarr data->name); 10692547Sarr MOD_SUNLOCK; 10790963Sarr error = MOD_EVENT(mod, MOD_LOAD); 10890963Sarr if (error) { 10990963Sarr MOD_EVENT(mod, MOD_UNLOAD); 11092547Sarr MOD_XLOCK; 11190963Sarr module_release(mod); 11292547Sarr MOD_XUNLOCK; 11391261Speter printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 11491261Speter " %d\n", data->name, (void *)data->evhand, data->priv, 11591067Sarr error); 11690963Sarr } 11725537Sdfr} 11825537Sdfr 11925537Sdfrint 12046693Spetermodule_register(const moduledata_t *data, linker_file_t container) 12125537Sdfr{ 12290963Sarr size_t namelen; 12390963Sarr module_t newmod; 12425537Sdfr 12592547Sarr MOD_SLOCK; 12690963Sarr newmod = module_lookupbyname(data->name); 12790963Sarr if (newmod != NULL) { 12892547Sarr MOD_SUNLOCK; 12991067Sarr printf("module_register: module %s already exists!\n", 13090963Sarr data->name); 13190980Sarr return (EEXIST); 13290963Sarr } 13392547Sarr MOD_SUNLOCK; 13490963Sarr namelen = strlen(data->name) + 1; 13590963Sarr newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 13690963Sarr if (newmod == NULL) 13790980Sarr return (ENOMEM); 13892547Sarr MOD_XLOCK; 13990963Sarr newmod->refs = 1; 14090963Sarr newmod->id = nextid++; 14190963Sarr newmod->name = (char *)(newmod + 1); 14290963Sarr strcpy(newmod->name, data->name); 14390963Sarr newmod->handler = data->evhand ? data->evhand : modevent_nop; 14490963Sarr newmod->arg = data->priv; 14590963Sarr bzero(&newmod->data, sizeof(newmod->data)); 14690963Sarr TAILQ_INSERT_TAIL(&modules, newmod, link); 14725537Sdfr 14890963Sarr if (container) 14990963Sarr TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 15090963Sarr newmod->file = container; 15192547Sarr MOD_XUNLOCK; 15290980Sarr return (0); 15325537Sdfr} 15425537Sdfr 15525537Sdfrvoid 15625537Sdfrmodule_reference(module_t mod) 15725537Sdfr{ 15825537Sdfr 15992547Sarr MOD_XLOCK_ASSERT; 16092547Sarr 16190963Sarr MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 16290963Sarr mod->refs++; 16325537Sdfr} 16425537Sdfr 16525537Sdfrvoid 16625537Sdfrmodule_release(module_t mod) 16725537Sdfr{ 16825537Sdfr 16992547Sarr MOD_XLOCK_ASSERT; 17092547Sarr 17190963Sarr if (mod->refs <= 0) 17290963Sarr panic("module_release: bad reference count"); 17325537Sdfr 17490963Sarr MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 17592547Sarr 17690963Sarr mod->refs--; 17790963Sarr if (mod->refs == 0) { 17890963Sarr TAILQ_REMOVE(&modules, mod, link); 17990963Sarr if (mod->file) 18090963Sarr TAILQ_REMOVE(&mod->file->modules, mod, flink); 18192547Sarr MOD_XUNLOCK; 18290963Sarr free(mod, M_MODULE); 18392547Sarr MOD_XLOCK; 18425537Sdfr } 18525537Sdfr} 18625537Sdfr 18725537Sdfrmodule_t 18890963Sarrmodule_lookupbyname(const char *name) 18925537Sdfr{ 19090963Sarr module_t mod; 19190963Sarr int err; 19225537Sdfr 19392547Sarr MOD_LOCK_ASSERT; 19492547Sarr 19590963Sarr TAILQ_FOREACH(mod, &modules, link) { 19690963Sarr err = strcmp(mod->name, name); 19790963Sarr if (err == 0) 19890980Sarr return (mod); 19990963Sarr } 20090980Sarr return (NULL); 20125537Sdfr} 20225537Sdfr 20325537Sdfrmodule_t 20425537Sdfrmodule_lookupbyid(int modid) 20525537Sdfr{ 20692547Sarr module_t mod; 20725537Sdfr 20892547Sarr MOD_LOCK_ASSERT; 20992547Sarr 21092547Sarr TAILQ_FOREACH(mod, &modules, link) 21192547Sarr if (mod->id == modid) 21292547Sarr return(mod); 21392547Sarr return (NULL); 21425537Sdfr} 21525537Sdfr 21625537Sdfrint 21725537Sdfrmodule_unload(module_t mod) 21825537Sdfr{ 21990963Sarr 22092547Sarr return (MOD_EVENT(mod, MOD_UNLOAD)); 22125537Sdfr} 22225537Sdfr 22325537Sdfrint 22425537Sdfrmodule_getid(module_t mod) 22525537Sdfr{ 22690963Sarr 22792547Sarr MOD_LOCK_ASSERT; 22890980Sarr return (mod->id); 22925537Sdfr} 23025537Sdfr 23125537Sdfrmodule_t 23225537Sdfrmodule_getfnext(module_t mod) 23325537Sdfr{ 23490963Sarr 23592547Sarr MOD_LOCK_ASSERT; 23690980Sarr return (TAILQ_NEXT(mod, flink)); 23725537Sdfr} 23825537Sdfr 23942435Sdfrvoid 24042435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap) 24142435Sdfr{ 24290963Sarr 24392547Sarr MOD_XLOCK_ASSERT; 24490963Sarr mod->data = *datap; 24542435Sdfr} 24642435Sdfr 24725537Sdfr/* 24825537Sdfr * Syscalls. 24925537Sdfr */ 25082749Sdillon/* 25182749Sdillon * MPSAFE 25282749Sdillon */ 25325537Sdfrint 25483366Sjulianmodnext(struct thread *td, struct modnext_args *uap) 25525537Sdfr{ 25690963Sarr module_t mod; 25790963Sarr int error = 0; 25825537Sdfr 25990963Sarr mtx_lock(&Giant); 26082749Sdillon 26190963Sarr td->td_retval[0] = -1; 26292547Sarr MOD_SLOCK; 26390963Sarr if (SCARG(uap, modid) == 0) { 26490963Sarr mod = TAILQ_FIRST(&modules); 26590963Sarr if (mod) 26690963Sarr td->td_retval[0] = mod->id; 26790963Sarr else 26890963Sarr error = ENOENT; 26990963Sarr goto done2; 27090963Sarr } 27190963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 27290963Sarr if (mod == NULL) { 27390963Sarr error = ENOENT; 27490963Sarr goto done2; 27590963Sarr } 27690963Sarr if (TAILQ_NEXT(mod, link)) 27790963Sarr td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 27882749Sdillon else 27990963Sarr td->td_retval[0] = 0; 28082749Sdillondone2: 28192547Sarr MOD_SUNLOCK; 28290963Sarr mtx_unlock(&Giant); 28390963Sarr return (error); 28425537Sdfr} 28525537Sdfr 28682749Sdillon/* 28782749Sdillon * MPSAFE 28882749Sdillon */ 28925537Sdfrint 29083366Sjulianmodfnext(struct thread *td, struct modfnext_args *uap) 29125537Sdfr{ 29290963Sarr module_t mod; 29390963Sarr int error; 29425537Sdfr 29590963Sarr td->td_retval[0] = -1; 29625537Sdfr 29790963Sarr mtx_lock(&Giant); 29882749Sdillon 29992547Sarr MOD_SLOCK; 30090963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 30190963Sarr if (mod == NULL) { 30290963Sarr error = ENOENT; 30390963Sarr } else { 30490963Sarr error = 0; 30590963Sarr if (TAILQ_NEXT(mod, flink)) 30690963Sarr td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 30790963Sarr else 30890963Sarr td->td_retval[0] = 0; 30990963Sarr } 31092547Sarr MOD_SUNLOCK; 31190963Sarr mtx_unlock(&Giant); 31290963Sarr return (error); 31325537Sdfr} 31425537Sdfr 31542435Sdfrstruct module_stat_v1 { 31691067Sarr int version; /* set to sizeof(struct module_stat) */ 31791067Sarr char name[MAXMODNAME]; 31891067Sarr int refs; 31991067Sarr int id; 32042435Sdfr}; 32142435Sdfr 32282749Sdillon/* 32382749Sdillon * MPSAFE 32482749Sdillon */ 32525537Sdfrint 32683366Sjulianmodstat(struct thread *td, struct modstat_args *uap) 32725537Sdfr{ 32890963Sarr module_t mod; 32992547Sarr modspecific_t data; 33090963Sarr int error = 0; 33192547Sarr int id, namelen, refs, version; 33290963Sarr struct module_stat *stat; 33392547Sarr char *name; 33425537Sdfr 33590963Sarr mtx_lock(&Giant); 33682749Sdillon 33792547Sarr MOD_SLOCK; 33890963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 33990963Sarr if (mod == NULL) { 34092547Sarr MOD_SUNLOCK; 34190963Sarr error = ENOENT; 34290963Sarr goto out; 34390963Sarr } 34492547Sarr id = mod->id; 34592547Sarr refs = mod->refs; 34692547Sarr name = mod->name; 34792547Sarr data = mod->data; 34892547Sarr MOD_SUNLOCK; 34990963Sarr stat = SCARG(uap, stat); 35025537Sdfr 35190963Sarr /* 35290963Sarr * Check the version of the user's structure. 35390963Sarr */ 35490963Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 35590963Sarr goto out; 35690963Sarr if (version != sizeof(struct module_stat_v1) 35790963Sarr && version != sizeof(struct module_stat)) { 35890963Sarr error = EINVAL; 35990963Sarr goto out; 36090963Sarr } 36190963Sarr namelen = strlen(mod->name) + 1; 36290963Sarr if (namelen > MAXMODNAME) 36390963Sarr namelen = MAXMODNAME; 36492547Sarr if ((error = copyout(name, &stat->name[0], namelen)) != 0) 36590963Sarr goto out; 36625537Sdfr 36792547Sarr if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 36890963Sarr goto out; 36992547Sarr if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 37090963Sarr goto out; 37125537Sdfr 37290963Sarr /* 37390963Sarr * >v1 stat includes module data. 37490963Sarr */ 37590963Sarr if (version == sizeof(struct module_stat)) { 37692547Sarr if ((error = copyout(&data, &stat->data, 37792547Sarr sizeof(data))) != 0) 37890963Sarr goto out; 37990963Sarr } 38090963Sarr td->td_retval[0] = 0; 38125537Sdfrout: 38290963Sarr mtx_unlock(&Giant); 38390980Sarr return (error); 38425537Sdfr} 38525537Sdfr 38682749Sdillon/* 38782749Sdillon * MPSAFE 38882749Sdillon */ 38925537Sdfrint 39083366Sjulianmodfind(struct thread *td, struct modfind_args *uap) 39125537Sdfr{ 39290963Sarr int error = 0; 39390963Sarr char name[MAXMODNAME]; 39490963Sarr module_t mod; 39525537Sdfr 39690963Sarr if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0) 39790963Sarr goto out; 39825537Sdfr 39990963Sarr mtx_lock(&Giant); 40092547Sarr MOD_SLOCK; 40190963Sarr mod = module_lookupbyname(name); 40290963Sarr if (mod == NULL) 40390963Sarr error = ENOENT; 40490963Sarr else 40592547Sarr td->td_retval[0] = module_getid(mod); 40692547Sarr MOD_SUNLOCK; 40790963Sarr mtx_unlock(&Giant); 40825537Sdfrout: 40990980Sarr return (error); 41025537Sdfr} 411