66
77use crate :: {
88 bindings,
9- block:: mq:: request:: RequestDataWrapper ,
10- block:: mq:: Request ,
9+ block:: mq:: { request:: RequestDataWrapper , Request } ,
1110 error:: { from_result, Result } ,
1211 prelude:: * ,
13- types:: ARef ,
12+ types:: { ARef , ForeignOwnable } ,
1413} ;
1514use core:: { marker:: PhantomData , sync:: atomic:: AtomicU64 , sync:: atomic:: Ordering } ;
1615
16+ type ForeignBorrowed < ' a , T > = <T as ForeignOwnable >:: Borrowed < ' a > ;
17+
1718/// Implement this trait to interface blk-mq as block devices.
1819///
1920/// To implement a block device driver, implement this trait as described in the
@@ -26,12 +27,20 @@ use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering}
2627/// [module level documentation]: kernel::block::mq
2728#[ macros:: vtable]
2829pub trait Operations : Sized {
30+ /// Data associated with the `struct request_queue` that is allocated for
31+ /// the `GenDisk` associated with this `Operations` implementation.
32+ type QueueData : ForeignOwnable ;
33+
2934 /// Called by the kernel to queue a request with the driver. If `is_last` is
3035 /// `false`, the driver is allowed to defer committing the request.
31- fn queue_rq ( rq : ARef < Request < Self > > , is_last : bool ) -> Result ;
36+ fn queue_rq (
37+ queue_data : ForeignBorrowed < ' _ , Self :: QueueData > ,
38+ rq : ARef < Request < Self > > ,
39+ is_last : bool ,
40+ ) -> Result ;
3241
3342 /// Called by the kernel to indicate that queued requests should be submitted.
34- fn commit_rqs ( ) ;
43+ fn commit_rqs ( queue_data : ForeignBorrowed < ' _ , Self :: QueueData > ) ;
3544
3645 /// Called by the kernel to poll the device for completed requests. Only
3746 /// used for poll queues.
@@ -70,7 +79,7 @@ impl<T: Operations> OperationsVTable<T> {
7079 /// promise to not access the request until the driver calls
7180 /// `bindings::blk_mq_end_request` for the request.
7281 unsafe extern "C" fn queue_rq_callback (
73- _hctx : * mut bindings:: blk_mq_hw_ctx ,
82+ hctx : * mut bindings:: blk_mq_hw_ctx ,
7483 bd : * const bindings:: blk_mq_queue_data ,
7584 ) -> bindings:: blk_status_t {
7685 // SAFETY: `bd.rq` is valid as required by the safety requirement for
@@ -88,10 +97,20 @@ impl<T: Operations> OperationsVTable<T> {
8897 // reference counted by `ARef` until then.
8998 let rq = unsafe { Request :: aref_from_raw ( ( * bd) . rq ) } ;
9099
100+ // SAFETY: `hctx` is valid as required by this function.
101+ let queue_data = unsafe { ( * ( * hctx) . queue ) . queuedata } ;
102+
103+ // SAFETY: `queue.queuedata` was created by `GenDisk::try_new()` with a
104+ // call to `ForeignOwnable::into_pointer()` to create `queuedata`.
105+ // `ForeignOwnable::from_foreign()` is only called when the tagset is
106+ // dropped, which happens after we are dropped.
107+ let queue_data = unsafe { T :: QueueData :: borrow ( queue_data. cast ( ) ) } ;
108+
91109 // SAFETY: We have exclusive access and we just set the refcount above.
92110 unsafe { Request :: start_unchecked ( & rq) } ;
93111
94112 let ret = T :: queue_rq (
113+ queue_data,
95114 rq,
96115 // SAFETY: `bd` is valid as required by the safety requirement for
97116 // this function.
@@ -110,9 +129,18 @@ impl<T: Operations> OperationsVTable<T> {
110129 ///
111130 /// # Safety
112131 ///
113- /// This function may only be called by blk-mq C infrastructure.
114- unsafe extern "C" fn commit_rqs_callback ( _hctx : * mut bindings:: blk_mq_hw_ctx ) {
115- T :: commit_rqs ( )
132+ /// This function may only be called by blk-mq C infrastructure. The caller
133+ /// must ensure that `hctx` is valid.
134+ unsafe extern "C" fn commit_rqs_callback ( hctx : * mut bindings:: blk_mq_hw_ctx ) {
135+ // SAFETY: `hctx` is valid as required by this function.
136+ let queue_data = unsafe { ( * ( * hctx) . queue ) . queuedata } ;
137+
138+ // SAFETY: `queue.queuedata` was created by `GenDisk::try_new()` with a
139+ // call to `ForeignOwnable::into_pointer()` to create `queuedata`.
140+ // `ForeignOwnable::from_foreign()` is only called when the tagset is
141+ // dropped, which happens after we are dropped.
142+ let queue_data = unsafe { T :: QueueData :: borrow ( queue_data. cast ( ) ) } ;
143+ T :: commit_rqs ( queue_data)
116144 }
117145
118146 /// This function is called by the C kernel. It is not currently
0 commit comments