public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [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