@@ -10,15 +10,19 @@ use crate::{
1010 bindings,
1111 device:: Device ,
1212 error:: { Error , Result } ,
13+ ffi:: c_void,
1314 prelude:: * ,
1415 revocable:: Revocable ,
1516 sync:: Arc ,
17+ types:: ARef ,
1618} ;
1719
1820use core:: ops:: Deref ;
1921
2022#[ pin_data]
2123struct DevresInner < T > {
24+ dev : ARef < Device > ,
25+ callback : unsafe extern "C" fn ( * mut c_void ) ,
2226 #[ pin]
2327 data : Revocable < T > ,
2428}
@@ -98,6 +102,8 @@ impl<T> DevresInner<T> {
98102 fn new ( dev : & Device , data : T , flags : Flags ) -> Result < Arc < DevresInner < T > > > {
99103 let inner = Arc :: pin_init (
100104 pin_init ! ( DevresInner {
105+ dev: dev. into( ) ,
106+ callback: Self :: devres_callback,
101107 data <- Revocable :: new( data) ,
102108 } ) ,
103109 flags,
@@ -109,9 +115,8 @@ impl<T> DevresInner<T> {
109115
110116 // SAFETY: `devm_add_action` guarantees to call `Self::devres_callback` once `dev` is
111117 // detached.
112- let ret = unsafe {
113- bindings:: devm_add_action ( dev. as_raw ( ) , Some ( Self :: devres_callback) , data as _ )
114- } ;
118+ let ret =
119+ unsafe { bindings:: devm_add_action ( dev. as_raw ( ) , Some ( inner. callback ) , data as _ ) } ;
115120
116121 if ret != 0 {
117122 // SAFETY: We just created another reference to `inner` in order to pass it to
@@ -124,6 +129,32 @@ impl<T> DevresInner<T> {
124129 Ok ( inner)
125130 }
126131
132+ fn as_ptr ( & self ) -> * const Self {
133+ self as _
134+ }
135+
136+ fn remove_action ( this : & Arc < Self > ) {
137+ // SAFETY:
138+ // - `self.inner.dev` is a valid `Device`,
139+ // - the `action` and `data` pointers are the exact same ones as given to devm_add_action()
140+ // previously,
141+ // - `self` is always valid, even if the action has been released already.
142+ let ret = unsafe {
143+ bindings:: devm_remove_action_nowarn (
144+ this. dev . as_raw ( ) ,
145+ Some ( this. callback ) ,
146+ this. as_ptr ( ) as _ ,
147+ )
148+ } ;
149+
150+ if ret == 0 {
151+ // SAFETY: We leaked an `Arc` reference to devm_add_action() in `DevresInner::new`; if
152+ // devm_remove_action_nowarn() was successful we can (and have to) claim back ownership
153+ // of this reference.
154+ let _ = unsafe { Arc :: from_raw ( this. as_ptr ( ) ) } ;
155+ }
156+ }
157+
127158 #[ allow( clippy:: missing_safety_doc) ]
128159 unsafe extern "C" fn devres_callback ( ptr : * mut kernel:: ffi:: c_void ) {
129160 let ptr = ptr as * mut DevresInner < T > ;
@@ -165,14 +196,6 @@ impl<T> Deref for Devres<T> {
165196
166197impl < T > Drop for Devres < T > {
167198 fn drop ( & mut self ) {
168- // Revoke the data, such that it gets dropped already and the actual resource is freed.
169- //
170- // `DevresInner` has to stay alive until the devres callback has been called. This is
171- // necessary since we don't know when `Devres` is dropped and calling
172- // `devm_remove_action()` instead could race with `devres_release_all()`.
173- //
174- // SAFETY: When `drop` runs, it's guaranteed that nobody is accessing the revocable data
175- // anymore, hence it is safe not to wait for the grace period to finish.
176- unsafe { self . revoke_nosync ( ) } ;
199+ DevresInner :: remove_action ( & self . 0 ) ;
177200 }
178201}
0 commit comments