]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tick: Do not set device to detached state in tick_shutdown()
authorBibo Mao <maobibo@loongson.cn>
Sat, 6 Sep 2025 06:49:51 +0000 (14:49 +0800)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 9 Sep 2025 11:39:00 +0000 (13:39 +0200)
tick_shutdown() sets the state of the clockevent device to detached
first and the invokes clockevents_exchange_device(), which in turn
invokes clockevents_switch_state().

But clockevents_switch_state() returns without invoking the device shutdown
callback as the device is already in detached state. As a consequence the
timer device is not shutdown when a CPU goes offline.

tick_shutdown() does this because it was originally invoked on a online CPU
and not on the outgoing CPU. It therefore could not access the clockevent
device of the already offlined CPU and just set the state.

Since commit 3b1596a21fbf tick_shutdown() is called on the outgoing CPU, so
the hardware device can be accessed.

Remove the state set before calling clockevents_exchange_device(), so that
the subsequent clockevents_switch_state() handles the state transition and
invokes the shutdown callback of the clockevent device.

[ tglx: Massaged change log ]

Fixes: 3b1596a21fbf ("clockevents: Shutdown and unregister current clockevents at CPUHP_AP_TICK_DYING")
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/all/20250906064952.3749122-2-maobibo@loongson.cn
kernel/time/clockevents.c
kernel/time/tick-common.c
kernel/time/tick-internal.h

index f3e831f62906f1635f3d9579cd91eef71f501b93..a59bc75ab7c5b4642a6a9cef2c0b7665ea097c19 100644 (file)
@@ -633,7 +633,7 @@ void tick_offline_cpu(unsigned int cpu)
        raw_spin_lock(&clockevents_lock);
 
        tick_broadcast_offline(cpu);
-       tick_shutdown(cpu);
+       tick_shutdown();
 
        /*
         * Unregister the clock event devices which were
index 9a3859443c042c14d89afcdb344b983232ed36fb..7e33d3f2e889b1a03ad69e7b39e93236c63de8ae 100644 (file)
@@ -411,24 +411,18 @@ int tick_cpu_dying(unsigned int dying_cpu)
 }
 
 /*
- * Shutdown an event device on a given cpu:
+ * Shutdown an event device on the outgoing CPU:
  *
- * This is called on a life CPU, when a CPU is dead. So we cannot
- * access the hardware device itself.
- * We just set the mode and remove it from the lists.
+ * Called by the dying CPU during teardown, with clockevents_lock held
+ * and interrupts disabled.
  */
-void tick_shutdown(unsigned int cpu)
+void tick_shutdown(void)
 {
-       struct tick_device *td = &per_cpu(tick_cpu_device, cpu);
+       struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
        struct clock_event_device *dev = td->evtdev;
 
        td->mode = TICKDEV_MODE_PERIODIC;
        if (dev) {
-               /*
-                * Prevent that the clock events layer tries to call
-                * the set mode function!
-                */
-               clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED);
                clockevents_exchange_device(dev, NULL);
                dev->event_handler = clockevents_handle_noop;
                td->evtdev = NULL;
index faac36de35b9ef43ff25261b4481e782e9070035..4e4f7bbe2a64bc9f49bef1056f16a8efe9032bda 100644 (file)
@@ -26,7 +26,7 @@ extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
 extern void tick_handle_periodic(struct clock_event_device *dev);
 extern void tick_check_new_device(struct clock_event_device *dev);
 extern void tick_offline_cpu(unsigned int cpu);
-extern void tick_shutdown(unsigned int cpu);
+extern void tick_shutdown(void);
 extern void tick_suspend(void);
 extern void tick_resume(void);
 extern bool tick_check_replacement(struct clock_event_device *curdev,