[PATCH] rnull: serialize configfs updates with power changes

From: Jiale Yao

Date: Mon Oct 19 2026 - 06:01:36 EST


From: Jiale Yao <jiale.yao@xxxxxxxxxxx>

The configuration stores check whether the device is powered before
parsing the new value, then take the mutex again to update the field.
A concurrent power-on can complete between these lock acquisitions,
allowing a live device configuration to be changed.

Parse the input before taking the mutex, then check powered and update
the configuration while holding the same lock.

Fixes: d969d504bc13 ("rnull: enable configuration via `configfs`")
Signed-off-by: Jiale Yao <yaojiale02@xxxxxxx>
---
drivers/block/rnull/configfs.rs | 42 ++++++++++++++++++++-------------
1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 32c10c3f4d0f..1808fcacfd55 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -174,15 +174,17 @@ impl configfs::AttributeOperations<1> for DeviceConfig {
}

fn store(this: &DeviceConfig, page: &[u8]) -> Result {
- if this.data.lock().powered {
- return Err(EBUSY);
- }
-
let text = core::str::from_utf8(page)?.trim();
let value = text.parse::<u32>().map_err(|_| EINVAL)?;

GenDiskBuilder::validate_block_size(value)?;
- this.data.lock().block_size = value;
+ let mut guard = this.data.lock();
+
+ if guard.powered {
+ return Err(EBUSY);
+ }
+
+ guard.block_size = value;
Ok(())
}
}
@@ -204,11 +206,14 @@ impl configfs::AttributeOperations<2> for DeviceConfig {
}

fn store(this: &DeviceConfig, page: &[u8]) -> Result {
- if this.data.lock().powered {
+ let value = kstrtobool_bytes(page)?;
+ let mut guard = this.data.lock();
+
+ if guard.powered {
return Err(EBUSY);
}

- this.data.lock().rotational = kstrtobool_bytes(page)?;
+ guard.rotational = value;

Ok(())
}
@@ -225,14 +230,15 @@ impl configfs::AttributeOperations<3> for DeviceConfig {
}

fn store(this: &DeviceConfig, page: &[u8]) -> Result {
- if this.data.lock().powered {
- return Err(EBUSY);
- }
-
let text = core::str::from_utf8(page)?.trim();
let value = text.parse::<u64>().map_err(|_| EINVAL)?;
+ let mut guard = this.data.lock();

- this.data.lock().capacity_mib = value;
+ if guard.powered {
+ return Err(EBUSY);
+ }
+
+ guard.capacity_mib = value;
Ok(())
}
}
@@ -248,14 +254,16 @@ impl configfs::AttributeOperations<4> for DeviceConfig {
}

fn store(this: &DeviceConfig, page: &[u8]) -> Result {
- if this.data.lock().powered {
- return Err(EBUSY);
- }
-
let text = core::str::from_utf8(page)?.trim();
let value = text.parse::<u8>().map_err(|_| EINVAL)?;
+ let value = IRQMode::try_from(value)?;
+ let mut guard = this.data.lock();
+
+ if guard.powered {
+ return Err(EBUSY);
+ }

- this.data.lock().irq_mode = IRQMode::try_from(value)?;
+ guard.irq_mode = value;
Ok(())
}
}
--
2.34.1