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 --- 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::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 { let tag_set: bindings::blk_mq_tag_set = pin_init::zeroed(); let tag_set: Result<_> = core::mem::size_of::() @@ -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::(), nr_maps: num_maps, ..tag_set -- 2.34.1