[PATCH v3 36/52] zsmalloc: Fix CPU hotplug callback registration
Srivatsa S. Bhat
srivatsa.bhat at linux.vnet.ibm.com
Tue Mar 11 07:39:59 EST 2014
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: Minchan Kim <minchan at kernel.org>
Cc: Nitin Gupta <ngupta at vflare.org>
Cc: Ingo Molnar <mingo at kernel.org>
Cc: linux-mm at kvack.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat at linux.vnet.ibm.com>
---
mm/zsmalloc.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index c03ca5e..36b4591 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -814,21 +814,32 @@ static void zs_exit(void)
{
int cpu;
+ cpu_notifier_register_begin();
+
for_each_online_cpu(cpu)
zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
- unregister_cpu_notifier(&zs_cpu_nb);
+ __unregister_cpu_notifier(&zs_cpu_nb);
+
+ cpu_notifier_register_done();
}
static int zs_init(void)
{
int cpu, ret;
- register_cpu_notifier(&zs_cpu_nb);
+ cpu_notifier_register_begin();
+
+ __register_cpu_notifier(&zs_cpu_nb);
for_each_online_cpu(cpu) {
ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
- if (notifier_to_errno(ret))
+ if (notifier_to_errno(ret)) {
+ cpu_notifier_register_done();
goto fail;
+ }
}
+
+ cpu_notifier_register_done();
+
return 0;
fail:
zs_exit();
More information about the Linuxppc-dev
mailing list