summaryrefslogtreecommitdiffstats
path: root/mm/zsmalloc.c
diff options
context:
space:
mode:
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>2014-03-10 16:39:59 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-20 08:43:45 -0400
commitf0e71fcd0fa6f3f5495cd9ad3f1e4acd94446a55 (patch)
treeef5dd3d4f22e32d9c750f93aa06e90c90e86d594 /mm/zsmalloc.c
parentcd45ae38035d1b7f98dd92429b59bbc8ba9443e9 (diff)
zsmalloc: Fix CPU hotplug callback registration
Subsystems that want to register CPU hotplug callbacks, as well as perform initialization for the CPUs that are already online, often do it as shown below: get_online_cpus(); for_each_online_cpu(cpu) init_cpu(cpu); register_cpu_notifier(&foobar_cpu_notifier); put_online_cpus(); This is wrong, since it is prone to ABBA deadlocks involving the cpu_add_remove_lock and the cpu_hotplug.lock (when running concurrently with CPU hotplug operations). Instead, the correct and race-free way of performing the callback registration is: cpu_notifier_register_begin(); for_each_online_cpu(cpu) init_cpu(cpu); /* Note the use of the double underscored version of the API */ __register_cpu_notifier(&foobar_cpu_notifier); cpu_notifier_register_done(); Fix the zsmalloc code by using this latter form of callback registration. Cc: Nitin Gupta <ngupta@vflare.org> Cc: Ingo Molnar <mingo@kernel.org> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'mm/zsmalloc.c')
-rw-r--r--mm/zsmalloc.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index c03ca5e9fe15..36b4591a7a2d 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -814,21 +814,32 @@ static void zs_exit(void)
814{ 814{
815 int cpu; 815 int cpu;
816 816
817 cpu_notifier_register_begin();
818
817 for_each_online_cpu(cpu) 819 for_each_online_cpu(cpu)
818 zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu); 820 zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
819 unregister_cpu_notifier(&zs_cpu_nb); 821 __unregister_cpu_notifier(&zs_cpu_nb);
822
823 cpu_notifier_register_done();
820} 824}
821 825
822static int zs_init(void) 826static int zs_init(void)
823{ 827{
824 int cpu, ret; 828 int cpu, ret;
825 829
826 register_cpu_notifier(&zs_cpu_nb); 830 cpu_notifier_register_begin();
831
832 __register_cpu_notifier(&zs_cpu_nb);
827 for_each_online_cpu(cpu) { 833 for_each_online_cpu(cpu) {
828 ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu); 834 ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
829 if (notifier_to_errno(ret)) 835 if (notifier_to_errno(ret)) {
836 cpu_notifier_register_done();
830 goto fail; 837 goto fail;
838 }
831 } 839 }
840
841 cpu_notifier_register_done();
842
832 return 0; 843 return 0;
833fail: 844fail:
834 zs_exit(); 845 zs_exit();