From 9f483e5b2f1263f7fad20bcc5b09d01d2da57f1f Mon Sep 17 00:00:00 2001 From: Chuyi Zhou Date: Thu, 9 Jul 2026 20:29:24 +0800 Subject: [PATCH] smp: Alloc percpu csd data in smpcfd_prepare_cpu() only once smp_call_function_many_cond() uses per-CPU CSD objects when queueing callbacks to remote CPUs, and the wait path later dereferences those CSDs from csd_lock_wait(). Making the wait path preemptible allows the initiating task to be preempted or migrated before it waits for completion. A target CPU can be offlined in that window. If smpcfd_dead_cpu() frees the target CPU's per-CPU CSD storage, csd_lock_wait() can later dereference freed memory. One way to protect the CSD storage is to free it via RCU or after a synchronization step in the CPU offline path, but that would add unnecessary complexity and can delay CPU shutdown. Allocate the per-CPU CSD storage the first time a CPU comes up and keep it allocated when the CPU is offlined. This allows csd_lock_wait() to access the CSD even when the target CPU is offlined after preemption is re-enabled and before the wait is invoked. Signed-off-by: Chuyi Zhou Signed-off-by: Thomas Gleixner Tested-by: Paul E. McKenney Reviewed-by: Sebastian Andrzej Siewior Acked-by: Muchun Song Link: https://patch.msgid.link/20260709122933.4021501-6-zhouchuyi@bytedance.com --- kernel/smp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index 19fdee6bf3eb..e6c1d839c187 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -64,7 +64,14 @@ int smpcfd_prepare_cpu(unsigned int cpu) free_cpumask_var(cfd->cpumask); return -ENOMEM; } - cfd->csd = alloc_percpu(call_single_data_t); + + /* + * Allocate the per-CPU CSD the first time a CPU comes up. It is + * not freed when the CPU is offlined, so csd_lock_wait() can access + * it even when the CPU was offlined after preemption was re-enabled. + */ + if (!cfd->csd) + cfd->csd = alloc_percpu(call_single_data_t); if (!cfd->csd) { free_cpumask_var(cfd->cpumask); free_cpumask_var(cfd->cpumask_ipi); @@ -80,7 +87,6 @@ int smpcfd_dead_cpu(unsigned int cpu) free_cpumask_var(cfd->cpumask); free_cpumask_var(cfd->cpumask_ipi); - free_percpu(cfd->csd); return 0; }