Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+16 -5
+16 -5
kernel/time/timer.c
··· 521 521 * Force expire obscene large timeouts to expire at the 522 522 * capacity limit of the wheel. 523 523 */ 524 - if (expires >= WHEEL_TIMEOUT_CUTOFF) 525 - expires = WHEEL_TIMEOUT_MAX; 524 + if (delta >= WHEEL_TIMEOUT_CUTOFF) 525 + expires = clk + WHEEL_TIMEOUT_MAX; 526 526 527 527 idx = calc_index(expires, LVL_DEPTH - 1); 528 528 } ··· 584 584 * Set the next expiry time and kick the CPU so it can reevaluate the 585 585 * wheel: 586 586 */ 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 + } 588 596 wake_up_nohz_cpu(base->cpu); 589 597 } 590 598 ··· 904 896 * If the next expiry value is > jiffies, then we fast forward to 905 897 * jiffies otherwise we forward to the next expiry value. 906 898 */ 907 - if (time_after(base->next_expiry, jnow)) 899 + if (time_after(base->next_expiry, jnow)) { 908 900 base->clk = jnow; 909 - else 901 + } else { 902 + if (WARN_ON_ONCE(time_before(base->next_expiry, base->clk))) 903 + return; 910 904 base->clk = base->next_expiry; 905 + } 911 906 #endif 912 907 } 913 908