Skip to content

Commit

Permalink
hrtimer: Unbreak hrtimer_force_reprogram()
Browse files Browse the repository at this point in the history
Since the recent consoliation of reprogramming functions,
hrtimer_force_reprogram() is affected by a check whether the new expiry
time is past the current expiry time.

This breaks the NOHZ logic as that relies on the fact that the tick hrtimer
is moved into the future. That means cpu_base->expires_next becomes stale
and subsequent reprogramming attempts fail as well until the situation is
cleaned up by an hrtimer interrupts.

For some yet unknown reason this leads to a complete stall, so for now
partially revert the offending commit to a known working state. The root
cause for the stall is still investigated and will be fixed in a subsequent
commit.

Fixes: b14bca9 ("hrtimer: Consolidate reprogramming code")
Reported-by: Mike Galbraith <efault@gmx.de>
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Mike Galbraith <efault@gmx.de>
Link: https://lore.kernel.org/r/8735recskh.ffs@tglx
  • Loading branch information
Thomas Gleixner committed Aug 12, 2021
1 parent 9482fd7 commit f80e214
Showing 1 changed file with 20 additions and 20 deletions.
40 changes: 20 additions & 20 deletions kernel/time/hrtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,24 +652,10 @@ static inline int hrtimer_hres_active(void)
return __hrtimer_hres_active(this_cpu_ptr(&hrtimer_bases));
}

static void
__hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal,
struct hrtimer *next_timer, ktime_t expires_next)
static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base,
struct hrtimer *next_timer,
ktime_t expires_next)
{
/*
* If the hrtimer interrupt is running, then it will reevaluate the
* clock bases and reprogram the clock event device.
*/
if (cpu_base->in_hrtirq)
return;

if (expires_next > cpu_base->expires_next)
return;

if (skip_equal && expires_next == cpu_base->expires_next)
return;

cpu_base->next_timer = next_timer;
cpu_base->expires_next = expires_next;

/*
Expand Down Expand Up @@ -707,8 +693,10 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)

expires_next = hrtimer_update_next_event(cpu_base);

__hrtimer_reprogram(cpu_base, skip_equal, cpu_base->next_timer,
expires_next);
if (skip_equal && expires_next == cpu_base->expires_next)
return;

__hrtimer_reprogram(cpu_base, cpu_base->next_timer, expires_next);
}

/* High resolution timer related functions */
Expand Down Expand Up @@ -863,7 +851,19 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
if (base->cpu_base != cpu_base)
return;

__hrtimer_reprogram(cpu_base, true, timer, expires);
if (expires >= cpu_base->expires_next)
return;

/*
* If the hrtimer interrupt is running, then it will reevaluate the
* clock bases and reprogram the clock event device.
*/
if (cpu_base->in_hrtirq)
return;

cpu_base->next_timer = timer;

__hrtimer_reprogram(cpu_base, timer, expires);
}

static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base,
Expand Down

0 comments on commit f80e214

Please sign in to comment.