diff options
author | Christoph Lameter <cl@linux-foundation.org> | 2010-01-05 01:34:50 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-01-05 01:34:50 -0500 |
commit | e1783a240f491fb233f04edc042e16b18a7a79ba (patch) | |
tree | b523bf2db00fff96f1ab488168fc16ab56c372aa /kernel/module.c | |
parent | 38b7827fcdd660f591d645bd3ae6644456a4773c (diff) |
module: Use this_cpu_xx to dynamically allocate counters
Use cpu ops to deal with the per cpu data instead of a local_t. Reduces memory
requirements, cache footprint and decreases cycle counts.
The this_cpu_xx operations are also used for !SMP mode. Otherwise we could
not drop the use of __module_ref_addr() which would make per cpu data handling
complicated. this_cpu_xx operations have their own fallback for !SMP.
V8-V9:
- Leave include asm/module.h since ringbuffer.c depends on it. Nothing else
does though. Another patch will deal with that.
- Remove spurious free.
Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/kernel/module.c b/kernel/module.c index e96b8ed1cb6a..9bf228052ec5 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -474,9 +474,10 @@ static void module_unload_init(struct module *mod) | |||
474 | 474 | ||
475 | INIT_LIST_HEAD(&mod->modules_which_use_me); | 475 | INIT_LIST_HEAD(&mod->modules_which_use_me); |
476 | for_each_possible_cpu(cpu) | 476 | for_each_possible_cpu(cpu) |
477 | local_set(__module_ref_addr(mod, cpu), 0); | 477 | per_cpu_ptr(mod->refptr, cpu)->count = 0; |
478 | |||
478 | /* Hold reference count during initialization. */ | 479 | /* Hold reference count during initialization. */ |
479 | local_set(__module_ref_addr(mod, raw_smp_processor_id()), 1); | 480 | __this_cpu_write(mod->refptr->count, 1); |
480 | /* Backwards compatibility macros put refcount during init. */ | 481 | /* Backwards compatibility macros put refcount during init. */ |
481 | mod->waiter = current; | 482 | mod->waiter = current; |
482 | } | 483 | } |
@@ -619,7 +620,7 @@ unsigned int module_refcount(struct module *mod) | |||
619 | int cpu; | 620 | int cpu; |
620 | 621 | ||
621 | for_each_possible_cpu(cpu) | 622 | for_each_possible_cpu(cpu) |
622 | total += local_read(__module_ref_addr(mod, cpu)); | 623 | total += per_cpu_ptr(mod->refptr, cpu)->count; |
623 | return total; | 624 | return total; |
624 | } | 625 | } |
625 | EXPORT_SYMBOL(module_refcount); | 626 | EXPORT_SYMBOL(module_refcount); |
@@ -796,14 +797,15 @@ static struct module_attribute refcnt = { | |||
796 | void module_put(struct module *module) | 797 | void module_put(struct module *module) |
797 | { | 798 | { |
798 | if (module) { | 799 | if (module) { |
799 | unsigned int cpu = get_cpu(); | 800 | preempt_disable(); |
800 | local_dec(__module_ref_addr(module, cpu)); | 801 | __this_cpu_dec(module->refptr->count); |
802 | |||
801 | trace_module_put(module, _RET_IP_, | 803 | trace_module_put(module, _RET_IP_, |
802 | local_read(__module_ref_addr(module, cpu))); | 804 | __this_cpu_read(module->refptr->count)); |
803 | /* Maybe they're waiting for us to drop reference? */ | 805 | /* Maybe they're waiting for us to drop reference? */ |
804 | if (unlikely(!module_is_live(module))) | 806 | if (unlikely(!module_is_live(module))) |
805 | wake_up_process(module->waiter); | 807 | wake_up_process(module->waiter); |
806 | put_cpu(); | 808 | preempt_enable(); |
807 | } | 809 | } |
808 | } | 810 | } |
809 | EXPORT_SYMBOL(module_put); | 811 | EXPORT_SYMBOL(module_put); |
@@ -1394,9 +1396,9 @@ static void free_module(struct module *mod) | |||
1394 | kfree(mod->args); | 1396 | kfree(mod->args); |
1395 | if (mod->percpu) | 1397 | if (mod->percpu) |
1396 | percpu_modfree(mod->percpu); | 1398 | percpu_modfree(mod->percpu); |
1397 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | 1399 | #if defined(CONFIG_MODULE_UNLOAD) |
1398 | if (mod->refptr) | 1400 | if (mod->refptr) |
1399 | percpu_modfree(mod->refptr); | 1401 | free_percpu(mod->refptr); |
1400 | #endif | 1402 | #endif |
1401 | /* Free lock-classes: */ | 1403 | /* Free lock-classes: */ |
1402 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1404 | lockdep_free_key_range(mod->module_core, mod->core_size); |
@@ -2159,9 +2161,8 @@ static noinline struct module *load_module(void __user *umod, | |||
2159 | mod = (void *)sechdrs[modindex].sh_addr; | 2161 | mod = (void *)sechdrs[modindex].sh_addr; |
2160 | kmemleak_load_module(mod, hdr, sechdrs, secstrings); | 2162 | kmemleak_load_module(mod, hdr, sechdrs, secstrings); |
2161 | 2163 | ||
2162 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | 2164 | #if defined(CONFIG_MODULE_UNLOAD) |
2163 | mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t), | 2165 | mod->refptr = alloc_percpu(struct module_ref); |
2164 | mod->name); | ||
2165 | if (!mod->refptr) { | 2166 | if (!mod->refptr) { |
2166 | err = -ENOMEM; | 2167 | err = -ENOMEM; |
2167 | goto free_init; | 2168 | goto free_init; |
@@ -2393,8 +2394,8 @@ static noinline struct module *load_module(void __user *umod, | |||
2393 | kobject_put(&mod->mkobj.kobj); | 2394 | kobject_put(&mod->mkobj.kobj); |
2394 | free_unload: | 2395 | free_unload: |
2395 | module_unload_free(mod); | 2396 | module_unload_free(mod); |
2396 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | 2397 | #if defined(CONFIG_MODULE_UNLOAD) |
2397 | percpu_modfree(mod->refptr); | 2398 | free_percpu(mod->refptr); |
2398 | free_init: | 2399 | free_init: |
2399 | #endif | 2400 | #endif |
2400 | module_free(mod, mod->module_init); | 2401 | module_free(mod, mod->module_init); |