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 adjusts 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.
-----BEGIN PGP SIGNATURE-----
-----END PGP SIGNATURE-----
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
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 <email@example.com>
Signed-off-by: Thomas Gleixner <firstname.lastname@example.org>
1 file changed