diff --git a/drivers/cube/cube_syscall.c b/drivers/cube/cube_syscall.c index 20c9b6398..c1a5b1038 100644 --- a/drivers/cube/cube_syscall.c +++ b/drivers/cube/cube_syscall.c @@ -95,6 +95,7 @@ static char store_device_path[256] = "/dev/vda"; static int __init cube_store_setup(char *str) { strscpy(store_device_path, str, sizeof(store_device_path)); + pr_info("cubelinux: cube_store= resolved to %s\n", store_device_path); return 1; } __setup("cube_store=", cube_store_setup); diff --git a/drivers/cube/cubelinux_store.rs b/drivers/cube/cubelinux_store.rs index cdc6ac2c1..5c2ebf020 100644 --- a/drivers/cube/cubelinux_store.rs +++ b/drivers/cube/cubelinux_store.rs @@ -4408,6 +4408,10 @@ pub unsafe extern "C" fn cubelinux_kernel_enum( out_len: *mut u64, out_cursor: *mut u64, ) -> i32 { + if let Err(e) = store_readable() { + pr_warn!("cubelinux: the store is not readable; refusing to answer\n"); + return -(e.to_errno() as i32); + } let mut wanted = [0u8; SPACE_ID_LEN]; // SAFETY: the caller guarantees 32 readable bytes at `space`. unsafe { core::ptr::copy_nonoverlapping(space, wanted.as_mut_ptr(), SPACE_ID_LEN) }; @@ -4690,8 +4694,34 @@ pub unsafe extern "C" fn cubelinux_kernel_flag_scan( /// /// # Safety /// `space_out` must point to 32 writable bytes. +/// Whether the store can be read at all, asked before an operation answers anything. +/// +/// A walk pointed at something that is not a store served invented records — a garbage space, a +/// zero-length value, a cursor that advanced on its own, forever — and a boot that hung instead of +/// saying what was wrong. Probing every branch of `Addressed::open()` showed why the earlier guesses +/// were wrong: it is entered, the file opens, and execution never gets past the control-block read, so +/// neither the packed fallback nor the guard written for it was ever on that path. Whatever answered +/// downstream answered over a device that cannot be read. +/// +/// So the question is asked here, where the answer leaves no room: four bytes at offset zero. +fn store_readable() -> Result<()> { + let file = store_file()?; + let mut head = KVVec::::with_capacity(8, GFP_KERNEL)?; + // The scratch is what `read_exact_at` reads *into*, and it asks for `min(left, scratch.len())` + // bytes — so a scratch with capacity but no length asks for zero bytes, gets zero, and the + // helper correctly reports a short read for every store, good or bad. Length, not capacity. + let mut scratch = KVVec::::with_capacity(4096, GFP_KERNEL)?; + scratch.resize(4096, 0, GFP_KERNEL)?; + read_exact_at(file, 0, IMAGE_MAGIC.len(), &mut head, &mut scratch)?; + Ok(()) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn cubelinux_kernel_spaces(cursor: u64, space_out: *mut u8) -> i32 { + if let Err(e) = store_readable() { + pr_warn!("cubelinux: the store is not readable; refusing to answer\n"); + return -(e.to_errno() as i32); + } match Addressed::open() { Ok(Some(image)) => return unsafe { v3_spaces(image, cursor, space_out) }, Ok(None) => {}