From e812356cf0a8927557999d89dfe227d6d91b01e6 Mon Sep 17 00:00:00 2001 From: vasilito Date: Thu, 2 Jul 2026 16:53:19 +0300 Subject: [PATCH] fix: per-CPU idle context race condition + nightly-2026-04-11 pin - Add try_idle_context() to ContextSwitchPercpu (switch.rs) Cross-CPU paths (steal_work, migrate_one_context) use try_idle_context() instead of idle_context() to avoid panic when APs haven't called context::init() yet. Returns Option instead of panicking. - Pin rust-toolchain.toml to nightly-2026-04-11 - Remove build artifacts (kernel, kernel.all, kernel.sym) from git tracking - This fixes the boot panic that occurred during multi-CPU scheduling --- .gitignore | 3 +++ Makefile | 4 ++-- rust-toolchain.toml | 2 +- src/context/switch.rs | 21 +++++++++++++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 7774614018..d11c3bd0f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ target /config.toml .gitlab-ci-local/ +kernel +kernel.all +kernel.sym diff --git a/Makefile b/Makefile index c4807317d8..5d7fc84e56 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,8 @@ TARGET_SPEC=$(RUST_TARGET_PATH)/$(ARCH)-unknown-kernel.json KERNEL_CARGO_FEATURES?= $(BUILD)/kernel.all: $(LD_SCRIPT) $(LOCKFILE) $(MANIFEST) $(TARGET_SPEC) $(shell find $(SOURCE) -name "*.rs" -type f) - cd $(SOURCE) && RUSTUP_TOOLCHAIN=nightly-2025-10-03 cargo rustc \ - -Z build-std=core,alloc -Zbuild-std-features=compiler-builtins-mem \ + cd $(SOURCE) && RUSTUP_TOOLCHAIN=nightly-2026-04-11 RUSTFLAGS="-Zunstable-options" cargo rustc \ + -Z json-target-spec -Z build-std=core,alloc -Zbuild-std-features=compiler-builtins-mem \ --bin kernel \ --manifest-path "$(MANIFEST)" \ --target "$(TARGET_SPEC)" \ diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 42f22f6190..3a5e6c3992 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-10-03" +channel = "nightly-2026-04-11" components = ["rust-src"] diff --git a/src/context/switch.rs b/src/context/switch.rs index 09d7e550c4..8f963ec512 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -399,7 +399,9 @@ fn steal_work( continue; }; - let victim_idle = victim.switch_internals.idle_context(); + let Some(victim_idle) = victim.switch_internals.try_idle_context() else { + continue; + }; let mut victim_lock = SchedQueuesLock::new(&victim.sched); let victim_queues = unsafe { victim_lock.queues_mut() }; @@ -469,7 +471,9 @@ fn migrate_one_context( return false; }; - let source_idle = source.switch_internals.idle_context(); + let Some(source_idle) = source.switch_internals.try_idle_context() else { + return false; + }; let moved = { let mut source_lock = SchedQueuesLock::new(&source.sched); let source_queues = unsafe { source_lock.queues_mut() }; @@ -1174,4 +1178,17 @@ impl ContextSwitchPercpu { .expect("no idle context present"), ) } + + /// Retrieves the current idle context if it has been initialized. + /// + /// This is the fallible variant of [`idle_context`], intended for + /// cross-CPU paths (`steal_work`, `migrate_one_context`) that may + /// access a PercpuBlock whose `context::init()` has not run yet + /// during AP bring-up. + /// + /// # Returns + /// `Some(Arc)` if the idle context is set, `None` otherwise. + pub fn try_idle_context(&self) -> Option> { + self.idle_ctxt.borrow().as_ref().map(Arc::clone) + } }