]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_module.c
Remove __P(). This was tested on the GENERIC kernel.
[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  * $FreeBSD$
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_post_sync, 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         mtx_lock(&Giant);
260
261         td->td_retval[0] = -1;
262         MOD_SLOCK;
263         if (SCARG(uap, modid) == 0) {
264                 mod = TAILQ_FIRST(&modules);
265                 if (mod)
266                         td->td_retval[0] = mod->id;
267                 else
268                         error = ENOENT;
269                 goto done2;
270         }
271         mod = module_lookupbyid(SCARG(uap, modid));
272         if (mod == NULL) {
273                 error = ENOENT;
274                 goto done2;
275         }
276         if (TAILQ_NEXT(mod, link))
277                 td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
278         else
279                 td->td_retval[0] = 0;
280 done2:
281         MOD_SUNLOCK;
282         mtx_unlock(&Giant);
283         return (error);
284 }
285
286 /*
287  * MPSAFE
288  */
289 int
290 modfnext(struct thread *td, struct modfnext_args *uap)
291 {
292         module_t mod;
293         int error;
294
295         td->td_retval[0] = -1;
296
297         mtx_lock(&Giant);
298
299         MOD_SLOCK;
300         mod = module_lookupbyid(SCARG(uap, modid));
301         if (mod == NULL) {
302                 error = ENOENT;
303         } else {
304                 error = 0;
305                 if (TAILQ_NEXT(mod, flink))
306                         td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
307                 else
308                         td->td_retval[0] = 0;
309         }
310         MOD_SUNLOCK;
311         mtx_unlock(&Giant);
312         return (error);
313 }
314
315 struct module_stat_v1 {
316         int     version;                /* set to sizeof(struct module_stat) */
317         char    name[MAXMODNAME];
318         int     refs;
319         int     id;
320 };
321
322 /*
323  * MPSAFE
324  */
325 int
326 modstat(struct thread *td, struct modstat_args *uap)
327 {
328         module_t mod;
329         modspecific_t data;
330         int error = 0;
331         int id, namelen, refs, version;
332         struct module_stat *stat;
333         char *name;
334
335         mtx_lock(&Giant);
336
337         MOD_SLOCK;
338         mod = module_lookupbyid(SCARG(uap, modid));
339         if (mod == NULL) {
340                 MOD_SUNLOCK;
341                 error = ENOENT;
342                 goto out;
343         }
344         id = mod->id;
345         refs = mod->refs;
346         name = mod->name;
347         data = mod->data;
348         MOD_SUNLOCK;
349         stat = SCARG(uap, stat);
350
351         /*
352          * Check the version of the user's structure.
353          */
354         if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
355                 goto out;
356         if (version != sizeof(struct module_stat_v1)
357             && version != sizeof(struct module_stat)) {
358                 error = EINVAL;
359                 goto out;
360         }
361         namelen = strlen(mod->name) + 1;
362         if (namelen > MAXMODNAME)
363                 namelen = MAXMODNAME;
364         if ((error = copyout(name, &stat->name[0], namelen)) != 0)
365                 goto out;
366
367         if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
368                 goto out;
369         if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
370                 goto out;
371
372         /*
373          * >v1 stat includes module data.
374          */
375         if (version == sizeof(struct module_stat)) {
376                 if ((error = copyout(&data, &stat->data, 
377                     sizeof(data))) != 0)
378                         goto out;
379         }
380         td->td_retval[0] = 0;
381 out:
382         mtx_unlock(&Giant);
383         return (error);
384 }
385
386 /*
387  * MPSAFE
388  */
389 int
390 modfind(struct thread *td, struct modfind_args *uap)
391 {
392         int error = 0;
393         char name[MAXMODNAME];
394         module_t mod;
395
396         if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
397                 goto out;
398
399         mtx_lock(&Giant);
400         MOD_SLOCK;
401         mod = module_lookupbyname(name);
402         if (mod == NULL)
403                 error = ENOENT;
404         else
405                 td->td_retval[0] = module_getid(mod);
406         MOD_SUNLOCK;
407         mtx_unlock(&Giant);
408 out:
409         return (error);
410 }