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.

tick: Do not set device to detached state in tick_shutdown()

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

authored by

Bibo Mao and committed by
Thomas Gleixner
fe2a449a 3c3af563

+7 -13
+1 -1
kernel/time/clockevents.c
··· 633 633 raw_spin_lock(&clockevents_lock); 634 634 635 635 tick_broadcast_offline(cpu); 636 - tick_shutdown(cpu); 636 + tick_shutdown(); 637 637 638 638 /* 639 639 * Unregister the clock event devices which were
+5 -11
kernel/time/tick-common.c
··· 411 411 } 412 412 413 413 /* 414 - * Shutdown an event device on a given cpu: 414 + * Shutdown an event device on the outgoing CPU: 415 415 * 416 - * This is called on a life CPU, when a CPU is dead. So we cannot 417 - * access the hardware device itself. 418 - * We just set the mode and remove it from the lists. 416 + * Called by the dying CPU during teardown, with clockevents_lock held 417 + * and interrupts disabled. 419 418 */ 420 - void tick_shutdown(unsigned int cpu) 419 + void tick_shutdown(void) 421 420 { 422 - struct tick_device *td = &per_cpu(tick_cpu_device, cpu); 421 + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); 423 422 struct clock_event_device *dev = td->evtdev; 424 423 425 424 td->mode = TICKDEV_MODE_PERIODIC; 426 425 if (dev) { 427 - /* 428 - * Prevent that the clock events layer tries to call 429 - * the set mode function! 430 - */ 431 - clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED); 432 426 clockevents_exchange_device(dev, NULL); 433 427 dev->event_handler = clockevents_handle_noop; 434 428 td->evtdev = NULL;
+1 -1
kernel/time/tick-internal.h
··· 26 26 extern void tick_handle_periodic(struct clock_event_device *dev); 27 27 extern void tick_check_new_device(struct clock_event_device *dev); 28 28 extern void tick_offline_cpu(unsigned int cpu); 29 - extern void tick_shutdown(unsigned int cpu); 29 + extern void tick_shutdown(void); 30 30 extern void tick_suspend(void); 31 31 extern void tick_resume(void); 32 32 extern bool tick_check_replacement(struct clock_event_device *curdev,