@@ -8,12 +8,13 @@ use crate::{
8
8
bindings,
9
9
block:: mq:: Operations ,
10
10
error:: Result ,
11
+ sync:: Refcount ,
11
12
types:: { ARef , AlwaysRefCounted , Opaque } ,
12
13
} ;
13
14
use core:: {
14
15
marker:: PhantomData ,
15
16
ptr:: { addr_of_mut, NonNull } ,
16
- sync:: atomic:: { AtomicU64 , Ordering } ,
17
+ sync:: atomic:: Ordering ,
17
18
} ;
18
19
19
20
/// A wrapper around a blk-mq [`struct request`]. This represents an IO request.
@@ -37,6 +38,9 @@ use core::{
37
38
/// We need to track 3 and 4 to ensure that it is safe to end the request and hand
38
39
/// back ownership to the block layer.
39
40
///
41
+ /// Note that driver can still obtain new `ARef` even if there is no `ARef`s in existence by using
42
+ /// `tag_to_rq`, hence the need to distinct B and C.
43
+ ///
40
44
/// The states are tracked through the private `refcount` field of
41
45
/// `RequestDataWrapper`. This structure lives in the private data area of the C
42
46
/// [`struct request`].
@@ -98,13 +102,17 @@ impl<T: Operations> Request<T> {
98
102
///
99
103
/// [`struct request`]: srctree/include/linux/blk-mq.h
100
104
fn try_set_end ( this : ARef < Self > ) -> Result < * mut bindings:: request , ARef < Self > > {
101
- // We can race with `TagSet::tag_to_rq`
102
- if let Err ( _old) = this. wrapper_ref ( ) . refcount ( ) . compare_exchange (
103
- 2 ,
104
- 0 ,
105
- Ordering :: Relaxed ,
106
- Ordering :: Relaxed ,
107
- ) {
105
+ // To hand back the ownership, we need the current refcount to be 2.
106
+ // Since we can race with `TagSet::tag_to_rq`, this needs to atomically reduce
107
+ // refcount to 0. `Refcount` does not provide a way to do this, so use the underlying
108
+ // atomics directly.
109
+ if this
110
+ . wrapper_ref ( )
111
+ . refcount ( )
112
+ . as_atomic ( )
113
+ . compare_exchange ( 2 , 0 , Ordering :: Relaxed , Ordering :: Relaxed )
114
+ . is_err ( )
115
+ {
108
116
return Err ( this) ;
109
117
}
110
118
@@ -168,13 +176,13 @@ pub(crate) struct RequestDataWrapper {
168
176
/// - 0: The request is owned by C block layer.
169
177
/// - 1: The request is owned by Rust abstractions but there are no [`ARef`] references to it.
170
178
/// - 2+: There are [`ARef`] references to the request.
171
- refcount : AtomicU64 ,
179
+ refcount : Refcount ,
172
180
}
173
181
174
182
impl RequestDataWrapper {
175
183
/// Return a reference to the refcount of the request that is embedding
176
184
/// `self`.
177
- pub ( crate ) fn refcount ( & self ) -> & AtomicU64 {
185
+ pub ( crate ) fn refcount ( & self ) -> & Refcount {
178
186
& self . refcount
179
187
}
180
188
@@ -184,7 +192,7 @@ impl RequestDataWrapper {
184
192
/// # Safety
185
193
///
186
194
/// - `this` must point to a live allocation of at least the size of `Self`.
187
- pub ( crate ) unsafe fn refcount_ptr ( this : * mut Self ) -> * mut AtomicU64 {
195
+ pub ( crate ) unsafe fn refcount_ptr ( this : * mut Self ) -> * mut Refcount {
188
196
// SAFETY: Because of the safety requirements of this function, the
189
197
// field projection is safe.
190
198
unsafe { addr_of_mut ! ( ( * this) . refcount) }
@@ -200,47 +208,13 @@ unsafe impl<T: Operations> Send for Request<T> {}
200
208
// mutate `self` are internally synchronized`
201
209
unsafe impl < T : Operations > Sync for Request < T > { }
202
210
203
- /// Store the result of `op(target.load())` in target, returning new value of
204
- /// target.
205
- fn atomic_relaxed_op_return ( target : & AtomicU64 , op : impl Fn ( u64 ) -> u64 ) -> u64 {
206
- let old = target. fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |x| Some ( op ( x) ) ) ;
207
-
208
- // SAFETY: Because the operation passed to `fetch_update` above always
209
- // return `Some`, `old` will always be `Ok`.
210
- let old = unsafe { old. unwrap_unchecked ( ) } ;
211
-
212
- op ( old)
213
- }
214
-
215
- /// Store the result of `op(target.load)` in `target` if `target.load() !=
216
- /// pred`, returning [`true`] if the target was updated.
217
- fn atomic_relaxed_op_unless ( target : & AtomicU64 , op : impl Fn ( u64 ) -> u64 , pred : u64 ) -> bool {
218
- target
219
- . fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |x| {
220
- if x == pred {
221
- None
222
- } else {
223
- Some ( op ( x) )
224
- }
225
- } )
226
- . is_ok ( )
227
- }
228
-
229
211
// SAFETY: All instances of `Request<T>` are reference counted. This
230
212
// implementation of `AlwaysRefCounted` ensure that increments to the ref count
231
213
// keeps the object alive in memory at least until a matching reference count
232
214
// decrement is executed.
233
215
unsafe impl < T : Operations > AlwaysRefCounted for Request < T > {
234
216
fn inc_ref ( & self ) {
235
- let refcount = & self . wrapper_ref ( ) . refcount ( ) ;
236
-
237
- #[ cfg_attr( not( CONFIG_DEBUG_MISC ) , allow( unused_variables) ) ]
238
- let updated = atomic_relaxed_op_unless ( refcount, |x| x + 1 , 0 ) ;
239
-
240
- #[ cfg( CONFIG_DEBUG_MISC ) ]
241
- if !updated {
242
- panic ! ( "Request refcount zero on clone" )
243
- }
217
+ self . wrapper_ref ( ) . refcount ( ) . inc ( ) ;
244
218
}
245
219
246
220
unsafe fn dec_ref ( obj : core:: ptr:: NonNull < Self > ) {
@@ -252,10 +226,10 @@ unsafe impl<T: Operations> AlwaysRefCounted for Request<T> {
252
226
let refcount = unsafe { & * RequestDataWrapper :: refcount_ptr ( wrapper_ptr) } ;
253
227
254
228
#[ cfg_attr( not( CONFIG_DEBUG_MISC ) , allow( unused_variables) ) ]
255
- let new_refcount = atomic_relaxed_op_return ( refcount, |x| x - 1 ) ;
229
+ let is_zero = refcount. dec_and_test ( ) ;
256
230
257
231
#[ cfg( CONFIG_DEBUG_MISC ) ]
258
- if new_refcount == 0 {
232
+ if is_zero {
259
233
panic ! ( "Request reached refcount zero in Rust abstractions" ) ;
260
234
}
261
235
}
0 commit comments