diff options
-rw-r--r-- | include/linux/module.h | 36 | ||||
-rw-r--r-- | kernel/module.c | 29 |
2 files changed, 29 insertions, 36 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 6cb1a3cab5d..2302f09ea2d 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/tracepoint.h> | 18 | #include <linux/tracepoint.h> |
19 | 19 | ||
20 | #include <asm/local.h> | 20 | #include <asm/local.h> |
21 | #include <linux/percpu.h> | ||
21 | #include <asm/module.h> | 22 | #include <asm/module.h> |
22 | 23 | ||
23 | #include <trace/events/module.h> | 24 | #include <trace/events/module.h> |
@@ -363,11 +364,9 @@ struct module | |||
363 | /* Destruction function. */ | 364 | /* Destruction function. */ |
364 | void (*exit)(void); | 365 | void (*exit)(void); |
365 | 366 | ||
366 | #ifdef CONFIG_SMP | 367 | struct module_ref { |
367 | char *refptr; | 368 | int count; |
368 | #else | 369 | } *refptr; |
369 | local_t ref; | ||
370 | #endif | ||
371 | #endif | 370 | #endif |
372 | 371 | ||
373 | #ifdef CONFIG_CONSTRUCTORS | 372 | #ifdef CONFIG_CONSTRUCTORS |
@@ -454,25 +453,16 @@ void __symbol_put(const char *symbol); | |||
454 | #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) | 453 | #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) |
455 | void symbol_put_addr(void *addr); | 454 | void symbol_put_addr(void *addr); |
456 | 455 | ||
457 | static inline local_t *__module_ref_addr(struct module *mod, int cpu) | ||
458 | { | ||
459 | #ifdef CONFIG_SMP | ||
460 | return (local_t *) (mod->refptr + per_cpu_offset(cpu)); | ||
461 | #else | ||
462 | return &mod->ref; | ||
463 | #endif | ||
464 | } | ||
465 | |||
466 | /* Sometimes we know we already have a refcount, and it's easier not | 456 | /* Sometimes we know we already have a refcount, and it's easier not |
467 | to handle the error case (which only happens with rmmod --wait). */ | 457 | to handle the error case (which only happens with rmmod --wait). */ |
468 | static inline void __module_get(struct module *module) | 458 | static inline void __module_get(struct module *module) |
469 | { | 459 | { |
470 | if (module) { | 460 | if (module) { |
471 | unsigned int cpu = get_cpu(); | 461 | preempt_disable(); |
472 | local_inc(__module_ref_addr(module, cpu)); | 462 | __this_cpu_inc(module->refptr->count); |
473 | trace_module_get(module, _THIS_IP_, | 463 | trace_module_get(module, _THIS_IP_, |
474 | local_read(__module_ref_addr(module, cpu))); | 464 | __this_cpu_read(module->refptr->count)); |
475 | put_cpu(); | 465 | preempt_enable(); |
476 | } | 466 | } |
477 | } | 467 | } |
478 | 468 | ||
@@ -481,15 +471,17 @@ static inline int try_module_get(struct module *module) | |||
481 | int ret = 1; | 471 | int ret = 1; |
482 | 472 | ||
483 | if (module) { | 473 | if (module) { |
484 | unsigned int cpu = get_cpu(); | 474 | preempt_disable(); |
475 | |||
485 | if (likely(module_is_live(module))) { | 476 | if (likely(module_is_live(module))) { |
486 | local_inc(__module_ref_addr(module, cpu)); | 477 | __this_cpu_inc(module->refptr->count); |
487 | trace_module_get(module, _THIS_IP_, | 478 | trace_module_get(module, _THIS_IP_, |
488 | local_read(__module_ref_addr(module, cpu))); | 479 | __this_cpu_read(module->refptr->count)); |
489 | } | 480 | } |
490 | else | 481 | else |
491 | ret = 0; | 482 | ret = 0; |
492 | put_cpu(); | 483 | |
484 | preempt_enable(); | ||
493 | } | 485 | } |
494 | return ret; | 486 | return ret; |
495 | } | 487 | } |
diff --git a/kernel/module.c b/kernel/module.c index e96b8ed1cb6..9bf228052ec 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); |