diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs index 0ca8715febe83..3833a5bec7a4a 100644 --- a/drivers/block/rnull/rnull.rs +++ b/drivers/block/rnull/rnull.rs @@ -97,4 +97,8 @@ impl Operations for NullBlkDevice { // point, and so `end_ok` cannot fail. .expect("Fatal error - expected to be able to end request"); } + + fn timeout(_rq: &mq::Request) -> mq::TimeoutReturn { + mq::TimeoutReturn::ResetTimer + } } diff --git a/rust/kernel/block/mq.rs b/rust/kernel/block/mq.rs index 1fd0d54dd5493..cfcfcd99addc3 100644 --- a/rust/kernel/block/mq.rs +++ b/rust/kernel/block/mq.rs @@ -98,6 +98,6 @@ mod operations; 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 8ad46129a52c4..a8ff5eb8dd31e 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -16,6 +16,16 @@ use core::marker::PhantomData; type ForeignBorrowed<'a, T> = ::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 @@ pub trait Operations: Sized { /// Called by the kernel when the request is completed. fn complete(rq: ARef>); + /// Called by the kernel when a request times out. + fn timeout(_rq: &Request) -> 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 OperationsVTable { 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::>() }; + + 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 OperationsVTable { 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 {