diff options
| -rw-r--r-- | include/linux/module.h | 10 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_main.c | 2 | ||||
| -rw-r--r-- | kernel/module.c | 57 |
3 files changed, 59 insertions, 10 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 7760c6d344a3..1375ee3f03aa 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -199,11 +199,11 @@ struct module_use { | |||
| 199 | struct module *source, *target; | 199 | struct module *source, *target; |
| 200 | }; | 200 | }; |
| 201 | 201 | ||
| 202 | enum module_state | 202 | enum module_state { |
| 203 | { | 203 | MODULE_STATE_LIVE, /* Normal state. */ |
| 204 | MODULE_STATE_LIVE, | 204 | MODULE_STATE_COMING, /* Full formed, running module_init. */ |
| 205 | MODULE_STATE_COMING, | 205 | MODULE_STATE_GOING, /* Going away. */ |
| 206 | MODULE_STATE_GOING, | 206 | MODULE_STATE_UNFORMED, /* Still setting it up. */ |
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | /** | 209 | /** |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 4d5f8d5612f3..8875254120b6 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
| @@ -1970,6 +1970,8 @@ static int kdb_lsmod(int argc, const char **argv) | |||
| 1970 | 1970 | ||
| 1971 | kdb_printf("Module Size modstruct Used by\n"); | 1971 | kdb_printf("Module Size modstruct Used by\n"); |
| 1972 | list_for_each_entry(mod, kdb_modules, list) { | 1972 | list_for_each_entry(mod, kdb_modules, list) { |
| 1973 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 1974 | continue; | ||
| 1973 | 1975 | ||
| 1974 | kdb_printf("%-20s%8u 0x%p ", mod->name, | 1976 | kdb_printf("%-20s%8u 0x%p ", mod->name, |
| 1975 | mod->core_size, (void *)mod); | 1977 | mod->core_size, (void *)mod); |
diff --git a/kernel/module.c b/kernel/module.c index 41bc1189b061..c3a2ee8e3679 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -188,6 +188,7 @@ struct load_info { | |||
| 188 | ongoing or failed initialization etc. */ | 188 | ongoing or failed initialization etc. */ |
| 189 | static inline int strong_try_module_get(struct module *mod) | 189 | static inline int strong_try_module_get(struct module *mod) |
| 190 | { | 190 | { |
| 191 | BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED); | ||
| 191 | if (mod && mod->state == MODULE_STATE_COMING) | 192 | if (mod && mod->state == MODULE_STATE_COMING) |
| 192 | return -EBUSY; | 193 | return -EBUSY; |
| 193 | if (try_module_get(mod)) | 194 | if (try_module_get(mod)) |
| @@ -343,6 +344,9 @@ bool each_symbol_section(bool (*fn)(const struct symsearch *arr, | |||
| 343 | #endif | 344 | #endif |
| 344 | }; | 345 | }; |
| 345 | 346 | ||
| 347 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 348 | continue; | ||
| 349 | |||
| 346 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) | 350 | if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) |
| 347 | return true; | 351 | return true; |
| 348 | } | 352 | } |
| @@ -450,16 +454,24 @@ const struct kernel_symbol *find_symbol(const char *name, | |||
| 450 | EXPORT_SYMBOL_GPL(find_symbol); | 454 | EXPORT_SYMBOL_GPL(find_symbol); |
| 451 | 455 | ||
| 452 | /* Search for module by name: must hold module_mutex. */ | 456 | /* Search for module by name: must hold module_mutex. */ |
| 453 | struct module *find_module(const char *name) | 457 | static struct module *find_module_all(const char *name, |
| 458 | bool even_unformed) | ||
| 454 | { | 459 | { |
| 455 | struct module *mod; | 460 | struct module *mod; |
| 456 | 461 | ||
| 457 | list_for_each_entry(mod, &modules, list) { | 462 | list_for_each_entry(mod, &modules, list) { |
| 463 | if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) | ||
| 464 | continue; | ||
| 458 | if (strcmp(mod->name, name) == 0) | 465 | if (strcmp(mod->name, name) == 0) |
| 459 | return mod; | 466 | return mod; |
| 460 | } | 467 | } |
| 461 | return NULL; | 468 | return NULL; |
| 462 | } | 469 | } |
| 470 | |||
| 471 | struct module *find_module(const char *name) | ||
| 472 | { | ||
| 473 | return find_module_all(name, false); | ||
| 474 | } | ||
| 463 | EXPORT_SYMBOL_GPL(find_module); | 475 | EXPORT_SYMBOL_GPL(find_module); |
| 464 | 476 | ||
| 465 | #ifdef CONFIG_SMP | 477 | #ifdef CONFIG_SMP |
| @@ -525,6 +537,8 @@ bool is_module_percpu_address(unsigned long addr) | |||
| 525 | preempt_disable(); | 537 | preempt_disable(); |
| 526 | 538 | ||
| 527 | list_for_each_entry_rcu(mod, &modules, list) { | 539 | list_for_each_entry_rcu(mod, &modules, list) { |
| 540 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 541 | continue; | ||
| 528 | if (!mod->percpu_size) | 542 | if (!mod->percpu_size) |
| 529 | continue; | 543 | continue; |
| 530 | for_each_possible_cpu(cpu) { | 544 | for_each_possible_cpu(cpu) { |
| @@ -1048,6 +1062,8 @@ static ssize_t show_initstate(struct module_attribute *mattr, | |||
| 1048 | case MODULE_STATE_GOING: | 1062 | case MODULE_STATE_GOING: |
| 1049 | state = "going"; | 1063 | state = "going"; |
| 1050 | break; | 1064 | break; |
| 1065 | default: | ||
| 1066 | BUG(); | ||
| 1051 | } | 1067 | } |
| 1052 | return sprintf(buffer, "%s\n", state); | 1068 | return sprintf(buffer, "%s\n", state); |
| 1053 | } | 1069 | } |
| @@ -1786,6 +1802,8 @@ void set_all_modules_text_rw(void) | |||
| 1786 | 1802 | ||
| 1787 | mutex_lock(&module_mutex); | 1803 | mutex_lock(&module_mutex); |
| 1788 | list_for_each_entry_rcu(mod, &modules, list) { | 1804 | list_for_each_entry_rcu(mod, &modules, list) { |
| 1805 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 1806 | continue; | ||
| 1789 | if ((mod->module_core) && (mod->core_text_size)) { | 1807 | if ((mod->module_core) && (mod->core_text_size)) { |
| 1790 | set_page_attributes(mod->module_core, | 1808 | set_page_attributes(mod->module_core, |
| 1791 | mod->module_core + mod->core_text_size, | 1809 | mod->module_core + mod->core_text_size, |
| @@ -1807,6 +1825,8 @@ void set_all_modules_text_ro(void) | |||
| 1807 | 1825 | ||
| 1808 | mutex_lock(&module_mutex); | 1826 | mutex_lock(&module_mutex); |
| 1809 | list_for_each_entry_rcu(mod, &modules, list) { | 1827 | list_for_each_entry_rcu(mod, &modules, list) { |
| 1828 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 1829 | continue; | ||
| 1810 | if ((mod->module_core) && (mod->core_text_size)) { | 1830 | if ((mod->module_core) && (mod->core_text_size)) { |
| 1811 | set_page_attributes(mod->module_core, | 1831 | set_page_attributes(mod->module_core, |
| 1812 | mod->module_core + mod->core_text_size, | 1832 | mod->module_core + mod->core_text_size, |
| @@ -2998,7 +3018,8 @@ static bool finished_loading(const char *name) | |||
| 2998 | 3018 | ||
| 2999 | mutex_lock(&module_mutex); | 3019 | mutex_lock(&module_mutex); |
| 3000 | mod = find_module(name); | 3020 | mod = find_module(name); |
| 3001 | ret = !mod || mod->state != MODULE_STATE_COMING; | 3021 | ret = !mod || mod->state == MODULE_STATE_LIVE |
| 3022 | || mod->state == MODULE_STATE_GOING; | ||
| 3002 | mutex_unlock(&module_mutex); | 3023 | mutex_unlock(&module_mutex); |
| 3003 | 3024 | ||
| 3004 | return ret; | 3025 | return ret; |
| @@ -3361,6 +3382,8 @@ const char *module_address_lookup(unsigned long addr, | |||
| 3361 | 3382 | ||
| 3362 | preempt_disable(); | 3383 | preempt_disable(); |
| 3363 | list_for_each_entry_rcu(mod, &modules, list) { | 3384 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3385 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3386 | continue; | ||
| 3364 | if (within_module_init(addr, mod) || | 3387 | if (within_module_init(addr, mod) || |
| 3365 | within_module_core(addr, mod)) { | 3388 | within_module_core(addr, mod)) { |
| 3366 | if (modname) | 3389 | if (modname) |
| @@ -3384,6 +3407,8 @@ int lookup_module_symbol_name(unsigned long addr, char *symname) | |||
| 3384 | 3407 | ||
| 3385 | preempt_disable(); | 3408 | preempt_disable(); |
| 3386 | list_for_each_entry_rcu(mod, &modules, list) { | 3409 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3410 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3411 | continue; | ||
| 3387 | if (within_module_init(addr, mod) || | 3412 | if (within_module_init(addr, mod) || |
| 3388 | within_module_core(addr, mod)) { | 3413 | within_module_core(addr, mod)) { |
| 3389 | const char *sym; | 3414 | const char *sym; |
| @@ -3408,6 +3433,8 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, | |||
| 3408 | 3433 | ||
| 3409 | preempt_disable(); | 3434 | preempt_disable(); |
| 3410 | list_for_each_entry_rcu(mod, &modules, list) { | 3435 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3436 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3437 | continue; | ||
| 3411 | if (within_module_init(addr, mod) || | 3438 | if (within_module_init(addr, mod) || |
| 3412 | within_module_core(addr, mod)) { | 3439 | within_module_core(addr, mod)) { |
| 3413 | const char *sym; | 3440 | const char *sym; |
| @@ -3435,6 +3462,8 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
| 3435 | 3462 | ||
| 3436 | preempt_disable(); | 3463 | preempt_disable(); |
| 3437 | list_for_each_entry_rcu(mod, &modules, list) { | 3464 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3465 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3466 | continue; | ||
| 3438 | if (symnum < mod->num_symtab) { | 3467 | if (symnum < mod->num_symtab) { |
| 3439 | *value = mod->symtab[symnum].st_value; | 3468 | *value = mod->symtab[symnum].st_value; |
| 3440 | *type = mod->symtab[symnum].st_info; | 3469 | *type = mod->symtab[symnum].st_info; |
| @@ -3477,9 +3506,12 @@ unsigned long module_kallsyms_lookup_name(const char *name) | |||
| 3477 | ret = mod_find_symname(mod, colon+1); | 3506 | ret = mod_find_symname(mod, colon+1); |
| 3478 | *colon = ':'; | 3507 | *colon = ':'; |
| 3479 | } else { | 3508 | } else { |
| 3480 | list_for_each_entry_rcu(mod, &modules, list) | 3509 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3510 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3511 | continue; | ||
| 3481 | if ((ret = mod_find_symname(mod, name)) != 0) | 3512 | if ((ret = mod_find_symname(mod, name)) != 0) |
| 3482 | break; | 3513 | break; |
| 3514 | } | ||
| 3483 | } | 3515 | } |
| 3484 | preempt_enable(); | 3516 | preempt_enable(); |
| 3485 | return ret; | 3517 | return ret; |
| @@ -3494,6 +3526,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, | |||
| 3494 | int ret; | 3526 | int ret; |
| 3495 | 3527 | ||
| 3496 | list_for_each_entry(mod, &modules, list) { | 3528 | list_for_each_entry(mod, &modules, list) { |
| 3529 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3530 | continue; | ||
| 3497 | for (i = 0; i < mod->num_symtab; i++) { | 3531 | for (i = 0; i < mod->num_symtab; i++) { |
| 3498 | ret = fn(data, mod->strtab + mod->symtab[i].st_name, | 3532 | ret = fn(data, mod->strtab + mod->symtab[i].st_name, |
| 3499 | mod, mod->symtab[i].st_value); | 3533 | mod, mod->symtab[i].st_value); |
| @@ -3509,6 +3543,7 @@ static char *module_flags(struct module *mod, char *buf) | |||
| 3509 | { | 3543 | { |
| 3510 | int bx = 0; | 3544 | int bx = 0; |
| 3511 | 3545 | ||
| 3546 | BUG_ON(mod->state == MODULE_STATE_UNFORMED); | ||
| 3512 | if (mod->taints || | 3547 | if (mod->taints || |
| 3513 | mod->state == MODULE_STATE_GOING || | 3548 | mod->state == MODULE_STATE_GOING || |
| 3514 | mod->state == MODULE_STATE_COMING) { | 3549 | mod->state == MODULE_STATE_COMING) { |
| @@ -3550,6 +3585,10 @@ static int m_show(struct seq_file *m, void *p) | |||
| 3550 | struct module *mod = list_entry(p, struct module, list); | 3585 | struct module *mod = list_entry(p, struct module, list); |
| 3551 | char buf[8]; | 3586 | char buf[8]; |
| 3552 | 3587 | ||
| 3588 | /* We always ignore unformed modules. */ | ||
| 3589 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3590 | return 0; | ||
| 3591 | |||
| 3553 | seq_printf(m, "%s %u", | 3592 | seq_printf(m, "%s %u", |
| 3554 | mod->name, mod->init_size + mod->core_size); | 3593 | mod->name, mod->init_size + mod->core_size); |
| 3555 | print_unload_info(m, mod); | 3594 | print_unload_info(m, mod); |
| @@ -3610,6 +3649,8 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) | |||
| 3610 | 3649 | ||
| 3611 | preempt_disable(); | 3650 | preempt_disable(); |
| 3612 | list_for_each_entry_rcu(mod, &modules, list) { | 3651 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3652 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3653 | continue; | ||
| 3613 | if (mod->num_exentries == 0) | 3654 | if (mod->num_exentries == 0) |
| 3614 | continue; | 3655 | continue; |
| 3615 | 3656 | ||
| @@ -3658,10 +3699,13 @@ struct module *__module_address(unsigned long addr) | |||
| 3658 | if (addr < module_addr_min || addr > module_addr_max) | 3699 | if (addr < module_addr_min || addr > module_addr_max) |
| 3659 | return NULL; | 3700 | return NULL; |
| 3660 | 3701 | ||
| 3661 | list_for_each_entry_rcu(mod, &modules, list) | 3702 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3703 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3704 | continue; | ||
| 3662 | if (within_module_core(addr, mod) | 3705 | if (within_module_core(addr, mod) |
| 3663 | || within_module_init(addr, mod)) | 3706 | || within_module_init(addr, mod)) |
| 3664 | return mod; | 3707 | return mod; |
| 3708 | } | ||
| 3665 | return NULL; | 3709 | return NULL; |
| 3666 | } | 3710 | } |
| 3667 | EXPORT_SYMBOL_GPL(__module_address); | 3711 | EXPORT_SYMBOL_GPL(__module_address); |
| @@ -3714,8 +3758,11 @@ void print_modules(void) | |||
| 3714 | printk(KERN_DEFAULT "Modules linked in:"); | 3758 | printk(KERN_DEFAULT "Modules linked in:"); |
| 3715 | /* Most callers should already have preempt disabled, but make sure */ | 3759 | /* Most callers should already have preempt disabled, but make sure */ |
| 3716 | preempt_disable(); | 3760 | preempt_disable(); |
| 3717 | list_for_each_entry_rcu(mod, &modules, list) | 3761 | list_for_each_entry_rcu(mod, &modules, list) { |
| 3762 | if (mod->state == MODULE_STATE_UNFORMED) | ||
| 3763 | continue; | ||
| 3718 | printk(" %s%s", mod->name, module_flags(mod, buf)); | 3764 | printk(" %s%s", mod->name, module_flags(mod, buf)); |
| 3765 | } | ||
| 3719 | preempt_enable(); | 3766 | preempt_enable(); |
| 3720 | if (last_unloaded_module[0]) | 3767 | if (last_unloaded_module[0]) |
| 3721 | printk(" [last unloaded: %s]", last_unloaded_module); | 3768 | printk(" [last unloaded: %s]", last_unloaded_module); |
