Skip to content

Commit

Permalink
[PATCH] dynticks: fix hrtimer rounding error in next_timer_interrupt
Browse files Browse the repository at this point in the history
The rework of next_timer_interrupt() fixed the timer wheel bugs, but
invented a rounding error versus the next hrtimer event. This is caused
by the conversion of the hrtimer internal representation to relative
jiffies.

This causes bug #8100:
http://bugzilla.kernel.org/show_bug.cgi?id=8100

next_timer_interrupt() returns "now" in such a case and causes the code
in tick_nohz_stop_sched_tick() to trigger the timer softirq, which is
bogus as no timer is due for expiry. This results in an endless context
switching between idle and ksoftirqd until a timer is due for expiry.

Modify the hrtimer evaluation so that, it returns now + 1, when the
conversion results in a delta < 1 jiffie.

It's confirmed to resolve bug #8100

Reported-by: Emil Karlson <jkarlson@cc.hut.fi>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Thomas Gleixner authored and Linus Torvalds committed Mar 25, 2007
1 parent 317ec6c commit 9501b6c
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions kernel/timer.c
Expand Up @@ -695,15 +695,28 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
{
ktime_t hr_delta = hrtimer_get_next_event();
struct timespec tsdelta;
unsigned long delta;

if (hr_delta.tv64 == KTIME_MAX)
return expires;

if (hr_delta.tv64 <= TICK_NSEC)
return now;
/*
* Expired timer available, let it expire in the next tick
*/
if (hr_delta.tv64 <= 0)
return now + 1;

tsdelta = ktime_to_timespec(hr_delta);
now += timespec_to_jiffies(&tsdelta);
delta = timespec_to_jiffies(&tsdelta);
/*
* Take rounding errors in to account and make sure, that it
* expires in the next tick. Otherwise we go into an endless
* ping pong due to tick_nohz_stop_sched_tick() retriggering
* the timer softirq
*/
if (delta < 1)
delta = 1;
now += delta;
if (time_before(now, expires))
return now;
return expires;
Expand Down

0 comments on commit 9501b6c

Please sign in to comment.