Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'timers-urgent-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Thomas Gleixner:
"Two regression fixes for the timer and timer migration code:

- Prevent endless timer requeuing which is caused by two CPUs racing
out of idle. This happens when the last CPU goes idle and therefore
has to ensure to expire the pending global timers and some other
CPU come out of idle at the same time and the other CPU wins the
race and expires the global queue. This causes the last CPU to
chase ghost timers forever and reprogramming it's clockevent device
endlessly.

Cure this by re-evaluating the wakeup time unconditionally.

- The split into local (pinned) and global timers in the timer wheel
caused a regression for NOHZ full as it broke the idle tracking of
global timers. On NOHZ full this prevents an self IPI being sent
which in turn causes the timer to be not programmed and not being
expired on time.

Restore the idle tracking for the global timer base so that the
self IPI condition for NOHZ full is working correctly again"

* tag 'timers-urgent-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
timers: Fix removed self-IPI on global timer's enqueue in nohz_full
timers/migration: Fix endless timer requeue after idle interrupts

+20 -3
+11 -1
kernel/time/timer.c
··· 642 642 * the base lock: 643 643 */ 644 644 if (base->is_idle) { 645 - WARN_ON_ONCE(!(timer->flags & TIMER_PINNED)); 645 + WARN_ON_ONCE(!(timer->flags & TIMER_PINNED || 646 + tick_nohz_full_cpu(base->cpu))); 646 647 wake_up_nohz_cpu(base->cpu); 647 648 } 648 649 } ··· 2293 2292 */ 2294 2293 if (!base_local->is_idle && time_after(nextevt, basej + 1)) { 2295 2294 base_local->is_idle = true; 2295 + /* 2296 + * Global timers queued locally while running in a task 2297 + * in nohz_full mode need a self-IPI to kick reprogramming 2298 + * in IRQ tail. 2299 + */ 2300 + if (tick_nohz_full_cpu(base_local->cpu)) 2301 + base_global->is_idle = true; 2296 2302 trace_timer_base_idle(true, base_local->cpu); 2297 2303 } 2298 2304 *idle = base_local->is_idle; ··· 2372 2364 * path. Required for BASE_LOCAL only. 2373 2365 */ 2374 2366 __this_cpu_write(timer_bases[BASE_LOCAL].is_idle, false); 2367 + if (tick_nohz_full_cpu(smp_processor_id())) 2368 + __this_cpu_write(timer_bases[BASE_GLOBAL].is_idle, false); 2375 2369 trace_timer_base_idle(false, smp_processor_id()); 2376 2370 2377 2371 /* Activate without holding the timer_base->lock */
+9 -2
kernel/time/timer_migration.c
··· 1038 1038 * in tmigr_handle_remote_up() anyway. Keep this check to speed up the 1039 1039 * return when nothing has to be done. 1040 1040 */ 1041 - if (!tmigr_check_migrator(tmc->tmgroup, tmc->childmask)) 1042 - return; 1041 + if (!tmigr_check_migrator(tmc->tmgroup, tmc->childmask)) { 1042 + /* 1043 + * If this CPU was an idle migrator, make sure to clear its wakeup 1044 + * value so it won't chase timers that have already expired elsewhere. 1045 + * This avoids endless requeue from tmigr_new_timer(). 1046 + */ 1047 + if (READ_ONCE(tmc->wakeup) == KTIME_MAX) 1048 + return; 1049 + } 1043 1050 1044 1051 data.now = get_jiffies_update(&data.basej); 1045 1052