From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751907AbcHIHhe (ORCPT ); Tue, 9 Aug 2016 03:37:34 -0400 Received: from terminus.zytor.com ([198.137.202.10]:33676 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750810AbcHIHha (ORCPT ); Tue, 9 Aug 2016 03:37:30 -0400 Date: Tue, 9 Aug 2016 00:37:18 -0700 From: tip-bot for Chris Metcalf Message-ID: Cc: cmetcalf@mellanox.com, john.stultz@linaro.org, hpa@zytor.com, mingo@kernel.org, tglx@linutronix.de, linux-kernel@vger.kernel.org, cl@linux.com, fweisbec@gmail.com Reply-To: linux-kernel@vger.kernel.org, cl@linux.com, fweisbec@gmail.com, cmetcalf@mellanox.com, john.stultz@linaro.org, hpa@zytor.com, mingo@kernel.org, tglx@linutronix.de In-Reply-To: <1470688147-22287-1-git-send-email-cmetcalf@mellanox.com> References: <1470688147-22287-1-git-send-email-cmetcalf@mellanox.com> To: linux-tip-commits@vger.kernel.org Subject: [tip:timers/urgent] timers: Fix get_next_timer_interrupt() computation Git-Commit-ID: 46c8f0b077a838eb1f6169bb370aab8ed98f7630 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: 46c8f0b077a838eb1f6169bb370aab8ed98f7630 Gitweb: http://git.kernel.org/tip/46c8f0b077a838eb1f6169bb370aab8ed98f7630 Author: Chris Metcalf AuthorDate: Mon, 8 Aug 2016 16:29:07 -0400 Committer: Thomas Gleixner CommitDate: Tue, 9 Aug 2016 09:31:55 +0200 timers: Fix get_next_timer_interrupt() computation The tick_nohz_stop_sched_tick() routine is not properly canceling the sched timer when nothing is pending, because get_next_timer_interrupt() is no longer returning KTIME_MAX in that case. This causes periodic interrupts when none are needed. When determining the next interrupt time, we first use __next_timer_interrupt() to get the first expiring timer in the timer wheel. If no timer is found, we return the base clock value plus NEXT_TIMER_MAX_DELTA to indicate there is no timer in the timer wheel. Back in get_next_timer_interrupt(), we set the "expires" value by converting the timer wheel expiry (in ticks) to a nsec value. But we don't want to do this if the timer wheel expiry value indicates no timer; we want to return KTIME_MAX. Prior to commit 500462a9de65 ("timers: Switch to a non-cascading wheel") we checked base->active_timers to see if any timers were active, and if not, we didn't touch the expiry value and so properly returned KTIME_MAX. Now we don't have active_timers. To fix this, we now just check the timer wheel expiry value to see if it is "now + NEXT_TIMER_MAX_DELTA", and if it is, we don't try to compute a new value based on it, but instead simply let the KTIME_MAX value in expires remain. Fixes: 500462a9de65 "timers: Switch to a non-cascading wheel" Signed-off-by: Chris Metcalf Cc: Frederic Weisbecker Cc: Christoph Lameter Cc: John Stultz Link: http://lkml.kernel.org/r/1470688147-22287-1-git-send-email-cmetcalf@mellanox.com Signed-off-by: Thomas Gleixner --- kernel/time/timer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 555670a..32bf6f7 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1496,6 +1496,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); u64 expires = KTIME_MAX; unsigned long nextevt; + bool is_max_delta; /* * Pretend that there is no timer pending if the cpu is offline. @@ -1506,6 +1507,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) spin_lock(&base->lock); nextevt = __next_timer_interrupt(base); + is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA); base->next_expiry = nextevt; /* * We have a fresh next event. Check whether we can forward the base: @@ -1519,7 +1521,8 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) expires = basem; base->is_idle = false; } else { - expires = basem + (nextevt - basej) * TICK_NSEC; + if (!is_max_delta) + expires = basem + (nextevt - basej) * TICK_NSEC; /* * If we expect to sleep more than a tick, mark the base idle: */