]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 07:12:40 +0000 (23:12 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Mar 2016 07:12:40 +0000 (23:12 -0800)
added patches:
clocksource-drivers-vt8500-increase-the-minimum-delta.patch
genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch

queue-4.4/clocksource-drivers-vt8500-increase-the-minimum-delta.patch [new file with mode: 0644]
queue-4.4/genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/clocksource-drivers-vt8500-increase-the-minimum-delta.patch b/queue-4.4/clocksource-drivers-vt8500-increase-the-minimum-delta.patch
new file mode 100644 (file)
index 0000000..0881113
--- /dev/null
@@ -0,0 +1,81 @@
+From f9eccf24615672896dc13251410c3f2f33a14f95 Mon Sep 17 00:00:00 2001
+From: Roman Volkov <rvolkov@v1ros.org>
+Date: Fri, 1 Jan 2016 16:24:41 +0300
+Subject: clocksource/drivers/vt8500: Increase the minimum delta
+
+From: Roman Volkov <rvolkov@v1ros.org>
+
+commit f9eccf24615672896dc13251410c3f2f33a14f95 upstream.
+
+The vt8500 clocksource driver declares itself as capable to handle the
+minimum delay of 4 cycles by passing the value into
+clockevents_config_and_register(). The vt8500_timer_set_next_event()
+requires the passed cycles value to be at least 16. The impact is that
+userspace hangs in nanosleep() calls with small delay intervals.
+
+This problem is reproducible in Linux 4.2 starting from:
+c6eb3f70d448 ('hrtimer: Get rid of hrtimer softirq')
+
+From Russell King, more detailed explanation:
+
+"It's a speciality of the StrongARM/PXA hardware. It takes a certain
+number of OSCR cycles for the value written to hit the compare registers.
+So, if a very small delta is written (eg, the compare register is written
+with a value of OSCR + 1), the OSCR will have incremented past this value
+before it hits the underlying hardware. The result is, that you end up
+waiting a very long time for the OSCR to wrap before the event fires.
+
+So, we introduce a check in set_next_event() to detect this and return
+-ETIME if the calculated delta is too small, which causes the generic
+clockevents code to retry after adding the min_delta specified in
+clockevents_config_and_register() to the current time value.
+
+min_delta must be sufficient that we don't re-trip the -ETIME check - if
+we do, we will return -ETIME, forward the next event time, try to set it,
+return -ETIME again, and basically lock the system up. So, min_delta
+must be larger than the check inside set_next_event(). A factor of two
+was chosen to ensure that this situation would never occur.
+
+The PXA code worked on PXA systems for years, and I'd suggest no one
+changes this mechanism without access to a wide range of PXA systems,
+otherwise they're risking breakage."
+
+Cc: Russell King <linux@arm.linux.org.uk>
+Acked-by: Alexey Charkov <alchark@gmail.com>
+Signed-off-by: Roman Volkov <rvolkov@v1ros.org>
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/clocksource/vt8500_timer.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/clocksource/vt8500_timer.c
++++ b/drivers/clocksource/vt8500_timer.c
+@@ -50,6 +50,8 @@
+ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
++#define MIN_OSCR_DELTA                16
++
+ static void __iomem *regbase;
+ static cycle_t vt8500_timer_read(struct clocksource *cs)
+@@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(u
+               cpu_relax();
+       writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
+-      if ((signed)(alarm - clocksource.read(&clocksource)) <= 16)
++      if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA)
+               return -ETIME;
+       writel(1, regbase + TIMER_IER_VAL);
+@@ -151,7 +153,7 @@ static void __init vt8500_timer_init(str
+               pr_err("%s: setup_irq failed for %s\n", __func__,
+                                                       clockevent.name);
+       clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
+-                                      4, 0xf0000000);
++                                      MIN_OSCR_DELTA * 2, 0xf0000000);
+ }
+ CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
diff --git a/queue-4.4/genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch b/queue-4.4/genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch
new file mode 100644 (file)
index 0000000..7011361
--- /dev/null
@@ -0,0 +1,99 @@
+From 570540d50710ed192e98e2f7f74578c9486b6b05 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Wed, 13 Jan 2016 14:07:25 +0100
+Subject: genirq: Validate action before dereferencing it in handle_irq_event_percpu()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 570540d50710ed192e98e2f7f74578c9486b6b05 upstream.
+
+commit 71f64340fc0e changed the handling of irq_desc->action from
+
+CPU 0                   CPU 1
+free_irq()              lock(desc)
+  lock(desc)            handle_edge_irq()
+                        if (desc->action) {
+                          handle_irq_event()
+                            action = desc->action
+                            unlock(desc)
+  desc->action = NULL       handle_irq_event_percpu(desc, action)
+                              action->xxx
+to
+
+CPU 0                   CPU 1
+free_irq()              lock(desc)
+  lock(desc)            handle_edge_irq()
+                        if (desc->action) {
+                          handle_irq_event()
+                            unlock(desc)
+  desc->action = NULL       handle_irq_event_percpu(desc, action)
+                              action = desc->action
+                              action->xxx
+
+So if free_irq manages to set the action to NULL between the unlock and before
+the readout, we happily dereference a null pointer.
+
+We could simply revert 71f64340fc0e, but we want to preserve the better code
+generation. A simple solution is to change the action loop from a do {} while
+to a while {} loop.
+
+This is safe because we either see a valid desc->action or NULL. If the action
+is about to be removed it is still valid as free_irq() is blocked on
+synchronize_irq().
+
+CPU 0                   CPU 1
+free_irq()              lock(desc)
+  lock(desc)            handle_edge_irq()
+                          handle_irq_event(desc)
+                            set(INPROGRESS)
+                            unlock(desc)
+                            handle_irq_event_percpu(desc)
+                            action = desc->action
+  desc->action = NULL           while (action) {
+                                  action->xxx
+                                  ...
+                                  action = action->next;
+  sychronize_irq()
+    while(INPROGRESS);      lock(desc)
+                            clr(INPROGRESS)
+free(action)
+
+That's basically the same mechanism as we have for shared
+interrupts. action->next can become NULL while handle_irq_event_percpu()
+runs. Either it sees the action or NULL. It does not matter, because action
+itself cannot go away before the interrupt in progress flag has been cleared.
+
+Fixes: commit 71f64340fc0e "genirq: Remove the second parameter from handle_irq_event_percpu()"
+Reported-by: zyjzyj2000@gmail.com
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Huang Shijie <shijie.huang@arm.com>
+Cc: Jiang Liu <jiang.liu@linux.intel.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1601131224190.3575@nanos
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/irq/handle.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/kernel/irq/handle.c
++++ b/kernel/irq/handle.c
+@@ -138,7 +138,8 @@ irqreturn_t handle_irq_event_percpu(stru
+       unsigned int flags = 0, irq = desc->irq_data.irq;
+       struct irqaction *action = desc->action;
+-      do {
++      /* action might have become NULL since we dropped the lock */
++      while (action) {
+               irqreturn_t res;
+               trace_irq_handler_entry(irq, action);
+@@ -173,7 +174,7 @@ irqreturn_t handle_irq_event_percpu(stru
+               retval |= res;
+               action = action->next;
+-      } while (action);
++      }
+       add_interrupt_randomness(irq, flags);
index 4bd9c3dbc7434e8cd603bba61df524925f9dbb1c..57b3ac8fa7963223a923b81eb5217f959ad636e1 100644 (file)
@@ -80,3 +80,5 @@ drm-i915-shut-up-gen8-sde-irq-dmesg-noise.patch
 ocfs2-unlock-inode-if-deleting-inode-from-orphan-fails.patch
 mm-thp-fix-smp-race-condition-between-thp-page-fault-and-madv_dontneed.patch
 mm-numa-quickly-fail-allocations-for-numa-balancing-on-full-nodes.patch
+genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch
+clocksource-drivers-vt8500-increase-the-minimum-delta.patch