[PATCH v2] riscv: smp: set CPU 0 possible in setup_smp()
Paul Sherman
shermanpauldylan at gmail.com
Tue Jul 14 21:51:31 PDT 2026
Vivian, Paul,
Thank you for the precise analysis. You are correct for mainline,
boot_cpu_init() calls set_cpu_possible(0, true) before setup_smp().
The hang was observed on a development tree based on Linux 7.0-rc2
with substantial percpu/SLUB allocator changes layered on top for
large NUMA geometry (4 nodes, 128GB). In that context I instrumented
rcu_init_one() and rcutree_prepare_cpu() via SBI ecall probes
(no JTAG/denugger available on this hardware) and observed:
Za ffffffff81035000 <- per_cpu_ptr(&rcu_data, 0) in rcu_init_one
Zn 0000000000000000 <- mynode was NULL at write time
rdp ffffffff81035000 <- same address at rcutree_prepare_cpu
mynode = NULL <- confirmed NULL dereference
The for_each_possible_cpu loop in rcu_init_one was skipping CPU 0
because cpu_possible_mask had not yet been populated at that point
in my tree's initialization order. The additional allocator changes
may have altered the timing.
I am rebasing onto 7.2-rc3. If the condition cannot be reproduced
there, please feel free to drop the patch.
The probe methodology above uses M-mode SBI ecalls as a poor man's
logic analyzer; happy to share the infrastructure if useful.
Paul Sherman
On Tue, Jul 14, 2026 at 9:01 PM Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>
> On 7/15/26 09:41, Paul Walmsley wrote:
>
> > On Tue, 14 Jul 2026, Paul Sherman wrote:
> >
> >> setup_smp() calls set_cpu_possible() for CPUs 1..nr_cpu_ids-1 but
> >> never for CPU 0 (the boot CPU). x86 handles this via
> >> init_cpu_possible(cpumask_of(0)); RISC-V has no equivalent.
> >>
> >> Without CPU 0 in cpu_possible_mask, rcu_init_one()'s
> >> for_each_possible_cpu() loop skips it, leaving rdp->mynode=NULL.
> >> rcutree_prepare_cpu() then dereferences NULL and hangs.
> >>
> >> Exposed on Sophgo SG2042 (64-hart, 4-NUMA) with Linux 7.2-rc3.
> >>
> >> Fixes: a4166aec1130 ("riscv: Deduplicate code in setup_smp()")
> >> Signed-off-by: Paul Sherman <shermanpauldylan at gmail.com>
> > Thanks, queued for v7.2-rc.
>
> I hope it's not too late to object, but I don't see how this could
> happen. This is what happens in start_kernel():
>
> assembly boot code
> -> start_kernel()
> -> boot_cpu_init();
> -> int cpu = smp_processor_id();
> /* cpu = 0 because INIT_THREAD_INFO(tsk) leaves it out */
>
> /* Mark the boot cpu "present", "online" etc for SMP and UP case */
> set_cpu_online(cpu, true);
> set_cpu_active(cpu, true);
> set_cpu_present(cpu, true);
> set_cpu_possible(cpu, true); /* <---- HERE */
> -> ...
> -> setup_arch(&command_line);
> -> setup_smp()
> -> for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++)
> if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID)
> set_cpu_possible(cpuid, true);
>
> So CPU 0 is already in cpu_possible_mask. This is also what I see by
> adding prints to setup_smp().
>
> * Paul Sherman: How did you reproduce this? Is your boot CPU not cpu 0
> (note: not the same as hart 0)?
>
> Vivian "dramforever" Wang
>
More information about the linux-riscv
mailing list