From: Danilo Krummrich <dakr@kernel.org>
To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org,
alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net,
bjorn3_gh@protonmail.com, benno.lossin@proton.me,
a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu
Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH 4/4] rust: devres: implement register_foreign_release()
Date: Thu, 12 Jun 2025 16:51:41 +0200 [thread overview]
Message-ID: <20250612145145.12143-5-dakr@kernel.org> (raw)
In-Reply-To: <20250612145145.12143-1-dakr@kernel.org>
register_foreign_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_foreign_release() is great optimization for the above, since it
does not require the synchronization of the Devres type.
Suggested-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/devres.rs | 80 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 4ee9037f4ad4..495dca6240fc 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -16,6 +16,7 @@
sync::{rcu, Completion},
types::{ARef, ForeignOwnable},
};
+use core::ops::Deref;
/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to
/// manage their lifetime.
@@ -303,3 +304,82 @@ pub fn register_foreign_boxed<T, E>(
register_foreign(dev, data)
}
+
+/// To be implemented by an object passed to [`register_foreign_release`].
+pub trait Release {
+ /// Called once the [`Device`] given to [`register_foreign_release`] is unbound.
+ fn release(&self);
+}
+
+impl<T: Release> Release for crate::sync::ArcBorrow<'_, T> {
+ fn release(&self) {
+ self.deref().release();
+ }
+}
+
+impl<T: Release> Release for Pin<&'_ T> {
+ fn release(&self) {
+ self.deref().release();
+ }
+}
+
+/// Consume the `data`, [`Release::release`] and [`Drop::drop`] `data` once `dev` is unbound.
+///
+/// # Examples
+///
+/// ```no_run
+/// use kernel::{device::{Bound, Device}, devres, devres::Release, sync::Arc};
+///
+/// struct Registration<T> {
+/// data: T,
+/// }
+///
+/// impl<T> Registration<T> {
+/// fn new(data: T) -> Result<Arc<Self>> {
+/// // register (e.g. class device, IRQ, etc.)
+///
+/// Ok(Arc::new(Self { data }, GFP_KERNEL)?)
+/// }
+/// }
+///
+/// impl<T> Release for Registration<T> {
+/// fn release(&self) {
+/// // unregister
+/// }
+/// }
+///
+/// fn from_bound_context(dev: &Device<Bound>) -> Result {
+/// let reg = Registration::new(0x42)?;
+///
+/// devres::register_foreign_release(dev, reg.clone())
+/// }
+/// ```
+pub fn register_foreign_release<P>(dev: &Device<Bound>, data: P) -> Result
+where
+ P: ForeignOwnable,
+ for<'a> P::Borrowed<'a>: Release,
+{
+ let ptr = data.into_foreign();
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe extern "C" fn callback<P>(ptr: *mut kernel::ffi::c_void)
+ where
+ P: ForeignOwnable,
+ for<'a> P::Borrowed<'a>: Release,
+ {
+ // SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid.
+ unsafe { P::borrow(ptr.cast()) }.release();
+
+ // SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid.
+ let _ = unsafe { P::from_foreign(ptr.cast()) };
+ }
+
+ // SAFETY:
+ // - `dev.as_raw()` is a pointer to a valid and bound device.
+ // - `ptr` is a valid pointer the `ForeignOwnable` devres takes ownership of.
+ to_result(unsafe {
+ // `devm_add_action_or_reset()` also calls `callback` on failure, such that the
+ // `ForeignOwnable` is released eventually.
+ bindings::devm_add_action_or_reset(dev.as_raw(), Some(callback::<P>), ptr.cast())
+ })
+}
--
2.49.0
next prev parent reply other threads:[~2025-06-12 14:52 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-12 14:51 [PATCH 0/4] Improvements for Devres Danilo Krummrich
2025-06-12 14:51 ` [PATCH 1/4] rust: revocable: support fallible PinInit types Danilo Krummrich
2025-06-12 15:48 ` Benno Lossin
2025-06-12 15:58 ` Danilo Krummrich
2025-06-12 16:17 ` Benno Lossin
2025-06-12 16:20 ` Danilo Krummrich
2025-06-12 14:51 ` [PATCH 2/4] rust: devres: replace Devres::new_foreign_owned() Danilo Krummrich
2025-06-13 3:14 ` Viresh Kumar
2025-06-21 21:10 ` Benno Lossin
2025-06-21 21:45 ` Danilo Krummrich
2025-06-22 7:42 ` Benno Lossin
2025-06-22 9:55 ` Danilo Krummrich
2025-06-22 20:18 ` Benno Lossin
2025-06-12 14:51 ` [PATCH 3/4] rust: devres: get rid of Devres' inner Arc Danilo Krummrich
2025-06-22 7:05 ` Benno Lossin
2025-06-22 12:08 ` Danilo Krummrich
2025-06-22 20:16 ` Benno Lossin
2025-06-22 15:45 ` Danilo Krummrich
2025-06-22 20:15 ` Benno Lossin
2025-06-12 14:51 ` Danilo Krummrich [this message]
2025-06-22 7:26 ` [PATCH 4/4] rust: devres: implement register_foreign_release() Benno Lossin
2025-06-22 12:46 ` Danilo Krummrich
2025-06-22 20:14 ` Benno Lossin
2025-06-22 20:25 ` Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250612145145.12143-5-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).