When an expiration delta falls into the last level of the wheel, we want to compare that delta against the maximum possible delay and reduce our delta to fit in if necessary.
However instead of comparing the delta against the maximum, we are comparing the actual expiry against the maximum. Then instead of fixing the delta to fit in, we set the maximum delta as the expiry value.
This can result in various undesired outcomes, the worst possible one being a timer expiring 15 days ahead to fire immediately.
Fixes: 500462a9de65 ("timers: Switch to a non-cascading wheel") Signed-off-by: Frederic Weisbecker frederic@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: Anna-Maria Behnsen anna-maria@linutronix.de Cc: Juri Lelli juri.lelli@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: stable@vger.kernel.org --- kernel/time/timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 9a838d38dbe6..df1ff803acc4 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -521,8 +521,8 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk) * Force expire obscene large timeouts to expire at the * capacity limit of the wheel. */ - if (expires >= WHEEL_TIMEOUT_CUTOFF) - expires = WHEEL_TIMEOUT_MAX; + if (delta >= WHEEL_TIMEOUT_CUTOFF) + expires = clk + WHEEL_TIMEOUT_MAX;
idx = calc_index(expires, LVL_DEPTH - 1); }
The following commit has been merged into the timers/urgent branch of tip:
Commit-ID: e2a71bdea81690b6ef11f4368261ec6f5b6891aa Gitweb: https://git.kernel.org/tip/e2a71bdea81690b6ef11f4368261ec6f5b6891aa Author: Frederic Weisbecker frederic@kernel.org AuthorDate: Fri, 17 Jul 2020 16:05:40 +02:00 Committer: Thomas Gleixner tglx@linutronix.de CommitterDate: Fri, 17 Jul 2020 21:44:05 +02:00
timer: Fix wheel index calculation on last level
When an expiration delta falls into the last level of the wheel, that delta has be compared against the maximum possible delay and reduced to fit in if necessary.
However instead of comparing the delta against the maximum, the code compares the actual expiry against the maximum. Then instead of fixing the delta to fit in, it sets the maximum delta as the expiry value.
This can result in various undesired outcomes, the worst possible one being a timer expiring 15 days ahead to fire immediately.
Fixes: 500462a9de65 ("timers: Switch to a non-cascading wheel") Signed-off-by: Frederic Weisbecker frederic@kernel.org Signed-off-by: Thomas Gleixner tglx@linutronix.de Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20200717140551.29076-2-frederic@kernel.org
--- kernel/time/timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 9a838d3..df1ff80 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -521,8 +521,8 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk) * Force expire obscene large timeouts to expire at the * capacity limit of the wheel. */ - if (expires >= WHEEL_TIMEOUT_CUTOFF) - expires = WHEEL_TIMEOUT_MAX; + if (delta >= WHEEL_TIMEOUT_CUTOFF) + expires = clk + WHEEL_TIMEOUT_MAX;
idx = calc_index(expires, LVL_DEPTH - 1); }
linux-stable-mirror@lists.linaro.org