[PATCH] dynticks: fix hrtimer rounding error in next_timer_interrupt
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>
This commit is contained in:
parent
317ec6cd00
commit
9501b6cf55
1 changed files with 16 additions and 3 deletions
|
@ -695,15 +695,28 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
|
||||||
{
|
{
|
||||||
ktime_t hr_delta = hrtimer_get_next_event();
|
ktime_t hr_delta = hrtimer_get_next_event();
|
||||||
struct timespec tsdelta;
|
struct timespec tsdelta;
|
||||||
|
unsigned long delta;
|
||||||
|
|
||||||
if (hr_delta.tv64 == KTIME_MAX)
|
if (hr_delta.tv64 == KTIME_MAX)
|
||||||
return expires;
|
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);
|
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))
|
if (time_before(now, expires))
|
||||||
return now;
|
return now;
|
||||||
return expires;
|
return expires;
|
||||||
|
|
Loading…
Reference in a new issue