]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_module.c
Fix issues with sparse cpu allocation. Consistently use mp_maxid + 1.
[FreeBSD/FreeBSD.git] / sys / kern / kern_module.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1997 Doug Rabson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "opt_compat.h"
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/eventhandler.h>
38 #include <sys/malloc.h>
39 #include <sys/sysproto.h>
40 #include <sys/sysent.h>
41 #include <sys/proc.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/reboot.h>
45 #include <sys/sx.h>
46 #include <sys/module.h>
47 #include <sys/linker.h>
48
49 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
50
51 struct module {
52         TAILQ_ENTRY(module)     link;   /* chain together all modules */
53         TAILQ_ENTRY(module)     flink;  /* all modules in a file */
54         struct linker_file      *file;  /* file which contains this module */
55         int                     refs;   /* reference count */
56         int                     id;     /* unique id number */
57         char                    *name;  /* module name */
58         modeventhand_t          handler;        /* event handler */
59         void                    *arg;   /* argument for handler */
60         modspecific_t           data;   /* module specific data */
61 };
62
63 #define MOD_EVENT(mod, type)    (mod)->handler((mod), (type), (mod)->arg)
64
65 static TAILQ_HEAD(modulelist, module) modules;
66 struct sx modules_sx;
67 static int nextid = 1;
68 static void module_shutdown(void *, int);
69
70 static int
71 modevent_nop(module_t mod, int what, void *arg)
72 {
73
74         switch(what) {
75         case MOD_LOAD:
76                 return (0);
77         case MOD_UNLOAD:
78                 return (EBUSY);
79         default:
80                 return (EOPNOTSUPP);
81         }
82 }
83
84 static void
85 module_init(void *arg)
86 {
87
88         sx_init(&modules_sx, "module subsystem sx lock");
89         TAILQ_INIT(&modules);
90         EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
91             SHUTDOWN_PRI_DEFAULT);
92 }
93
94 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
95
96 static void
97 module_shutdown(void *arg1, int arg2)
98 {
99         module_t mod;
100
101         if (arg2 & RB_NOSYNC)
102                 return;
103         mtx_lock(&Giant);
104         MOD_SLOCK;
105         TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link)
106                 MOD_EVENT(mod, MOD_SHUTDOWN);
107         MOD_SUNLOCK;
108         mtx_unlock(&Giant);
109 }
110
111 void
112 module_register_init(const void *arg)
113 {
114         const moduledata_t *data = (const moduledata_t *)arg;
115         int error;
116         module_t mod;
117
118         mtx_lock(&Giant);
119         MOD_SLOCK;
120         mod = module_lookupbyname(data->name);
121         if (mod == NULL)
122                 panic("module_register_init: module named %s not found\n",
123                     data->name);
124         MOD_SUNLOCK;
125         error = MOD_EVENT(mod, MOD_LOAD);
126         if (error) {
127                 MOD_EVENT(mod, MOD_UNLOAD);
128                 MOD_XLOCK;
129                 module_release(mod);
130                 MOD_XUNLOCK;
131                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
132                     " %d\n", data->name, (void *)data->evhand, data->priv,
133                     error); 
134         } else {
135                 MOD_XLOCK;
136                 if (mod->file) {
137                         /*
138                          * Once a module is successfully loaded, move
139                          * it to the head of the module list for this
140                          * linker file.  This resorts the list so that
141                          * when the kernel linker iterates over the
142                          * modules to unload them, it will unload them
143                          * in the reverse order they were loaded.
144                          */
145                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
146                         TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
147                 }
148                 MOD_XUNLOCK;
149         }
150         mtx_unlock(&Giant);
151 }
152
153 int
154 module_register(const moduledata_t *data, linker_file_t container)
155 {
156         size_t namelen;
157         module_t newmod;
158
159         MOD_XLOCK;
160         newmod = module_lookupbyname(data->name);
161         if (newmod != NULL) {
162                 MOD_XUNLOCK;
163                 printf("%s: cannot register %s from %s; already loaded from %s\n",
164                     __func__, data->name, container->filename, newmod->file->filename);
165                 return (EEXIST);
166         }
167         namelen = strlen(data->name) + 1;
168         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
169         newmod->refs = 1;
170         newmod->id = nextid++;
171         newmod->name = (char *)(newmod + 1);
172         strcpy(newmod->name, data->name);
173         newmod->handler = data->evhand ? data->evhand : modevent_nop;
174         newmod->arg = data->priv;
175         bzero(&newmod->data, sizeof(newmod->data));
176         TAILQ_INSERT_TAIL(&modules, newmod, link);
177
178         if (container)
179                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
180         newmod->file = container;
181         MOD_XUNLOCK;
182         return (0);
183 }
184
185 void
186 module_reference(module_t mod)
187 {
188
189         MOD_XLOCK_ASSERT;
190
191         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
192         mod->refs++;
193 }
194
195 void
196 module_release(module_t mod)
197 {
198
199         MOD_XLOCK_ASSERT;
200
201         if (mod->refs <= 0)
202                 panic("module_release: bad reference count");
203
204         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
205         
206         mod->refs--;
207         if (mod->refs == 0) {
208                 TAILQ_REMOVE(&modules, mod, link);
209                 if (mod->file)
210                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
211                 free(mod, M_MODULE);
212         }
213 }
214
215 module_t
216 module_lookupbyname(const char *name)
217 {
218         module_t mod;
219         int err;
220
221         MOD_LOCK_ASSERT;
222
223         TAILQ_FOREACH(mod, &modules, link) {
224                 err = strcmp(mod->name, name);
225                 if (err == 0)
226                         return (mod);
227         }
228         return (NULL);
229 }
230
231 module_t
232 module_lookupbyid(int modid)
233 {
234         module_t mod;
235
236         MOD_LOCK_ASSERT;
237
238         TAILQ_FOREACH(mod, &modules, link)
239                 if (mod->id == modid)
240                         return(mod);
241         return (NULL);
242 }
243
244 int
245 module_quiesce(module_t mod)
246 {
247         int error;
248
249         mtx_lock(&Giant);
250         error = MOD_EVENT(mod, MOD_QUIESCE);
251         mtx_unlock(&Giant);
252         if (error == EOPNOTSUPP || error == EINVAL)
253                 error = 0;
254         return (error);
255 }
256
257 int
258 module_unload(module_t mod)
259 {
260         int error;
261
262         mtx_lock(&Giant);
263         error = MOD_EVENT(mod, MOD_UNLOAD);
264         mtx_unlock(&Giant);
265         return (error);
266 }
267
268 int
269 module_getid(module_t mod)
270 {
271
272         MOD_LOCK_ASSERT;
273         return (mod->id);
274 }
275
276 module_t
277 module_getfnext(module_t mod)
278 {
279
280         MOD_LOCK_ASSERT;
281         return (TAILQ_NEXT(mod, flink));
282 }
283
284 const char *
285 module_getname(module_t mod)
286 {
287
288         MOD_LOCK_ASSERT;
289         return (mod->name);
290 }
291
292 void
293 module_setspecific(module_t mod, modspecific_t *datap)
294 {
295
296         MOD_XLOCK_ASSERT;
297         mod->data = *datap;
298 }
299
300 linker_file_t
301 module_file(module_t mod)
302 {
303
304         return (mod->file);
305 }
306
307 /*
308  * Syscalls.
309  */
310 int
311 sys_modnext(struct thread *td, struct modnext_args *uap)
312 {
313         module_t mod;
314         int error = 0;
315
316         td->td_retval[0] = -1;
317
318         MOD_SLOCK;
319         if (uap->modid == 0) {
320                 mod = TAILQ_FIRST(&modules);
321                 if (mod)
322                         td->td_retval[0] = mod->id;
323                 else
324                         error = ENOENT;
325                 goto done2;
326         }
327         mod = module_lookupbyid(uap->modid);
328         if (mod == NULL) {
329                 error = ENOENT;
330                 goto done2;
331         }
332         if (TAILQ_NEXT(mod, link))
333                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
334         else
335                 td->td_retval[0] = 0;
336 done2:
337         MOD_SUNLOCK;
338         return (error);
339 }
340
341 int
342 sys_modfnext(struct thread *td, struct modfnext_args *uap)
343 {
344         module_t mod;
345         int error;
346
347         td->td_retval[0] = -1;
348
349         MOD_SLOCK;
350         mod = module_lookupbyid(uap->modid);
351         if (mod == NULL) {
352                 error = ENOENT;
353         } else {
354                 error = 0;
355                 if (TAILQ_NEXT(mod, flink))
356                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
357                 else
358                         td->td_retval[0] = 0;
359         }
360         MOD_SUNLOCK;
361         return (error);
362 }
363
364 struct module_stat_v1 {
365         int     version;                /* set to sizeof(struct module_stat) */
366         char    name[MAXMODNAME];
367         int     refs;
368         int     id;
369 };
370
371 int
372 sys_modstat(struct thread *td, struct modstat_args *uap)
373 {
374         module_t mod;
375         modspecific_t data;
376         int error = 0;
377         int id, namelen, refs, version;
378         struct module_stat *stat;
379         char *name;
380
381         MOD_SLOCK;
382         mod = module_lookupbyid(uap->modid);
383         if (mod == NULL) {
384                 MOD_SUNLOCK;
385                 return (ENOENT);
386         }
387         id = mod->id;
388         refs = mod->refs;
389         name = mod->name;
390         data = mod->data;
391         MOD_SUNLOCK;
392         stat = uap->stat;
393
394         /*
395          * Check the version of the user's structure.
396          */
397         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
398                 return (error);
399         if (version != sizeof(struct module_stat_v1)
400             && version != sizeof(struct module_stat))
401                 return (EINVAL);
402         namelen = strlen(mod->name) + 1;
403         if (namelen > MAXMODNAME)
404                 namelen = MAXMODNAME;
405         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
406                 return (error);
407
408         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
409                 return (error);
410         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
411                 return (error);
412
413         /*
414          * >v1 stat includes module data.
415          */
416         if (version == sizeof(struct module_stat))
417                 if ((error = copyout(&data, &stat->data, 
418                     sizeof(data))) != 0)
419                         return (error);
420         td->td_retval[0] = 0;
421         return (error);
422 }
423
424 int
425 sys_modfind(struct thread *td, struct modfind_args *uap)
426 {
427         int error = 0;
428         char name[MAXMODNAME];
429         module_t mod;
430
431         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
432                 return (error);
433
434         MOD_SLOCK;
435         mod = module_lookupbyname(name);
436         if (mod == NULL)
437                 error = ENOENT;
438         else
439                 td->td_retval[0] = module_getid(mod);
440         MOD_SUNLOCK;
441         return (error);
442 }
443
444 MODULE_VERSION(kernel, __FreeBSD_version);
445
446 #ifdef COMPAT_FREEBSD32
447 #include <sys/mount.h>
448 #include <sys/socket.h>
449 #include <compat/freebsd32/freebsd32_util.h>
450 #include <compat/freebsd32/freebsd32.h>
451 #include <compat/freebsd32/freebsd32_proto.h>
452
453 typedef union modspecific32 {
454         int             intval;
455         uint32_t        uintval;
456         int             longval;
457         uint32_t        ulongval;
458 } modspecific32_t;
459
460 struct module_stat32 {
461         int             version;
462         char            name[MAXMODNAME];
463         int             refs;
464         int             id;
465         modspecific32_t data;
466 };
467
468 int
469 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
470 {
471         module_t mod;
472         modspecific32_t data32;
473         int error = 0;
474         int id, namelen, refs, version;
475         struct module_stat32 *stat32;
476         char *name;
477
478         MOD_SLOCK;
479         mod = module_lookupbyid(uap->modid);
480         if (mod == NULL) {
481                 MOD_SUNLOCK;
482                 return (ENOENT);
483         }
484
485         id = mod->id;
486         refs = mod->refs;
487         name = mod->name;
488         CP(mod->data, data32, intval);
489         CP(mod->data, data32, uintval);
490         CP(mod->data, data32, longval);
491         CP(mod->data, data32, ulongval);
492         MOD_SUNLOCK;
493         stat32 = uap->stat;
494
495         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
496                 return (error);
497         if (version != sizeof(struct module_stat_v1)
498             && version != sizeof(struct module_stat32))
499                 return (EINVAL);
500         namelen = strlen(mod->name) + 1;
501         if (namelen > MAXMODNAME)
502                 namelen = MAXMODNAME;
503         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
504                 return (error);
505
506         if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
507                 return (error);
508         if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
509                 return (error);
510
511         /*
512          * >v1 stat includes module data.
513          */
514         if (version == sizeof(struct module_stat32))
515                 if ((error = copyout(&data32, &stat32->data,
516                     sizeof(data32))) != 0)
517                         return (error);
518         td->td_retval[0] = 0;
519         return (error);
520 }
521 #endif