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 tracing ring-buffer code by using this latter form of callback
registration.

Cc: Frederic Weisbecker <fweis...@gmail.com>
Cc: Ingo Molnar <mi...@kernel.org>
Acked-by: Steven Rostedt <rost...@goodmis.org>
Signed-off-by: Srivatsa S. Bhat <srivatsa.b...@linux.vnet.ibm.com>
---

 kernel/trace/ring_buffer.c |   19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 294b8a2..0893233 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1301,7 +1301,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long 
size, unsigned flags,
         * In that off case, we need to allocate for all possible cpus.
         */
 #ifdef CONFIG_HOTPLUG_CPU
-       get_online_cpus();
+       cpu_notifier_register_begin();
        cpumask_copy(buffer->cpumask, cpu_online_mask);
 #else
        cpumask_copy(buffer->cpumask, cpu_possible_mask);
@@ -1324,10 +1324,10 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long 
size, unsigned flags,
 #ifdef CONFIG_HOTPLUG_CPU
        buffer->cpu_notify.notifier_call = rb_cpu_notify;
        buffer->cpu_notify.priority = 0;
-       register_cpu_notifier(&buffer->cpu_notify);
+       __register_cpu_notifier(&buffer->cpu_notify);
+       cpu_notifier_register_done();
 #endif
 
-       put_online_cpus();
        mutex_init(&buffer->mutex);
 
        return buffer;
@@ -1341,7 +1341,9 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long 
size, unsigned flags,
 
  fail_free_cpumask:
        free_cpumask_var(buffer->cpumask);
-       put_online_cpus();
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_notifier_register_done();
+#endif
 
  fail_free_buffer:
        kfree(buffer);
@@ -1358,16 +1360,17 @@ ring_buffer_free(struct ring_buffer *buffer)
 {
        int cpu;
 
-       get_online_cpus();
-
 #ifdef CONFIG_HOTPLUG_CPU
-       unregister_cpu_notifier(&buffer->cpu_notify);
+       cpu_notifier_register_begin();
+       __unregister_cpu_notifier(&buffer->cpu_notify);
 #endif
 
        for_each_buffer_cpu(buffer, cpu)
                rb_free_cpu_buffer(buffer->buffers[cpu]);
 
-       put_online_cpus();
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_notifier_register_done();
+#endif
 
        kfree(buffer->buffers);
        free_cpumask_var(buffer->cpumask);

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to