]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Aug 2013 17:55:46 +0000 (10:55 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Aug 2013 17:55:46 +0000 (10:55 -0700)
added patches:
xen-smp-initialize-ipi-vectors-before-marking-cpu-online.patch

queue-3.10/series
queue-3.10/xen-smp-initialize-ipi-vectors-before-marking-cpu-online.patch [new file with mode: 0644]

index e347ba8c0989a841100657cbde65ffad3de31e80..dbb31f683f557b7c51bd3f50fd13ac8b7d9e418f 100644 (file)
@@ -33,3 +33,4 @@ tracing-trace_remove_event_call-should-fail-if-call-file-is-in-use.patch
 tracing-kprobes-fail-to-unregister-if-probe-event-files-are-in-use.patch
 tracing-uprobes-fail-to-unregister-if-probe-event-files-are-in-use.patch
 ftrace-check-module-functions-being-traced-on-reload.patch
+xen-smp-initialize-ipi-vectors-before-marking-cpu-online.patch
diff --git a/queue-3.10/xen-smp-initialize-ipi-vectors-before-marking-cpu-online.patch b/queue-3.10/xen-smp-initialize-ipi-vectors-before-marking-cpu-online.patch
new file mode 100644 (file)
index 0000000..7dc9b16
--- /dev/null
@@ -0,0 +1,185 @@
+From fc78d343fa74514f6fd117b5ef4cd27e4ac30236 Mon Sep 17 00:00:00 2001
+From: Chuck Anderson <chuck.anderson@oracle.com>
+Date: Tue, 6 Aug 2013 15:12:19 -0700
+Subject: xen/smp: initialize IPI vectors before marking CPU online
+
+From: Chuck Anderson <chuck.anderson@oracle.com>
+
+commit fc78d343fa74514f6fd117b5ef4cd27e4ac30236 upstream.
+
+An older PVHVM guest (v3.0 based) crashed during vCPU hot-plug with:
+
+       kernel BUG at drivers/xen/events.c:1328!
+
+RCU has detected that a CPU has not entered a quiescent state within the
+grace period.  It needs to send the CPU a reschedule IPI if it is not
+offline.  rcu_implicit_offline_qs() does this check:
+
+       /*
+        * If the CPU is offline, it is in a quiescent state.  We can
+        * trust its state not to change because interrupts are disabled.
+        */
+       if (cpu_is_offline(rdp->cpu)) {
+               rdp->offline_fqs++;
+               return 1;
+       }
+
+       Else the CPU is online.  Send it a reschedule IPI.
+
+The CPU is in the middle of being hot-plugged and has been marked online
+(!cpu_is_offline()).  See start_secondary():
+
+       set_cpu_online(smp_processor_id(), true);
+       ...
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+
+start_secondary() then waits for the CPU bringing up the hot-plugged CPU to
+mark it as active:
+
+       /*
+        * Wait until the cpu which brought this one up marked it
+        * online before enabling interrupts. If we don't do that then
+        * we can end up waking up the softirq thread before this cpu
+        * reached the active state, which makes the scheduler unhappy
+        * and schedule the softirq thread on the wrong cpu. This is
+        * only observable with forced threaded interrupts, but in
+        * theory it could also happen w/o them. It's just way harder
+        * to achieve.
+        */
+       while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
+               cpu_relax();
+
+       /* enable local interrupts */
+       local_irq_enable();
+
+The CPU being hot-plugged will be marked active after it has been fully
+initialized by the CPU managing the hot-plug.  In the Xen PVHVM case
+xen_smp_intr_init() is called to set up the hot-plugged vCPU's
+XEN_RESCHEDULE_VECTOR.
+
+The hot-plugging CPU is marked online, not marked active and does not have
+its IPI vectors set up.  rcu_implicit_offline_qs() sees the hot-plugging
+cpu is !cpu_is_offline() and tries to send it a reschedule IPI:
+This will lead to:
+
+       kernel BUG at drivers/xen/events.c:1328!
+
+       xen_send_IPI_one()
+       xen_smp_send_reschedule()
+       rcu_implicit_offline_qs()
+       rcu_implicit_dynticks_qs()
+       force_qs_rnp()
+       force_quiescent_state()
+       __rcu_process_callbacks()
+       rcu_process_callbacks()
+       __do_softirq()
+       call_softirq()
+       do_softirq()
+       irq_exit()
+       xen_evtchn_do_upcall()
+
+because xen_send_IPI_one() will attempt to use an uninitialized IRQ for
+the XEN_RESCHEDULE_VECTOR.
+
+There is at least one other place that has caused the same crash:
+
+       xen_smp_send_reschedule()
+       wake_up_idle_cpu()
+       add_timer_on()
+       clocksource_watchdog()
+       call_timer_fn()
+       run_timer_softirq()
+       __do_softirq()
+       call_softirq()
+       do_softirq()
+       irq_exit()
+       xen_evtchn_do_upcall()
+       xen_hvm_callback_vector()
+
+clocksource_watchdog() uses cpu_online_mask to pick the next CPU to handle
+a watchdog timer:
+
+       /*
+        * Cycle through CPUs to check if the CPUs stay synchronized
+        * to each other.
+        */
+       next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
+       if (next_cpu >= nr_cpu_ids)
+               next_cpu = cpumask_first(cpu_online_mask);
+       watchdog_timer.expires += WATCHDOG_INTERVAL;
+       add_timer_on(&watchdog_timer, next_cpu);
+
+This resulted in an attempt to send an IPI to a hot-plugging CPU that
+had not initialized its reschedule vector. One option would be to make
+the RCU code check to not check for CPU offline but for CPU active.
+As becoming active is done after a CPU is online (in older kernels).
+
+But Srivatsa pointed out that "the cpu_active vs cpu_online ordering has been
+completely reworked - in the online path, cpu_active is set *before* cpu_online,
+and also, in the cpu offline path, the cpu_active bit is reset in the CPU_DYING
+notification instead of CPU_DOWN_PREPARE." Drilling in this the bring-up
+path: "[brought up CPU].. send out a CPU_STARTING notification, and in response
+to that, the scheduler sets the CPU in the cpu_active_mask. Again, this mask
+is better left to the scheduler alone, since it has the intelligence to use it
+judiciously."
+
+The conclusion was that:
+"
+1. At the IPI sender side:
+
+   It is incorrect to send an IPI to an offline CPU (cpu not present in
+   the cpu_online_mask). There are numerous places where we check this
+   and warn/complain.
+
+2. At the IPI receiver side:
+
+   It is incorrect to let the world know of our presence (by setting
+   ourselves in global bitmasks) until our initialization steps are complete
+   to such an extent that we can handle the consequences (such as
+   receiving interrupts without crashing the sender etc.)
+" (from Srivatsa)
+
+As the native code enables the interrupts at some point we need to be
+able to service them. In other words a CPU must have valid IPI vectors
+if it has been marked online.
+
+It doesn't need to handle the IPI (interrupts may be disabled) but needs
+to have valid IPI vectors because another CPU may find it in cpu_online_mask
+and attempt to send it an IPI.
+
+This patch will change the order of the Xen vCPU bring-up functions so that
+Xen vectors have been set up before start_secondary() is called.
+It also will not continue to bring up a Xen vCPU if xen_smp_intr_init() fails
+to initialize it.
+
+Orabug 13823853
+Signed-off-by Chuck Anderson <chuck.anderson@oracle.com>
+Acked-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Jonghwan Choi <jhbird.choi@samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/xen/smp.c |   11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/xen/smp.c
++++ b/arch/x86/xen/smp.c
+@@ -667,8 +667,15 @@ static void __init xen_hvm_smp_prepare_c
+ static int __cpuinit xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
+ {
+       int rc;
+-      rc = native_cpu_up(cpu, tidle);
+-      WARN_ON (xen_smp_intr_init(cpu));
++      /*
++       * xen_smp_intr_init() needs to run before native_cpu_up()
++       * so that IPI vectors are set up on the booting CPU before
++       * it is marked online in native_cpu_up().
++      */
++      rc = xen_smp_intr_init(cpu);
++      WARN_ON(rc);
++      if (!rc)
++              rc =  native_cpu_up(cpu, tidle);
+       return rc;
+ }