diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/kernel/module.c b/kernel/module.c index 9f8d23d8b3a8..1016b75b026a 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -521,11 +521,13 @@ static void module_unload_init(struct module *mod) | |||
| 521 | int cpu; | 521 | int cpu; |
| 522 | 522 | ||
| 523 | INIT_LIST_HEAD(&mod->modules_which_use_me); | 523 | INIT_LIST_HEAD(&mod->modules_which_use_me); |
| 524 | for_each_possible_cpu(cpu) | 524 | for_each_possible_cpu(cpu) { |
| 525 | per_cpu_ptr(mod->refptr, cpu)->count = 0; | 525 | per_cpu_ptr(mod->refptr, cpu)->incs = 0; |
| 526 | per_cpu_ptr(mod->refptr, cpu)->decs = 0; | ||
| 527 | } | ||
| 526 | 528 | ||
| 527 | /* Hold reference count during initialization. */ | 529 | /* Hold reference count during initialization. */ |
| 528 | __this_cpu_write(mod->refptr->count, 1); | 530 | __this_cpu_write(mod->refptr->incs, 1); |
| 529 | /* Backwards compatibility macros put refcount during init. */ | 531 | /* Backwards compatibility macros put refcount during init. */ |
| 530 | mod->waiter = current; | 532 | mod->waiter = current; |
| 531 | } | 533 | } |
| @@ -664,12 +666,28 @@ static int try_stop_module(struct module *mod, int flags, int *forced) | |||
| 664 | 666 | ||
| 665 | unsigned int module_refcount(struct module *mod) | 667 | unsigned int module_refcount(struct module *mod) |
| 666 | { | 668 | { |
| 667 | unsigned int total = 0; | 669 | unsigned int incs = 0, decs = 0; |
| 668 | int cpu; | 670 | int cpu; |
| 669 | 671 | ||
| 670 | for_each_possible_cpu(cpu) | 672 | for_each_possible_cpu(cpu) |
| 671 | total += per_cpu_ptr(mod->refptr, cpu)->count; | 673 | decs += per_cpu_ptr(mod->refptr, cpu)->decs; |
| 672 | return total; | 674 | /* |
| 675 | * ensure the incs are added up after the decs. | ||
| 676 | * module_put ensures incs are visible before decs with smp_wmb. | ||
| 677 | * | ||
| 678 | * This 2-count scheme avoids the situation where the refcount | ||
| 679 | * for CPU0 is read, then CPU0 increments the module refcount, | ||
| 680 | * then CPU1 drops that refcount, then the refcount for CPU1 is | ||
| 681 | * read. We would record a decrement but not its corresponding | ||
| 682 | * increment so we would see a low count (disaster). | ||
| 683 | * | ||
| 684 | * Rare situation? But module_refcount can be preempted, and we | ||
| 685 | * might be tallying up 4096+ CPUs. So it is not impossible. | ||
| 686 | */ | ||
| 687 | smp_rmb(); | ||
| 688 | for_each_possible_cpu(cpu) | ||
| 689 | incs += per_cpu_ptr(mod->refptr, cpu)->incs; | ||
| 690 | return incs - decs; | ||
| 673 | } | 691 | } |
| 674 | EXPORT_SYMBOL(module_refcount); | 692 | EXPORT_SYMBOL(module_refcount); |
| 675 | 693 | ||
| @@ -846,10 +864,11 @@ void module_put(struct module *module) | |||
| 846 | { | 864 | { |
| 847 | if (module) { | 865 | if (module) { |
| 848 | preempt_disable(); | 866 | preempt_disable(); |
| 849 | __this_cpu_dec(module->refptr->count); | 867 | smp_wmb(); /* see comment in module_refcount */ |
| 868 | __this_cpu_inc(module->refptr->decs); | ||
| 850 | 869 | ||
| 851 | trace_module_put(module, _RET_IP_, | 870 | trace_module_put(module, _RET_IP_, |
| 852 | __this_cpu_read(module->refptr->count)); | 871 | __this_cpu_read(module->refptr->decs)); |
| 853 | /* Maybe they're waiting for us to drop reference? */ | 872 | /* Maybe they're waiting for us to drop reference? */ |
| 854 | if (unlikely(!module_is_live(module))) | 873 | if (unlikely(!module_is_live(module))) |
| 855 | wake_up_process(module->waiter); | 874 | wake_up_process(module->waiter); |
