Skip to content

Commit cf84e14

Browse files
lwz23kawasaki
authored andcommitted
rust: block: mq: safely abstract the timeout callback
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 <[email protected]>
1 parent 6b4d829 commit cf84e14

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

rust/kernel/block/mq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,6 @@ mod operations;
9898
mod request;
9999
mod tag_set;
100100

101-
pub use operations::Operations;
101+
pub use operations::{Operations, TimeoutReturn};
102102
pub use request::Request;
103103
pub use tag_set::TagSet;

rust/kernel/block/mq/operations.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ use core::marker::PhantomData;
1616

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

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

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

181+
/// This function is called by the C kernel. A pointer to this function is
182+
/// installed in the `blk_mq_ops` vtable for the driver.
183+
///
184+
/// # Safety
185+
///
186+
/// This function may only be called by blk-mq C infrastructure. `rq` must
187+
/// point to a valid request that is still live for the duration of this
188+
/// callback.
189+
unsafe extern "C" fn timeout_callback(
190+
rq: *mut bindings::request,
191+
) -> bindings::blk_eh_timer_return {
192+
// SAFETY: `rq` is valid as required by the safety requirements for
193+
// this function, and the private data is initialized while the request
194+
// is live.
195+
let rq = unsafe { &*rq.cast::<Request<T>>() };
196+
197+
T::timeout(rq) as bindings::blk_eh_timer_return
198+
}
199+
166200
/// This function is called by the C kernel. A pointer to this function is
167201
/// installed in the `blk_mq_ops` vtable for the driver.
168202
///
@@ -262,7 +296,11 @@ impl<T: Operations> OperationsVTable<T> {
262296
put_budget: None,
263297
set_rq_budget_token: None,
264298
get_rq_budget_token: None,
265-
timeout: None,
299+
timeout: if T::HAS_TIMEOUT {
300+
Some(Self::timeout_callback)
301+
} else {
302+
None
303+
},
266304
poll: if T::HAS_POLL {
267305
Some(Self::poll_callback)
268306
} else {

0 commit comments

Comments
 (0)