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