Deleted Added
sdiff udiff text old ( 83366 ) new ( 90963 )
full compact
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 unchanged lines hidden (view full) ---

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