fix(rcu): move context trackers out of lazy state (#2223)

RcuState embedded the full per-CPU context tracker array. The spin::Once lazy initialization path consequently reserved about 17 KiB of kernel stack even after initialization, which could exhaust a 32 KiB task stack when reached through IRQ and softirq wakeup paths.

Build the tracker array directly in heap storage and retain it as a fixed boxed slice. This preserves tracker indexing, alignment, lifetime, synchronization, and hotplug semantics while removing the CPU-count-sized object from the lazy state value.

Validated with a release kernel build, RCU PR1/PR2/PR3/PR5 selftests, three cold-cache apt update runs, one cached update, and a 200-process execution stress run.

Signed-off-by: longjin <longjin@dragonos.org>
This commit is contained in:
LoGin
2026-08-30 10:23:02 +08:00
committed by GitHub
parent c2ba5d209e
commit b6096d7bcc
+7 -5
View File
@@ -423,7 +423,7 @@ struct RcuState {
worker_started: AtomicBool,
worker_should_stop: AtomicBool,
gp_active: AtomicBool,
contexts: [RcuContextTracker; PerCpu::MAX_CPU_NUM as usize],
contexts: Box<[RcuContextTracker]>,
cpu_callbacks: Box<[RcuCpuCallbacks]>,
inner: SpinLock<RcuStateInner>,
callback_ownership: SpinLock<()>,
@@ -440,9 +440,11 @@ struct RcuState {
impl RcuState {
fn new() -> Self {
// Construct the cache-line-aligned per-CPU records directly in heap
// storage. Materializing the complete array in this function's stack
// frame can exhaust the BSP's fixed 32-KiB boot stack.
// Construct both per-CPU arrays directly in heap storage. Embedding
// contexts in RcuState makes lazy initialization reserve a large stack
// frame even on the already-initialized fast path.
let mut contexts = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
contexts.resize_with(PerCpu::MAX_CPU_NUM as usize, RcuContextTracker::new);
let mut cpu_callbacks = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
cpu_callbacks.resize_with(PerCpu::MAX_CPU_NUM as usize, RcuCpuCallbacks::new);
@@ -452,7 +454,7 @@ impl RcuState {
worker_started: AtomicBool::new(false),
worker_should_stop: AtomicBool::new(false),
gp_active: AtomicBool::new(false),
contexts: [const { RcuContextTracker::new() }; PerCpu::MAX_CPU_NUM as usize],
contexts: contexts.into_boxed_slice(),
cpu_callbacks: cpu_callbacks.into_boxed_slice(),
inner: SpinLock::new(RcuStateInner::new()),
callback_ownership: SpinLock::new(()),