[PATCH v2 17/83] block: rnull: add submit queue count config option
From: Andreas Hindborg
Date: Tue Jun 09 2026 - 15:13:20 EST
Allow user space to control the number of submission queues when creating
null block devices.
Signed-off-by: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
---
drivers/block/rnull/configfs.rs | 56 +++++++++++++++++++++++++++++++++--------
drivers/block/rnull/rnull.rs | 56 +++++++++++++++++++++++++++--------------
2 files changed, 83 insertions(+), 29 deletions(-)
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 8daf2ca409ba..0dea92a9079b 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -60,7 +60,10 @@ impl AttributeOperations<0> for Config {
fn show(_this: &Config, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
let mut writer = kernel::str::Formatter::new(page);
- writer.write_str("blocksize,size,rotational,irqmode,completion_nsec,memory_backed\n")?;
+ writer.write_str(
+ "blocksize,size,rotational,irqmode,completion_nsec,memory_backed,\
+ submit_queues\n",
+ )?;
Ok(writer.bytes_written())
}
}
@@ -85,6 +88,7 @@ fn make_group(
irqmode: 4,
completion_nsec: 5,
memory_backed: 6,
+ submit_queues: 7,
],
};
@@ -103,6 +107,7 @@ fn make_group(
completion_time: time::Delta::ZERO,
name: name.try_into()?,
memory_backed: false,
+ submit_queues: 1,
}),
}),
core::iter::empty(),
@@ -168,6 +173,7 @@ struct DeviceConfigInner {
completion_time: time::Delta,
disk: Option<GenDisk<NullBlkDevice>>,
memory_backed: bool,
+ submit_queues: u32,
}
#[vtable]
@@ -191,15 +197,16 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
let mut guard = this.data.lock();
if !guard.powered && power_op {
- guard.disk = Some(NullBlkDevice::new(
- &guard.name,
- guard.block_size,
- guard.rotational,
- guard.capacity_mib,
- guard.irq_mode,
- guard.completion_time,
- guard.memory_backed,
- )?);
+ guard.disk = Some(NullBlkDevice::new(crate::NullBlkOptions {
+ name: &guard.name,
+ block_size: guard.block_size,
+ rotational: guard.rotational,
+ capacity_mib: guard.capacity_mib,
+ irq_mode: guard.irq_mode,
+ completion_time: guard.completion_time,
+ memory_backed: guard.memory_backed,
+ submit_queues: guard.submit_queues,
+ })?);
guard.powered = true;
} else if guard.powered && !power_op {
drop(guard.disk.take());
@@ -232,3 +239,32 @@ fn from_str(s: &str) -> Result<Self> {
}
configfs_simple_bool_field!(DeviceConfig, 6, memory_backed);
+
+#[vtable]
+impl configfs::AttributeOperations<7> for DeviceConfig {
+ type Data = DeviceConfig;
+
+ fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ let mut writer = kernel::str::Formatter::new(page);
+ writer.write_fmt(fmt!("{}\n", this.data.lock().submit_queues))?;
+ Ok(writer.bytes_written())
+ }
+
+ 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(|_| kernel::error::code::EINVAL)?;
+
+ if value == 0 || value > kernel::cpu::num_possible_cpus() {
+ return Err(kernel::error::code::EINVAL);
+ }
+
+ this.data.lock().submit_queues = value;
+ Ok(())
+ }
+}
diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs
index 8e4d2b270bcf..a7c35f33631a 100644
--- a/drivers/block/rnull/rnull.rs
+++ b/drivers/block/rnull/rnull.rs
@@ -78,6 +78,10 @@
default: false,
description: "Create a memory-backed block device.",
},
+ submit_queues: u32 {
+ default: 1,
+ description: "Number of submission queues",
+ },
},
}
@@ -100,15 +104,16 @@ fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
for i in 0..module_parameters::nr_devices.value() {
let name = CString::try_from_fmt(fmt!("rnullb{}", i))?;
- let disk = NullBlkDevice::new(
- &name,
- module_parameters::bs.value(),
- module_parameters::rotational.value(),
- module_parameters::gb.value() * 1024,
- module_parameters::irqmode.value().try_into()?,
- Delta::from_nanos(completion_time),
- module_parameters::memory_backed.value(),
- )?;
+ let disk = NullBlkDevice::new(NullBlkOptions {
+ name: &name,
+ block_size: module_parameters::bs.value(),
+ rotational: module_parameters::rotational.value(),
+ capacity_mib: module_parameters::gb.value() * 1024,
+ irq_mode: module_parameters::irqmode.value().try_into()?,
+ completion_time: Delta::from_nanos(completion_time),
+ memory_backed: module_parameters::memory_backed.value(),
+ submit_queues: module_parameters::submit_queues.value(),
+ })?;
disks.push(disk, GFP_KERNEL)?;
}
@@ -122,25 +127,38 @@ fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
}
}
+struct NullBlkOptions<'a> {
+ name: &'a CStr,
+ block_size: u32,
+ rotational: bool,
+ capacity_mib: u64,
+ irq_mode: IRQMode,
+ completion_time: Delta,
+ memory_backed: bool,
+ submit_queues: u32,
+}
struct NullBlkDevice;
impl NullBlkDevice {
- fn new(
- name: &CStr,
- block_size: u32,
- rotational: bool,
- capacity_mib: u64,
- irq_mode: IRQMode,
- completion_time: Delta,
- memory_backed: bool,
- ) -> Result<GenDisk<Self>> {
+ fn new(options: NullBlkOptions<'_>) -> Result<GenDisk<Self>> {
+ let NullBlkOptions {
+ name,
+ block_size,
+ rotational,
+ capacity_mib,
+ irq_mode,
+ completion_time,
+ memory_backed,
+ submit_queues,
+ } = options;
+
let flags = if memory_backed {
mq::tag_set::Flag::Blocking.into()
} else {
mq::tag_set::Flags::default()
};
- let tagset = Arc::pin_init(TagSet::new(1, 256, 1, flags), GFP_KERNEL)?;
+ let tagset = Arc::pin_init(TagSet::new(submit_queues, 256, 1, flags), GFP_KERNEL)?;
let queue_data = Box::pin_init(
pin_init!(QueueData {
--
2.51.2