[PATCH 65/79] block: rust: add `queue_rqs` vtable hook

Andreas Hindborg
2026-02-15T23:44:21Z

Add support for the `queue_rqs` callback to the Rust block layer
bindings. This callback allows drivers to receive multiple requests in
a single call, enabling batch processing optimizations.

The callback receives a `RequestList` containing the requests to be
processed. Drivers should remove successfully processed requests from
the list; any remaining requests will be requeued individually.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/block/mq/operations.rs | 61 +++++++++++++++++++++++++++++++++++++-
rust/kernel/block/mq/request.rs | 26 ++++++++++++++++
2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs
index bccc1903a0d10..e4de6db807e18 100644
--- a/rust/kernel/block/mq/operations.rs
+++ b/rust/kernel/block/mq/operations.rs
@@ -18,6 +18,8 @@
use core::{marker::PhantomData, ptr::NonNull};
use pin_init::PinInit;

+use super::request_list::RequestList;
+
type ForeignBorrowed<'a, T> = <T as ForeignOwnable>::Borrowed<'a>;

/// Implement this trait to interface blk-mq as block devices.
@@ -68,6 +70,15 @@ fn queue_rq(
is_poll: bool,
) -> BlkResult;

+ /// Called by the kernel to queue a list of requests with the driver.
+ fn queue_rqs(
+ _hw_data: ForeignBorrowed<'_, Self::HwData>,
+ _queue_data: ForeignBorrowed<'_, Self::QueueData>,
+ _requests: &mut RequestList<Self>,
+ ) {
+ build_error!(crate::error::VTABLE_DEFAULT_ERROR)
+ }
+
/// Called by the kernel to indicate that queued requests should be submitted.
fn commit_rqs(
hw_data: ForeignBorrowed<'_, Self::HwData>,
@@ -208,6 +219,50 @@ impl<T: Operations> OperationsVTable<T> {
}
}

+ /// This function is called by the C kernel to queue a list of new requests.
+ ///
+ /// Driver is guaranteed that each request belongs to the same queue. If the
+ /// driver doesn't empty the `rqlist` completely, then the rest will be
+ /// queued individually by the block layer upon return.
+ ///
+ /// # SAFETY
+ ///
+ /// - `requests` must satisfy the safety requirements of `RequestList<T>`
+ /// - All requests in `requests` must belong to the same hardware context.
+ unsafe extern "C" fn queue_rqs_callback(requests: *mut bindings::rq_list) {
+ // SAFETY:
+ // - By the safety requirements of this function, `requests` is valid for use as a
+ // `RequestList`.
+ // - We have exclusive access to `requests` for the duration of this function.
+ let requests = unsafe { RequestList::from_raw(requests) };
+
+ let rq_ptr = requests.peek_raw();
+
+ if rq_ptr.is_null() {
+ return;
+ }
+
+ // SAFETY: By function safety requirements, rq_ptr is pointing to a
+ // valid request.
+ let hctx = unsafe { (*rq_ptr).mq_hctx };
+
+ // SAFETY: The safety requirement for this function ensure that `hctx`
+ // is valid and that `driver_data` was produced by a call to
+ // `into_foreign` in `Self::init_hctx_callback`.
+ let hw_data = unsafe { T::HwData::borrow((*hctx).driver_data) };
+
+ // SAFETY: `hctx` is valid as required by this function.
+ let queue_data = unsafe { (*(*hctx).queue).queuedata };
+
+ // SAFETY: `queue.queuedata` was created by `GenDiskBuilder::build` with
+ // a call to `ForeignOwnable::into_foreign` to create `queuedata`.
+ // `ForeignOwnable::from_foreign` is only called when the tagset is
+ // dropped, which happens after we are dropped.
+ let queue_data = unsafe { T::QueueData::borrow(queue_data) };
+
+ T::queue_rqs(hw_data, queue_data, requests);
+ }
+
/// This function is called by the C kernel. A pointer to this function is
/// installed in the `blk_mq_ops` vtable for the driver.
///
@@ -450,7 +505,11 @@ impl<T: Operations> OperationsVTable<T> {

const VTABLE: bindings::blk_mq_ops = bindings::blk_mq_ops {
queue_rq: Some(Self::queue_rq_callback),
- queue_rqs: None,
+ queue_rqs: if T::HAS_QUEUE_RQS {
+ Some(Self::queue_rqs_callback)
+ } else {
+ None
+ },
commit_rqs: Some(Self::commit_rqs_callback),
get_budget: None,
put_budget: None,
diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs
index bc655d202ca01..e22af7ea77bbc 100644
--- a/rust/kernel/block/mq/request.rs
+++ b/rust/kernel/block/mq/request.rs
@@ -148,6 +148,32 @@ pub fn queue(&self) -> &RequestQueue<T> {
pub fn as_raw(&self) -> *mut bindings::request {
self.0.get()
}
+
+ // Return a valid hctx pointer.
+ fn hctx_raw(&self) -> *mut bindings::blk_mq_hw_ctx {
+ // SAFETY: The requests is guaranteed to be associated with a hardware
+ // context while we have access to it.
+ unsafe { (*self.0.get()).mq_hctx }
+ }
+
+ /// Get a reference to the [`T::HwData`] for the hardware context that this
+ /// request is associated with.
+ pub fn hw_data(&self) -> <T::HwData as ForeignOwnable>::Borrowed<'_> {
+ let hctx = self.hctx_raw();
+
+ // SAFETY: `hctx` is valid and `driver_data` was produced by a call to
+ // `into_foreign` in `Operations::init_hctx_callback`.
+ unsafe { T::HwData::borrow((*hctx).driver_data) }
+ }
+
+ pub fn is_poll(&self) -> bool {
+ let hctx = self.hctx_raw();
+
+ u32::from(
+ // SAFETY: `hctx_raw` returns a valid pointer.
+ unsafe { (*hctx).type_ },
+ ) == bindings::hctx_type_HCTX_TYPE_POLL
+ }
}

/// A wrapper around a blk-mq [`struct request`]. This represents an IO request.

--
2.51.2