]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
trace, ring-buffer: Fix CPU hotplug callback registration
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Mon, 10 Mar 2014 20:41:56 +0000 (02:11 +0530)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 20 Mar 2014 12:43:48 +0000 (13:43 +0100)
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 <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
kernel/trace/ring_buffer.c

index fc4da2d97f9b6e280b2e29a525e478958cb495d4..c634868c2921ca39837c3a36773c36fa4a3273d5 100644 (file)
@@ -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);