xref: /freebsd/sys/kern/kern_module.c (revision 1a1c04b6b3b8bf09b04915160b30c8778a82bf0a)
1cea6c86cSDoug Rabson /*-
2cea6c86cSDoug Rabson  * Copyright (c) 1997 Doug Rabson
3cea6c86cSDoug Rabson  * All rights reserved.
4cea6c86cSDoug Rabson  *
5cea6c86cSDoug Rabson  * Redistribution and use in source and binary forms, with or without
6cea6c86cSDoug Rabson  * modification, are permitted provided that the following conditions
7cea6c86cSDoug Rabson  * are met:
8cea6c86cSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
9cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer.
10cea6c86cSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
11cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
12cea6c86cSDoug Rabson  *    documentation and/or other materials provided with the distribution.
13cea6c86cSDoug Rabson  *
14cea6c86cSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cea6c86cSDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cea6c86cSDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17cea6c86cSDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cea6c86cSDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cea6c86cSDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cea6c86cSDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cea6c86cSDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cea6c86cSDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cea6c86cSDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cea6c86cSDoug Rabson  * SUCH DAMAGE.
25cea6c86cSDoug Rabson  */
26cea6c86cSDoug Rabson 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
30cea6c86cSDoug Rabson #include <sys/param.h>
31cea6c86cSDoug Rabson #include <sys/kernel.h>
32cea6c86cSDoug Rabson #include <sys/systm.h>
33fcb893a8SMike Smith #include <sys/eventhandler.h>
34cea6c86cSDoug Rabson #include <sys/malloc.h>
35cea6c86cSDoug Rabson #include <sys/sysproto.h>
36cea6c86cSDoug Rabson #include <sys/sysent.h>
37cb226aaaSPoul-Henning Kamp #include <sys/proc.h>
38835a82eeSMatthew Dillon #include <sys/lock.h>
39835a82eeSMatthew Dillon #include <sys/mutex.h>
401a1c04b6SDon Lewis #include <sys/reboot.h>
419b3851e9SAndrew R. Reiter #include <sys/sx.h>
429b3851e9SAndrew R. Reiter #include <sys/module.h>
439b3851e9SAndrew R. Reiter #include <sys/linker.h>
44cea6c86cSDoug Rabson 
45959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
46cea6c86cSDoug Rabson 
47e3975643SJake Burkholder typedef TAILQ_HEAD(, module) modulelist_t;
48cea6c86cSDoug Rabson struct module {
49e3975643SJake Burkholder 	TAILQ_ENTRY(module)	link;	/* chain together all modules */
50e3975643SJake Burkholder 	TAILQ_ENTRY(module)	flink;	/* all modules in a file */
51cea6c86cSDoug Rabson 	struct linker_file	*file;	/* file which contains this module */
52cea6c86cSDoug Rabson 	int			refs;	/* reference count */
53cea6c86cSDoug Rabson 	int 			id;	/* unique id number */
54cea6c86cSDoug Rabson 	char 			*name;	/* module name */
55cea6c86cSDoug Rabson 	modeventhand_t 		handler;	/* event handler */
56cea6c86cSDoug Rabson 	void 			*arg;	/* argument for handler */
57a35261efSDoug Rabson 	modspecific_t 		data;	/* module specific data */
58cea6c86cSDoug Rabson };
59cea6c86cSDoug Rabson 
60cea6c86cSDoug Rabson #define MOD_EVENT(mod, type)	(mod)->handler((mod), (type), (mod)->arg)
61cea6c86cSDoug Rabson 
62cea6c86cSDoug Rabson static modulelist_t modules;
639b3851e9SAndrew R. Reiter struct sx modules_sx;
64cea6c86cSDoug Rabson static int nextid = 1;
65fcb893a8SMike Smith static void module_shutdown(void *, int);
66cea6c86cSDoug Rabson 
67845ccef4SPeter Wemm static int
68845ccef4SPeter Wemm modevent_nop(module_t mod, int what, void *arg)
69845ccef4SPeter Wemm {
70e2ad640eSPoul-Henning Kamp 
71e2ad640eSPoul-Henning Kamp 	switch(what) {
72e2ad640eSPoul-Henning Kamp 	case MOD_LOAD:
73b65420f9SAndrew R. Reiter 		return (0);
74e2ad640eSPoul-Henning Kamp 	case MOD_UNLOAD:
75e2ad640eSPoul-Henning Kamp 		return (EBUSY);
76e2ad640eSPoul-Henning Kamp 	default:
77e2ad640eSPoul-Henning Kamp 		return (EOPNOTSUPP);
78e2ad640eSPoul-Henning Kamp 	}
79845ccef4SPeter Wemm }
80845ccef4SPeter Wemm 
81cea6c86cSDoug Rabson static void
82cea6c86cSDoug Rabson module_init(void *arg)
83cea6c86cSDoug Rabson {
84287698b4SAndrew R. Reiter 
859b3851e9SAndrew R. Reiter 	sx_init(&modules_sx, "module subsystem sx lock");
86cea6c86cSDoug Rabson 	TAILQ_INIT(&modules);
872488f309SPeter Wemm 	EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
88fcb893a8SMike Smith 	    SHUTDOWN_PRI_DEFAULT);
89cea6c86cSDoug Rabson }
90cea6c86cSDoug Rabson 
91287698b4SAndrew R. Reiter SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
92cea6c86cSDoug Rabson 
93cea6c86cSDoug Rabson static void
94fcb893a8SMike Smith module_shutdown(void *arg1, int arg2)
95cea6c86cSDoug Rabson {
96cea6c86cSDoug Rabson 	module_t mod;
97cea6c86cSDoug Rabson 
981a1c04b6SDon Lewis 	if (arg2 & RB_NOSYNC)
991a1c04b6SDon Lewis 		return;
1009b3851e9SAndrew R. Reiter 	MOD_SLOCK;
101fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(mod, &modules, link)
102cea6c86cSDoug Rabson 		MOD_EVENT(mod, MOD_SHUTDOWN);
1039b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
104cea6c86cSDoug Rabson }
105cea6c86cSDoug Rabson 
106cea6c86cSDoug Rabson void
1073cfc69e6SMatthew Dillon module_register_init(const void *arg)
108cea6c86cSDoug Rabson {
1093cfc69e6SMatthew Dillon 	const moduledata_t *data = (const moduledata_t *)arg;
110cea6c86cSDoug Rabson 	int error;
111b5b15c3fSPeter Wemm 	module_t mod;
112cea6c86cSDoug Rabson 
1139b3851e9SAndrew R. Reiter 	MOD_SLOCK;
114b5b15c3fSPeter Wemm 	mod = module_lookupbyname(data->name);
115b5b15c3fSPeter Wemm 	if (mod == NULL)
116287698b4SAndrew R. Reiter 		panic("module_register_init: module named %s not found\n",
117287698b4SAndrew R. Reiter 		    data->name);
1189b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
119b5b15c3fSPeter Wemm 	error = MOD_EVENT(mod, MOD_LOAD);
120b5b15c3fSPeter Wemm 	if (error) {
121b5b15c3fSPeter Wemm 		MOD_EVENT(mod, MOD_UNLOAD);
1229b3851e9SAndrew R. Reiter 		MOD_XLOCK;
123b5b15c3fSPeter Wemm 		module_release(mod);
1249b3851e9SAndrew R. Reiter 		MOD_XUNLOCK;
125bd47bef5SPeter Wemm 		printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
126bd47bef5SPeter Wemm 		    " %d\n", data->name, (void *)data->evhand, data->priv,
127287698b4SAndrew R. Reiter 		    error);
128cea6c86cSDoug Rabson 	}
129b5b15c3fSPeter Wemm }
130cea6c86cSDoug Rabson 
131cea6c86cSDoug Rabson int
132b5b15c3fSPeter Wemm module_register(const moduledata_t *data, linker_file_t container)
133cea6c86cSDoug Rabson {
134cea6c86cSDoug Rabson 	size_t namelen;
135cea6c86cSDoug Rabson 	module_t newmod;
136cea6c86cSDoug Rabson 
1379b3851e9SAndrew R. Reiter 	MOD_SLOCK;
138b5b15c3fSPeter Wemm 	newmod = module_lookupbyname(data->name);
139b5b15c3fSPeter Wemm 	if (newmod != NULL) {
1409b3851e9SAndrew R. Reiter 		MOD_SUNLOCK;
141287698b4SAndrew R. Reiter 		printf("module_register: module %s already exists!\n",
142287698b4SAndrew R. Reiter 		    data->name);
143b65420f9SAndrew R. Reiter 		return (EEXIST);
144b5b15c3fSPeter Wemm 	}
1459b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
146b5b15c3fSPeter Wemm 	namelen = strlen(data->name) + 1;
147a163d034SWarner Losh 	newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
148287698b4SAndrew R. Reiter 	if (newmod == NULL)
149b65420f9SAndrew R. Reiter 		return (ENOMEM);
1509b3851e9SAndrew R. Reiter 	MOD_XLOCK;
151cea6c86cSDoug Rabson 	newmod->refs = 1;
152cea6c86cSDoug Rabson 	newmod->id = nextid++;
153cea6c86cSDoug Rabson 	newmod->name = (char *)(newmod + 1);
154b5b15c3fSPeter Wemm 	strcpy(newmod->name, data->name);
155845ccef4SPeter Wemm 	newmod->handler = data->evhand ? data->evhand : modevent_nop;
156b5b15c3fSPeter Wemm 	newmod->arg = data->priv;
157a35261efSDoug Rabson 	bzero(&newmod->data, sizeof(newmod->data));
158cea6c86cSDoug Rabson 	TAILQ_INSERT_TAIL(&modules, newmod, link);
159cea6c86cSDoug Rabson 
160b5b15c3fSPeter Wemm 	if (container)
161f3b0d442SPeter Wemm 		TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
1621d23cba9SPeter Wemm 	newmod->file = container;
1639b3851e9SAndrew R. Reiter 	MOD_XUNLOCK;
164b65420f9SAndrew R. Reiter 	return (0);
165cea6c86cSDoug Rabson }
166cea6c86cSDoug Rabson 
167cea6c86cSDoug Rabson void
168cea6c86cSDoug Rabson module_reference(module_t mod)
169cea6c86cSDoug Rabson {
170cea6c86cSDoug Rabson 
1719b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1729b3851e9SAndrew R. Reiter 
173287698b4SAndrew R. Reiter 	MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
174cea6c86cSDoug Rabson 	mod->refs++;
175cea6c86cSDoug Rabson }
176cea6c86cSDoug Rabson 
177cea6c86cSDoug Rabson void
178cea6c86cSDoug Rabson module_release(module_t mod)
179cea6c86cSDoug Rabson {
180287698b4SAndrew R. Reiter 
1819b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1829b3851e9SAndrew R. Reiter 
183cea6c86cSDoug Rabson 	if (mod->refs <= 0)
184cea6c86cSDoug Rabson 		panic("module_release: bad reference count");
185cea6c86cSDoug Rabson 
186cea6c86cSDoug Rabson 	MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
187cea6c86cSDoug Rabson 
188cea6c86cSDoug Rabson 	mod->refs--;
189cea6c86cSDoug Rabson 	if (mod->refs == 0) {
190cea6c86cSDoug Rabson 		TAILQ_REMOVE(&modules, mod, link);
191287698b4SAndrew R. Reiter 		if (mod->file)
192cea6c86cSDoug Rabson 			TAILQ_REMOVE(&mod->file->modules, mod, flink);
1939b3851e9SAndrew R. Reiter 		MOD_XUNLOCK;
194cea6c86cSDoug Rabson 		free(mod, M_MODULE);
1959b3851e9SAndrew R. Reiter 		MOD_XLOCK;
196cea6c86cSDoug Rabson 	}
197cea6c86cSDoug Rabson }
198cea6c86cSDoug Rabson 
199cea6c86cSDoug Rabson module_t
200cea6c86cSDoug Rabson module_lookupbyname(const char *name)
201cea6c86cSDoug Rabson {
202cea6c86cSDoug Rabson 	module_t mod;
203287698b4SAndrew R. Reiter 	int err;
204cea6c86cSDoug Rabson 
2059b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
2069b3851e9SAndrew R. Reiter 
207fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(mod, &modules, link) {
208287698b4SAndrew R. Reiter 		err = strcmp(mod->name, name);
209287698b4SAndrew R. Reiter 		if (err == 0)
210b65420f9SAndrew R. Reiter 			return (mod);
211cea6c86cSDoug Rabson 	}
212b65420f9SAndrew R. Reiter 	return (NULL);
213cea6c86cSDoug Rabson }
214cea6c86cSDoug Rabson 
215cea6c86cSDoug Rabson module_t
216cea6c86cSDoug Rabson module_lookupbyid(int modid)
217cea6c86cSDoug Rabson {
218cea6c86cSDoug Rabson         module_t mod;
219cea6c86cSDoug Rabson 
2209b3851e9SAndrew R. Reiter         MOD_LOCK_ASSERT;
2219b3851e9SAndrew R. Reiter 
2229b3851e9SAndrew R. Reiter         TAILQ_FOREACH(mod, &modules, link)
223cea6c86cSDoug Rabson                 if (mod->id == modid)
224b65420f9SAndrew R. Reiter                         return(mod);
225b65420f9SAndrew R. Reiter         return (NULL);
226cea6c86cSDoug Rabson }
227cea6c86cSDoug Rabson 
228cea6c86cSDoug Rabson int
22965a311fcSPoul-Henning Kamp module_unload(module_t mod, int flags)
230cea6c86cSDoug Rabson {
23165a311fcSPoul-Henning Kamp 	int error;
232287698b4SAndrew R. Reiter 
23365a311fcSPoul-Henning Kamp 	error = MOD_EVENT(mod, MOD_QUIESCE);
2343e019deaSPoul-Henning Kamp 	if (error == EOPNOTSUPP || error == EINVAL)
23565a311fcSPoul-Henning Kamp 		error = 0;
23665a311fcSPoul-Henning Kamp 	if (flags == LINKER_UNLOAD_NORMAL && error != 0)
23765a311fcSPoul-Henning Kamp 		return (error);
238b65420f9SAndrew R. Reiter         return (MOD_EVENT(mod, MOD_UNLOAD));
239cea6c86cSDoug Rabson }
240cea6c86cSDoug Rabson 
241cea6c86cSDoug Rabson int
242cea6c86cSDoug Rabson module_getid(module_t mod)
243cea6c86cSDoug Rabson {
244287698b4SAndrew R. Reiter 
2459b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
246b65420f9SAndrew R. Reiter 	return (mod->id);
247cea6c86cSDoug Rabson }
248cea6c86cSDoug Rabson 
249cea6c86cSDoug Rabson module_t
250cea6c86cSDoug Rabson module_getfnext(module_t mod)
251cea6c86cSDoug Rabson {
252287698b4SAndrew R. Reiter 
2539b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
254b65420f9SAndrew R. Reiter 	return (TAILQ_NEXT(mod, flink));
255cea6c86cSDoug Rabson }
256cea6c86cSDoug Rabson 
257a35261efSDoug Rabson void
258a35261efSDoug Rabson module_setspecific(module_t mod, modspecific_t *datap)
259a35261efSDoug Rabson {
260287698b4SAndrew R. Reiter 
2619b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
262a35261efSDoug Rabson 	mod->data = *datap;
263a35261efSDoug Rabson }
264a35261efSDoug Rabson 
265cea6c86cSDoug Rabson /*
266cea6c86cSDoug Rabson  * Syscalls.
267cea6c86cSDoug Rabson  */
268835a82eeSMatthew Dillon /*
269835a82eeSMatthew Dillon  * MPSAFE
270835a82eeSMatthew Dillon  */
271cea6c86cSDoug Rabson int
272b40ce416SJulian Elischer modnext(struct thread *td, struct modnext_args *uap)
273cea6c86cSDoug Rabson {
274cea6c86cSDoug Rabson 	module_t mod;
275835a82eeSMatthew Dillon 	int error = 0;
276835a82eeSMatthew Dillon 
277b40ce416SJulian Elischer 	td->td_retval[0] = -1;
278e024f583SAndrew R. Reiter 
2799b3851e9SAndrew R. Reiter 	MOD_SLOCK;
280d1e405c5SAlfred Perlstein 	if (uap->modid == 0) {
281cea6c86cSDoug Rabson 		mod = TAILQ_FIRST(&modules);
282835a82eeSMatthew Dillon 		if (mod)
283b40ce416SJulian Elischer 			td->td_retval[0] = mod->id;
284835a82eeSMatthew Dillon 		else
285835a82eeSMatthew Dillon 			error = ENOENT;
286835a82eeSMatthew Dillon 		goto done2;
287cea6c86cSDoug Rabson 	}
288d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
289835a82eeSMatthew Dillon 	if (mod == NULL) {
290835a82eeSMatthew Dillon 		error = ENOENT;
291835a82eeSMatthew Dillon 		goto done2;
292835a82eeSMatthew Dillon 	}
293cea6c86cSDoug Rabson 	if (TAILQ_NEXT(mod, link))
294b40ce416SJulian Elischer 		td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
295cea6c86cSDoug Rabson 	else
296b40ce416SJulian Elischer 		td->td_retval[0] = 0;
297835a82eeSMatthew Dillon done2:
2989b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
299835a82eeSMatthew Dillon 	return (error);
300cea6c86cSDoug Rabson }
301cea6c86cSDoug Rabson 
302835a82eeSMatthew Dillon /*
303835a82eeSMatthew Dillon  * MPSAFE
304835a82eeSMatthew Dillon  */
305cea6c86cSDoug Rabson int
306b40ce416SJulian Elischer modfnext(struct thread *td, struct modfnext_args *uap)
307cea6c86cSDoug Rabson {
308cea6c86cSDoug Rabson 	module_t mod;
309835a82eeSMatthew Dillon 	int error;
310cea6c86cSDoug Rabson 
311b40ce416SJulian Elischer 	td->td_retval[0] = -1;
312cea6c86cSDoug Rabson 
3139b3851e9SAndrew R. Reiter 	MOD_SLOCK;
314d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
315835a82eeSMatthew Dillon 	if (mod == NULL) {
316835a82eeSMatthew Dillon 		error = ENOENT;
317835a82eeSMatthew Dillon 	} else {
318835a82eeSMatthew Dillon 		error = 0;
319cea6c86cSDoug Rabson 		if (TAILQ_NEXT(mod, flink))
320b40ce416SJulian Elischer 			td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
321cea6c86cSDoug Rabson 		else
322b40ce416SJulian Elischer 			td->td_retval[0] = 0;
323835a82eeSMatthew Dillon 	}
3249b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
325835a82eeSMatthew Dillon 	return (error);
326cea6c86cSDoug Rabson }
327cea6c86cSDoug Rabson 
328a35261efSDoug Rabson struct module_stat_v1 {
329a35261efSDoug Rabson 	int	version;		/* set to sizeof(struct module_stat) */
330a35261efSDoug Rabson 	char	name[MAXMODNAME];
331a35261efSDoug Rabson 	int	refs;
332a35261efSDoug Rabson 	int	id;
333a35261efSDoug Rabson };
334a35261efSDoug Rabson 
335835a82eeSMatthew Dillon /*
336835a82eeSMatthew Dillon  * MPSAFE
337835a82eeSMatthew Dillon  */
338cea6c86cSDoug Rabson int
339b40ce416SJulian Elischer modstat(struct thread *td, struct modstat_args *uap)
340cea6c86cSDoug Rabson {
341cea6c86cSDoug Rabson 	module_t mod;
3429b3851e9SAndrew R. Reiter 	modspecific_t data;
343cea6c86cSDoug Rabson 	int error = 0;
3449b3851e9SAndrew R. Reiter 	int id, namelen, refs, version;
345cea6c86cSDoug Rabson 	struct module_stat *stat;
3469b3851e9SAndrew R. Reiter 	char *name;
347cea6c86cSDoug Rabson 
3489b3851e9SAndrew R. Reiter 	MOD_SLOCK;
349d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
350835a82eeSMatthew Dillon 	if (mod == NULL) {
3519b3851e9SAndrew R. Reiter 		MOD_SUNLOCK;
352e024f583SAndrew R. Reiter 		return (ENOENT);
353835a82eeSMatthew Dillon 	}
3549b3851e9SAndrew R. Reiter 	id = mod->id;
3559b3851e9SAndrew R. Reiter 	refs = mod->refs;
3569b3851e9SAndrew R. Reiter 	name = mod->name;
3579b3851e9SAndrew R. Reiter 	data = mod->data;
3589b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
359d1e405c5SAlfred Perlstein 	stat = uap->stat;
360cea6c86cSDoug Rabson 
361cea6c86cSDoug Rabson 	/*
362cea6c86cSDoug Rabson 	 * Check the version of the user's structure.
363cea6c86cSDoug Rabson 	 */
364d254af07SMatthew Dillon 	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
365e024f583SAndrew R. Reiter 		return (error);
366a35261efSDoug Rabson 	if (version != sizeof(struct module_stat_v1)
367e024f583SAndrew R. Reiter 	    && version != sizeof(struct module_stat))
368e024f583SAndrew R. Reiter 		return (EINVAL);
369cea6c86cSDoug Rabson 	namelen = strlen(mod->name) + 1;
370cea6c86cSDoug Rabson 	if (namelen > MAXMODNAME)
371cea6c86cSDoug Rabson 		namelen = MAXMODNAME;
3729b3851e9SAndrew R. Reiter 	if ((error = copyout(name, &stat->name[0], namelen)) != 0)
373e024f583SAndrew R. Reiter 		return (error);
374cea6c86cSDoug Rabson 
3759b3851e9SAndrew R. Reiter 	if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
376e024f583SAndrew R. Reiter 		return (error);
3779b3851e9SAndrew R. Reiter 	if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
378e024f583SAndrew R. Reiter 		return (error);
379cea6c86cSDoug Rabson 
380a35261efSDoug Rabson 	/*
381a35261efSDoug Rabson 	 * >v1 stat includes module data.
382a35261efSDoug Rabson 	 */
383e024f583SAndrew R. Reiter 	if (version == sizeof(struct module_stat))
3849b3851e9SAndrew R. Reiter 		if ((error = copyout(&data, &stat->data,
3859b3851e9SAndrew R. Reiter 		    sizeof(data))) != 0)
386e024f583SAndrew R. Reiter 			return (error);
387b40ce416SJulian Elischer 	td->td_retval[0] = 0;
388b65420f9SAndrew R. Reiter 	return (error);
389cea6c86cSDoug Rabson }
390cea6c86cSDoug Rabson 
391835a82eeSMatthew Dillon /*
392835a82eeSMatthew Dillon  * MPSAFE
393835a82eeSMatthew Dillon  */
394cea6c86cSDoug Rabson int
395b40ce416SJulian Elischer modfind(struct thread *td, struct modfind_args *uap)
396cea6c86cSDoug Rabson {
397cea6c86cSDoug Rabson 	int error = 0;
398cea6c86cSDoug Rabson 	char name[MAXMODNAME];
399cea6c86cSDoug Rabson 	module_t mod;
400cea6c86cSDoug Rabson 
401d1e405c5SAlfred Perlstein 	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
402e024f583SAndrew R. Reiter 		return (error);
403cea6c86cSDoug Rabson 
4049b3851e9SAndrew R. Reiter 	MOD_SLOCK;
405cea6c86cSDoug Rabson 	mod = module_lookupbyname(name);
406835a82eeSMatthew Dillon 	if (mod == NULL)
407cea6c86cSDoug Rabson 		error = ENOENT;
408cea6c86cSDoug Rabson 	else
4099b3851e9SAndrew R. Reiter 		td->td_retval[0] = module_getid(mod);
4109b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
411b65420f9SAndrew R. Reiter 	return (error);
412cea6c86cSDoug Rabson }
413