Merge branch 'linus' into smp/core
[sfrench/cifs-2.6.git] / kernel / smp.c
index 822fabb7e3e1580a979f7c65ea3dfdb26b1e86c6..8c714583786b701d42627ccddb9c06462b757d5d 100644 (file)
@@ -46,6 +46,8 @@ static DEFINE_PER_CPU_ALIGNED(struct call_function_data, cfd_data);
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct llist_head, call_single_queue);
 
+static DEFINE_PER_CPU(atomic_t, trigger_backtrace) = ATOMIC_INIT(1);
+
 static void __flush_smp_call_function_queue(bool warn_cpu_offline);
 
 int smpcfd_prepare_cpu(unsigned int cpu)
@@ -253,13 +255,15 @@ static bool csd_lock_wait_toolong(call_single_data_t *csd, u64 ts0, u64 *ts1, in
                         *bug_id, !cpu_cur_csd ? "unresponsive" : "handling this request");
        }
        if (cpu >= 0) {
-               dump_cpu_task(cpu);
+               if (atomic_cmpxchg_acquire(&per_cpu(trigger_backtrace, cpu), 1, 0))
+                       dump_cpu_task(cpu);
                if (!cpu_cur_csd) {
                        pr_alert("csd: Re-sending CSD lock (#%d) IPI from CPU#%02d to CPU#%02d\n", *bug_id, raw_smp_processor_id(), cpu);
                        arch_send_call_function_single_ipi(cpu);
                }
        }
-       dump_stack();
+       if (firsttime)
+               dump_stack();
        *ts1 = ts2;
 
        return false;
@@ -433,9 +437,14 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
        struct llist_node *entry, *prev;
        struct llist_head *head;
        static bool warned;
+       atomic_t *tbt;
 
        lockdep_assert_irqs_disabled();
 
+       /* Allow waiters to send backtrace NMI from here onwards */
+       tbt = this_cpu_ptr(&trigger_backtrace);
+       atomic_set_release(tbt, 1);
+
        head = this_cpu_ptr(&call_single_queue);
        entry = llist_del_all(head);
        entry = llist_reverse_order(entry);