Deleted Added
full compact
kern_module.c (132167) kern_module.c (132199)
1/*-
2 * Copyright (c) 1997 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1997 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/kern/kern_module.c 132167 2004-07-14 22:37:36Z phk $");
28__FBSDID("$FreeBSD: head/sys/kern/kern_module.c 132199 2004-07-15 08:26:07Z phk $");
29
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/systm.h>
33#include <sys/eventhandler.h>
34#include <sys/malloc.h>
35#include <sys/sysproto.h>
36#include <sys/sysent.h>
37#include <sys/proc.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/sx.h>
41#include <sys/module.h>
42#include <sys/linker.h>
43
44static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
45
46typedef TAILQ_HEAD(, module) modulelist_t;
47struct module {
48 TAILQ_ENTRY(module) link; /* chain together all modules */
49 TAILQ_ENTRY(module) flink; /* all modules in a file */
50 struct linker_file *file; /* file which contains this module */
51 int refs; /* reference count */
52 int id; /* unique id number */
53 char *name; /* module name */
54 modeventhand_t handler; /* event handler */
55 void *arg; /* argument for handler */
56 modspecific_t data; /* module specific data */
57};
58
59#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
60
61static modulelist_t modules;
62struct sx modules_sx;
63static int nextid = 1;
64static void module_shutdown(void *, int);
65
66static int
67modevent_nop(module_t mod, int what, void *arg)
68{
69
70 switch(what) {
71 case MOD_LOAD:
72 return (0);
73 case MOD_UNLOAD:
74 return (EBUSY);
75 default:
76 return (EOPNOTSUPP);
77 }
78}
79
80static void
81module_init(void *arg)
82{
83
84 sx_init(&modules_sx, "module subsystem sx lock");
85 TAILQ_INIT(&modules);
86 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
87 SHUTDOWN_PRI_DEFAULT);
88}
89
90SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
91
92static void
93module_shutdown(void *arg1, int arg2)
94{
95 module_t mod;
96
97 MOD_SLOCK;
98 TAILQ_FOREACH(mod, &modules, link)
99 MOD_EVENT(mod, MOD_SHUTDOWN);
100 MOD_SUNLOCK;
101}
102
103void
104module_register_init(const void *arg)
105{
106 const moduledata_t *data = (const moduledata_t *)arg;
107 int error;
108 module_t mod;
109
110 MOD_SLOCK;
111 mod = module_lookupbyname(data->name);
112 if (mod == NULL)
113 panic("module_register_init: module named %s not found\n",
114 data->name);
115 MOD_SUNLOCK;
116 error = MOD_EVENT(mod, MOD_LOAD);
117 if (error) {
118 MOD_EVENT(mod, MOD_UNLOAD);
119 MOD_XLOCK;
120 module_release(mod);
121 MOD_XUNLOCK;
122 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
123 " %d\n", data->name, (void *)data->evhand, data->priv,
124 error);
125 }
126}
127
128int
129module_register(const moduledata_t *data, linker_file_t container)
130{
131 size_t namelen;
132 module_t newmod;
133
134 MOD_SLOCK;
135 newmod = module_lookupbyname(data->name);
136 if (newmod != NULL) {
137 MOD_SUNLOCK;
138 printf("module_register: module %s already exists!\n",
139 data->name);
140 return (EEXIST);
141 }
142 MOD_SUNLOCK;
143 namelen = strlen(data->name) + 1;
144 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
145 if (newmod == NULL)
146 return (ENOMEM);
147 MOD_XLOCK;
148 newmod->refs = 1;
149 newmod->id = nextid++;
150 newmod->name = (char *)(newmod + 1);
151 strcpy(newmod->name, data->name);
152 newmod->handler = data->evhand ? data->evhand : modevent_nop;
153 newmod->arg = data->priv;
154 bzero(&newmod->data, sizeof(newmod->data));
155 TAILQ_INSERT_TAIL(&modules, newmod, link);
156
157 if (container)
158 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
159 newmod->file = container;
160 MOD_XUNLOCK;
161 return (0);
162}
163
164void
165module_reference(module_t mod)
166{
167
168 MOD_XLOCK_ASSERT;
169
170 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
171 mod->refs++;
172}
173
174void
175module_release(module_t mod)
176{
177
178 MOD_XLOCK_ASSERT;
179
180 if (mod->refs <= 0)
181 panic("module_release: bad reference count");
182
183 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
184
185 mod->refs--;
186 if (mod->refs == 0) {
187 TAILQ_REMOVE(&modules, mod, link);
188 if (mod->file)
189 TAILQ_REMOVE(&mod->file->modules, mod, flink);
190 MOD_XUNLOCK;
191 free(mod, M_MODULE);
192 MOD_XLOCK;
193 }
194}
195
196module_t
197module_lookupbyname(const char *name)
198{
199 module_t mod;
200 int err;
201
202 MOD_LOCK_ASSERT;
203
204 TAILQ_FOREACH(mod, &modules, link) {
205 err = strcmp(mod->name, name);
206 if (err == 0)
207 return (mod);
208 }
209 return (NULL);
210}
211
212module_t
213module_lookupbyid(int modid)
214{
215 module_t mod;
216
217 MOD_LOCK_ASSERT;
218
219 TAILQ_FOREACH(mod, &modules, link)
220 if (mod->id == modid)
221 return(mod);
222 return (NULL);
223}
224
225int
226module_unload(module_t mod, int flags)
227{
228 int error;
229
230 error = MOD_EVENT(mod, MOD_QUIESCE);
29
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/systm.h>
33#include <sys/eventhandler.h>
34#include <sys/malloc.h>
35#include <sys/sysproto.h>
36#include <sys/sysent.h>
37#include <sys/proc.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/sx.h>
41#include <sys/module.h>
42#include <sys/linker.h>
43
44static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
45
46typedef TAILQ_HEAD(, module) modulelist_t;
47struct module {
48 TAILQ_ENTRY(module) link; /* chain together all modules */
49 TAILQ_ENTRY(module) flink; /* all modules in a file */
50 struct linker_file *file; /* file which contains this module */
51 int refs; /* reference count */
52 int id; /* unique id number */
53 char *name; /* module name */
54 modeventhand_t handler; /* event handler */
55 void *arg; /* argument for handler */
56 modspecific_t data; /* module specific data */
57};
58
59#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
60
61static modulelist_t modules;
62struct sx modules_sx;
63static int nextid = 1;
64static void module_shutdown(void *, int);
65
66static int
67modevent_nop(module_t mod, int what, void *arg)
68{
69
70 switch(what) {
71 case MOD_LOAD:
72 return (0);
73 case MOD_UNLOAD:
74 return (EBUSY);
75 default:
76 return (EOPNOTSUPP);
77 }
78}
79
80static void
81module_init(void *arg)
82{
83
84 sx_init(&modules_sx, "module subsystem sx lock");
85 TAILQ_INIT(&modules);
86 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
87 SHUTDOWN_PRI_DEFAULT);
88}
89
90SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
91
92static void
93module_shutdown(void *arg1, int arg2)
94{
95 module_t mod;
96
97 MOD_SLOCK;
98 TAILQ_FOREACH(mod, &modules, link)
99 MOD_EVENT(mod, MOD_SHUTDOWN);
100 MOD_SUNLOCK;
101}
102
103void
104module_register_init(const void *arg)
105{
106 const moduledata_t *data = (const moduledata_t *)arg;
107 int error;
108 module_t mod;
109
110 MOD_SLOCK;
111 mod = module_lookupbyname(data->name);
112 if (mod == NULL)
113 panic("module_register_init: module named %s not found\n",
114 data->name);
115 MOD_SUNLOCK;
116 error = MOD_EVENT(mod, MOD_LOAD);
117 if (error) {
118 MOD_EVENT(mod, MOD_UNLOAD);
119 MOD_XLOCK;
120 module_release(mod);
121 MOD_XUNLOCK;
122 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
123 " %d\n", data->name, (void *)data->evhand, data->priv,
124 error);
125 }
126}
127
128int
129module_register(const moduledata_t *data, linker_file_t container)
130{
131 size_t namelen;
132 module_t newmod;
133
134 MOD_SLOCK;
135 newmod = module_lookupbyname(data->name);
136 if (newmod != NULL) {
137 MOD_SUNLOCK;
138 printf("module_register: module %s already exists!\n",
139 data->name);
140 return (EEXIST);
141 }
142 MOD_SUNLOCK;
143 namelen = strlen(data->name) + 1;
144 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
145 if (newmod == NULL)
146 return (ENOMEM);
147 MOD_XLOCK;
148 newmod->refs = 1;
149 newmod->id = nextid++;
150 newmod->name = (char *)(newmod + 1);
151 strcpy(newmod->name, data->name);
152 newmod->handler = data->evhand ? data->evhand : modevent_nop;
153 newmod->arg = data->priv;
154 bzero(&newmod->data, sizeof(newmod->data));
155 TAILQ_INSERT_TAIL(&modules, newmod, link);
156
157 if (container)
158 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
159 newmod->file = container;
160 MOD_XUNLOCK;
161 return (0);
162}
163
164void
165module_reference(module_t mod)
166{
167
168 MOD_XLOCK_ASSERT;
169
170 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
171 mod->refs++;
172}
173
174void
175module_release(module_t mod)
176{
177
178 MOD_XLOCK_ASSERT;
179
180 if (mod->refs <= 0)
181 panic("module_release: bad reference count");
182
183 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
184
185 mod->refs--;
186 if (mod->refs == 0) {
187 TAILQ_REMOVE(&modules, mod, link);
188 if (mod->file)
189 TAILQ_REMOVE(&mod->file->modules, mod, flink);
190 MOD_XUNLOCK;
191 free(mod, M_MODULE);
192 MOD_XLOCK;
193 }
194}
195
196module_t
197module_lookupbyname(const char *name)
198{
199 module_t mod;
200 int err;
201
202 MOD_LOCK_ASSERT;
203
204 TAILQ_FOREACH(mod, &modules, link) {
205 err = strcmp(mod->name, name);
206 if (err == 0)
207 return (mod);
208 }
209 return (NULL);
210}
211
212module_t
213module_lookupbyid(int modid)
214{
215 module_t mod;
216
217 MOD_LOCK_ASSERT;
218
219 TAILQ_FOREACH(mod, &modules, link)
220 if (mod->id == modid)
221 return(mod);
222 return (NULL);
223}
224
225int
226module_unload(module_t mod, int flags)
227{
228 int error;
229
230 error = MOD_EVENT(mod, MOD_QUIESCE);
231 if (error == EOPNOTSUPP)
231 if (error == EOPNOTSUPP || error == EINVAL)
232 error = 0;
233 if (flags == LINKER_UNLOAD_NORMAL && error != 0)
234 return (error);
235 return (MOD_EVENT(mod, MOD_UNLOAD));
236}
237
238int
239module_getid(module_t mod)
240{
241
242 MOD_LOCK_ASSERT;
243 return (mod->id);
244}
245
246module_t
247module_getfnext(module_t mod)
248{
249
250 MOD_LOCK_ASSERT;
251 return (TAILQ_NEXT(mod, flink));
252}
253
254void
255module_setspecific(module_t mod, modspecific_t *datap)
256{
257
258 MOD_XLOCK_ASSERT;
259 mod->data = *datap;
260}
261
262/*
263 * Syscalls.
264 */
265/*
266 * MPSAFE
267 */
268int
269modnext(struct thread *td, struct modnext_args *uap)
270{
271 module_t mod;
272 int error = 0;
273
274 td->td_retval[0] = -1;
275
276 MOD_SLOCK;
277 if (uap->modid == 0) {
278 mod = TAILQ_FIRST(&modules);
279 if (mod)
280 td->td_retval[0] = mod->id;
281 else
282 error = ENOENT;
283 goto done2;
284 }
285 mod = module_lookupbyid(uap->modid);
286 if (mod == NULL) {
287 error = ENOENT;
288 goto done2;
289 }
290 if (TAILQ_NEXT(mod, link))
291 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
292 else
293 td->td_retval[0] = 0;
294done2:
295 MOD_SUNLOCK;
296 return (error);
297}
298
299/*
300 * MPSAFE
301 */
302int
303modfnext(struct thread *td, struct modfnext_args *uap)
304{
305 module_t mod;
306 int error;
307
308 td->td_retval[0] = -1;
309
310 MOD_SLOCK;
311 mod = module_lookupbyid(uap->modid);
312 if (mod == NULL) {
313 error = ENOENT;
314 } else {
315 error = 0;
316 if (TAILQ_NEXT(mod, flink))
317 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
318 else
319 td->td_retval[0] = 0;
320 }
321 MOD_SUNLOCK;
322 return (error);
323}
324
325struct module_stat_v1 {
326 int version; /* set to sizeof(struct module_stat) */
327 char name[MAXMODNAME];
328 int refs;
329 int id;
330};
331
332/*
333 * MPSAFE
334 */
335int
336modstat(struct thread *td, struct modstat_args *uap)
337{
338 module_t mod;
339 modspecific_t data;
340 int error = 0;
341 int id, namelen, refs, version;
342 struct module_stat *stat;
343 char *name;
344
345 MOD_SLOCK;
346 mod = module_lookupbyid(uap->modid);
347 if (mod == NULL) {
348 MOD_SUNLOCK;
349 return (ENOENT);
350 }
351 id = mod->id;
352 refs = mod->refs;
353 name = mod->name;
354 data = mod->data;
355 MOD_SUNLOCK;
356 stat = uap->stat;
357
358 /*
359 * Check the version of the user's structure.
360 */
361 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
362 return (error);
363 if (version != sizeof(struct module_stat_v1)
364 && version != sizeof(struct module_stat))
365 return (EINVAL);
366 namelen = strlen(mod->name) + 1;
367 if (namelen > MAXMODNAME)
368 namelen = MAXMODNAME;
369 if ((error = copyout(name, &stat->name[0], namelen)) != 0)
370 return (error);
371
372 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
373 return (error);
374 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
375 return (error);
376
377 /*
378 * >v1 stat includes module data.
379 */
380 if (version == sizeof(struct module_stat))
381 if ((error = copyout(&data, &stat->data,
382 sizeof(data))) != 0)
383 return (error);
384 td->td_retval[0] = 0;
385 return (error);
386}
387
388/*
389 * MPSAFE
390 */
391int
392modfind(struct thread *td, struct modfind_args *uap)
393{
394 int error = 0;
395 char name[MAXMODNAME];
396 module_t mod;
397
398 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
399 return (error);
400
401 MOD_SLOCK;
402 mod = module_lookupbyname(name);
403 if (mod == NULL)
404 error = ENOENT;
405 else
406 td->td_retval[0] = module_getid(mod);
407 MOD_SUNLOCK;
408 return (error);
409}
232 error = 0;
233 if (flags == LINKER_UNLOAD_NORMAL && error != 0)
234 return (error);
235 return (MOD_EVENT(mod, MOD_UNLOAD));
236}
237
238int
239module_getid(module_t mod)
240{
241
242 MOD_LOCK_ASSERT;
243 return (mod->id);
244}
245
246module_t
247module_getfnext(module_t mod)
248{
249
250 MOD_LOCK_ASSERT;
251 return (TAILQ_NEXT(mod, flink));
252}
253
254void
255module_setspecific(module_t mod, modspecific_t *datap)
256{
257
258 MOD_XLOCK_ASSERT;
259 mod->data = *datap;
260}
261
262/*
263 * Syscalls.
264 */
265/*
266 * MPSAFE
267 */
268int
269modnext(struct thread *td, struct modnext_args *uap)
270{
271 module_t mod;
272 int error = 0;
273
274 td->td_retval[0] = -1;
275
276 MOD_SLOCK;
277 if (uap->modid == 0) {
278 mod = TAILQ_FIRST(&modules);
279 if (mod)
280 td->td_retval[0] = mod->id;
281 else
282 error = ENOENT;
283 goto done2;
284 }
285 mod = module_lookupbyid(uap->modid);
286 if (mod == NULL) {
287 error = ENOENT;
288 goto done2;
289 }
290 if (TAILQ_NEXT(mod, link))
291 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
292 else
293 td->td_retval[0] = 0;
294done2:
295 MOD_SUNLOCK;
296 return (error);
297}
298
299/*
300 * MPSAFE
301 */
302int
303modfnext(struct thread *td, struct modfnext_args *uap)
304{
305 module_t mod;
306 int error;
307
308 td->td_retval[0] = -1;
309
310 MOD_SLOCK;
311 mod = module_lookupbyid(uap->modid);
312 if (mod == NULL) {
313 error = ENOENT;
314 } else {
315 error = 0;
316 if (TAILQ_NEXT(mod, flink))
317 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
318 else
319 td->td_retval[0] = 0;
320 }
321 MOD_SUNLOCK;
322 return (error);
323}
324
325struct module_stat_v1 {
326 int version; /* set to sizeof(struct module_stat) */
327 char name[MAXMODNAME];
328 int refs;
329 int id;
330};
331
332/*
333 * MPSAFE
334 */
335int
336modstat(struct thread *td, struct modstat_args *uap)
337{
338 module_t mod;
339 modspecific_t data;
340 int error = 0;
341 int id, namelen, refs, version;
342 struct module_stat *stat;
343 char *name;
344
345 MOD_SLOCK;
346 mod = module_lookupbyid(uap->modid);
347 if (mod == NULL) {
348 MOD_SUNLOCK;
349 return (ENOENT);
350 }
351 id = mod->id;
352 refs = mod->refs;
353 name = mod->name;
354 data = mod->data;
355 MOD_SUNLOCK;
356 stat = uap->stat;
357
358 /*
359 * Check the version of the user's structure.
360 */
361 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
362 return (error);
363 if (version != sizeof(struct module_stat_v1)
364 && version != sizeof(struct module_stat))
365 return (EINVAL);
366 namelen = strlen(mod->name) + 1;
367 if (namelen > MAXMODNAME)
368 namelen = MAXMODNAME;
369 if ((error = copyout(name, &stat->name[0], namelen)) != 0)
370 return (error);
371
372 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
373 return (error);
374 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
375 return (error);
376
377 /*
378 * >v1 stat includes module data.
379 */
380 if (version == sizeof(struct module_stat))
381 if ((error = copyout(&data, &stat->data,
382 sizeof(data))) != 0)
383 return (error);
384 td->td_retval[0] = 0;
385 return (error);
386}
387
388/*
389 * MPSAFE
390 */
391int
392modfind(struct thread *td, struct modfind_args *uap)
393{
394 int error = 0;
395 char name[MAXMODNAME];
396 module_t mod;
397
398 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
399 return (error);
400
401 MOD_SLOCK;
402 mod = module_lookupbyname(name);
403 if (mod == NULL)
404 error = ENOENT;
405 else
406 td->td_retval[0] = module_getid(mod);
407 MOD_SUNLOCK;
408 return (error);
409}