@@ -10,12 +10,120 @@ use crate::{
1010 error:: { from_result, Result } ,
1111 prelude:: * ,
1212 sync:: { aref:: ARef , Refcount } ,
13- types:: ForeignOwnable ,
13+ types:: { ForeignOwnable , Opaque } ,
1414} ;
1515use core:: marker:: PhantomData ;
1616
1717type ForeignBorrowed < ' a , T > = <T as ForeignOwnable >:: Borrowed < ' a > ;
1818
19+ /// A borrowed blk-mq hardware queue context.
20+ ///
21+ /// # Invariants
22+ ///
23+ /// [`HwCtx`] is a transparent wrapper around a live `bindings::blk_mq_hw_ctx`.
24+ #[ repr( transparent) ]
25+ pub struct HwCtx ( Opaque < bindings:: blk_mq_hw_ctx > ) ;
26+
27+ impl HwCtx {
28+ /// Creates a reference to an [`HwCtx`] from a valid raw pointer.
29+ ///
30+ /// # Safety
31+ ///
32+ /// The caller must ensure that `ptr` points to a live
33+ /// `bindings::blk_mq_hw_ctx` for the duration of `'a`.
34+ ///
35+ /// The caller must also ensure that the returned reference is the only
36+ /// Rust view used to access the underlying hardware context for the
37+ /// duration of `'a`.
38+ pub ( crate ) unsafe fn from_raw < ' a > ( ptr : * mut bindings:: blk_mq_hw_ctx ) -> & ' a Self {
39+ // SAFETY: `Self` is a transparent wrapper around `bindings::blk_mq_hw_ctx`.
40+ unsafe { & * ptr. cast ( ) }
41+ }
42+
43+ /// Returns a raw pointer to the underlying `struct blk_mq_hw_ctx`.
44+ pub fn as_ptr ( & self ) -> * mut bindings:: blk_mq_hw_ctx {
45+ self as * const Self as * mut bindings:: blk_mq_hw_ctx
46+ }
47+
48+ /// Returns the index of this hardware queue.
49+ pub fn queue_num ( & self ) -> u32 {
50+ // SAFETY: By the type invariant, `self` wraps a live hardware context.
51+ unsafe { ( * self . as_ptr ( ) ) . queue_num }
52+ }
53+ }
54+
55+ /// A borrowed blk-mq completion batching context.
56+ ///
57+ /// # Invariants
58+ ///
59+ /// [`IoCompBatch`] is a transparent wrapper around a live
60+ /// `bindings::io_comp_batch`.
61+ #[ repr( transparent) ]
62+ pub struct IoCompBatch ( Opaque < bindings:: io_comp_batch > ) ;
63+
64+ impl IoCompBatch {
65+ /// Creates an optional reference to an [`IoCompBatch`] from a raw pointer.
66+ ///
67+ /// # Safety
68+ ///
69+ /// If `ptr` is non-null, the caller must ensure that it points to a live
70+ /// `bindings::io_comp_batch` for the duration of `'a`.
71+ ///
72+ /// The caller must also ensure that the returned reference is the only
73+ /// Rust view used to access the underlying completion batch for the
74+ /// duration of `'a`.
75+ pub ( crate ) unsafe fn from_raw < ' a > ( ptr : * mut bindings:: io_comp_batch ) -> Option < & ' a Self > {
76+ if ptr. is_null ( ) {
77+ None
78+ } else {
79+ // SAFETY: `Self` is a transparent wrapper around `bindings::io_comp_batch`.
80+ Some ( unsafe { & * ptr. cast ( ) } )
81+ }
82+ }
83+
84+ /// Returns a raw pointer to the underlying `struct io_comp_batch`.
85+ pub fn as_ptr ( & self ) -> * mut bindings:: io_comp_batch {
86+ self as * const Self as * mut bindings:: io_comp_batch
87+ }
88+ }
89+
90+ /// Result returned from blk-mq poll callbacks.
91+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
92+ pub enum PollResult {
93+ /// The driver completed the given number of requests.
94+ Completed ( u32 ) ,
95+
96+ /// The driver cannot make progress and blk-mq should stop polling.
97+ Stop ,
98+ }
99+
100+ impl PollResult {
101+ /// Returns a result indicating that no requests were completed.
102+ pub const fn none ( ) -> Self {
103+ Self :: Completed ( 0 )
104+ }
105+
106+ /// Returns a result indicating that `completed` requests were completed.
107+ pub const fn completed ( completed : u32 ) -> Self {
108+ Self :: Completed ( completed)
109+ }
110+
111+ /// Returns a result indicating that blk-mq should stop polling for now.
112+ pub const fn stop ( ) -> Self {
113+ Self :: Stop
114+ }
115+
116+ fn as_raw ( self ) -> crate :: ffi:: c_int {
117+ match self {
118+ Self :: Completed ( completed) => {
119+ debug_assert ! ( completed <= crate :: ffi:: c_int:: MAX as u32 ) ;
120+ completed as crate :: ffi:: c_int
121+ }
122+ Self :: Stop => -1 ,
123+ }
124+ }
125+ }
126+
19127/// Implement this trait to interface blk-mq as block devices.
20128///
21129/// To implement a block device driver, implement this trait as described in the
@@ -48,7 +156,11 @@ pub trait Operations: Sized {
48156
49157 /// Called by the kernel to poll the device for completed requests. Only
50158 /// used for poll queues.
51- fn poll ( ) -> bool {
159+ fn poll (
160+ _queue_data : ForeignBorrowed < ' _ , Self :: QueueData > ,
161+ _hctx : & HwCtx ,
162+ _iob : Option < & IoCompBatch > ,
163+ ) -> PollResult {
52164 build_error ! ( crate :: error:: VTABLE_DEFAULT_ERROR )
53165 }
54166}
@@ -168,12 +280,31 @@ impl<T: Operations> OperationsVTable<T> {
168280 ///
169281 /// # Safety
170282 ///
171- /// This function may only be called by blk-mq C infrastructure.
283+ /// This function may only be called by blk-mq C infrastructure. The caller
284+ /// must ensure that `hctx` is valid. If non-null, `iob` must point to a
285+ /// live completion batch for the duration of this callback.
172286 unsafe extern "C" fn poll_callback (
173- _hctx : * mut bindings:: blk_mq_hw_ctx ,
174- _iob : * mut bindings:: io_comp_batch ,
287+ hctx : * mut bindings:: blk_mq_hw_ctx ,
288+ iob : * mut bindings:: io_comp_batch ,
175289 ) -> crate :: ffi:: c_int {
176- T :: poll ( ) . into ( )
290+ // SAFETY: `hctx` is valid as required by this function.
291+ let hctx = unsafe { HwCtx :: from_raw ( hctx) } ;
292+
293+ // SAFETY: `hctx` is live as required by this function, so the request
294+ // queue and its `queuedata` are also live for the duration of this
295+ // callback.
296+ let queue_data = unsafe { ( * ( * hctx. as_ptr ( ) ) . queue ) . queuedata } ;
297+
298+ // SAFETY: `queue.queuedata` was created by `GenDiskBuilder::build`
299+ // with a call to `ForeignOwnable::into_foreign` to create
300+ // `queuedata`. `ForeignOwnable::from_foreign` is only called when the
301+ // tagset is dropped, which happens after we are dropped.
302+ let queue_data = unsafe { T :: QueueData :: borrow ( queue_data) } ;
303+
304+ // SAFETY: If non-null, `iob` is valid as required by this function.
305+ let iob = unsafe { IoCompBatch :: from_raw ( iob) } ;
306+
307+ T :: poll ( queue_data, hctx, iob) . as_raw ( )
177308 }
178309
179310 /// This function is called by the C kernel. A pointer to this function is
0 commit comments