Skip to content

Commit 1f71add

Browse files
committed
tick/sched: Do not mess with an enqueued hrtimer
Kaike reported that in tests rdma hrtimers occasionaly stopped working. He did great debugging, which provided enough context to decode the problem. CPU 3 CPU 2 idle start sched_timer expires = 712171000000 queue->next = sched_timer start rdmavt timer. expires = 712172915662 lock(baseof(CPU3)) tick_nohz_stop_tick() tick = 716767000000 timerqueue_add(tmr) hrtimer_set_expires(sched_timer, tick); sched_timer->expires = 716767000000 <---- FAIL if (tmr->expires < queue->next->expires) hrtimer_start(sched_timer) queue->next = tmr; lock(baseof(CPU3)) unlock(baseof(CPU3)) timerqueue_remove() timerqueue_add() ts->sched_timer is queued and queue->next is pointing to it, but then ts->sched_timer.expires is modified. This not only corrupts the ordering of the timerqueue RB tree, it also makes CPU2 see the new expiry time of timerqueue->next->expires when checking whether timerqueue->next needs to be updated. So CPU2 sees that the rdma timer is earlier than timerqueue->next and sets the rdma timer as new next. Depending on whether it had also seen the new time at RB tree enqueue, it might have queued the rdma timer at the wrong place and then after removing the sched_timer the RB tree is completely hosed. The problem was introduced with a commit which tried to solve inconsistency between the hrtimer in the tick_sched data and the underlying hardware clockevent. It split out hrtimer_set_expires() to store the new tick time in both the NOHZ and the NOHZ + HIGHRES case, but missed the fact that in the NOHZ + HIGHRES case the hrtimer might still be queued. Use hrtimer_start(timer, tick...) for the NOHZ + HIGHRES case which sets timer->expires after canceling the timer and move the hrtimer_set_expires() invocation into the NOHZ only code path which is not affected as it merily uses the hrtimer as next event storage so code pathes can be shared with the NOHZ + HIGHRES case. Fixes: d4af6d9 ("nohz: Fix spurious warning when hrtimer and clockevent get out of sync") Reported-by: "Wan Kaike" <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Frederic Weisbecker <[email protected]> Cc: "Marciniszyn Mike" <[email protected]> Cc: Anna-Maria Gleixner <[email protected]> Cc: [email protected] Cc: "Dalessandro Dennis" <[email protected]> Cc: "Fleck John" <[email protected]> Cc: [email protected] Cc: Peter Zijlstra <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: "Weiny Ira" <[email protected]> Cc: "[email protected]" Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 6d08b06 commit 1f71add

File tree

1 file changed

+5
-5
lines changed

1 file changed

+5
-5
lines changed

kernel/time/tick-sched.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -804,12 +804,12 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
804804
return;
805805
}
806806

807-
hrtimer_set_expires(&ts->sched_timer, tick);
808-
809-
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
810-
hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED);
811-
else
807+
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
808+
hrtimer_start(&ts->sched_timer, tick, HRTIMER_MODE_ABS_PINNED);
809+
} else {
810+
hrtimer_set_expires(&ts->sched_timer, tick);
812811
tick_program_event(tick, 1);
812+
}
813813
}
814814

815815
static void tick_nohz_retain_tick(struct tick_sched *ts)

0 commit comments

Comments
 (0)