kern_module.c revision 215544
153812Salfred/*-
253812Salfred * Copyright (c) 1997 Doug Rabson
353812Salfred * All rights reserved.
453812Salfred *
553812Salfred * Redistribution and use in source and binary forms, with or without
653812Salfred * modification, are permitted provided that the following conditions
7103388Smini * are met:
853812Salfred * 1. Redistributions of source code must retain the above copyright
975369Sdeischen *    notice, this list of conditions and the following disclaimer.
1075369Sdeischen * 2. Redistributions in binary form must reproduce the above copyright
1175369Sdeischen *    notice, this list of conditions and the following disclaimer in the
1275369Sdeischen *    documentation and/or other materials provided with the distribution.
1371581Sdeischen *
14113658Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15113658Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16113658Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17113658Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1853812Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1971581Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2053812Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21113658Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22115278Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2353812Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2453812Salfred * SUCH DAMAGE.
25113658Sdeischen */
26113658Sdeischen
27113658Sdeischen#include "opt_compat.h"
28113658Sdeischen
29113658Sdeischen#include <sys/cdefs.h>
30116972Sdavidxu__FBSDID("$FreeBSD: head/sys/kern/kern_module.c 215544 2010-11-19 19:43:56Z attilio $");
31116972Sdavidxu
32116972Sdavidxu#include <sys/param.h>
33116972Sdavidxu#include <sys/kernel.h>
34116972Sdavidxu#include <sys/systm.h>
3554708Sdeischen#include <sys/eventhandler.h>
36113658Sdeischen#include <sys/malloc.h>
37113658Sdeischen#include <sys/sysproto.h>
3854708Sdeischen#include <sys/sysent.h>
39113658Sdeischen#include <sys/proc.h>
4054708Sdeischen#include <sys/lock.h>
4154708Sdeischen#include <sys/mutex.h>
4254708Sdeischen#include <sys/reboot.h>
4354708Sdeischen#include <sys/sx.h>
4454708Sdeischen#include <sys/module.h>
4553812Salfred#include <sys/linker.h>
4653812Salfred
4753812Salfredstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures");
48113658Sdeischen
4953812Salfredtypedef TAILQ_HEAD(modulelst, module) modulelist_t;
5053812Salfredstruct module {
51113658Sdeischen	TAILQ_ENTRY(module)	link;	/* chain together all modules */
52113658Sdeischen	TAILQ_ENTRY(module)	flink;	/* all modules in a file */
53113658Sdeischen	struct linker_file	*file;	/* file which contains this module */
54113658Sdeischen	int			refs;	/* reference count */
55113658Sdeischen	int 			id;	/* unique id number */
56113658Sdeischen	char 			*name;	/* module name */
57113658Sdeischen	modeventhand_t 		handler;	/* event handler */
58113658Sdeischen	void 			*arg;	/* argument for handler */
59113658Sdeischen	modspecific_t 		data;	/* module specific data */
60113658Sdeischen};
61113658Sdeischen
6253812Salfred#define MOD_EVENT(mod, type)	(mod)->handler((mod), (type), (mod)->arg)
63111035Smini
64111035Sministatic modulelist_t modules;
6553812Salfredstruct sx modules_sx;
6653812Salfredstatic int nextid = 1;
67113658Sdeischenstatic void module_shutdown(void *, int);
68113658Sdeischen
6953812Salfredstatic int
7053812Salfredmodevent_nop(module_t mod, int what, void *arg)
7176909Sjasone{
72115278Sdeischen
73115278Sdeischen	switch(what) {
74115278Sdeischen	case MOD_LOAD:
75113658Sdeischen		return (0);
76115278Sdeischen	case MOD_UNLOAD:
77115278Sdeischen		return (EBUSY);
78115278Sdeischen	default:
79115278Sdeischen		return (EOPNOTSUPP);
80115278Sdeischen	}
81115278Sdeischen}
82115278Sdeischen
8381750Sjasonestatic void
8481750Sjasonemodule_init(void *arg)
8561681Sjasone{
8653812Salfred
8753812Salfred	sx_init(&modules_sx, "module subsystem sx lock");
8853812Salfred	TAILQ_INIT(&modules);
8953812Salfred	EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
9053812Salfred	    SHUTDOWN_PRI_DEFAULT);
9153812Salfred}
9253812Salfred
9353812SalfredSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
9453812Salfred
9556277Sjasonestatic void
9656277Sjasonemodule_shutdown(void *arg1, int arg2)
9753812Salfred{
9853812Salfred	module_t mod;
99113658Sdeischen
100113658Sdeischen	if (arg2 & RB_NOSYNC)
10156277Sjasone		return;
10253812Salfred	mtx_lock(&Giant);
10353812Salfred	MOD_SLOCK;
10453812Salfred	TAILQ_FOREACH_REVERSE(mod, &modules, modulelst, link)
10553812Salfred		MOD_EVENT(mod, MOD_SHUTDOWN);
10653812Salfred	MOD_SUNLOCK;
10753812Salfred	mtx_unlock(&Giant);
10853812Salfred}
10954708Sdeischen
110113658Sdeischenvoid
111113658Sdeischenmodule_register_init(const void *arg)
112116972Sdavidxu{
11353812Salfred	const moduledata_t *data = (const moduledata_t *)arg;
11454708Sdeischen	int error;
115113658Sdeischen	module_t mod;
116113658Sdeischen
117113658Sdeischen	mtx_lock(&Giant);
118113658Sdeischen	MOD_SLOCK;
119113658Sdeischen	mod = module_lookupbyname(data->name);
120113658Sdeischen	if (mod == NULL)
121115278Sdeischen		panic("module_register_init: module named %s not found\n",
122115278Sdeischen		    data->name);
123115278Sdeischen	MOD_SUNLOCK;
124115278Sdeischen	error = MOD_EVENT(mod, MOD_LOAD);
125115278Sdeischen	if (error) {
126115278Sdeischen		MOD_EVENT(mod, MOD_UNLOAD);
127115278Sdeischen		MOD_XLOCK;
128115278Sdeischen		module_release(mod);
129115278Sdeischen		MOD_XUNLOCK;
13053812Salfred		printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
13153812Salfred		    " %d\n", data->name, (void *)data->evhand, data->priv,
13253812Salfred		    error);
13353812Salfred	} else {
13453812Salfred		MOD_XLOCK;
13571581Sdeischen		if (mod->file) {
13653812Salfred			/*
13771581Sdeischen			 * Once a module is succesfully loaded, move
13853812Salfred			 * it to the head of the module list for this
13953812Salfred			 * linker file.  This resorts the list so that
140113658Sdeischen			 * when the kernel linker iterates over the
14153812Salfred			 * modules to unload them, it will unload them
142113658Sdeischen			 * in the reverse order they were loaded.
143113658Sdeischen			 */
144113658Sdeischen			TAILQ_REMOVE(&mod->file->modules, mod, flink);
14571581Sdeischen			TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
14653812Salfred		}
14753812Salfred		MOD_XUNLOCK;
14853812Salfred	}
14953812Salfred	mtx_unlock(&Giant);
15053812Salfred}
15171581Sdeischen
15271581Sdeischenint
153113658Sdeischenmodule_register(const moduledata_t *data, linker_file_t container)
15453812Salfred{
15553812Salfred	size_t namelen;
15653812Salfred	module_t newmod;
15753812Salfred
15853812Salfred	MOD_XLOCK;
15971581Sdeischen	newmod = module_lookupbyname(data->name);
16053812Salfred	if (newmod != NULL) {
16153812Salfred		MOD_XUNLOCK;
16253812Salfred		printf("module_register: module %s already exists!\n",
16353812Salfred		    data->name);
16453812Salfred		return (EEXIST);
16553812Salfred	}
166113658Sdeischen	namelen = strlen(data->name) + 1;
167113658Sdeischen	newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
168113658Sdeischen	if (newmod == NULL) {
169113658Sdeischen		MOD_XUNLOCK;
170113658Sdeischen		return (ENOMEM);
171113658Sdeischen	}
17253812Salfred	newmod->refs = 1;
17353812Salfred	newmod->id = nextid++;
17453812Salfred	newmod->name = (char *)(newmod + 1);
17553812Salfred	strcpy(newmod->name, data->name);
17671581Sdeischen	newmod->handler = data->evhand ? data->evhand : modevent_nop;
17753812Salfred	newmod->arg = data->priv;
17871581Sdeischen	bzero(&newmod->data, sizeof(newmod->data));
17953812Salfred	TAILQ_INSERT_TAIL(&modules, newmod, link);
18053812Salfred
181113658Sdeischen	if (container)
18253812Salfred		TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
183113658Sdeischen	newmod->file = container;
184113658Sdeischen	MOD_XUNLOCK;
185113658Sdeischen	return (0);
18671581Sdeischen}
18753812Salfred
18853812Salfredvoid
18953812Salfredmodule_reference(module_t mod)
19053812Salfred{
19171581Sdeischen
192113658Sdeischen	MOD_XLOCK_ASSERT;
19353812Salfred
19453812Salfred	MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
19553812Salfred	mod->refs++;
19653812Salfred}
19753812Salfred
19871581Sdeischenvoid
19953812Salfredmodule_release(module_t mod)
20053812Salfred{
20153812Salfred
20253812Salfred	MOD_XLOCK_ASSERT;
20353812Salfred
20453812Salfred	if (mod->refs <= 0)
205113658Sdeischen		panic("module_release: bad reference count");
206113658Sdeischen
207113658Sdeischen	MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
208113658Sdeischen
209113658Sdeischen	mod->refs--;
210113658Sdeischen	if (mod->refs == 0) {
21153812Salfred		TAILQ_REMOVE(&modules, mod, link);
21253812Salfred		if (mod->file)
21353812Salfred			TAILQ_REMOVE(&mod->file->modules, mod, flink);
214113658Sdeischen		free(mod, M_MODULE);
215113658Sdeischen	}
21653812Salfred}
21771581Sdeischen
218113658Sdeischenmodule_t
21953812Salfredmodule_lookupbyname(const char *name)
22053812Salfred{
22153812Salfred	module_t mod;
22253812Salfred	int err;
22353812Salfred
224113658Sdeischen	MOD_LOCK_ASSERT;
225113658Sdeischen
226113658Sdeischen	TAILQ_FOREACH(mod, &modules, link) {
227113658Sdeischen		err = strcmp(mod->name, name);
228113658Sdeischen		if (err == 0)
229113658Sdeischen			return (mod);
230113658Sdeischen	}
231113658Sdeischen	return (NULL);
232113658Sdeischen}
233113658Sdeischen
234113658Sdeischenmodule_t
235113658Sdeischenmodule_lookupbyid(int modid)
236113658Sdeischen{
237113658Sdeischen        module_t mod;
238113658Sdeischen
239113658Sdeischen        MOD_LOCK_ASSERT;
240113658Sdeischen
24153812Salfred        TAILQ_FOREACH(mod, &modules, link)
24253812Salfred                if (mod->id == modid)
24353812Salfred                        return(mod);
24453812Salfred        return (NULL);
24553812Salfred}
24653812Salfred
247113658Sdeischenint
24853812Salfredmodule_quiesce(module_t mod)
24971581Sdeischen{
25071581Sdeischen	int error;
251114187Sdeischen
252113658Sdeischen	mtx_lock(&Giant);
253114187Sdeischen	error = MOD_EVENT(mod, MOD_QUIESCE);
254113658Sdeischen	mtx_unlock(&Giant);
255113658Sdeischen	if (error == EOPNOTSUPP || error == EINVAL)
256113658Sdeischen		error = 0;
257113658Sdeischen	return (error);
258113658Sdeischen}
25953812Salfred
260114187Sdeischenint
261113658Sdeischenmodule_unload(module_t mod)
262113658Sdeischen{
263114187Sdeischen	int error;
26453812Salfred
26553812Salfred	mtx_lock(&Giant);
26653812Salfred	error = MOD_EVENT(mod, MOD_UNLOAD);
267113658Sdeischen	mtx_unlock(&Giant);
26853812Salfred	return (error);
269114187Sdeischen}
270113658Sdeischen
27153812Salfredint
272113658Sdeischenmodule_getid(module_t mod)
273114187Sdeischen{
27453812Salfred
27556277Sjasone	MOD_LOCK_ASSERT;
27656277Sjasone	return (mod->id);
27756277Sjasone}
27856277Sjasone
27971581Sdeischenmodule_t
28056277Sjasonemodule_getfnext(module_t mod)
28171581Sdeischen{
28271581Sdeischen
28371581Sdeischen	MOD_LOCK_ASSERT;
284114187Sdeischen	return (TAILQ_NEXT(mod, flink));
285113658Sdeischen}
286113658Sdeischen
287114187Sdeischenconst char *
288113658Sdeischenmodule_getname(module_t mod)
28956277Sjasone{
29056277Sjasone
291114187Sdeischen	MOD_LOCK_ASSERT;
29256277Sjasone	return (mod->name);
293}
294
295void
296module_setspecific(module_t mod, modspecific_t *datap)
297{
298
299	MOD_XLOCK_ASSERT;
300	mod->data = *datap;
301}
302
303linker_file_t
304module_file(module_t mod)
305{
306
307	return (mod->file);
308}
309
310/*
311 * Syscalls.
312 */
313int
314modnext(struct thread *td, struct modnext_args *uap)
315{
316	module_t mod;
317	int error = 0;
318
319	td->td_retval[0] = -1;
320
321	MOD_SLOCK;
322	if (uap->modid == 0) {
323		mod = TAILQ_FIRST(&modules);
324		if (mod)
325			td->td_retval[0] = mod->id;
326		else
327			error = ENOENT;
328		goto done2;
329	}
330	mod = module_lookupbyid(uap->modid);
331	if (mod == NULL) {
332		error = ENOENT;
333		goto done2;
334	}
335	if (TAILQ_NEXT(mod, link))
336		td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
337	else
338		td->td_retval[0] = 0;
339done2:
340	MOD_SUNLOCK;
341	return (error);
342}
343
344int
345modfnext(struct thread *td, struct modfnext_args *uap)
346{
347	module_t mod;
348	int error;
349
350	td->td_retval[0] = -1;
351
352	MOD_SLOCK;
353	mod = module_lookupbyid(uap->modid);
354	if (mod == NULL) {
355		error = ENOENT;
356	} else {
357		error = 0;
358		if (TAILQ_NEXT(mod, flink))
359			td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
360		else
361			td->td_retval[0] = 0;
362	}
363	MOD_SUNLOCK;
364	return (error);
365}
366
367struct module_stat_v1 {
368	int	version;		/* set to sizeof(struct module_stat) */
369	char	name[MAXMODNAME];
370	int	refs;
371	int	id;
372};
373
374int
375modstat(struct thread *td, struct modstat_args *uap)
376{
377	module_t mod;
378	modspecific_t data;
379	int error = 0;
380	int id, namelen, refs, version;
381	struct module_stat *stat;
382	char *name;
383
384	MOD_SLOCK;
385	mod = module_lookupbyid(uap->modid);
386	if (mod == NULL) {
387		MOD_SUNLOCK;
388		return (ENOENT);
389	}
390	id = mod->id;
391	refs = mod->refs;
392	name = mod->name;
393	data = mod->data;
394	MOD_SUNLOCK;
395	stat = uap->stat;
396
397	/*
398	 * Check the version of the user's structure.
399	 */
400	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
401		return (error);
402	if (version != sizeof(struct module_stat_v1)
403	    && version != sizeof(struct module_stat))
404		return (EINVAL);
405	namelen = strlen(mod->name) + 1;
406	if (namelen > MAXMODNAME)
407		namelen = MAXMODNAME;
408	if ((error = copyout(name, &stat->name[0], namelen)) != 0)
409		return (error);
410
411	if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
412		return (error);
413	if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
414		return (error);
415
416	/*
417	 * >v1 stat includes module data.
418	 */
419	if (version == sizeof(struct module_stat))
420		if ((error = copyout(&data, &stat->data,
421		    sizeof(data))) != 0)
422			return (error);
423	td->td_retval[0] = 0;
424	return (error);
425}
426
427int
428modfind(struct thread *td, struct modfind_args *uap)
429{
430	int error = 0;
431	char name[MAXMODNAME];
432	module_t mod;
433
434	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
435		return (error);
436
437	MOD_SLOCK;
438	mod = module_lookupbyname(name);
439	if (mod == NULL)
440		error = ENOENT;
441	else
442		td->td_retval[0] = module_getid(mod);
443	MOD_SUNLOCK;
444	return (error);
445}
446
447MODULE_VERSION(kernel, __FreeBSD_version);
448
449#ifdef COMPAT_FREEBSD32
450#include <sys/mount.h>
451#include <sys/socket.h>
452#include <compat/freebsd32/freebsd32_util.h>
453#include <compat/freebsd32/freebsd32.h>
454#include <compat/freebsd32/freebsd32_proto.h>
455
456typedef union modspecific32 {
457	int		intval;
458	uint32_t	uintval;
459	int		longval;
460	uint32_t	ulongval;
461} modspecific32_t;
462
463struct module_stat32 {
464	int		version;
465	char		name[MAXMODNAME];
466	int		refs;
467	int		id;
468	modspecific32_t	data;
469};
470
471int
472freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
473{
474	module_t mod;
475	modspecific32_t data32;
476	int error = 0;
477	int id, namelen, refs, version;
478	struct module_stat32 *stat32;
479	char *name;
480
481	MOD_SLOCK;
482	mod = module_lookupbyid(uap->modid);
483	if (mod == NULL) {
484		MOD_SUNLOCK;
485		return (ENOENT);
486	}
487
488	id = mod->id;
489	refs = mod->refs;
490	name = mod->name;
491	CP(mod->data, data32, intval);
492	CP(mod->data, data32, uintval);
493	CP(mod->data, data32, longval);
494	CP(mod->data, data32, ulongval);
495	MOD_SUNLOCK;
496	stat32 = uap->stat;
497
498	if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
499		return (error);
500	if (version != sizeof(struct module_stat_v1)
501	    && version != sizeof(struct module_stat32))
502		return (EINVAL);
503	namelen = strlen(mod->name) + 1;
504	if (namelen > MAXMODNAME)
505		namelen = MAXMODNAME;
506	if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
507		return (error);
508
509	if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
510		return (error);
511	if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
512		return (error);
513
514	/*
515	 * >v1 stat includes module data.
516	 */
517	if (version == sizeof(struct module_stat32))
518		if ((error = copyout(&data32, &stat32->data,
519		    sizeof(data32))) != 0)
520			return (error);
521	td->td_retval[0] = 0;
522	return (error);
523}
524#endif
525