cubelinux: initialise STORE_FILE, the mutex that was never initialised
STORE_FILE is declared `unsafe(uninit) static ... Mutex<Option<StoreFile>> = None` and nothing ever called STORE_FILE.init(). Its sibling SPACE_STARTS is initialised explicitly in CubeStoreModule::init; this one was simply missed. The failure mode is why it hid. A zeroed mutex satisfies the uncontended fast path — the count reads 0, which means "unlocked" — so one writer at a time works and nothing looks wrong. The first CONTENDED lock takes __mutex_lock_slowpath, which splices the task into the mutex's wait list; that list is uninitialised, so its head is NULL and the splice stores through it. A write to address 0 in kernel mode, after which the task returns with interrupts disabled and preemption held — a machine that cannot panic, log, or recover. Found by verify-file-store.sh MODE=race: twelve concurrent puts to a store that is a file on the root filesystem oopsed in cubelinux_store::store_file, while twelve sequential ones passed with exact log accounting (816 bytes of log, generation 13). The same signature is on the box, where the store had several writers and the box froze with no panic despite panic=30.
This commit is contained in:
@@ -4168,6 +4168,23 @@ impl kernel::InPlaceModule for CubeStoreModule {
|
||||
pr_info!("cubelinux: store reader registered at /dev/cubelinux\n");
|
||||
// SAFETY: called exactly once, in the module initializer, before anything can take it.
|
||||
unsafe { SPACE_STARTS.init() };
|
||||
// STORE_FILE needs the same treatment, and it was the one that went without.
|
||||
//
|
||||
// The failure mode is why it hid for so long. A zeroed mutex satisfies the uncontended
|
||||
// fast path — the count reads 0, which means "unlocked" — so one writer at a time works
|
||||
// perfectly and nothing looks wrong. The first *contended* lock takes
|
||||
// __mutex_lock_slowpath, which splices the task into the mutex's wait list; that list is
|
||||
// uninitialised, so its head is NULL and the splice stores through it. A write to address
|
||||
// 0 in kernel mode, after which the task returns with interrupts disabled and
|
||||
// preemption held, which is a machine that cannot panic, log, or recover.
|
||||
//
|
||||
// Found by verify-file-store.sh MODE=race: twelve concurrent puts to a store that is a
|
||||
// file on the root filesystem oopsed in cubelinux_store::store_file, while twelve
|
||||
// sequential ones passed with exact log accounting. The same signature is on the box,
|
||||
// where the store had several writers: a hard freeze with no panic despite panic=30, and
|
||||
// a journal that simply stops.
|
||||
// SAFETY: called exactly once, in the module initializer, before anything can take it.
|
||||
unsafe { STORE_FILE.init() };
|
||||
try_pin_init!(Self {
|
||||
_miscdev <- MiscDeviceRegistration::register(MiscDeviceOptions {
|
||||
name: c_str!("cubelinux"),
|
||||
|
||||
Reference in New Issue
Block a user