Add support for the `map_queues` callback to the Rust block layer bindings. This callback allows drivers to customize the mapping between CPUs and hardware queues. The callback receives a mutable reference to the `TagSet`, and drivers can use the `TagSet::update_maps` method to configure the mappings for each queue type. Signed-off-by: Andreas Hindborg --- rust/kernel/block/mq/operations.rs | 28 ++++++++++++++++++++++++++-- rust/kernel/block/mq/tag_set.rs | 13 +++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index 3f84ebadec86b..017fad010d174 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -8,7 +8,7 @@ bindings, block::{ error::BlkResult, - mq::{gen_disk::GenDiskRef, request::RequestDataWrapper, IdleRequest, Request}, + mq::{gen_disk::GenDiskRef, request::RequestDataWrapper, IdleRequest, Request, TagSet}, }, error::{from_result, to_result, Result}, prelude::*, @@ -101,6 +101,11 @@ fn report_zones( ) -> Result { Err(ENOTSUPP) } + + /// Called by the kernel to map submission queues to CPU cores. + fn map_queues(_tag_set: &TagSet) { + build_error!(crate::error::VTABLE_DEFAULT_ERROR) + } } /// A vtable for blk-mq to interact with a block device driver. @@ -394,6 +399,21 @@ impl OperationsVTable { }) } + /// This function is called by the C kernel. A pointer to this function is + /// installed in the `blk_mq_ops` vtable for the driver. + /// + /// # Safety + /// + /// This function may only be called by blk-mq C infrastructure. `tag_set` + /// must be a pointer to a valid and initialized `TagSet`. The pointee + /// must be valid for use as a reference at least the duration of this call. + unsafe extern "C" fn map_queues_callback(tag_set: *mut bindings::blk_mq_tag_set) { + // SAFETY: The safety requirements of this function satiesfies the + // requirements of `TagSet::from_ptr`. + let tag_set = unsafe { TagSet::from_ptr(tag_set) }; + T::map_queues(tag_set); + } + const VTABLE: bindings::blk_mq_ops = bindings::blk_mq_ops { queue_rq: Some(Self::queue_rq_callback), queue_rqs: None, @@ -415,7 +435,11 @@ impl OperationsVTable { exit_request: Some(Self::exit_request_callback), cleanup_rq: None, busy: None, - map_queues: None, + map_queues: if T::HAS_MAP_QUEUES { + Some(Self::map_queues_callback) + } else { + None + }, #[cfg(CONFIG_BLK_DEBUG_FS)] show_rq: None, }; diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index 600c9c6249123..330ff28c91507 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -89,6 +89,19 @@ pub fn new( pub(crate) fn raw_tag_set(&self) -> *mut bindings::blk_mq_tag_set { self.inner.get() } + + /// Create a `TagSet` from a raw pointer. + /// + /// # Safety + /// + /// `ptr` must be a pointer to a valid and initialized `TagSet`. There + /// may be no other mutable references to the tag set. The pointee must be + /// live and valid at least for the duration of the returned lifetime `'a`. + pub(crate) unsafe fn from_ptr<'a>(ptr: *mut bindings::blk_mq_tag_set) -> &'a Self { + // SAFETY: By the safety requirements of this function, `ptr` is valid + // for use as a reference for the duration of `'a`. + unsafe { &*(ptr.cast::()) } + } } #[pinned_drop] -- 2.51.2