* [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring
@ 2026-04-10 9:08 ` Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 1/2] rust: block: mq: safely expose TagSet flags Wenzhao Liao
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Wenzhao Liao @ 2026-04-10 9:08 UTC (permalink / raw)
To: axboe, a.hindborg, ojeda, linux-block, rust-for-linux
Cc: bjorn3_gh, aliceryhl, lossin, boqun, dakr, gary, sunke, tmgross,
linux-kernel
This RFC series fills a practical gap in the Rust block-mq abstraction by
exposing blk_mq_tag_set.flags safely, then wires one in-tree consumer
(`rnull`) via configfs as a reference.
Patch 1 introduces `TagSetFlags` and `TagSet::new_with_flags(...)` while
keeping `TagSet::new(...)` for compatibility.
Patch 2 adds a `blocking` configfs attribute to `rnull` and maps it to
`TagSetFlags::BLOCKING` when powering on a device.
Validation summary:
- Out-of-tree build on rust-next (LLVM=-15): defconfig, rustavailable.
- Enabled CONFIG_RUST=y, CONFIG_CONFIGFS_FS=y, CONFIG_BLK_DEV_RUST_NULL=m.
- Built vmlinux and drivers/block/rnull/rnull_mod.ko successfully.
- QEMU runtime test (initramfs automation) verifies:
- `/sys/kernel/config/rnull/features` contains `blocking`;
- writing `blocking` while powered on fails with busy semantics;
- writing `blocking` after power off succeeds again.
Comments on API naming and any preferred follow-up scope are welcome.
Wenzhao Liao (2):
rust: block: mq: safely expose TagSet flags
block: rnull: support BLK_MQ_F_BLOCKING via configfs
drivers/block/rnull/configfs.rs | 32 +++++++++++-
drivers/block/rnull/rnull.rs | 11 ++++-
rust/kernel/block/mq.rs | 2 +-
rust/kernel/block/mq/tag_set.rs | 86 ++++++++++++++++++++++++++++++++-
4 files changed, 126 insertions(+), 5 deletions(-)
base-commit: 3418d862679ac6da0b6bd681b18b3189c4fad20d
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC PATCH 1/2] rust: block: mq: safely expose TagSet flags
2026-04-10 9:08 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Wenzhao Liao
@ 2026-04-10 9:08 ` Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs Wenzhao Liao
2026-04-10 12:39 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Andreas Hindborg
2 siblings, 0 replies; 4+ messages in thread
From: Wenzhao Liao @ 2026-04-10 9:08 UTC (permalink / raw)
To: axboe, a.hindborg, ojeda, linux-block, rust-for-linux
Cc: bjorn3_gh, aliceryhl, lossin, boqun, dakr, gary, sunke, tmgross,
linux-kernel
TagSet::new() currently hardcodes blk_mq_tag_set.flags to 0.
That prevents Rust block drivers from declaring blk-mq queue flags.
Introduce TagSetFlags as a typed wrapper for BLK_MQ_F_* bits.
Add TagSet::new_with_flags() so drivers can pass flags explicitly.
Keep TagSet::new() as a compatibility wrapper using empty flags.
Re-export TagSetFlags from kernel::block::mq for driver imports.
Build-tested with LLVM=-15 in an out-of-tree rust-next build.
Validation includes vmlinux and drivers/block/rnull/rnull_mod.ko.
Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
rust/kernel/block/mq.rs | 2 +-
rust/kernel/block/mq/tag_set.rs | 86 ++++++++++++++++++++++++++++++++-
2 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/block/mq.rs b/rust/kernel/block/mq.rs
index 1fd0d54dd549..799afdf36539 100644
--- a/rust/kernel/block/mq.rs
+++ b/rust/kernel/block/mq.rs
@@ -100,4 +100,4 @@
pub use operations::Operations;
pub use request::Request;
-pub use tag_set::TagSet;
+pub use tag_set::{TagSet, TagSetFlags};
diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs
index dae9df408a86..72d9bce5b11f 100644
--- a/rust/kernel/block/mq/tag_set.rs
+++ b/rust/kernel/block/mq/tag_set.rs
@@ -16,6 +16,80 @@
use core::{convert::TryInto, marker::PhantomData};
use pin_init::{pin_data, pinned_drop, PinInit};
+/// Flags that control blk-mq tag set behavior.
+///
+/// They can be combined with the operators `|`, `&`, and `!`.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct TagSetFlags(u32);
+
+impl TagSetFlags {
+ /// Returns an empty instance where no flags are set.
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ /// Register as a blocking blk-mq driver device.
+ pub const BLOCKING: Self = Self::new(bindings::BLK_MQ_F_BLOCKING as u32);
+
+ /// Use an underlying blk-mq device for completing I/O.
+ pub const STACKING: Self = Self::new(bindings::BLK_MQ_F_STACKING as u32);
+
+ /// Share hardware contexts between tags.
+ pub const TAG_HCTX_SHARED: Self = Self::new(bindings::BLK_MQ_F_TAG_HCTX_SHARED as u32);
+
+ /// Allocate tags on a round-robin basis.
+ pub const TAG_RR: Self = Self::new(bindings::BLK_MQ_F_TAG_RR as u32);
+
+ /// Disable the I/O scheduler by default.
+ pub const NO_SCHED_BY_DEFAULT: Self =
+ Self::new(bindings::BLK_MQ_F_NO_SCHED_BY_DEFAULT as u32);
+
+ /// Check whether `flags` is contained in `self`.
+ pub fn contains(self, flags: Self) -> bool {
+ (self & flags) == flags
+ }
+
+ pub(crate) const fn as_raw(self) -> u32 {
+ self.0
+ }
+
+ const fn all_bits() -> u32 {
+ Self::BLOCKING.0
+ | Self::STACKING.0
+ | Self::TAG_HCTX_SHARED.0
+ | Self::TAG_RR.0
+ | Self::NO_SCHED_BY_DEFAULT.0
+ }
+
+ const fn new(value: u32) -> Self {
+ Self(value)
+ }
+}
+
+impl core::ops::BitOr for TagSetFlags {
+ type Output = Self;
+
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+}
+
+impl core::ops::BitAnd for TagSetFlags {
+ type Output = Self;
+
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+}
+
+impl core::ops::Not for TagSetFlags {
+ type Output = Self;
+
+ fn not(self) -> Self::Output {
+ Self(!self.0 & Self::all_bits())
+ }
+}
+
/// A wrapper for the C `struct blk_mq_tag_set`.
///
/// `struct blk_mq_tag_set` contains a `struct list_head` and so must be pinned.
@@ -37,6 +111,16 @@ pub fn new(
nr_hw_queues: u32,
num_tags: u32,
num_maps: u32,
+ ) -> impl PinInit<Self, error::Error> {
+ Self::new_with_flags(nr_hw_queues, num_tags, num_maps, TagSetFlags::empty())
+ }
+
+ /// Try to create a new tag set with the given blk-mq flags.
+ pub fn new_with_flags(
+ nr_hw_queues: u32,
+ num_tags: u32,
+ num_maps: u32,
+ flags: TagSetFlags,
) -> impl PinInit<Self, error::Error> {
let tag_set: bindings::blk_mq_tag_set = pin_init::zeroed();
let tag_set: Result<_> = core::mem::size_of::<RequestDataWrapper>()
@@ -49,7 +133,7 @@ pub fn new(
numa_node: bindings::NUMA_NO_NODE,
queue_depth: num_tags,
cmd_size,
- flags: 0,
+ flags: flags.as_raw(),
driver_data: core::ptr::null_mut::<crate::ffi::c_void>(),
nr_maps: num_maps,
..tag_set
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs
2026-04-10 9:08 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 1/2] rust: block: mq: safely expose TagSet flags Wenzhao Liao
@ 2026-04-10 9:08 ` Wenzhao Liao
2026-04-10 12:39 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Andreas Hindborg
2 siblings, 0 replies; 4+ messages in thread
From: Wenzhao Liao @ 2026-04-10 9:08 UTC (permalink / raw)
To: axboe, a.hindborg, ojeda, linux-block, rust-for-linux
Cc: bjorn3_gh, aliceryhl, lossin, boqun, dakr, gary, sunke, tmgross,
linux-kernel
Add a new configfs boolean attribute named blocking.
Advertise blocking in the rnull features list.
On power-on, map blocking=1 to TagSetFlags::BLOCKING.
Create the tag set with TagSet::new_with_flags().
Keep default blocking=0 to preserve existing behavior.
Like other parameters, blocking writes return -EBUSY while powered on.
Validated with LLVM=-15 out-of-tree builds and QEMU runtime tests.
Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
drivers/block/rnull/configfs.rs | 32 +++++++++++++++++++++++++++++++-
drivers/block/rnull/rnull.rs | 11 +++++++++--
2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 7c2eb5c0b722..a9d46a511340 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -35,7 +35,7 @@ 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\n")?;
+ writer.write_str("blocksize,size,rotational,irqmode,blocking\n")?;
Ok(writer.bytes_written())
}
}
@@ -58,6 +58,7 @@ fn make_group(
rotational: 2,
size: 3,
irqmode: 4,
+ blocking: 5,
],
};
@@ -73,6 +74,7 @@ fn make_group(
disk: None,
capacity_mib: 4096,
irq_mode: IRQMode::None,
+ blocking: false,
name: name.try_into()?,
}),
}),
@@ -122,6 +124,7 @@ struct DeviceConfigInner {
rotational: bool,
capacity_mib: u64,
irq_mode: IRQMode,
+ blocking: bool,
disk: Option<GenDisk<NullBlkDevice>>,
}
@@ -152,6 +155,7 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
guard.rotational,
guard.capacity_mib,
guard.irq_mode,
+ guard.blocking,
)?);
guard.powered = true;
} else if guard.powered && !power_op {
@@ -259,3 +263,29 @@ fn store(this: &DeviceConfig, page: &[u8]) -> Result {
Ok(())
}
}
+
+#[vtable]
+impl configfs::AttributeOperations<5> 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().blocking {
+ 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().blocking = kstrtobool_bytes(page)?;
+ Ok(())
+ }
+}
diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs
index 0ca8715febe8..d7ebd504d8df 100644
--- a/drivers/block/rnull/rnull.rs
+++ b/drivers/block/rnull/rnull.rs
@@ -11,7 +11,7 @@
mq::{
self,
gen_disk::{self, GenDisk},
- Operations, TagSet,
+ Operations, TagSet, TagSetFlags,
},
},
prelude::*,
@@ -51,8 +51,15 @@ fn new(
rotational: bool,
capacity_mib: u64,
irq_mode: IRQMode,
+ blocking: bool,
) -> Result<GenDisk<Self>> {
- let tagset = Arc::pin_init(TagSet::new(1, 256, 1), GFP_KERNEL)?;
+ let flags = if blocking {
+ TagSetFlags::BLOCKING
+ } else {
+ TagSetFlags::empty()
+ };
+
+ let tagset = Arc::pin_init(TagSet::new_with_flags(1, 256, 1, flags), GFP_KERNEL)?;
let queue_data = Box::new(QueueData { irq_mode }, GFP_KERNEL)?;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring
2026-04-10 9:08 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 1/2] rust: block: mq: safely expose TagSet flags Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs Wenzhao Liao
@ 2026-04-10 12:39 ` Andreas Hindborg
2 siblings, 0 replies; 4+ messages in thread
From: Andreas Hindborg @ 2026-04-10 12:39 UTC (permalink / raw)
To: Wenzhao Liao, axboe, ojeda, linux-block, rust-for-linux
Cc: bjorn3_gh, aliceryhl, lossin, boqun, dakr, gary, sunke, tmgross,
linux-kernel
Hi Wenzhao,
"Wenzhao Liao" <wenzhaoliao@ruc.edu.cn> writes:
> This RFC series fills a practical gap in the Rust block-mq abstraction by
> exposing blk_mq_tag_set.flags safely, then wires one in-tree consumer
> (`rnull`) via configfs as a reference.
Patches for this functionality is already submitted to list [1]. Please
take a look if those patches solve your requirement. If you require this
functionality in the kernel, please help by reviewing the patches in
that series.
Best regards,
Andreas Hindborg
[1] https://lore.kernel.org/rust-for-linux/20260216-rnull-v6-19-rc5-send-v1-12-de9a7af4b469@kernel.org/
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-10 12:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <ne6CiAojHihZEG_ev_i0nlu5Pnr_zliA5ODFH5OM1m8muKLCmOMTquymtKmTOSHR9wTVYSki1RzBYq9rhtEUhw==@protonmail.internalid>
2026-04-10 9:08 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 1/2] rust: block: mq: safely expose TagSet flags Wenzhao Liao
2026-04-10 9:08 ` [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs Wenzhao Liao
2026-04-10 12:39 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Andreas Hindborg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox