From: Greg Kroah-Hartman Date: Tue, 1 Mar 2016 07:12:40 +0000 (-0800) Subject: 4.4-stable patches X-Git-Tag: v3.10.99~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9c6735ec8c06f489ef58ba85fd122b1e76237d41;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: clocksource-drivers-vt8500-increase-the-minimum-delta.patch genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch --- 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 index 00000000000..0881113a4a9 --- /dev/null +++ b/queue-4.4/clocksource-drivers-vt8500-increase-the-minimum-delta.patch @@ -0,0 +1,81 @@ +From f9eccf24615672896dc13251410c3f2f33a14f95 Mon Sep 17 00:00:00 2001 +From: Roman Volkov +Date: Fri, 1 Jan 2016 16:24:41 +0300 +Subject: clocksource/drivers/vt8500: Increase the minimum delta + +From: Roman Volkov + +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 +Acked-by: Alexey Charkov +Signed-off-by: Roman Volkov +Signed-off-by: Daniel Lezcano +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..701136137ea --- /dev/null +++ b/queue-4.4/genirq-validate-action-before-dereferencing-it-in-handle_irq_event_percpu.patch @@ -0,0 +1,99 @@ +From 570540d50710ed192e98e2f7f74578c9486b6b05 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Wed, 13 Jan 2016 14:07:25 +0100 +Subject: genirq: Validate action before dereferencing it in handle_irq_event_percpu() + +From: Thomas Gleixner + +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 +Cc: Huang Shijie +Cc: Jiang Liu +Cc: Peter Zijlstra +Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1601131224190.3575@nanos +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + diff --git a/queue-4.4/series b/queue-4.4/series index 4bd9c3dbc74..57b3ac8fa79 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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