Skip to content

Commit e430d80

Browse files
lrq-maxKAGA-KOKO
authored andcommitted
timer: Read jiffies once when forwarding base clk
The timer delayed for more than 3 seconds warning was triggered during testing. Workqueue: events_unbound sched_tick_remote RIP: 0010:sched_tick_remote+0xee/0x100 ... Call Trace: process_one_work+0x18c/0x3a0 worker_thread+0x30/0x380 kthread+0x113/0x130 ret_from_fork+0x22/0x40 The reason is that the code in collect_expired_timers() uses jiffies unprotected: if (next_event > jiffies) base->clk = jiffies; As the compiler is allowed to reload the value base->clk can advance between the check and the store and in the worst case advance farther than next event. That causes the timer expiry to be delayed until the wheel pointer wraps around. Convert the code to use READ_ONCE() Fixes: 2369683 ("timers: Optimize collect_expired_timers() for NOHZ") Signed-off-by: Li RongQing <[email protected]> Signed-off-by: Liang ZhiCheng <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 7f2444d commit e430d80

File tree

1 file changed

+5
-3
lines changed

1 file changed

+5
-3
lines changed

kernel/time/timer.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,24 +1678,26 @@ void timer_clear_idle(void)
16781678
static int collect_expired_timers(struct timer_base *base,
16791679
struct hlist_head *heads)
16801680
{
1681+
unsigned long now = READ_ONCE(jiffies);
1682+
16811683
/*
16821684
* NOHZ optimization. After a long idle sleep we need to forward the
16831685
* base to current jiffies. Avoid a loop by searching the bitfield for
16841686
* the next expiring timer.
16851687
*/
1686-
if ((long)(jiffies - base->clk) > 2) {
1688+
if ((long)(now - base->clk) > 2) {
16871689
unsigned long next = __next_timer_interrupt(base);
16881690

16891691
/*
16901692
* If the next timer is ahead of time forward to current
16911693
* jiffies, otherwise forward to the next expiry time:
16921694
*/
1693-
if (time_after(next, jiffies)) {
1695+
if (time_after(next, now)) {
16941696
/*
16951697
* The call site will increment base->clk and then
16961698
* terminate the expiry loop immediately.
16971699
*/
1698-
base->clk = jiffies;
1700+
base->clk = now;
16991701
return 0;
17001702
}
17011703
base->clk = next;

0 commit comments

Comments
 (0)