[PATCH] tick/broadcast: Fix smp_processor_id()-in-preemptible warnings

From: Yu Liao
Date: Wed Jul 31 2024 - 06:22:49 EST


David reports that commit f7d43dd206e7 ("tick/broadcast: Make takeover
of broadcast hrtimer reliable") introduced the following splat with
CONFIG_DEBUG_PREEMPT enabled:

[ 1734.414952] BUG: using smp_processor_id() in preemptible [00000000] code: systemd-sleep/4619
[ 1734.414957] caller is hotplug_cpu__broadcast_tick_pull+0x1c/0xc0
[ 1734.414964] CPU: 0 UID: 0 PID: 4619 Comm: systemd-sleep Tainted: P OE 6.11.0-rc1-linan-4 #292
[ 1734.414968] Tainted: [P]=PROPRIETARY_MODULE, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
[ 1734.414969] Hardware name: Micro-Star International Co., Ltd. MS-7B89/B450M MORTAR MAX (MS-7B89), BIOS 2.80 06/10/2020
[ 1734.414970] Call Trace:
[ 1734.414974] <TASK>
[ 1734.414978] dump_stack_lvl+0x60/0x80
[ 1734.414982] check_preemption_disabled+0xce/0xe0
[ 1734.414987] hotplug_cpu__broadcast_tick_pull+0x1c/0xc0
[ 1734.414996] takedown_cpu+0x97/0x130
[ 1734.414999] cpuhp_invoke_callback+0xf8/0x450

this_cpu_ptr() calls smp_processor_id() in a preemptible context. Fix
this by moving the this_cpu operation to interrupt disable code segment.

Also, use __this_cpu_read() instead of this_cpu_ptr() to save a few
instructions.

this_cpu_ptr(&tick_cpu_device):
callq 0xffffffff81ef4a30 <debug_smp_processor_id>
mov $0x20b60,%r12
mov %eax,%eax
add -0x7d7cb4e0(,%rax,8),%r12
callq 0xffffffff81ef4a30 <debug_smp_processor_id>
mov %eax,%eax
lock btr %rax,0x23f5fc6(%rip)
mov (%r12),%rax
mov $0x1,%esi
mov 0x18(%rax),%rdi

__this_cpu_read(tick_cpu_device.evtdev):
mov $0xffffffff82742a33,%rdi
callq 0xffffffff81ef4a60 <__this_cpu_preempt_check>
mov %gs:0x7eed2098(%rip),%r12 # 0x20b60 <tick_cpu_device>
callq 0xffffffff81ef4a30 <debug_smp_processor_id>
mov %eax,%eax
lock btr %rax,0x23f5fc8(%rip)
mov 0x18(%r12),%rdi
mov $0x1,%esi

Fixes: f7d43dd206e7 ("tick/broadcast: Make takeover of broadcast hrtimer reliable")
Reported-by: David Wang <00107082@xxxxxxx>
Suggested-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Signed-off-by: Yu Liao <liaoyu15@xxxxxxxxxx>
---
kernel/time/tick-broadcast.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index b4843099a8da..85f7d0017e90 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -1141,7 +1141,6 @@ void tick_broadcast_switch_to_oneshot(void)
#ifdef CONFIG_HOTPLUG_CPU
void hotplug_cpu__broadcast_tick_pull(int deadcpu)
{
- struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
struct clock_event_device *bc;
unsigned long flags;

@@ -1167,8 +1166,10 @@ void hotplug_cpu__broadcast_tick_pull(int deadcpu)
* device to avoid the starvation.
*/
if (tick_check_broadcast_expired()) {
+ struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
+
cpumask_clear_cpu(smp_processor_id(), tick_broadcast_force_mask);
- tick_program_event(td->evtdev->next_event, 1);
+ tick_program_event(dev->next_event, 1);
}

/* This moves the broadcast assignment to this CPU: */
--
2.33.0