On Thu, Jun 26, 2025 at 01:37:22PM -0700, Boqun Feng wrote: > On Thu, Jun 26, 2025 at 10:00:43PM +0200, Danilo Krummrich wrote: > > register_release() is useful when a device resource has associated data, > > but does not require the capability of accessing it or manually releasing > > it. > > > > If we would want to be able to access the device resource and release the > > device resource manually before the device is unbound, but still keep > > access to the associated data, we could implement it as follows. > > > > struct Registration<T> { > > inner: Devres<RegistrationInner>, > > data: T, > > } > > > > However, if we never need to access the resource or release it manually, > > register_release() is great optimization for the above, since it does not > > require the synchronization of the Devres type. > > > > Suggested-by: Alice Ryhl <aliceryhl@xxxxxxxxxx> > > Signed-off-by: Danilo Krummrich <dakr@xxxxxxxxxx> > > --- > > rust/kernel/devres.rs | 73 +++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 73 insertions(+) > > > > diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs > > index 3ce8d6161778..92aca78874ff 100644 > > --- a/rust/kernel/devres.rs > > +++ b/rust/kernel/devres.rs > > @@ -353,3 +353,76 @@ pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flag > > > > register_foreign(dev, data) > > } > > + > > +/// [`Devres`]-releaseable resource. > > +/// > > +/// Register an object implementing this trait with [`register_release`]. Its `release` > > +/// function will be called once the device is being unbound. > > +pub trait Release { > > + /// The [`ForeignOwnable`] pointer type consumed by [`register_release`]. > > + type Ptr: ForeignOwnable; > > + > > + /// Called once the [`Device`] given to [`register_release`] is unbound. > > + fn release(this: Self::Ptr); > > +} > > + > > I would like to point out the limitation of this design, say you have a > `Foo` that can ipml `Release`, with this, I think you could only support > either `Arc<Foo>` or `KBox<Foo>`. You cannot support both as the input > for `register_release()`. Maybe we want: > > pub trait Release<Ptr: ForeignOwnable> { > fn release(this: Ptr); > } Good catch! I think this wasn't possible without ForeignOwnable::Target. Here's the diff for the change: diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 92aca78874ff..42a9cd2812d8 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -358,12 +358,9 @@ pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flag /// /// Register an object implementing this trait with [`register_release`]. Its `release` /// function will be called once the device is being unbound. -pub trait Release { - /// The [`ForeignOwnable`] pointer type consumed by [`register_release`]. - type Ptr: ForeignOwnable; - +pub trait Release<Ptr: ForeignOwnable> { /// Called once the [`Device`] given to [`register_release`] is unbound. - fn release(this: Self::Ptr); + fn release(this: Ptr); } /// Consume the `data`, [`Release::release`] and [`Drop::drop`] `data` once `dev` is unbound. @@ -384,9 +381,7 @@ pub trait Release { /// } /// } /// -/// impl Release for Registration { -/// type Ptr = Arc<Self>; -/// +/// impl Release<Arc<Self>> for Registration { /// fn release(this: Arc<Self>) { /// // unregister /// } @@ -401,7 +396,7 @@ pub trait Release { pub fn register_release<P>(dev: &Device<Bound>, data: P) -> Result where P: ForeignOwnable, - P::Target: Release<Ptr = P> + Send, + P::Target: Release<P> + Send, { let ptr = data.into_foreign(); @@ -409,7 +404,7 @@ pub fn register_release<P>(dev: &Device<Bound>, data: P) -> Result unsafe extern "C" fn callback<P>(ptr: *mut kernel::ffi::c_void) where P: ForeignOwnable, - P::Target: Release<Ptr = P>, + P::Target: Release<P>, { // SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid. let data = unsafe { P::from_foreign(ptr.cast()) };