[PATCH 22/79] block: rnull: add no_sched module parameter and configfs attribute

From: Andreas Hindborg

Date: Sun Feb 15 2026 - 18:45:35 EST


Add support for disabling the default IO scheduler by adding:
- no_sched module parameter to control scheduler selection at device
creation.
- no_sched configfs attribute (ID 11) for runtime configuration.
- Use of NO_DEFAULT_SCHEDULER flag when no_sched is enabled.

This allows bypassing the default 'mq-deadline' scheduler and using 'none'
instead, which can improve performance for certain workloads. The flag
selection logic is updated to use compound assignment operators for better
readability.

Signed-off-by: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
---
drivers/block/rnull/configfs.rs | 31 +++++++++++++++++++++++++++++++
drivers/block/rnull/rnull.rs | 25 ++++++++++++++++++-------
2 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 4ec9be440105d..18e32a87673aa 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -95,6 +95,7 @@ fn make_group(
use_per_node_hctx: 8,
home_node: 9,
discard: 10,
+ no_sched:11,
],
};

@@ -116,6 +117,7 @@ fn make_group(
submit_queues: 1,
home_node: bindings::NUMA_NO_NODE,
discard: false,
+ no_sched: false,
}),
}),
core::iter::empty(),
@@ -174,6 +176,7 @@ struct DeviceConfigInner {
submit_queues: u32,
home_node: i32,
discard: bool,
+ no_sched: bool,
}

#[vtable]
@@ -208,6 +211,7 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
submit_queues: guard.submit_queues,
home_node: guard.home_node,
discard: guard.discard,
+ no_sched: guard.no_sched,
})?);
guard.powered = true;
} else if guard.powered && !power_op {
@@ -336,3 +340,30 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
Ok(())
})
);
+
+#[vtable]
+impl configfs::AttributeOperations<11> for DeviceConfig {
+ type Data = DeviceConfig;
+
+ fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
+ let mut writer = kernel::str::Formatter::new(page);
+
+ if this.data.lock().no_sched {
+ writer.write_str("1\n")?;
+ } else {
+ writer.write_str("0\n")?;
+ }
+
+ Ok(writer.bytes_written())
+ }
+
+ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
+ if this.data.lock().powered {
+ return Err(EBUSY);
+ }
+
+ this.data.lock().no_sched = kstrtobool_bytes(page)?;
+
+ Ok(())
+ }
+}
diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs
index d1fb5fbc0c0be..9a301b06fc5e0 100644
--- a/drivers/block/rnull/rnull.rs
+++ b/drivers/block/rnull/rnull.rs
@@ -29,8 +29,8 @@
new_mutex,
new_xarray,
page::{
- SafePage, //
- PAGE_SIZE,
+ SafePage,
+ PAGE_SIZE, //
},
pr_info,
prelude::*,
@@ -112,6 +112,10 @@
description:
"Support discard operations (requires memory-backed null_blk device). Default: false",
},
+ no_sched: u8 {
+ default: 0,
+ description: "No IO scheduler",
+ },
},
}

@@ -150,6 +154,7 @@ fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
submit_queues,
home_node: *module_parameters::home_node.value(),
discard: *module_parameters::discard.value() != 0,
+ no_sched: *module_parameters::no_sched.value() != 0,
})?;
disks.push(disk, GFP_KERNEL)?;
}
@@ -175,6 +180,7 @@ struct NullBlkOptions<'a> {
submit_queues: u32,
home_node: i32,
discard: bool,
+ no_sched: bool,
}
struct NullBlkDevice;

@@ -191,13 +197,18 @@ fn new(options: NullBlkOptions<'_>) -> Result<GenDisk<Self>> {
submit_queues,
home_node,
discard,
+ no_sched,
} = options;

- let flags = if memory_backed {
- mq::tag_set::Flag::Blocking.into()
- } else {
- mq::tag_set::Flags::default()
- };
+ let mut flags = mq::tag_set::Flags::default();
+
+ if memory_backed {
+ flags |= mq::tag_set::Flag::Blocking;
+ }
+
+ if no_sched {
+ flags |= mq::tag_set::Flag::NoDefaultScheduler;
+ }

if home_node > kernel::num_online_nodes().try_into()? {
return Err(code::EINVAL);

--
2.51.2