From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751062AbdL2WuF (ORCPT ); Fri, 29 Dec 2017 17:50:05 -0500 Received: from terminus.zytor.com ([65.50.211.136]:35607 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750982AbdL2WuC (ORCPT ); Fri, 29 Dec 2017 17:50:02 -0500 Date: Fri, 29 Dec 2017 14:46:40 -0800 From: tip-bot for Thomas Gleixner Message-ID: Cc: hpa@zytor.com, bigeasy@linutronix.de, mingo@kernel.org, bigeasy@linutronix.d, peterz@infradead.org, paulmck@linux.vnet.ibm.com, fweisbec@gmail.com, tglx@linutronix.de, linux-kernel@vger.kernel.org, anna-maria@linutronix.de Reply-To: tglx@linutronix.de, linux-kernel@vger.kernel.org, anna-maria@linutronix.de, hpa@zytor.com, bigeasy@linutronix.de, paulmck@linux.vnet.ibm.com, bigeasy@linutronix.d, mingo@kernel.org, peterz@infradead.org, fweisbec@gmail.com In-Reply-To: References: To: linux-tip-commits@vger.kernel.org Subject: [tip:timers/urgent] nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick() Git-Commit-ID: 5d62c183f9e9df1deeea0906d099a94e8a43047a X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 5d62c183f9e9df1deeea0906d099a94e8a43047a Gitweb: https://git.kernel.org/tip/5d62c183f9e9df1deeea0906d099a94e8a43047a Author: Thomas Gleixner AuthorDate: Fri, 22 Dec 2017 15:51:13 +0100 Committer: Thomas Gleixner CommitDate: Fri, 29 Dec 2017 23:13:10 +0100 nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick() 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 Signed-off-by: Thomas Gleixner Acked-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul McKenney Cc: Anna-Maria Gleixner Cc: Sebastian Siewior Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1712272156050.2431@nanos --- kernel/time/tick-sched.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 77555fa..f7cc7ab 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -650,6 +650,11 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) ts->next_tick = 0; } +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) { @@ -666,8 +671,18 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, } while (read_seqretry(&jiffies_lock, seq)); ts->last_jiffies = basejiff; - if (rcu_needs_cpu(basemono, &next_rcu) || - arch_needs_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(basemono, &next_rcu) || arch_needs_cpu() || + irq_work_needs_cpu() || local_timer_softirq_pending()) { next_tick = basemono + TICK_NSEC; } else { /*