@@ -23,9 +23,22 @@ use crate::{
2323 rcu,
2424 Arc , //
2525 } ,
26- types:: ForeignOwnable ,
26+ types:: {
27+ ForeignOwnable ,
28+ Opaque , //
29+ } ,
2730} ;
2831
32+ /// Inner type that embeds a `struct devres_node` and the `Revocable<T>`.
33+ #[ repr( C ) ]
34+ #[ pin_data]
35+ struct Inner < T > {
36+ #[ pin]
37+ node : Opaque < bindings:: devres_node > ,
38+ #[ pin]
39+ data : Revocable < T > ,
40+ }
41+
2942/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to
3043/// manage their lifetime.
3144///
@@ -111,12 +124,64 @@ use crate::{
111124/// ```
112125pub struct Devres < T : Send > {
113126 dev : ARef < Device > ,
114- /// Pointer to [`Self::devres_callback`].
115- ///
116- /// Has to be stored, since Rust does not guarantee to always return the same address for a
117- /// function. However, the C API uses the address as a key.
118- callback : unsafe extern "C" fn ( * mut c_void ) ,
119- data : Arc < Revocable < T > > ,
127+ inner : Arc < Inner < T > > ,
128+ }
129+
130+ // Calling the FFI functions from the `base` module directly from the `Devres<T>` impl may result in
131+ // them being called directly from driver modules. This happens since the Rust compiler will use
132+ // monomorphisation, so it might happen that functions are instantiated within the calling driver
133+ // module. For now, work around this with `#[inline(never)]` helpers.
134+ //
135+ // TODO: Remove once a more generic solution has been implemented. For instance, we may be able to
136+ // leverage `bindgen` to take care of this depending on whether a symbol is (already) exported.
137+ mod base {
138+ use kernel:: {
139+ bindings,
140+ prelude:: * , //
141+ } ;
142+
143+ #[ inline( never) ]
144+ #[ allow( clippy:: missing_safety_doc) ]
145+ pub ( super ) unsafe fn devres_node_init (
146+ node : * mut bindings:: devres_node ,
147+ release : bindings:: dr_node_release_t ,
148+ free : bindings:: dr_node_free_t ,
149+ ) {
150+ // SAFETY: Safety requirements are the same as `bindings::devres_node_init`.
151+ unsafe { bindings:: devres_node_init ( node, release, free) }
152+ }
153+
154+ #[ inline( never) ]
155+ #[ allow( clippy:: missing_safety_doc) ]
156+ pub ( super ) unsafe fn devres_set_node_dbginfo (
157+ node : * mut bindings:: devres_node ,
158+ name : * const c_char ,
159+ size : usize ,
160+ ) {
161+ // SAFETY: Safety requirements are the same as `bindings::devres_set_node_dbginfo`.
162+ unsafe { bindings:: devres_set_node_dbginfo ( node, name, size) }
163+ }
164+
165+ #[ inline( never) ]
166+ #[ allow( clippy:: missing_safety_doc) ]
167+ pub ( super ) unsafe fn devres_node_add (
168+ dev : * mut bindings:: device ,
169+ node : * mut bindings:: devres_node ,
170+ ) {
171+ // SAFETY: Safety requirements are the same as `bindings::devres_node_add`.
172+ unsafe { bindings:: devres_node_add ( dev, node) }
173+ }
174+
175+ #[ must_use]
176+ #[ inline( never) ]
177+ #[ allow( clippy:: missing_safety_doc) ]
178+ pub ( super ) unsafe fn devres_node_remove (
179+ dev : * mut bindings:: device ,
180+ node : * mut bindings:: devres_node ,
181+ ) -> bool {
182+ // SAFETY: Safety requirements are the same as `bindings::devres_node_remove`.
183+ unsafe { bindings:: devres_node_remove ( dev, node) }
184+ }
120185}
121186
122187impl < T : Send > Devres < T > {
@@ -128,58 +193,86 @@ impl<T: Send> Devres<T> {
128193 where
129194 Error : From < E > ,
130195 {
131- let callback = Self :: devres_callback;
132- let data = Arc :: pin_init ( Revocable :: new ( data) , GFP_KERNEL ) ?;
133- let devres_data = data. clone ( ) ;
196+ let inner = Arc :: pin_init :: < Error > (
197+ try_pin_init ! ( Inner {
198+ node <- Opaque :: ffi_init( |node: * mut bindings:: devres_node| {
199+ // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
200+ unsafe {
201+ base:: devres_node_init(
202+ node,
203+ Some ( Self :: devres_node_release) ,
204+ Some ( Self :: devres_node_free_node) ,
205+ )
206+ } ;
207+
208+ // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
209+ unsafe {
210+ base:: devres_set_node_dbginfo(
211+ node,
212+ // TODO: Use `core::any::type_name::<T>()` once it is a `const fn`,
213+ // such that we can convert the `&str` to a `&CStr` at compile-time.
214+ c"Devres<T>" . as_char_ptr( ) ,
215+ core:: mem:: size_of:: <Revocable <T >>( ) ,
216+ )
217+ } ;
218+ } ) ,
219+ data <- Revocable :: new( data) ,
220+ } ) ,
221+ GFP_KERNEL ,
222+ ) ?;
134223
135224 // SAFETY:
136- // - `dev.as_raw()` is a pointer to a valid bound device.
137- // - `data` is guaranteed to be a valid for the duration of the lifetime of `Self`.
138- // - `devm_add_action()` is guaranteed not to call `callback` for the entire lifetime of
139- // `dev`.
140- to_result ( unsafe {
141- bindings:: devm_add_action (
142- dev. as_raw ( ) ,
143- Some ( callback) ,
144- Arc :: as_ptr ( & data) . cast_mut ( ) . cast ( ) ,
145- )
146- } ) ?;
147-
148- // `devm_add_action()` was successful and has consumed the reference count.
149- core:: mem:: forget ( devres_data) ;
225+ // - `dev` is a valid pointer to a bound `struct device`.
226+ // - `node` is a valid pointer to a `struct devres_node`.
227+ // - `devres_node_add()` is guaranteed not to call `devres_node_release()` for the entire
228+ // lifetime of `dev`.
229+ unsafe { base:: devres_node_add ( dev. as_raw ( ) , inner. node . get ( ) ) } ;
230+
231+ // Take additional reference count for `devres_node_add()`.
232+ core:: mem:: forget ( inner. clone ( ) ) ;
150233
151234 Ok ( Self {
152235 dev : dev. into ( ) ,
153- callback,
154- data,
236+ inner,
155237 } )
156238 }
157239
158240 fn data ( & self ) -> & Revocable < T > {
159- & self . data
241+ & self . inner . data
160242 }
161243
162244 #[ allow( clippy:: missing_safety_doc) ]
163- unsafe extern "C" fn devres_callback ( ptr : * mut kernel:: ffi:: c_void ) {
164- // SAFETY: In `Self::new` we've passed a valid pointer of `Revocable<T>` to
165- // `devm_add_action()`, hence `ptr` must be a valid pointer to `Revocable<T>`.
166- let data = unsafe { Arc :: from_raw ( ptr. cast :: < Revocable < T > > ( ) ) } ;
245+ unsafe extern "C" fn devres_node_release (
246+ _dev : * mut bindings:: device ,
247+ node : * mut bindings:: devres_node ,
248+ ) {
249+ let node = Opaque :: cast_from ( node) ;
250+
251+ // SAFETY: `node` is in the same allocation as its container.
252+ let inner = unsafe { kernel:: container_of!( node, Inner <T >, node) } ;
253+
254+ // SAFETY: `inner` is a valid `Inner<T>` pointer.
255+ let inner = unsafe { & * inner } ;
256+
257+ inner. data . revoke ( ) ;
258+ }
259+
260+ #[ allow( clippy:: missing_safety_doc) ]
261+ unsafe extern "C" fn devres_node_free_node ( node : * mut bindings:: devres_node ) {
262+ let node = Opaque :: cast_from ( node) ;
263+
264+ // SAFETY: `node` is in the same allocation as its container.
265+ let inner = unsafe { kernel:: container_of!( node, Inner <T >, node) } ;
167266
168- data. revoke ( ) ;
267+ // SAFETY: `inner` points to the entire `Inner<T>` allocation.
268+ drop ( unsafe { Arc :: from_raw ( inner) } ) ;
169269 }
170270
171- fn remove_action ( & self ) -> bool {
271+ fn remove_node ( & self ) -> bool {
172272 // SAFETY:
173- // - `self.dev` is a valid `Device`,
174- // - the `action` and `data` pointers are the exact same ones as given to
175- // `devm_add_action()` previously,
176- ( unsafe {
177- bindings:: devm_remove_action_nowarn (
178- self . dev . as_raw ( ) ,
179- Some ( self . callback ) ,
180- core:: ptr:: from_ref ( self . data ( ) ) . cast_mut ( ) . cast ( ) ,
181- )
182- } == 0 )
273+ // - `self.device().as_raw()` is a valid pointer to a bound `struct device`.
274+ // - `self.inner.node.get()` is a valid pointer to a `struct devres_node`.
275+ unsafe { base:: devres_node_remove ( self . device ( ) . as_raw ( ) , self . inner . node . get ( ) ) }
183276 }
184277
185278 /// Return a reference of the [`Device`] this [`Devres`] instance has been created with.
@@ -261,12 +354,12 @@ impl<T: Send> Drop for Devres<T> {
261354 // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
262355 // anymore, hence it is safe not to wait for the grace period to finish.
263356 if unsafe { self . data ( ) . revoke_nosync ( ) } {
264- // We revoked `self.data` before the devres action did, hence try to remove it.
265- if self . remove_action ( ) {
357+ // We revoked `self.data` before devres did, hence try to remove it.
358+ if self . remove_node ( ) {
266359 // SAFETY: In `Self::new` we have taken an additional reference count of `self.data`
267- // for `devm_add_action ()`. Since `remove_action ()` was successful, we have to drop
360+ // for `devres_node_add ()`. Since `remove_node ()` was successful, we have to drop
268361 // this additional reference count.
269- drop ( unsafe { Arc :: from_raw ( Arc :: as_ptr ( & self . data ) ) } ) ;
362+ drop ( unsafe { Arc :: from_raw ( Arc :: as_ptr ( & self . inner ) ) } ) ;
270363 }
271364 }
272365 }
0 commit comments