lkml.org 
[lkml]   [2018]   [Feb]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 147/254] nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick()
    3.16.55-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Thomas Gleixner <tglx@linutronix.de>

    commit 5d62c183f9e9df1deeea0906d099a94e8a43047a upstream.

    The conditions in irq_exit() to invoke tick_nohz_irq_exit() which
    subsequently invokes tick_nohz_stop_sched_tick() are:

    if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu))

    If need_resched() is not set, but a timer softirq is pending then this is
    an indication that the softirq code punted and delegated the execution to
    softirqd. need_resched() is not true because the current interrupted task
    takes precedence over softirqd.

    Invoking tick_nohz_irq_exit() in this case can cause an endless loop of
    timer interrupts because the timer wheel contains an expired timer, but
    softirqs are not yet executed. So it returns an immediate expiry request,
    which causes the timer to fire immediately again. Lather, rinse and
    repeat....

    Prevent that by adding a check for a pending timer soft interrupt to the
    conditions in tick_nohz_stop_sched_tick() which avoid calling
    get_next_timer_interrupt(). That keeps the tick sched timer on the tick and
    prevents a repetitive programming of an already expired timer.

    Reported-by: Sebastian Siewior <bigeasy@linutronix.d>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
    Cc: Anna-Maria Gleixner <anna-maria@linutronix.de>
    Cc: Sebastian Siewior <bigeasy@linutronix.de>
    Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1712272156050.2431@nanos
    [bwh: Backported to 3.16: adjust context]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    kernel/time/tick-sched.c | 19 +++++++++++++++++--
    1 file changed, 17 insertions(+), 2 deletions(-)

    --- a/kernel/time/tick-sched.c
    +++ b/kernel/time/tick-sched.c
    @@ -527,6 +527,11 @@ u64 get_cpu_iowait_time_us(int cpu, u64
    }
    EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);

    +static inline bool local_timer_softirq_pending(void)
    +{
    + return local_softirq_pending() & TIMER_SOFTIRQ;
    +}
    +
    static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
    ktime_t now, int cpu)
    {
    @@ -545,8 +550,18 @@ static ktime_t tick_nohz_stop_sched_tick
    last_jiffies = jiffies;
    } while (read_seqretry(&jiffies_lock, seq));

    - if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
    - arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
    + /*
    + * Keep the periodic tick, when RCU, architecture or irq_work
    + * requests it.
    + * Aside of that check whether the local timer softirq is
    + * pending. If so its a bad idea to call get_next_timer_interrupt()
    + * because there is an already expired timer, so it will request
    + * immeditate expiry, which rearms the hardware timer with a
    + * minimal delta which brings us back to this place
    + * immediately. Lather, rinse and repeat...
    + */
    + if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || arch_needs_cpu(cpu) ||
    + irq_work_needs_cpu() || local_timer_softirq_pending()) {
    next_jiffies = last_jiffies + 1;
    delta_jiffies = 1;
    } else {
    \
     
     \ /
      Last update: 2018-02-28 17:01    [W:4.363 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site