]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_module.c
unbound: Vendor import 1.19.0
[FreeBSD/FreeBSD.git] / sys / kern / kern_module.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 <sys/cdefs.h>
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/reboot.h>
41 #include <sys/sx.h>
42 #include <sys/module.h>
43 #include <sys/linker.h>
44
45 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
46
47 struct 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
61 static TAILQ_HEAD(modulelist, module) modules;
62 struct sx modules_sx;
63 static int nextid = 1;
64 static void module_shutdown(void *, int);
65
66 static int
67 modevent_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
80 static void
81 module_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
90 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL);
91
92 static void
93 module_shutdown(void *arg1, int arg2)
94 {
95         module_t mod;
96
97         if (arg2 & RB_NOSYNC)
98                 return;
99         mtx_lock(&Giant);
100         MOD_SLOCK;
101         TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link)
102                 MOD_EVENT(mod, MOD_SHUTDOWN);
103         MOD_SUNLOCK;
104         mtx_unlock(&Giant);
105 }
106
107 void
108 module_register_init(const void *arg)
109 {
110         const moduledata_t *data = (const moduledata_t *)arg;
111         int error;
112         module_t mod;
113
114         mtx_lock(&Giant);
115         MOD_SLOCK;
116         mod = module_lookupbyname(data->name);
117         if (mod == NULL)
118                 panic("module_register_init: module named %s not found\n",
119                     data->name);
120         MOD_SUNLOCK;
121         error = MOD_EVENT(mod, MOD_LOAD);
122         if (error) {
123                 MOD_EVENT(mod, MOD_UNLOAD);
124                 MOD_XLOCK;
125                 module_release(mod);
126                 MOD_XUNLOCK;
127                 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
128                     " %d\n", data->name, (void *)data->evhand, data->priv,
129                     error); 
130         } else {
131                 MOD_XLOCK;
132                 if (mod->file) {
133                         /*
134                          * Once a module is successfully loaded, move
135                          * it to the head of the module list for this
136                          * linker file.  This resorts the list so that
137                          * when the kernel linker iterates over the
138                          * modules to unload them, it will unload them
139                          * in the reverse order they were loaded.
140                          */
141                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
142                         TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
143                 }
144                 MOD_XUNLOCK;
145         }
146         mtx_unlock(&Giant);
147 }
148
149 int
150 module_register(const moduledata_t *data, linker_file_t container)
151 {
152         size_t namelen;
153         module_t newmod;
154
155         MOD_XLOCK;
156         newmod = module_lookupbyname(data->name);
157         if (newmod != NULL) {
158                 MOD_XUNLOCK;
159                 printf("%s: cannot register %s from %s; already loaded from %s\n",
160                     __func__, data->name, container->filename, newmod->file->filename);
161                 return (EEXIST);
162         }
163         namelen = strlen(data->name) + 1;
164         newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
165         newmod->refs = 1;
166         newmod->id = nextid++;
167         newmod->name = (char *)(newmod + 1);
168         strcpy(newmod->name, data->name);
169         newmod->handler = data->evhand ? data->evhand : modevent_nop;
170         newmod->arg = data->priv;
171         bzero(&newmod->data, sizeof(newmod->data));
172         TAILQ_INSERT_TAIL(&modules, newmod, link);
173
174         if (container)
175                 TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
176         newmod->file = container;
177         MOD_XUNLOCK;
178         return (0);
179 }
180
181 void
182 module_reference(module_t mod)
183 {
184
185         MOD_XLOCK_ASSERT;
186
187         MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
188         mod->refs++;
189 }
190
191 void
192 module_release(module_t mod)
193 {
194
195         MOD_XLOCK_ASSERT;
196
197         if (mod->refs <= 0)
198                 panic("module_release: bad reference count");
199
200         MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
201
202         mod->refs--;
203         if (mod->refs == 0) {
204                 TAILQ_REMOVE(&modules, mod, link);
205                 if (mod->file)
206                         TAILQ_REMOVE(&mod->file->modules, mod, flink);
207                 free(mod, M_MODULE);
208         }
209 }
210
211 module_t
212 module_lookupbyname(const char *name)
213 {
214         module_t mod;
215         int err;
216
217         MOD_LOCK_ASSERT;
218
219         TAILQ_FOREACH(mod, &modules, link) {
220                 err = strcmp(mod->name, name);
221                 if (err == 0)
222                         return (mod);
223         }
224         return (NULL);
225 }
226
227 module_t
228 module_lookupbyid(int modid)
229 {
230         module_t mod;
231
232         MOD_LOCK_ASSERT;
233
234         TAILQ_FOREACH(mod, &modules, link)
235                 if (mod->id == modid)
236                         return(mod);
237         return (NULL);
238 }
239
240 int
241 module_quiesce(module_t mod)
242 {
243         int error;
244
245         mtx_lock(&Giant);
246         error = MOD_EVENT(mod, MOD_QUIESCE);
247         mtx_unlock(&Giant);
248         if (error == EOPNOTSUPP || error == EINVAL)
249                 error = 0;
250         return (error);
251 }
252
253 int
254 module_unload(module_t mod)
255 {
256         int error;
257
258         mtx_lock(&Giant);
259         error = MOD_EVENT(mod, MOD_UNLOAD);
260         mtx_unlock(&Giant);
261         return (error);
262 }
263
264 int
265 module_getid(module_t mod)
266 {
267
268         MOD_LOCK_ASSERT;
269         return (mod->id);
270 }
271
272 module_t
273 module_getfnext(module_t mod)
274 {
275
276         MOD_LOCK_ASSERT;
277         return (TAILQ_NEXT(mod, flink));
278 }
279
280 const char *
281 module_getname(module_t mod)
282 {
283
284         MOD_LOCK_ASSERT;
285         return (mod->name);
286 }
287
288 void
289 module_setspecific(module_t mod, modspecific_t *datap)
290 {
291
292         MOD_XLOCK_ASSERT;
293         mod->data = *datap;
294 }
295
296 linker_file_t
297 module_file(module_t mod)
298 {
299
300         return (mod->file);
301 }
302
303 /*
304  * Syscalls.
305  */
306 int
307 sys_modnext(struct thread *td, struct modnext_args *uap)
308 {
309         module_t mod;
310         int error = 0;
311
312         td->td_retval[0] = -1;
313
314         MOD_SLOCK;
315         if (uap->modid == 0) {
316                 mod = TAILQ_FIRST(&modules);
317                 if (mod)
318                         td->td_retval[0] = mod->id;
319                 else
320                         error = ENOENT;
321                 goto done2;
322         }
323         mod = module_lookupbyid(uap->modid);
324         if (mod == NULL) {
325                 error = ENOENT;
326                 goto done2;
327         }
328         if (TAILQ_NEXT(mod, link))
329                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
330         else
331                 td->td_retval[0] = 0;
332 done2:
333         MOD_SUNLOCK;
334         return (error);
335 }
336
337 int
338 sys_modfnext(struct thread *td, struct modfnext_args *uap)
339 {
340         module_t mod;
341         int error;
342
343         td->td_retval[0] = -1;
344
345         MOD_SLOCK;
346         mod = module_lookupbyid(uap->modid);
347         if (mod == NULL) {
348                 error = ENOENT;
349         } else {
350                 error = 0;
351                 if (TAILQ_NEXT(mod, flink))
352                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
353                 else
354                         td->td_retval[0] = 0;
355         }
356         MOD_SUNLOCK;
357         return (error);
358 }
359
360 struct module_stat_v1 {
361         int     version;                /* set to sizeof(struct module_stat) */
362         char    name[MAXMODNAMEV1V2];
363         int     refs;
364         int     id;
365 };
366
367 struct module_stat_v2 {
368         int     version;                /* set to sizeof(struct module_stat) */
369         char    name[MAXMODNAMEV1V2];
370         int     refs;
371         int     id;
372         modspecific_t   data;
373 };
374
375 int
376 sys_modstat(struct thread *td, struct modstat_args *uap)
377 {
378         module_t mod;
379         modspecific_t data;
380         int error = 0;
381         int id, namelen, refs, version;
382         struct module_stat *stat;
383         struct module_stat_v2 *stat_v2;
384         char *name;
385         bool is_v1v2;
386
387         MOD_SLOCK;
388         mod = module_lookupbyid(uap->modid);
389         if (mod == NULL) {
390                 MOD_SUNLOCK;
391                 return (ENOENT);
392         }
393         id = mod->id;
394         refs = mod->refs;
395         name = mod->name;
396         data = mod->data;
397         MOD_SUNLOCK;
398         stat = uap->stat;
399
400         /*
401          * Check the version of the user's structure.
402          */
403         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
404                 return (error);
405         is_v1v2 = (version == sizeof(struct module_stat_v1) ||
406             version == sizeof(struct module_stat_v2));
407         if (!is_v1v2 && version != sizeof(struct module_stat))
408                 return (EINVAL);
409         namelen = strlen(mod->name) + 1;
410         if (is_v1v2 && namelen > MAXMODNAMEV1V2)
411                 namelen = MAXMODNAMEV1V2;
412         else if (namelen > MAXMODNAMEV3)
413                 namelen = MAXMODNAMEV3;
414         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
415                 return (error);
416
417         /* Extending MAXMODNAME gives an offset change for v3. */
418         if (is_v1v2) {
419                 stat_v2 = (struct module_stat_v2 *)stat;
420                 if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0)
421                         return (error);
422                 if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0)
423                         return (error);
424         } else {
425                 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
426                         return (error);
427                 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
428                         return (error);
429         }
430
431         /*
432          * >v1 stat includes module data.
433          */
434         if (version == sizeof(struct module_stat_v2)) {
435                 if ((error = copyout(&data, &stat_v2->data,
436                     sizeof(data))) != 0)
437                         return (error);
438         } else if (version == sizeof(struct module_stat)) {
439                 if ((error = copyout(&data, &stat->data, 
440                     sizeof(data))) != 0)
441                         return (error);
442         }
443         td->td_retval[0] = 0;
444         return (error);
445 }
446
447 int
448 sys_modfind(struct thread *td, struct modfind_args *uap)
449 {
450         int error = 0;
451         char name[MAXMODNAMEV3];
452         module_t mod;
453
454         if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
455                 return (error);
456
457         MOD_SLOCK;
458         mod = module_lookupbyname(name);
459         if (mod == NULL)
460                 error = ENOENT;
461         else
462                 td->td_retval[0] = module_getid(mod);
463         MOD_SUNLOCK;
464         return (error);
465 }
466
467 MODULE_VERSION(kernel, __FreeBSD_version);
468
469 #ifdef COMPAT_FREEBSD32
470 #include <sys/mount.h>
471 #include <sys/socket.h>
472 #include <compat/freebsd32/freebsd32_util.h>
473 #include <compat/freebsd32/freebsd32.h>
474 #include <compat/freebsd32/freebsd32_proto.h>
475
476 typedef union modspecific32 {
477         int             intval;
478         uint32_t        uintval;
479         int             longval;
480         uint32_t        ulongval;
481 } modspecific32_t;
482
483 struct module_stat32_v2 {
484         int             version;
485         char            name[MAXMODNAMEV1V2];
486         int             refs;
487         int             id;
488         modspecific32_t data;
489 };
490
491 struct module_stat32 {
492         int             version;
493         char            name[MAXMODNAME];
494         int             refs;
495         int             id;
496         modspecific32_t data;
497 };
498
499 int
500 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
501 {
502         module_t mod;
503         modspecific32_t data32;
504         int error = 0;
505         int id, namelen, refs, version;
506         struct module_stat32 *stat32;
507         struct module_stat32_v2 *stat32_v2;
508         char *name;
509         bool is_v1v2;
510
511         MOD_SLOCK;
512         mod = module_lookupbyid(uap->modid);
513         if (mod == NULL) {
514                 MOD_SUNLOCK;
515                 return (ENOENT);
516         }
517
518         id = mod->id;
519         refs = mod->refs;
520         name = mod->name;
521         _Static_assert(sizeof(data32) == sizeof(data32.uintval),
522             "bad modspecific32_t size");
523         CP(mod->data, data32, uintval);
524         MOD_SUNLOCK;
525         stat32 = uap->stat;
526
527         if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
528                 return (error);
529         is_v1v2 = (version == sizeof(struct module_stat_v1) ||
530             version == sizeof(struct module_stat32_v2));
531         if (!is_v1v2 && version != sizeof(struct module_stat32))
532                 return (EINVAL);
533         namelen = strlen(mod->name) + 1;
534         if (is_v1v2 && namelen > MAXMODNAMEV1V2)
535                 namelen = MAXMODNAMEV1V2;
536         else if (namelen > MAXMODNAMEV3)
537                 namelen = MAXMODNAMEV3;
538         if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
539                 return (error);
540
541         /* Extending MAXMODNAME gives an offset change for v3. */
542         if (is_v1v2) {
543                 stat32_v2 = (struct module_stat32_v2 *)stat32;
544                 if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0)
545                         return (error);
546                 if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0)
547                         return (error);
548         } else {
549                 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
550                         return (error);
551                 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
552                         return (error);
553         }
554
555         /*
556          * >v1 stat includes module data.
557          */
558         if (version == sizeof(struct module_stat32_v2)) {
559                 if ((error = copyout(&data32, &stat32_v2->data,
560                     sizeof(data32))) != 0)
561                         return (error);
562         } else if (version == sizeof(struct module_stat32)) {
563                 if ((error = copyout(&data32, &stat32->data,
564                     sizeof(data32))) != 0)
565                         return (error);
566         }
567         td->td_retval[0] = 0;
568         return (error);
569 }
570 #endif