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 * $FreeBSD: releng/5.1/sys/kern/kern_module.c 111119 2003-02-19 05:47:46Z imp $
27 */
28
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/systm.h>
32 #include <sys/eventhandler.h>
33 #include <sys/malloc.h>
34 #include <sys/sysproto.h>
35 #include <sys/sysent.h>
36 #include <sys/proc.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/sx.h>
40 #include <sys/module.h>
41 #include <sys/linker.h>
42
43 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
44
45 typedef TAILQ_HEAD(, module) modulelist_t;
46 struct module {
47 TAILQ_ENTRY(module) link; /* chain together all modules */
48 TAILQ_ENTRY(module) flink; /* all modules in a file */
49 struct linker_file *file; /* file which contains this module */
50 int refs; /* reference count */
51 int id; /* unique id number */
52 char *name; /* module name */
53 modeventhand_t handler; /* event handler */
54 void *arg; /* argument for handler */
55 modspecific_t data; /* module specific data */
56 };
57
58 #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
59
60 static modulelist_t modules;
61 struct sx modules_sx;
62 static int nextid = 1;
63 static void module_shutdown(void *, int);
64
65 static int
66 modevent_nop(module_t mod, int what, void *arg)
67 {
68 return (0);
69 }
70
71 static void
72 module_init(void *arg)
73 {
74
75 sx_init(&modules_sx, "module subsystem sx lock");
76 TAILQ_INIT(&modules);
77 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
78 SHUTDOWN_PRI_DEFAULT);
79 }
80
81 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
82
83 static void
84 module_shutdown(void *arg1, int arg2)
85 {
86 module_t mod;
87
88 MOD_SLOCK;
89 TAILQ_FOREACH(mod, &modules, link)
90 MOD_EVENT(mod, MOD_SHUTDOWN);
91 MOD_SUNLOCK;
92 }
93
94 void
95 module_register_init(const void *arg)
96 {
97 const moduledata_t *data = (const moduledata_t *)arg;
98 int error;
99 module_t mod;
100
101 MOD_SLOCK;
102 mod = module_lookupbyname(data->name);
103 if (mod == NULL)
104 panic("module_register_init: module named %s not found\n",
105 data->name);
106 MOD_SUNLOCK;
107 error = MOD_EVENT(mod, MOD_LOAD);
108 if (error) {
109 MOD_EVENT(mod, MOD_UNLOAD);
110 MOD_XLOCK;
111 module_release(mod);
112 MOD_XUNLOCK;
113 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
114 " %d\n", data->name, (void *)data->evhand, data->priv,
115 error);
116 }
117 }
118
119 int
120 module_register(const moduledata_t *data, linker_file_t container)
121 {
122 size_t namelen;
123 module_t newmod;
124
125 MOD_SLOCK;
126 newmod = module_lookupbyname(data->name);
127 if (newmod != NULL) {
128 MOD_SUNLOCK;
129 printf("module_register: module %s already exists!\n",
130 data->name);
131 return (EEXIST);
132 }
133 MOD_SUNLOCK;
134 namelen = strlen(data->name) + 1;
135 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
136 if (newmod == NULL)
137 return (ENOMEM);
138 MOD_XLOCK;
139 newmod->refs = 1;
140 newmod->id = nextid++;
141 newmod->name = (char *)(newmod + 1);
142 strcpy(newmod->name, data->name);
143 newmod->handler = data->evhand ? data->evhand : modevent_nop;
144 newmod->arg = data->priv;
145 bzero(&newmod->data, sizeof(newmod->data));
146 TAILQ_INSERT_TAIL(&modules, newmod, link);
147
148 if (container)
149 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
150 newmod->file = container;
151 MOD_XUNLOCK;
152 return (0);
153 }
154
155 void
156 module_reference(module_t mod)
157 {
158
159 MOD_XLOCK_ASSERT;
160
161 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
162 mod->refs++;
163 }
164
165 void
166 module_release(module_t mod)
167 {
168
169 MOD_XLOCK_ASSERT;
170
171 if (mod->refs <= 0)
172 panic("module_release: bad reference count");
173
174 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
175
176 mod->refs--;
177 if (mod->refs == 0) {
178 TAILQ_REMOVE(&modules, mod, link);
179 if (mod->file)
180 TAILQ_REMOVE(&mod->file->modules, mod, flink);
181 MOD_XUNLOCK;
182 free(mod, M_MODULE);
183 MOD_XLOCK;
184 }
185 }
186
187 module_t
188 module_lookupbyname(const char *name)
189 {
190 module_t mod;
191 int err;
192
193 MOD_LOCK_ASSERT;
194
195 TAILQ_FOREACH(mod, &modules, link) {
196 err = strcmp(mod->name, name);
197 if (err == 0)
198 return (mod);
199 }
200 return (NULL);
201 }
202
203 module_t
204 module_lookupbyid(int modid)
205 {
206 module_t mod;
207
208 MOD_LOCK_ASSERT;
209
210 TAILQ_FOREACH(mod, &modules, link)
211 if (mod->id == modid)
212 return(mod);
213 return (NULL);
214 }
215
216 int
217 module_unload(module_t mod)
218 {
219
220 return (MOD_EVENT(mod, MOD_UNLOAD));
221 }
222
223 int
224 module_getid(module_t mod)
225 {
226
227 MOD_LOCK_ASSERT;
228 return (mod->id);
229 }
230
231 module_t
232 module_getfnext(module_t mod)
233 {
234
235 MOD_LOCK_ASSERT;
236 return (TAILQ_NEXT(mod, flink));
237 }
238
239 void
240 module_setspecific(module_t mod, modspecific_t *datap)
241 {
242
243 MOD_XLOCK_ASSERT;
244 mod->data = *datap;
245 }
246
247 /*
248 * Syscalls.
249 */
250 /*
251 * MPSAFE
252 */
253 int
254 modnext(struct thread *td, struct modnext_args *uap)
255 {
256 module_t mod;
257 int error = 0;
258
259 td->td_retval[0] = -1;
260
261 MOD_SLOCK;
262 if (uap->modid == 0) {
263 mod = TAILQ_FIRST(&modules);
264 if (mod)
265 td->td_retval[0] = mod->id;
266 else
267 error = ENOENT;
268 goto done2;
269 }
270 mod = module_lookupbyid(uap->modid);
271 if (mod == NULL) {
272 error = ENOENT;
273 goto done2;
274 }
275 if (TAILQ_NEXT(mod, link))
276 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
277 else
278 td->td_retval[0] = 0;
279 done2:
280 MOD_SUNLOCK;
281 return (error);
282 }
283
284 /*
285 * MPSAFE
286 */
287 int
288 modfnext(struct thread *td, struct modfnext_args *uap)
289 {
290 module_t mod;
291 int error;
292
293 td->td_retval[0] = -1;
294
295 MOD_SLOCK;
296 mod = module_lookupbyid(uap->modid);
297 if (mod == NULL) {
298 error = ENOENT;
299 } else {
300 error = 0;
301 if (TAILQ_NEXT(mod, flink))
302 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
303 else
304 td->td_retval[0] = 0;
305 }
306 MOD_SUNLOCK;
307 return (error);
308 }
309
310 struct module_stat_v1 {
311 int version; /* set to sizeof(struct module_stat) */
312 char name[MAXMODNAME];
313 int refs;
314 int id;
315 };
316
317 /*
318 * MPSAFE
319 */
320 int
321 modstat(struct thread *td, struct modstat_args *uap)
322 {
323 module_t mod;
324 modspecific_t data;
325 int error = 0;
326 int id, namelen, refs, version;
327 struct module_stat *stat;
328 char *name;
329
330 MOD_SLOCK;
331 mod = module_lookupbyid(uap->modid);
332 if (mod == NULL) {
333 MOD_SUNLOCK;
334 return (ENOENT);
335 }
336 id = mod->id;
337 refs = mod->refs;
338 name = mod->name;
339 data = mod->data;
340 MOD_SUNLOCK;
341 stat = uap->stat;
342
343 /*
344 * Check the version of the user's structure.
345 */
346 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
347 return (error);
348 if (version != sizeof(struct module_stat_v1)
349 && version != sizeof(struct module_stat))
350 return (EINVAL);
351 namelen = strlen(mod->name) + 1;
352 if (namelen > MAXMODNAME)
353 namelen = MAXMODNAME;
354 if ((error = copyout(name, &stat->name[0], namelen)) != 0)
355 return (error);
356
357 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
358 return (error);
359 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
360 return (error);
361
362 /*
363 * >v1 stat includes module data.
364 */
365 if (version == sizeof(struct module_stat))
366 if ((error = copyout(&data, &stat->data,
367 sizeof(data))) != 0)
368 return (error);
369 td->td_retval[0] = 0;
370 return (error);
371 }
372
373 /*
374 * MPSAFE
375 */
376 int
377 modfind(struct thread *td, struct modfind_args *uap)
378 {
379 int error = 0;
380 char name[MAXMODNAME];
381 module_t mod;
382
383 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
384 return (error);
385
386 MOD_SLOCK;
387 mod = module_lookupbyname(name);
388 if (mod == NULL)
389 error = ENOENT;
390 else
391 td->td_retval[0] = module_getid(mod);
392 MOD_SUNLOCK;
393 return (error);
394 }
Cache object: 307244a027a16b087c83b369fa602ff3
|