Skip to content

Commit 66e4b63

Browse files
committed
Merge tag 'timers-urgent-2020-07-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into master
Pull timer fixes from Thomas Gleixner: "Two fixes for the timer wheel: - A timer which is already expired at enqueue time can set the base->next_expiry value backwards. As a consequence base->clk can be set back as well. This can lead to timers expiring early. Add a sanity check to prevent this. - When a timer is queued with an expiry time beyond the wheel capacity then it should be queued in the bucket of the last wheel level which is expiring last. The code adjusted the expiry time to the maximum wheel capacity, which is only correct when the wheel clock is 0. Aside of that the check whether the delta is larger than wheel capacity does not check the delta, it checks the expiry value itself. As a result timers can expire at random. Fix this by checking the right variable and adjust expiry time so it becomes base->clock plus capacity which places it into the outmost bucket in the last wheel level" * tag 'timers-urgent-2020-07-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: timer: Fix wheel index calculation on last level timer: Prevent base->clk from moving backward
2 parents 43768f7 + e2a71bd commit 66e4b63

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

kernel/time/timer.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,8 @@ static int calc_wheel_index(unsigned long expires, unsigned long clk)
521521
* Force expire obscene large timeouts to expire at the
522522
* capacity limit of the wheel.
523523
*/
524-
if (expires >= WHEEL_TIMEOUT_CUTOFF)
525-
expires = WHEEL_TIMEOUT_MAX;
524+
if (delta >= WHEEL_TIMEOUT_CUTOFF)
525+
expires = clk + WHEEL_TIMEOUT_MAX;
526526

527527
idx = calc_index(expires, LVL_DEPTH - 1);
528528
}
@@ -584,7 +584,15 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
584584
* Set the next expiry time and kick the CPU so it can reevaluate the
585585
* wheel:
586586
*/
587-
base->next_expiry = timer->expires;
587+
if (time_before(timer->expires, base->clk)) {
588+
/*
589+
* Prevent from forward_timer_base() moving the base->clk
590+
* backward
591+
*/
592+
base->next_expiry = base->clk;
593+
} else {
594+
base->next_expiry = timer->expires;
595+
}
588596
wake_up_nohz_cpu(base->cpu);
589597
}
590598

@@ -896,10 +904,13 @@ static inline void forward_timer_base(struct timer_base *base)
896904
* If the next expiry value is > jiffies, then we fast forward to
897905
* jiffies otherwise we forward to the next expiry value.
898906
*/
899-
if (time_after(base->next_expiry, jnow))
907+
if (time_after(base->next_expiry, jnow)) {
900908
base->clk = jnow;
901-
else
909+
} else {
910+
if (WARN_ON_ONCE(time_before(base->next_expiry, base->clk)))
911+
return;
902912
base->clk = base->next_expiry;
913+
}
903914
#endif
904915
}
905916

0 commit comments

Comments
 (0)