From: Danilo Krummrich <dakr@kernel.org>
To: gregkh@linuxfoundation.org, rafael@kernel.org,
acourbot@nvidia.com, aliceryhl@google.com,
david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org,
viresh.kumar@linaro.org, m.wilczynski@samsung.com,
ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org,
abdiel.janulgue@gmail.com, robin.murphy@arm.com,
markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org,
gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org,
a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev,
daniel.almeida@collabora.com
Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org,
nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org,
Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH 1/3] rust: devres: add DevresLt for ForLt-aware device resource access
Date: Wed, 6 May 2026 23:58:33 +0200 [thread overview]
Message-ID: <20260506220012.855173-2-dakr@kernel.org> (raw)
In-Reply-To: <20260506220012.855173-1-dakr@kernel.org>
Devres<T> stores resources as T and returns &'bound T from access(). For
lifetime-parameterized types like Bar<'bound, SIZE> that are transmuted
to 'static for storage, this exposes the synthetic 'static lifetime to
callers -- any method on the stored type that returns a reference with
its lifetime parameter would yield a &'static reference, which is
unsound.
Add DevresLt<F: ForLt>, a thin wrapper around Devres<F::Of<'static>>
that applies ForLt::cast_ref in all access methods to shorten the stored
'static lifetime to the caller's borrow lifetime.
Devres<T: Send> remains unchanged for static resource types.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/devres.rs | 97 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 90 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 58efe80474bd..c9c698901871 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -24,6 +24,7 @@
Arc, //
},
types::{
+ ForLt,
ForeignOwnable,
Opaque, //
},
@@ -122,7 +123,7 @@ struct Inner<T> {
/// # Ok(())
/// # }
/// ```
-pub struct Devres<T: Send> {
+pub struct Devres<T: Send + 'static> {
dev: ARef<Device>,
inner: Arc<Inner<T>>,
}
@@ -184,7 +185,7 @@ pub(super) unsafe fn devres_node_remove(
}
}
-impl<T: Send> Devres<T> {
+impl<T: Send + 'static> Devres<T> {
/// Creates a new [`Devres`] instance of the given `data`.
///
/// The `data` encapsulated within the returned `Devres` instance' `data` will be
@@ -237,7 +238,7 @@ pub fn new<E>(dev: &Device<Bound>, data: impl PinInit<T, E>) -> Result<Self>
})
}
- fn data(&self) -> &Revocable<T> {
+ pub(crate) fn data(&self) -> &Revocable<T> {
&self.inner.data
}
@@ -297,15 +298,19 @@ pub fn device(&self) -> &Device {
/// #![cfg(CONFIG_PCI)]
/// use kernel::{
/// device::Core,
- /// devres::Devres,
+ /// devres::DevresLt,
/// io::{
/// Io,
/// IoKnownSize, //
/// },
- /// pci, //
+ /// pci,
+ /// types::ForLt, //
/// };
///
- /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<'_, 0x4>>) -> Result {
+ /// fn from_core(
+ /// dev: &pci::Device<Core>,
+ /// devres: DevresLt<ForLt!(pci::Bar<'_, 0x4>)>,
+ /// ) -> Result {
/// let bar = devres.access(dev.as_ref())?;
///
/// let _ = bar.read32(0x0);
@@ -353,7 +358,7 @@ unsafe impl<T: Send> Send for Devres<T> {}
// SAFETY: `Devres` can be shared with any task, if `T: Sync`.
unsafe impl<T: Send + Sync> Sync for Devres<T> {}
-impl<T: Send> Drop for Devres<T> {
+impl<T: Send + 'static> Drop for Devres<T> {
fn drop(&mut self) {
// SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
// anymore, hence it is safe not to wait for the grace period to finish.
@@ -369,6 +374,84 @@ fn drop(&mut self) {
}
}
+/// Guard returned by [`DevresLt::try_access`].
+///
+/// Dereferences to `F::Of<'bound>`, applying [`ForLt::cast_ref`] to shorten the lifetime of the
+/// stored data to the guard's borrow lifetime.
+pub struct DevresGuard<'bound, F: ForLt>(RevocableGuard<'bound, F::Of<'static>>);
+
+impl<'bound, F: ForLt> core::ops::Deref for DevresGuard<'bound, F> {
+ type Target = F::Of<'bound>;
+
+ fn deref(&self) -> &Self::Target {
+ F::cast_ref(&*self.0)
+ }
+}
+
+/// Device-managed resource with [`ForLt`](trait@ForLt)-aware access.
+///
+/// `DevresLt` wraps [`Devres`] and applies [`ForLt::cast_ref`] in its access methods to shorten
+/// the stored `'static` lifetime to the caller's borrow lifetime. This prevents transmuted
+/// `'static` lifetimes from leaking to users.
+///
+/// Use this for resource types that implement [`ForLt`](trait@ForLt) and are stored with a
+/// transmuted `'static` lifetime (e.g. [`pci::Bar`]).
+///
+/// [`pci::Bar`]: crate::pci::Bar
+pub struct DevresLt<F: ForLt>(Devres<F::Of<'static>>)
+where
+ F::Of<'static>: Send;
+
+impl<F: ForLt> DevresLt<F>
+where
+ F::Of<'static>: Send,
+{
+ /// Creates a new [`DevresLt`] instance of the given `data`.
+ pub fn new<E>(dev: &Device<Bound>, data: impl PinInit<F::Of<'static>, E>) -> Result<Self>
+ where
+ Error: From<E>,
+ {
+ Ok(Self(Devres::new(dev, data)?))
+ }
+
+ /// Return a reference of the [`Device`] this [`DevresLt`] instance has been created with.
+ pub fn device(&self) -> &Device {
+ self.0.device()
+ }
+
+ /// Obtain `&'bound F::Of<'bound>`, bypassing the [`Revocable`].
+ ///
+ /// This method works like [`Devres::access`], but shortens the returned reference's lifetime
+ /// from `'static` to `'bound` via [`ForLt::cast_ref`].
+ pub fn access<'bound>(
+ &'bound self,
+ dev: &'bound Device<Bound>,
+ ) -> Result<&'bound F::Of<'bound>> {
+ self.0.access(dev).map(F::cast_ref)
+ }
+
+ /// [`DevresLt`] accessor for [`Revocable::try_access`].
+ pub fn try_access(&self) -> Option<DevresGuard<'_, F>> {
+ self.0.data().try_access().map(DevresGuard)
+ }
+
+ /// [`DevresLt`] accessor for [`Revocable::try_access_with`].
+ pub fn try_access_with<R, G>(&self, f: G) -> Option<R>
+ where
+ G: for<'bound> FnOnce(&'bound F::Of<'bound>) -> R,
+ {
+ self.0.data().try_access_with(|data| f(F::cast_ref(data)))
+ }
+
+ /// [`DevresLt`] accessor for [`Revocable::try_access_with_guard`].
+ pub fn try_access_with_guard<'bound>(
+ &'bound self,
+ guard: &'bound rcu::Guard,
+ ) -> Option<&'bound F::Of<'bound>> {
+ self.0.data().try_access_with_guard(guard).map(F::cast_ref)
+ }
+}
+
/// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound.
fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result
where
--
2.54.0
next prev parent reply other threads:[~2026-05-06 22:00 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-06 21:58 [PATCH 0/3] rust: devres: add DevresLt for ForLt-aware device resource access Danilo Krummrich
2026-05-06 21:58 ` Danilo Krummrich [this message]
2026-05-06 21:58 ` [PATCH 2/3] rust: pci: return DevresLt from Bar::into_devres() Danilo Krummrich
2026-05-06 21:58 ` [PATCH 3/3] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() 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=20260506220012.855173-2-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=abdiel.janulgue@gmail.com \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=david.m.ertman@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=igor.korotin@linux.dev \
--cc=ira.weiny@intel.com \
--cc=kwilczynski@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=m.wilczynski@samsung.com \
--cc=markus.probst@posteo.de \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=ukleinek@kernel.org \
--cc=viresh.kumar@linaro.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.