diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-05 14:59:04 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-04 23:29:05 -0400 |
commit | 9f85a4bbb1cf56f65b3d065a5f88204a757f2325 (patch) | |
tree | 28d674a40dcab0e0c31349736718993f1e9377d4 /kernel/module.c | |
parent | 40dd2560ec2df21036db9ec8b971f92d98fd1969 (diff) |
module: refactor load_module part 4
Allocate references inside module_unload_init(), clean up inside
module_unload_free().
This version fixed to do allocation before __this_cpu_write, thanks to
bug reports from linux-next from Dave Young <hidave.darkstar@gmail.com>
and Stephen Rothwell <sfr@canb.auug.org.au>.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 32 |
1 files changed, 15 insertions, 17 deletions
diff --git a/kernel/module.c b/kernel/module.c index d8faf35cba84..241bc41dd6be 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -524,8 +524,12 @@ static char last_unloaded_module[MODULE_NAME_LEN+1]; | |||
524 | EXPORT_TRACEPOINT_SYMBOL(module_get); | 524 | EXPORT_TRACEPOINT_SYMBOL(module_get); |
525 | 525 | ||
526 | /* Init the unload section of the module. */ | 526 | /* Init the unload section of the module. */ |
527 | static void module_unload_init(struct module *mod) | 527 | static int module_unload_init(struct module *mod) |
528 | { | 528 | { |
529 | mod->refptr = alloc_percpu(struct module_ref); | ||
530 | if (!mod->refptr) | ||
531 | return -ENOMEM; | ||
532 | |||
529 | INIT_LIST_HEAD(&mod->source_list); | 533 | INIT_LIST_HEAD(&mod->source_list); |
530 | INIT_LIST_HEAD(&mod->target_list); | 534 | INIT_LIST_HEAD(&mod->target_list); |
531 | 535 | ||
@@ -533,6 +537,8 @@ static void module_unload_init(struct module *mod) | |||
533 | __this_cpu_write(mod->refptr->incs, 1); | 537 | __this_cpu_write(mod->refptr->incs, 1); |
534 | /* Backwards compatibility macros put refcount during init. */ | 538 | /* Backwards compatibility macros put refcount during init. */ |
535 | mod->waiter = current; | 539 | mod->waiter = current; |
540 | |||
541 | return 0; | ||
536 | } | 542 | } |
537 | 543 | ||
538 | /* Does a already use b? */ | 544 | /* Does a already use b? */ |
@@ -612,6 +618,8 @@ static void module_unload_free(struct module *mod) | |||
612 | kfree(use); | 618 | kfree(use); |
613 | } | 619 | } |
614 | mutex_unlock(&module_mutex); | 620 | mutex_unlock(&module_mutex); |
621 | |||
622 | free_percpu(mod->refptr); | ||
615 | } | 623 | } |
616 | 624 | ||
617 | #ifdef CONFIG_MODULE_FORCE_UNLOAD | 625 | #ifdef CONFIG_MODULE_FORCE_UNLOAD |
@@ -885,8 +893,9 @@ int ref_module(struct module *a, struct module *b) | |||
885 | } | 893 | } |
886 | EXPORT_SYMBOL_GPL(ref_module); | 894 | EXPORT_SYMBOL_GPL(ref_module); |
887 | 895 | ||
888 | static inline void module_unload_init(struct module *mod) | 896 | static inline int module_unload_init(struct module *mod) |
889 | { | 897 | { |
898 | return 0; | ||
890 | } | 899 | } |
891 | #endif /* CONFIG_MODULE_UNLOAD */ | 900 | #endif /* CONFIG_MODULE_UNLOAD */ |
892 | 901 | ||
@@ -1559,10 +1568,7 @@ static void free_module(struct module *mod) | |||
1559 | module_free(mod, mod->module_init); | 1568 | module_free(mod, mod->module_init); |
1560 | kfree(mod->args); | 1569 | kfree(mod->args); |
1561 | percpu_modfree(mod); | 1570 | percpu_modfree(mod); |
1562 | #if defined(CONFIG_MODULE_UNLOAD) | 1571 | |
1563 | if (mod->refptr) | ||
1564 | free_percpu(mod->refptr); | ||
1565 | #endif | ||
1566 | /* Free lock-classes: */ | 1572 | /* Free lock-classes: */ |
1567 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1573 | lockdep_free_key_range(mod->module_core, mod->core_size); |
1568 | 1574 | ||
@@ -2442,15 +2448,10 @@ static noinline struct module *load_module(void __user *umod, | |||
2442 | goto free_percpu; | 2448 | goto free_percpu; |
2443 | } | 2449 | } |
2444 | 2450 | ||
2445 | #if defined(CONFIG_MODULE_UNLOAD) | ||
2446 | mod->refptr = alloc_percpu(struct module_ref); | ||
2447 | if (!mod->refptr) { | ||
2448 | err = -ENOMEM; | ||
2449 | goto free_init; | ||
2450 | } | ||
2451 | #endif | ||
2452 | /* Now we've moved module, initialize linked lists, etc. */ | 2451 | /* Now we've moved module, initialize linked lists, etc. */ |
2453 | module_unload_init(mod); | 2452 | err = module_unload_init(mod); |
2453 | if (err) | ||
2454 | goto free_init; | ||
2454 | 2455 | ||
2455 | /* Set up license info based on the info section */ | 2456 | /* Set up license info based on the info section */ |
2456 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 2457 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
@@ -2619,10 +2620,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2619 | cleanup: | 2620 | cleanup: |
2620 | free_modinfo(mod); | 2621 | free_modinfo(mod); |
2621 | module_unload_free(mod); | 2622 | module_unload_free(mod); |
2622 | #if defined(CONFIG_MODULE_UNLOAD) | ||
2623 | free_percpu(mod->refptr); | ||
2624 | free_init: | 2623 | free_init: |
2625 | #endif | ||
2626 | module_free(mod, mod->module_init); | 2624 | module_free(mod, mod->module_init); |
2627 | module_free(mod, mod->module_core); | 2625 | module_free(mod, mod->module_core); |
2628 | /* mod will be freed with core. Don't access it beyond this line! */ | 2626 | /* mod will be freed with core. Don't access it beyond this line! */ |