]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
hrtimers: Unconditionally update target CPU base after offline timer migration
authorXiongfeng Wang <wangxiongfeng2@huawei.com>
Tue, 5 Aug 2025 08:10:25 +0000 (16:10 +0800)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 9 Sep 2025 12:05:16 +0000 (14:05 +0200)
When testing softirq based hrtimers on an ARM32 board, with high resolution
mode and NOHZ inactive, softirq based hrtimers fail to expire after being
moved away from an offline CPU:

CPU0 CPU1
hrtimer_start(..., HRTIMER_MODE_SOFT);
cpu_down(CPU1) ...
hrtimers_cpu_dying()
  // Migrate timers to CPU0
  smp_call_function_single(CPU0, returgger_next_event);
  retrigger_next_event()
    if (!highres && !nohz)
        return;

As retrigger_next_event() is a NOOP when both high resolution timers and
NOHZ are inactive CPU0's hrtimer_cpu_base::softirq_expires_next is not
updated and the migrated softirq timers never expire unless there is a
softirq based hrtimer queued on CPU0 later.

Fix this by removing the hrtimer_hres_active() and tick_nohz_active() check
in retrigger_next_event(), which enforces a full update of the CPU base.
As this is not a fast path the extra cost does not matter.

[ tglx: Massaged change log ]

Fixes: 5c0930ccaad5 ("hrtimers: Push pending hrtimers away from outgoing CPU earlier")
Co-developed-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250805081025.54235-1-wangxiongfeng2@huawei.com
kernel/time/hrtimer.c

index 30899a8cc52c0a9203ce0216fe47f5f19a7bf6ec..e8c479329282f9a219bd4ecd17067ef3ac51be13 100644 (file)
@@ -787,10 +787,10 @@ static void retrigger_next_event(void *arg)
         * of the next expiring timer is enough. The return from the SMP
         * function call will take care of the reprogramming in case the
         * CPU was in a NOHZ idle sleep.
+        *
+        * In periodic low resolution mode, the next softirq expiration
+        * must also be updated.
         */
-       if (!hrtimer_hres_active(base) && !tick_nohz_active)
-               return;
-
        raw_spin_lock(&base->lock);
        hrtimer_update_base(base);
        if (hrtimer_hres_active(base))
@@ -2295,11 +2295,6 @@ int hrtimers_cpu_dying(unsigned int dying_cpu)
                                     &new_base->clock_base[i]);
        }
 
-       /*
-        * The migration might have changed the first expiring softirq
-        * timer on this CPU. Update it.
-        */
-       __hrtimer_get_next_event(new_base, HRTIMER_ACTIVE_SOFT);
        /* Tell the other CPU to retrigger the next event */
        smp_call_function_single(ncpu, retrigger_next_event, NULL, 0);