[RFC PATCH 1/2] rust: block: mq: safely abstract the timeout callback

From: Wenzhao Liao

Date: Fri Apr 10 2026 - 13:05:13 EST


Add a typed TimeoutReturn enum for blk-mq timeout handlers and
extend the Operations trait with an optional timeout callback.

The new callback borrows Request instead of taking an ARef because
timeout is a synchronous notification from blk-mq and does not
transfer request ownership to the driver.

Wire the callback into OperationsVTable and keep drivers that do not
implement timeout on the existing timeout: None path.

Signed-off-by: Wenzhao Liao <wenzhaoliao@xxxxxxxxxx>
---
rust/kernel/block/mq.rs | 2 +-
rust/kernel/block/mq/operations.rs | 40 +++++++++++++++++++++++++++++-
2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/block/mq.rs b/rust/kernel/block/mq.rs
index 1fd0d54dd549..cfcfcd99addc 100644
--- a/rust/kernel/block/mq.rs
+++ b/rust/kernel/block/mq.rs
@@ -98,6 +98,6 @@
mod request;
mod tag_set;

-pub use operations::Operations;
+pub use operations::{Operations, TimeoutReturn};
pub use request::Request;
pub use tag_set::TagSet;
diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs
index 8ad46129a52c..a8ff5eb8dd31 100644
--- a/rust/kernel/block/mq/operations.rs
+++ b/rust/kernel/block/mq/operations.rs
@@ -16,6 +16,16 @@

type ForeignBorrowed<'a, T> = <T as ForeignOwnable>::Borrowed<'a>;

+/// Return value for blk-mq timeout handlers.
+#[repr(u32)]
+pub enum TimeoutReturn {
+ /// The driver completed the request or will complete it later.
+ Done = bindings::blk_eh_timer_return_BLK_EH_DONE,
+
+ /// Reset the request timer and keep waiting for completion.
+ ResetTimer = bindings::blk_eh_timer_return_BLK_EH_RESET_TIMER,
+}
+
/// Implement this trait to interface blk-mq as block devices.
///
/// To implement a block device driver, implement this trait as described in the
@@ -46,6 +56,11 @@ fn queue_rq(
/// Called by the kernel when the request is completed.
fn complete(rq: ARef<Request<Self>>);

+ /// Called by the kernel when a request times out.
+ fn timeout(_rq: &Request<Self>) -> TimeoutReturn {
+ build_error!(crate::error::VTABLE_DEFAULT_ERROR)
+ }
+
/// Called by the kernel to poll the device for completed requests. Only
/// used for poll queues.
fn poll() -> bool {
@@ -163,6 +178,25 @@ impl<T: Operations> OperationsVTable<T> {
T::complete(aref);
}

+ /// 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. `rq` must
+ /// point to a valid request that is still live for the duration of this
+ /// callback.
+ unsafe extern "C" fn timeout_callback(
+ rq: *mut bindings::request,
+ ) -> bindings::blk_eh_timer_return {
+ // SAFETY: `rq` is valid as required by the safety requirements for
+ // this function, and the private data is initialized while the request
+ // is live.
+ let rq = unsafe { &*rq.cast::<Request<T>>() };
+
+ T::timeout(rq) as bindings::blk_eh_timer_return
+ }
+
/// This function is called by the C kernel. A pointer to this function is
/// installed in the `blk_mq_ops` vtable for the driver.
///
@@ -262,7 +296,11 @@ impl<T: Operations> OperationsVTable<T> {
put_budget: None,
set_rq_budget_token: None,
get_rq_budget_token: None,
- timeout: None,
+ timeout: if T::HAS_TIMEOUT {
+ Some(Self::timeout_callback)
+ } else {
+ None
+ },
poll: if T::HAS_POLL {
Some(Self::poll_callback)
} else {
--
2.34.1