kern_module.c revision 91067
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 91067 2002-02-22 13:33:10Z 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> 3625537Sdfr#include <sys/module.h> 3725537Sdfr#include <sys/linker.h> 3830994Sphk#include <sys/proc.h> 3982749Sdillon#include <sys/lock.h> 4082749Sdillon#include <sys/mutex.h> 4125537Sdfr 4269774Sphkstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 4325537Sdfr 4460938Sjaketypedef TAILQ_HEAD(, module) modulelist_t; 4525537Sdfrstruct module { 4690963Sarr TAILQ_ENTRY(module) link; /* chain together all modules */ 4790963Sarr TAILQ_ENTRY(module) flink; /* all modules in a file */ 4890963Sarr struct linker_file *file; /* file which contains this module */ 4990963Sarr int refs; /* reference count */ 5090963Sarr int id; /* unique id number */ 5190963Sarr char *name; /* module name */ 5290963Sarr modeventhand_t handler; /* event handler */ 5390963Sarr void *arg; /* argument for handler */ 5490963Sarr modspecific_t data; /* module specific data */ 5525537Sdfr}; 5625537Sdfr 5790963Sarr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 5825537Sdfr 5925537Sdfrstatic modulelist_t modules; 6025537Sdfrstatic int nextid = 1; 6190963Sarrstatic void module_shutdown(void *, int); 6225537Sdfr 6352991Speterstatic int 6490963Sarrmodevent_nop(module_t mod, int what, void *arg) 6552991Speter{ 6690980Sarr return (0); 6752991Speter} 6852991Speter 6952991Speter 7025537Sdfrstatic void 7190963Sarrmodule_init(void *arg) 7225537Sdfr{ 7390963Sarr 7490963Sarr TAILQ_INIT(&modules); 7590963Sarr EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL, 7690963Sarr SHUTDOWN_PRI_DEFAULT); 7725537Sdfr} 7825537Sdfr 7990963SarrSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0) 8025537Sdfr 8125537Sdfrstatic void 8290963Sarrmodule_shutdown(void *arg1, int arg2) 8325537Sdfr{ 8490963Sarr module_t mod; 8525537Sdfr 8690963Sarr TAILQ_FOREACH(mod, &modules, link) 8790963Sarr MOD_EVENT(mod, MOD_SHUTDOWN); 8825537Sdfr} 8925537Sdfr 9025537Sdfrvoid 9143387Sdillonmodule_register_init(const void *arg) 9225537Sdfr{ 9390963Sarr const moduledata_t *data = (const moduledata_t *)arg; 9490963Sarr int error; 9590963Sarr module_t mod; 9625537Sdfr 9790963Sarr mod = module_lookupbyname(data->name); 9890963Sarr if (mod == NULL) 9991067Sarr panic("module_register_init: module named %s not found\n", 10090963Sarr data->name); 10190963Sarr error = MOD_EVENT(mod, MOD_LOAD); 10290963Sarr if (error) { 10390963Sarr MOD_EVENT(mod, MOD_UNLOAD); 10490963Sarr module_release(mod); 10591067Sarr printf("module_register_init: MOD_LOAD (%s, %lx, %p) error" 10691067Sarr " %d\n", data->name, data->evhand, data->priv, 10791067Sarr error); 10890963Sarr } 10925537Sdfr} 11025537Sdfr 11125537Sdfrint 11246693Spetermodule_register(const moduledata_t *data, linker_file_t container) 11325537Sdfr{ 11490963Sarr size_t namelen; 11590963Sarr module_t newmod; 11625537Sdfr 11790963Sarr newmod = module_lookupbyname(data->name); 11890963Sarr if (newmod != NULL) { 11991067Sarr printf("module_register: module %s already exists!\n", 12090963Sarr data->name); 12190980Sarr return (EEXIST); 12290963Sarr } 12390963Sarr namelen = strlen(data->name) + 1; 12490963Sarr newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 12590963Sarr if (newmod == NULL) 12690980Sarr return (ENOMEM); 12790963Sarr newmod->refs = 1; 12890963Sarr newmod->id = nextid++; 12990963Sarr newmod->name = (char *)(newmod + 1); 13090963Sarr strcpy(newmod->name, data->name); 13190963Sarr newmod->handler = data->evhand ? data->evhand : modevent_nop; 13290963Sarr newmod->arg = data->priv; 13390963Sarr bzero(&newmod->data, sizeof(newmod->data)); 13490963Sarr TAILQ_INSERT_TAIL(&modules, newmod, link); 13525537Sdfr 13690963Sarr if (container) 13790963Sarr TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 13890963Sarr newmod->file = container; 13990980Sarr return (0); 14025537Sdfr} 14125537Sdfr 14225537Sdfrvoid 14325537Sdfrmodule_reference(module_t mod) 14425537Sdfr{ 14525537Sdfr 14690963Sarr MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 14790963Sarr mod->refs++; 14825537Sdfr} 14925537Sdfr 15025537Sdfrvoid 15125537Sdfrmodule_release(module_t mod) 15225537Sdfr{ 15325537Sdfr 15490963Sarr if (mod->refs <= 0) 15590963Sarr panic("module_release: bad reference count"); 15625537Sdfr 15790963Sarr MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 15890963Sarr 15990963Sarr mod->refs--; 16090963Sarr if (mod->refs == 0) { 16190963Sarr TAILQ_REMOVE(&modules, mod, link); 16290963Sarr if (mod->file) 16390963Sarr TAILQ_REMOVE(&mod->file->modules, mod, flink); 16490963Sarr free(mod, M_MODULE); 16525537Sdfr } 16625537Sdfr} 16725537Sdfr 16825537Sdfrmodule_t 16990963Sarrmodule_lookupbyname(const char *name) 17025537Sdfr{ 17190963Sarr module_t mod; 17290963Sarr int err; 17325537Sdfr 17490963Sarr TAILQ_FOREACH(mod, &modules, link) { 17590963Sarr err = strcmp(mod->name, name); 17690963Sarr if (err == 0) 17790980Sarr return (mod); 17890963Sarr } 17990980Sarr return (NULL); 18025537Sdfr} 18125537Sdfr 18225537Sdfrmodule_t 18325537Sdfrmodule_lookupbyid(int modid) 18425537Sdfr{ 18590980Sarr module_t mod; 18625537Sdfr 18790963Sarr TAILQ_FOREACH(mod, &modules, link) { 18890963Sarr if (mod->id == modid) 18990980Sarr return (mod); 19090963Sarr } 19190980Sarr return (NULL); 19225537Sdfr} 19325537Sdfr 19425537Sdfrint 19525537Sdfrmodule_unload(module_t mod) 19625537Sdfr{ 19790963Sarr 19890980Sarr return (MOD_EVENT(mod, MOD_UNLOAD)); 19925537Sdfr} 20025537Sdfr 20125537Sdfrint 20225537Sdfrmodule_getid(module_t mod) 20325537Sdfr{ 20490963Sarr 20590980Sarr return (mod->id); 20625537Sdfr} 20725537Sdfr 20825537Sdfrmodule_t 20925537Sdfrmodule_getfnext(module_t mod) 21025537Sdfr{ 21190963Sarr 21290980Sarr return (TAILQ_NEXT(mod, flink)); 21325537Sdfr} 21425537Sdfr 21542435Sdfrvoid 21642435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap) 21742435Sdfr{ 21890963Sarr 21990963Sarr mod->data = *datap; 22042435Sdfr} 22142435Sdfr 22225537Sdfr/* 22325537Sdfr * Syscalls. 22425537Sdfr */ 22582749Sdillon/* 22682749Sdillon * MPSAFE 22782749Sdillon */ 22825537Sdfrint 22983366Sjulianmodnext(struct thread *td, struct modnext_args *uap) 23025537Sdfr{ 23190963Sarr module_t mod; 23290963Sarr int error = 0; 23325537Sdfr 23490963Sarr mtx_lock(&Giant); 23582749Sdillon 23690963Sarr td->td_retval[0] = -1; 23790963Sarr if (SCARG(uap, modid) == 0) { 23890963Sarr mod = TAILQ_FIRST(&modules); 23990963Sarr if (mod) 24090963Sarr td->td_retval[0] = mod->id; 24190963Sarr else 24290963Sarr error = ENOENT; 24390963Sarr goto done2; 24490963Sarr } 24590963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 24690963Sarr if (mod == NULL) { 24790963Sarr error = ENOENT; 24890963Sarr goto done2; 24990963Sarr } 25090963Sarr if (TAILQ_NEXT(mod, link)) 25190963Sarr td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 25282749Sdillon else 25390963Sarr td->td_retval[0] = 0; 25482749Sdillondone2: 25590963Sarr mtx_unlock(&Giant); 25690963Sarr return (error); 25725537Sdfr} 25825537Sdfr 25982749Sdillon/* 26082749Sdillon * MPSAFE 26182749Sdillon */ 26225537Sdfrint 26383366Sjulianmodfnext(struct thread *td, struct modfnext_args *uap) 26425537Sdfr{ 26590963Sarr module_t mod; 26690963Sarr int error; 26725537Sdfr 26890963Sarr td->td_retval[0] = -1; 26925537Sdfr 27090963Sarr mtx_lock(&Giant); 27182749Sdillon 27290963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 27390963Sarr if (mod == NULL) { 27490963Sarr error = ENOENT; 27590963Sarr } else { 27690963Sarr error = 0; 27790963Sarr if (TAILQ_NEXT(mod, flink)) 27890963Sarr td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 27990963Sarr else 28090963Sarr td->td_retval[0] = 0; 28190963Sarr } 28290963Sarr mtx_unlock(&Giant); 28390963Sarr return (error); 28425537Sdfr} 28525537Sdfr 28642435Sdfrstruct module_stat_v1 { 28791067Sarr int version; /* set to sizeof(struct module_stat) */ 28891067Sarr char name[MAXMODNAME]; 28991067Sarr int refs; 29091067Sarr int id; 29142435Sdfr}; 29242435Sdfr 29382749Sdillon/* 29482749Sdillon * MPSAFE 29582749Sdillon */ 29625537Sdfrint 29783366Sjulianmodstat(struct thread *td, struct modstat_args *uap) 29825537Sdfr{ 29990963Sarr module_t mod; 30090963Sarr int error = 0; 30190963Sarr int namelen; 30290963Sarr int version; 30390963Sarr struct module_stat *stat; 30425537Sdfr 30590963Sarr mtx_lock(&Giant); 30682749Sdillon 30790963Sarr mod = module_lookupbyid(SCARG(uap, modid)); 30890963Sarr if (mod == NULL) { 30990963Sarr error = ENOENT; 31090963Sarr goto out; 31190963Sarr } 31290963Sarr stat = SCARG(uap, stat); 31325537Sdfr 31490963Sarr /* 31590963Sarr * Check the version of the user's structure. 31690963Sarr */ 31790963Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 31890963Sarr goto out; 31990963Sarr if (version != sizeof(struct module_stat_v1) 32090963Sarr && version != sizeof(struct module_stat)) { 32190963Sarr error = EINVAL; 32290963Sarr goto out; 32390963Sarr } 32490963Sarr namelen = strlen(mod->name) + 1; 32590963Sarr if (namelen > MAXMODNAME) 32690963Sarr namelen = MAXMODNAME; 32790963Sarr if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0) 32890963Sarr goto out; 32925537Sdfr 33090963Sarr if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0) 33190963Sarr goto out; 33290963Sarr if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0) 33390963Sarr goto out; 33425537Sdfr 33590963Sarr /* 33690963Sarr * >v1 stat includes module data. 33790963Sarr */ 33890963Sarr if (version == sizeof(struct module_stat)) { 33990963Sarr if ((error = copyout(&mod->data, &stat->data, 34090963Sarr sizeof(mod->data))) != 0) 34190963Sarr goto out; 34290963Sarr } 34390963Sarr td->td_retval[0] = 0; 34425537Sdfrout: 34590963Sarr mtx_unlock(&Giant); 34690980Sarr return (error); 34725537Sdfr} 34825537Sdfr 34982749Sdillon/* 35082749Sdillon * MPSAFE 35182749Sdillon */ 35225537Sdfrint 35383366Sjulianmodfind(struct thread *td, struct modfind_args *uap) 35425537Sdfr{ 35590963Sarr int error = 0; 35690963Sarr char name[MAXMODNAME]; 35790963Sarr module_t mod; 35825537Sdfr 35990963Sarr if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0) 36090963Sarr goto out; 36125537Sdfr 36290963Sarr mtx_lock(&Giant); 36390963Sarr mod = module_lookupbyname(name); 36490963Sarr if (mod == NULL) 36590963Sarr error = ENOENT; 36690963Sarr else 36790963Sarr td->td_retval[0] = mod->id; 36890963Sarr mtx_unlock(&Giant); 36925537Sdfrout: 37090980Sarr return (error); 37125537Sdfr} 372