kern_module.c revision 215544
153812Salfred/*- 253812Salfred * Copyright (c) 1997 Doug Rabson 353812Salfred * All rights reserved. 453812Salfred * 553812Salfred * Redistribution and use in source and binary forms, with or without 653812Salfred * modification, are permitted provided that the following conditions 7103388Smini * are met: 853812Salfred * 1. Redistributions of source code must retain the above copyright 975369Sdeischen * notice, this list of conditions and the following disclaimer. 1075369Sdeischen * 2. Redistributions in binary form must reproduce the above copyright 1175369Sdeischen * notice, this list of conditions and the following disclaimer in the 1275369Sdeischen * documentation and/or other materials provided with the distribution. 1371581Sdeischen * 14113658Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15113658Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16113658Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17113658Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1853812Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1971581Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2053812Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21113658Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22115278Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2353812Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2453812Salfred * SUCH DAMAGE. 25113658Sdeischen */ 26113658Sdeischen 27113658Sdeischen#include "opt_compat.h" 28113658Sdeischen 29113658Sdeischen#include <sys/cdefs.h> 30116972Sdavidxu__FBSDID("$FreeBSD: head/sys/kern/kern_module.c 215544 2010-11-19 19:43:56Z attilio $"); 31116972Sdavidxu 32116972Sdavidxu#include <sys/param.h> 33116972Sdavidxu#include <sys/kernel.h> 34116972Sdavidxu#include <sys/systm.h> 3554708Sdeischen#include <sys/eventhandler.h> 36113658Sdeischen#include <sys/malloc.h> 37113658Sdeischen#include <sys/sysproto.h> 3854708Sdeischen#include <sys/sysent.h> 39113658Sdeischen#include <sys/proc.h> 4054708Sdeischen#include <sys/lock.h> 4154708Sdeischen#include <sys/mutex.h> 4254708Sdeischen#include <sys/reboot.h> 4354708Sdeischen#include <sys/sx.h> 4454708Sdeischen#include <sys/module.h> 4553812Salfred#include <sys/linker.h> 4653812Salfred 4753812Salfredstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 48113658Sdeischen 4953812Salfredtypedef TAILQ_HEAD(modulelst, module) modulelist_t; 5053812Salfredstruct module { 51113658Sdeischen TAILQ_ENTRY(module) link; /* chain together all modules */ 52113658Sdeischen TAILQ_ENTRY(module) flink; /* all modules in a file */ 53113658Sdeischen struct linker_file *file; /* file which contains this module */ 54113658Sdeischen int refs; /* reference count */ 55113658Sdeischen int id; /* unique id number */ 56113658Sdeischen char *name; /* module name */ 57113658Sdeischen modeventhand_t handler; /* event handler */ 58113658Sdeischen void *arg; /* argument for handler */ 59113658Sdeischen modspecific_t data; /* module specific data */ 60113658Sdeischen}; 61113658Sdeischen 6253812Salfred#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 63111035Smini 64111035Sministatic modulelist_t modules; 6553812Salfredstruct sx modules_sx; 6653812Salfredstatic int nextid = 1; 67113658Sdeischenstatic void module_shutdown(void *, int); 68113658Sdeischen 6953812Salfredstatic int 7053812Salfredmodevent_nop(module_t mod, int what, void *arg) 7176909Sjasone{ 72115278Sdeischen 73115278Sdeischen switch(what) { 74115278Sdeischen case MOD_LOAD: 75113658Sdeischen return (0); 76115278Sdeischen case MOD_UNLOAD: 77115278Sdeischen return (EBUSY); 78115278Sdeischen default: 79115278Sdeischen return (EOPNOTSUPP); 80115278Sdeischen } 81115278Sdeischen} 82115278Sdeischen 8381750Sjasonestatic void 8481750Sjasonemodule_init(void *arg) 8561681Sjasone{ 8653812Salfred 8753812Salfred sx_init(&modules_sx, "module subsystem sx lock"); 8853812Salfred TAILQ_INIT(&modules); 8953812Salfred EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, 9053812Salfred SHUTDOWN_PRI_DEFAULT); 9153812Salfred} 9253812Salfred 9353812SalfredSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); 9453812Salfred 9556277Sjasonestatic void 9656277Sjasonemodule_shutdown(void *arg1, int arg2) 9753812Salfred{ 9853812Salfred module_t mod; 99113658Sdeischen 100113658Sdeischen if (arg2 & RB_NOSYNC) 10156277Sjasone return; 10253812Salfred mtx_lock(&Giant); 10353812Salfred MOD_SLOCK; 10453812Salfred TAILQ_FOREACH_REVERSE(mod, &modules, modulelst, link) 10553812Salfred MOD_EVENT(mod, MOD_SHUTDOWN); 10653812Salfred MOD_SUNLOCK; 10753812Salfred mtx_unlock(&Giant); 10853812Salfred} 10954708Sdeischen 110113658Sdeischenvoid 111113658Sdeischenmodule_register_init(const void *arg) 112116972Sdavidxu{ 11353812Salfred const moduledata_t *data = (const moduledata_t *)arg; 11454708Sdeischen int error; 115113658Sdeischen module_t mod; 116113658Sdeischen 117113658Sdeischen mtx_lock(&Giant); 118113658Sdeischen MOD_SLOCK; 119113658Sdeischen mod = module_lookupbyname(data->name); 120113658Sdeischen if (mod == NULL) 121115278Sdeischen panic("module_register_init: module named %s not found\n", 122115278Sdeischen data->name); 123115278Sdeischen MOD_SUNLOCK; 124115278Sdeischen error = MOD_EVENT(mod, MOD_LOAD); 125115278Sdeischen if (error) { 126115278Sdeischen MOD_EVENT(mod, MOD_UNLOAD); 127115278Sdeischen MOD_XLOCK; 128115278Sdeischen module_release(mod); 129115278Sdeischen MOD_XUNLOCK; 13053812Salfred printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 13153812Salfred " %d\n", data->name, (void *)data->evhand, data->priv, 13253812Salfred error); 13353812Salfred } else { 13453812Salfred MOD_XLOCK; 13571581Sdeischen if (mod->file) { 13653812Salfred /* 13771581Sdeischen * Once a module is succesfully loaded, move 13853812Salfred * it to the head of the module list for this 13953812Salfred * linker file. This resorts the list so that 140113658Sdeischen * when the kernel linker iterates over the 14153812Salfred * modules to unload them, it will unload them 142113658Sdeischen * in the reverse order they were loaded. 143113658Sdeischen */ 144113658Sdeischen TAILQ_REMOVE(&mod->file->modules, mod, flink); 14571581Sdeischen TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); 14653812Salfred } 14753812Salfred MOD_XUNLOCK; 14853812Salfred } 14953812Salfred mtx_unlock(&Giant); 15053812Salfred} 15171581Sdeischen 15271581Sdeischenint 153113658Sdeischenmodule_register(const moduledata_t *data, linker_file_t container) 15453812Salfred{ 15553812Salfred size_t namelen; 15653812Salfred module_t newmod; 15753812Salfred 15853812Salfred MOD_XLOCK; 15971581Sdeischen newmod = module_lookupbyname(data->name); 16053812Salfred if (newmod != NULL) { 16153812Salfred MOD_XUNLOCK; 16253812Salfred printf("module_register: module %s already exists!\n", 16353812Salfred data->name); 16453812Salfred return (EEXIST); 16553812Salfred } 166113658Sdeischen namelen = strlen(data->name) + 1; 167113658Sdeischen newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 168113658Sdeischen if (newmod == NULL) { 169113658Sdeischen MOD_XUNLOCK; 170113658Sdeischen return (ENOMEM); 171113658Sdeischen } 17253812Salfred newmod->refs = 1; 17353812Salfred newmod->id = nextid++; 17453812Salfred newmod->name = (char *)(newmod + 1); 17553812Salfred strcpy(newmod->name, data->name); 17671581Sdeischen newmod->handler = data->evhand ? data->evhand : modevent_nop; 17753812Salfred newmod->arg = data->priv; 17871581Sdeischen bzero(&newmod->data, sizeof(newmod->data)); 17953812Salfred TAILQ_INSERT_TAIL(&modules, newmod, link); 18053812Salfred 181113658Sdeischen if (container) 18253812Salfred TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 183113658Sdeischen newmod->file = container; 184113658Sdeischen MOD_XUNLOCK; 185113658Sdeischen return (0); 18671581Sdeischen} 18753812Salfred 18853812Salfredvoid 18953812Salfredmodule_reference(module_t mod) 19053812Salfred{ 19171581Sdeischen 192113658Sdeischen MOD_XLOCK_ASSERT; 19353812Salfred 19453812Salfred MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 19553812Salfred mod->refs++; 19653812Salfred} 19753812Salfred 19871581Sdeischenvoid 19953812Salfredmodule_release(module_t mod) 20053812Salfred{ 20153812Salfred 20253812Salfred MOD_XLOCK_ASSERT; 20353812Salfred 20453812Salfred if (mod->refs <= 0) 205113658Sdeischen panic("module_release: bad reference count"); 206113658Sdeischen 207113658Sdeischen MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 208113658Sdeischen 209113658Sdeischen mod->refs--; 210113658Sdeischen if (mod->refs == 0) { 21153812Salfred TAILQ_REMOVE(&modules, mod, link); 21253812Salfred if (mod->file) 21353812Salfred TAILQ_REMOVE(&mod->file->modules, mod, flink); 214113658Sdeischen free(mod, M_MODULE); 215113658Sdeischen } 21653812Salfred} 21771581Sdeischen 218113658Sdeischenmodule_t 21953812Salfredmodule_lookupbyname(const char *name) 22053812Salfred{ 22153812Salfred module_t mod; 22253812Salfred int err; 22353812Salfred 224113658Sdeischen MOD_LOCK_ASSERT; 225113658Sdeischen 226113658Sdeischen TAILQ_FOREACH(mod, &modules, link) { 227113658Sdeischen err = strcmp(mod->name, name); 228113658Sdeischen if (err == 0) 229113658Sdeischen return (mod); 230113658Sdeischen } 231113658Sdeischen return (NULL); 232113658Sdeischen} 233113658Sdeischen 234113658Sdeischenmodule_t 235113658Sdeischenmodule_lookupbyid(int modid) 236113658Sdeischen{ 237113658Sdeischen module_t mod; 238113658Sdeischen 239113658Sdeischen MOD_LOCK_ASSERT; 240113658Sdeischen 24153812Salfred TAILQ_FOREACH(mod, &modules, link) 24253812Salfred if (mod->id == modid) 24353812Salfred return(mod); 24453812Salfred return (NULL); 24553812Salfred} 24653812Salfred 247113658Sdeischenint 24853812Salfredmodule_quiesce(module_t mod) 24971581Sdeischen{ 25071581Sdeischen int error; 251114187Sdeischen 252113658Sdeischen mtx_lock(&Giant); 253114187Sdeischen error = MOD_EVENT(mod, MOD_QUIESCE); 254113658Sdeischen mtx_unlock(&Giant); 255113658Sdeischen if (error == EOPNOTSUPP || error == EINVAL) 256113658Sdeischen error = 0; 257113658Sdeischen return (error); 258113658Sdeischen} 25953812Salfred 260114187Sdeischenint 261113658Sdeischenmodule_unload(module_t mod) 262113658Sdeischen{ 263114187Sdeischen int error; 26453812Salfred 26553812Salfred mtx_lock(&Giant); 26653812Salfred error = MOD_EVENT(mod, MOD_UNLOAD); 267113658Sdeischen mtx_unlock(&Giant); 26853812Salfred return (error); 269114187Sdeischen} 270113658Sdeischen 27153812Salfredint 272113658Sdeischenmodule_getid(module_t mod) 273114187Sdeischen{ 27453812Salfred 27556277Sjasone MOD_LOCK_ASSERT; 27656277Sjasone return (mod->id); 27756277Sjasone} 27856277Sjasone 27971581Sdeischenmodule_t 28056277Sjasonemodule_getfnext(module_t mod) 28171581Sdeischen{ 28271581Sdeischen 28371581Sdeischen MOD_LOCK_ASSERT; 284114187Sdeischen return (TAILQ_NEXT(mod, flink)); 285113658Sdeischen} 286113658Sdeischen 287114187Sdeischenconst char * 288113658Sdeischenmodule_getname(module_t mod) 28956277Sjasone{ 29056277Sjasone 291114187Sdeischen MOD_LOCK_ASSERT; 29256277Sjasone return (mod->name); 293} 294 295void 296module_setspecific(module_t mod, modspecific_t *datap) 297{ 298 299 MOD_XLOCK_ASSERT; 300 mod->data = *datap; 301} 302 303linker_file_t 304module_file(module_t mod) 305{ 306 307 return (mod->file); 308} 309 310/* 311 * Syscalls. 312 */ 313int 314modnext(struct thread *td, struct modnext_args *uap) 315{ 316 module_t mod; 317 int error = 0; 318 319 td->td_retval[0] = -1; 320 321 MOD_SLOCK; 322 if (uap->modid == 0) { 323 mod = TAILQ_FIRST(&modules); 324 if (mod) 325 td->td_retval[0] = mod->id; 326 else 327 error = ENOENT; 328 goto done2; 329 } 330 mod = module_lookupbyid(uap->modid); 331 if (mod == NULL) { 332 error = ENOENT; 333 goto done2; 334 } 335 if (TAILQ_NEXT(mod, link)) 336 td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 337 else 338 td->td_retval[0] = 0; 339done2: 340 MOD_SUNLOCK; 341 return (error); 342} 343 344int 345modfnext(struct thread *td, struct modfnext_args *uap) 346{ 347 module_t mod; 348 int error; 349 350 td->td_retval[0] = -1; 351 352 MOD_SLOCK; 353 mod = module_lookupbyid(uap->modid); 354 if (mod == NULL) { 355 error = ENOENT; 356 } else { 357 error = 0; 358 if (TAILQ_NEXT(mod, flink)) 359 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 360 else 361 td->td_retval[0] = 0; 362 } 363 MOD_SUNLOCK; 364 return (error); 365} 366 367struct module_stat_v1 { 368 int version; /* set to sizeof(struct module_stat) */ 369 char name[MAXMODNAME]; 370 int refs; 371 int id; 372}; 373 374int 375modstat(struct thread *td, struct modstat_args *uap) 376{ 377 module_t mod; 378 modspecific_t data; 379 int error = 0; 380 int id, namelen, refs, version; 381 struct module_stat *stat; 382 char *name; 383 384 MOD_SLOCK; 385 mod = module_lookupbyid(uap->modid); 386 if (mod == NULL) { 387 MOD_SUNLOCK; 388 return (ENOENT); 389 } 390 id = mod->id; 391 refs = mod->refs; 392 name = mod->name; 393 data = mod->data; 394 MOD_SUNLOCK; 395 stat = uap->stat; 396 397 /* 398 * Check the version of the user's structure. 399 */ 400 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 401 return (error); 402 if (version != sizeof(struct module_stat_v1) 403 && version != sizeof(struct module_stat)) 404 return (EINVAL); 405 namelen = strlen(mod->name) + 1; 406 if (namelen > MAXMODNAME) 407 namelen = MAXMODNAME; 408 if ((error = copyout(name, &stat->name[0], namelen)) != 0) 409 return (error); 410 411 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 412 return (error); 413 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 414 return (error); 415 416 /* 417 * >v1 stat includes module data. 418 */ 419 if (version == sizeof(struct module_stat)) 420 if ((error = copyout(&data, &stat->data, 421 sizeof(data))) != 0) 422 return (error); 423 td->td_retval[0] = 0; 424 return (error); 425} 426 427int 428modfind(struct thread *td, struct modfind_args *uap) 429{ 430 int error = 0; 431 char name[MAXMODNAME]; 432 module_t mod; 433 434 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) 435 return (error); 436 437 MOD_SLOCK; 438 mod = module_lookupbyname(name); 439 if (mod == NULL) 440 error = ENOENT; 441 else 442 td->td_retval[0] = module_getid(mod); 443 MOD_SUNLOCK; 444 return (error); 445} 446 447MODULE_VERSION(kernel, __FreeBSD_version); 448 449#ifdef COMPAT_FREEBSD32 450#include <sys/mount.h> 451#include <sys/socket.h> 452#include <compat/freebsd32/freebsd32_util.h> 453#include <compat/freebsd32/freebsd32.h> 454#include <compat/freebsd32/freebsd32_proto.h> 455 456typedef union modspecific32 { 457 int intval; 458 uint32_t uintval; 459 int longval; 460 uint32_t ulongval; 461} modspecific32_t; 462 463struct module_stat32 { 464 int version; 465 char name[MAXMODNAME]; 466 int refs; 467 int id; 468 modspecific32_t data; 469}; 470 471int 472freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) 473{ 474 module_t mod; 475 modspecific32_t data32; 476 int error = 0; 477 int id, namelen, refs, version; 478 struct module_stat32 *stat32; 479 char *name; 480 481 MOD_SLOCK; 482 mod = module_lookupbyid(uap->modid); 483 if (mod == NULL) { 484 MOD_SUNLOCK; 485 return (ENOENT); 486 } 487 488 id = mod->id; 489 refs = mod->refs; 490 name = mod->name; 491 CP(mod->data, data32, intval); 492 CP(mod->data, data32, uintval); 493 CP(mod->data, data32, longval); 494 CP(mod->data, data32, ulongval); 495 MOD_SUNLOCK; 496 stat32 = uap->stat; 497 498 if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) 499 return (error); 500 if (version != sizeof(struct module_stat_v1) 501 && version != sizeof(struct module_stat32)) 502 return (EINVAL); 503 namelen = strlen(mod->name) + 1; 504 if (namelen > MAXMODNAME) 505 namelen = MAXMODNAME; 506 if ((error = copyout(name, &stat32->name[0], namelen)) != 0) 507 return (error); 508 509 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) 510 return (error); 511 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) 512 return (error); 513 514 /* 515 * >v1 stat includes module data. 516 */ 517 if (version == sizeof(struct module_stat32)) 518 if ((error = copyout(&data32, &stat32->data, 519 sizeof(data32))) != 0) 520 return (error); 521 td->td_retval[0] = 0; 522 return (error); 523} 524#endif 525