* [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; 5+ 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] 5+ 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; 5+ 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] 5+ 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-17 12:43 ` kernel test robot
2026-04-10 12:39 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Andreas Hindborg
2 siblings, 1 reply; 5+ 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] 5+ 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; 5+ 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] 5+ messages in thread
* Re: [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs
2026-04-10 9:08 ` [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs Wenzhao Liao
@ 2026-04-17 12:43 ` kernel test robot
0 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-04-17 12:43 UTC (permalink / raw)
To: Wenzhao Liao; +Cc: oe-kbuild-all
Hi Wenzhao,
[This is a private test report for your RFC patch.]
kernel test robot noticed the following build errors:
[auto build test ERROR on 3418d862679ac6da0b6bd681b18b3189c4fad20d]
url: https://github.com/intel-lab-lkp/linux/commits/Wenzhao-Liao/rust-block-mq-safely-expose-TagSet-flags/20260417-073541
base: 3418d862679ac6da0b6bd681b18b3189c4fad20d
patch link: https://lore.kernel.org/r/20260410090829.1409430-3-wenzhaoliao%40ruc.edu.cn
patch subject: [RFC PATCH 2/2] block: rnull: support BLK_MQ_F_BLOCKING via configfs
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260417/202604171406.R782cnZM-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260417/202604171406.R782cnZM-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604171406.R782cnZM-lkp@intel.com/
All errors (new ones prefixed by >>):
PATH=/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INFO PATH=/opt/cross/rustc-1.88.0-bindgen-0.72.1/cargo/bin:/opt/cross/clang-20/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/usr/bin/timeout -k 100 12h /usr/bin/make KCFLAGS=\ -fno-crash-diagnostics\ -Wno-error=return-type\ -Wreturn-type\ -funsigned-char\ -Wundef\ -falign-functions=64 W=1 --keep-going LLVM=1 -j32 -C source O=/kbuild/obj/consumer/x86_64-rhel-9.4-rust ARCH=x86_64 SHELL=/bin/bash rustfmtcheck
make: Entering directory '/kbuild/src/consumer'
make[1]: Entering directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
>> Diff in rust/kernel/block/mq/tag_set.rs:41:
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);
+ 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 {
>> Diff in rust/kernel/block/mq/tag_set.rs:41:
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);
+ 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 {
>> Diff in rust/kernel/block/mq/tag_set.rs:41:
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);
+ 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 {
>> Diff in rust/kernel/block/mq/tag_set.rs:41:
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);
+ 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 {
make[2]: *** [Makefile:1913: rustfmt] Error 123
make[2]: Target 'rustfmtcheck' not remade because of errors.
make[1]: Leaving directory '/kbuild/obj/consumer/x86_64-rhel-9.4-rust'
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'rustfmtcheck' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'rustfmtcheck' not remade because of errors.
make: Leaving directory '/kbuild/src/consumer'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-17 12:43 UTC | newest]
Thread overview: 5+ 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-17 12:43 ` kernel test robot
2026-04-10 12:39 ` [RFC PATCH 0/2] rust block-mq TagSet flags plumbing and rnull blocking wiring Andreas Hindborg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.