]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_module.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / kern / kern_module.c
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 "opt_compat.h"
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/eventhandler.h>
36 #include <sys/malloc.h>
37 #include <sys/sysproto.h>
38 #include <sys/sysent.h>
39 #include <sys/proc.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/reboot.h>
43 #include <sys/sx.h>
44 #include <sys/module.h>
45 #include <sys/linker.h>
46
47 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
48
49 typedef TAILQ_HEAD(, module) modulelist_t;
50 struct module {
51         TAILQ_ENTRY(module)     link;   /* chain together all modules */
52         TAILQ_ENTRY(module)     flink;  /* all modules in a file */
53         struct linker_file      *file;  /* file which contains this module */
54         int                     refs;   /* reference count */
55         int                     id;     /* unique id number */
56         char                    *name;  /* module name */
57         modeventhand_t          handler;        /* event handler */
58         void                    *arg;   /* argument for handler */
59         modspecific_t           data;   /* module specific data */
60 };
61
62 #define MOD_EVENT(mod, type)    (mod)->handler((mod), (type), (mod)->arg)
63
64 static modulelist_t modules;
65 struct sx modules_sx;
66 static int nextid = 1;
67 static void module_shutdown(void *, int);
68
69 static int
70 modevent_nop(module_t mod, int what, void *arg)
71 {
72
73         switch(what) {
74         case MOD_LOAD:
75                 return (0);
76         case MOD_UNLOAD:
77                 return (EBUSY);
78         default:
79                 return (EOPNOTSUPP);
80         }
81 }
82
83 static void
84 module_init(void *arg)
85 {
86
87         sx_init(&modules_sx, "module subsystem sx lock");
88         TAILQ_INIT(&modules);
89         EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
90             SHUTDOWN_PRI_DEFAULT);
91 }
92
93 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
94
95 static void
96 module_shutdown(void *arg1, int arg2)
97 {
98         module_t mod;
99
100         if (arg2 & RB_NOSYNC)
101                 return;
102         mtx_lock(&Giant);
103         MOD_SLOCK;
104         TAILQ_FOREACH(mod, &modules, link)
105                 MOD_EVENT(mod, MOD_SHUTDOWN);
106         MOD_SUNLOCK;
107         mtx_unlock(&Giant);
108 }
109
110 void
111 module_register_init(const void *arg)
112 {
113         const moduledata_t *data = (const moduledata_t *)arg;
114         int error;
115         module_t mod;
116
117         mtx_lock(&Giant);
118         MOD_SLOCK;
119         mod = module_lookupbyname(data->name);
120         if (mod == NULL)
121                 panic("module_register_init: module named %s not found\n",
122                     data->name);
123         MOD_SUNLOCK;
124         error = MOD_EVENT(mod, MOD_LOAD);
125         if (error) {
126                 MOD_EVENT(mod, MOD_UNLOAD);
127                 MOD_XLOCK;
128                 module_release(mod);
129                 MOD_XUNLOCK;
130                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
131                     " %d\n", data->name, (void *)data->evhand, data->priv,
132                     error); 
133         }
134         mtx_unlock(&Giant);
135 }
136
137 int
138 module_register(const moduledata_t *data, linker_file_t container)
139 {
140         size_t namelen;
141         module_t newmod;
142
143         MOD_XLOCK;
144         newmod = module_lookupbyname(data->name);
145         if (newmod != NULL) {
146                 MOD_XUNLOCK;
147                 printf("module_register: module %s already exists!\n",
148                     data->name);
149                 return (EEXIST);
150         }
151         namelen = strlen(data->name) + 1;
152         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
153         if (newmod == NULL) {
154                 MOD_XUNLOCK;
155                 return (ENOMEM);
156         }
157         newmod->refs = 1;
158         newmod->id = nextid++;
159         newmod->name = (char *)(newmod + 1);
160         strcpy(newmod->name, data->name);
161         newmod->handler = data->evhand ? data->evhand : modevent_nop;
162         newmod->arg = data->priv;
163         bzero(&newmod->data, sizeof(newmod->data));
164         TAILQ_INSERT_TAIL(&modules, newmod, link);
165
166         if (container)
167                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
168         newmod->file = container;
169         MOD_XUNLOCK;
170         return (0);
171 }
172
173 void
174 module_reference(module_t mod)
175 {
176
177         MOD_XLOCK_ASSERT;
178
179         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
180         mod->refs++;
181 }
182
183 void
184 module_release(module_t mod)
185 {
186
187         MOD_XLOCK_ASSERT;
188
189         if (mod->refs <= 0)
190                 panic("module_release: bad reference count");
191
192         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
193         
194         mod->refs--;
195         if (mod->refs == 0) {
196                 TAILQ_REMOVE(&modules, mod, link);
197                 if (mod->file)
198                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
199                 MOD_XUNLOCK;
200                 free(mod, M_MODULE);
201                 MOD_XLOCK;
202         }
203 }
204
205 module_t
206 module_lookupbyname(const char *name)
207 {
208         module_t mod;
209         int err;
210
211         MOD_LOCK_ASSERT;
212
213         TAILQ_FOREACH(mod, &modules, link) {
214                 err = strcmp(mod->name, name);
215                 if (err == 0)
216                         return (mod);
217         }
218         return (NULL);
219 }
220
221 module_t
222 module_lookupbyid(int modid)
223 {
224         module_t mod;
225
226         MOD_LOCK_ASSERT;
227
228         TAILQ_FOREACH(mod, &modules, link)
229                 if (mod->id == modid)
230                         return(mod);
231         return (NULL);
232 }
233
234 int
235 module_unload(module_t mod, int flags)
236 {
237         int error;
238
239         mtx_lock(&Giant);
240         error = MOD_EVENT(mod, MOD_QUIESCE);
241         if (error == EOPNOTSUPP || error == EINVAL)
242                 error = 0;
243         if (error == 0 || flags == LINKER_UNLOAD_FORCE)
244                 error = MOD_EVENT(mod, MOD_UNLOAD);
245         mtx_unlock(&Giant);
246         return (error);
247 }
248
249 int
250 module_getid(module_t mod)
251 {
252
253         MOD_LOCK_ASSERT;
254         return (mod->id);
255 }
256
257 module_t
258 module_getfnext(module_t mod)
259 {
260
261         MOD_LOCK_ASSERT;
262         return (TAILQ_NEXT(mod, flink));
263 }
264
265 void
266 module_setspecific(module_t mod, modspecific_t *datap)
267 {
268
269         MOD_XLOCK_ASSERT;
270         mod->data = *datap;
271 }
272
273 linker_file_t
274 module_file(module_t mod)
275 {
276
277         return (mod->file);
278 }
279
280 /*
281  * Syscalls.
282  */
283 int
284 modnext(struct thread *td, struct modnext_args *uap)
285 {
286         module_t mod;
287         int error = 0;
288
289         td->td_retval[0] = -1;
290
291         MOD_SLOCK;
292         if (uap->modid == 0) {
293                 mod = TAILQ_FIRST(&modules);
294                 if (mod)
295                         td->td_retval[0] = mod->id;
296                 else
297                         error = ENOENT;
298                 goto done2;
299         }
300         mod = module_lookupbyid(uap->modid);
301         if (mod == NULL) {
302                 error = ENOENT;
303                 goto done2;
304         }
305         if (TAILQ_NEXT(mod, link))
306                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
307         else
308                 td->td_retval[0] = 0;
309 done2:
310         MOD_SUNLOCK;
311         return (error);
312 }
313
314 int
315 modfnext(struct thread *td, struct modfnext_args *uap)
316 {
317         module_t mod;
318         int error;
319
320         td->td_retval[0] = -1;
321
322         MOD_SLOCK;
323         mod = module_lookupbyid(uap->modid);
324         if (mod == NULL) {
325                 error = ENOENT;
326         } else {
327                 error = 0;
328                 if (TAILQ_NEXT(mod, flink))
329                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
330                 else
331                         td->td_retval[0] = 0;
332         }
333         MOD_SUNLOCK;
334         return (error);
335 }
336
337 struct module_stat_v1 {
338         int     version;                /* set to sizeof(struct module_stat) */
339         char    name[MAXMODNAME];
340         int     refs;
341         int     id;
342 };
343
344 int
345 modstat(struct thread *td, struct modstat_args *uap)
346 {
347         module_t mod;
348         modspecific_t data;
349         int error = 0;
350         int id, namelen, refs, version;
351         struct module_stat *stat;
352         char *name;
353
354         MOD_SLOCK;
355         mod = module_lookupbyid(uap->modid);
356         if (mod == NULL) {
357                 MOD_SUNLOCK;
358                 return (ENOENT);
359         }
360         id = mod->id;
361         refs = mod->refs;
362         name = mod->name;
363         data = mod->data;
364         MOD_SUNLOCK;
365         stat = uap->stat;
366
367         /*
368          * Check the version of the user's structure.
369          */
370         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
371                 return (error);
372         if (version != sizeof(struct module_stat_v1)
373             && version != sizeof(struct module_stat))
374                 return (EINVAL);
375         namelen = strlen(mod->name) + 1;
376         if (namelen > MAXMODNAME)
377                 namelen = MAXMODNAME;
378         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
379                 return (error);
380
381         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
382                 return (error);
383         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
384                 return (error);
385
386         /*
387          * >v1 stat includes module data.
388          */
389         if (version == sizeof(struct module_stat))
390                 if ((error = copyout(&data, &stat->data, 
391                     sizeof(data))) != 0)
392                         return (error);
393         td->td_retval[0] = 0;
394         return (error);
395 }
396
397 int
398 modfind(struct thread *td, struct modfind_args *uap)
399 {
400         int error = 0;
401         char name[MAXMODNAME];
402         module_t mod;
403
404         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
405                 return (error);
406
407         MOD_SLOCK;
408         mod = module_lookupbyname(name);
409         if (mod == NULL)
410                 error = ENOENT;
411         else
412                 td->td_retval[0] = module_getid(mod);
413         MOD_SUNLOCK;
414         return (error);
415 }
416
417 MODULE_VERSION(kernel, __FreeBSD_version);
418
419 #ifdef COMPAT_IA32
420 #include <sys/mount.h>
421 #include <sys/socket.h>
422 #include <compat/freebsd32/freebsd32_util.h>
423 #include <compat/freebsd32/freebsd32.h>
424 #include <compat/freebsd32/freebsd32_proto.h>
425
426 typedef union modspecific32 {
427         int             intval;
428         u_int32_t       uintval;
429         int             longval;
430         u_int32_t       ulongval;
431 } modspecific32_t;
432
433 struct module_stat32 {
434         int             version;
435         char            name[MAXMODNAME];
436         int             refs;
437         int             id;
438         modspecific32_t data;
439 };
440
441 int
442 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
443 {
444         module_t mod;
445         modspecific32_t data32;
446         int error = 0;
447         int id, namelen, refs, version;
448         struct module_stat32 *stat32;
449         char *name;
450
451         MOD_SLOCK;
452         mod = module_lookupbyid(uap->modid);
453         if (mod == NULL) {
454                 MOD_SUNLOCK;
455                 return (ENOENT);
456         }
457
458         id = mod->id;
459         refs = mod->refs;
460         name = mod->name;
461         CP(mod->data, data32, intval);
462         CP(mod->data, data32, uintval);
463         CP(mod->data, data32, longval);
464         CP(mod->data, data32, ulongval);
465         MOD_SUNLOCK;
466         stat32 = uap->stat;
467
468         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
469                 return (error);
470         if (version != sizeof(struct module_stat_v1)
471             && version != sizeof(struct module_stat32))
472                 return (EINVAL);
473         namelen = strlen(mod->name) + 1;
474         if (namelen > MAXMODNAME)
475                 namelen = MAXMODNAME;
476         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
477                 return (error);
478
479         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
480                 return (error);
481         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
482                 return (error);
483
484         /*
485          * >v1 stat includes module data.
486          */
487         if (version == sizeof(struct module_stat32))
488                 if ((error = copyout(&data32, &stat32->data,
489                     sizeof(data32))) != 0)
490                         return (error);
491         td->td_retval[0] = 0;
492         return (error);
493 }
494 #endif