NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
* [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt
@ 2026-06-03  1:10 Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

The ForLt trait currently guarantees covariance, which allows safe
lifetime shortening via cast_ref(). However, some types (e.g. those
containing Mutex<&'bound T>) are invariant over their lifetime parameter
and cannot safely use cast_ref().

This series splits ForLt into two traits:

  - ForLt: base trait providing unsafe cast_ref_unchecked() for all
    lifetime-parameterized types.

  - CovariantForLt: unsafe subtrait that guarantees covariance,
    providing a safe cast_ref() method.

For invariant types, a closure-based API (registration_data_with()) is
added to the auxiliary subsystem. The closure's HRTB prevents the caller
from choosing a concrete lifetime, which would be unsound for invariant
types.

On top of that, this series adds DevresLt<F: ForLt>, a thin wrapper
around Devres<F::Of<'static>> that shortens the stored 'static lifetime
back to the caller's borrow scope. DevresLt provides both closure-based
access (access_with/try_access_with for ForLt types) and direct
reference access (access/try_access for CovariantForLt types).

Also implement ForLt and CovariantForLt for Bar, IoMem and
ExclusiveIoMem, and update their into_devres() methods to return
DevresLt. Provide convenience type aliases DevresBar, DevresIoMem and
DevresExclusiveIoMem.

Changes in v2:
- Fold the ForLt -> CovariantForLt rename and the new ForLt base trait
  into this series
- Add closure-based registration_data_with() for auxiliary ForLt types
- Add auxiliary sample demonstrating ForLt with an invariant Mutex type
- DevresLt: add closure-based access_with()/try_access_with() for ForLt
  types alongside direct access()/try_access() for CovariantForLt types
- Make DevresLt::new() unsafe; callers must guarantee the data outlives
  the device binding
- Implement both ForLt and CovariantForLt (previously just ForLt) for
  Bar, IoMem, ExclusiveIoMem
- Various safety comment and documentation improvements

Danilo Krummrich (7):
  rust: types: rename ForLt to CovariantForLt
  rust: types: introduce ForLt base trait for CovariantForLt
  rust: auxiliary: add registration_data_with() for ForLt types
  rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type
  rust: devres: add DevresLt for ForLt-aware device resource access
  rust: pci: return DevresLt from Bar::into_devres()
  rust: io: mem: return DevresLt from
    IoMem/ExclusiveIoMem::into_devres()

 drivers/gpu/nova-core/driver.rs       |   4 +-
 drivers/pwm/pwm_th1520.rs             |   5 +-
 rust/kernel/auxiliary.rs              |  74 +++++++++++++---
 rust/kernel/devres.rs                 | 110 +++++++++++++++++++++++
 rust/kernel/io/mem.rs                 |  65 +++++++++-----
 rust/kernel/pci.rs                    |   1 +
 rust/kernel/pci/io.rs                 |  37 +++++---
 rust/kernel/types.rs                  |   1 +
 rust/kernel/types/for_lt.rs           | 122 ++++++++++++++++++++------
 rust/macros/for_lt.rs                 |  52 ++++++++---
 rust/macros/lib.rs                    |  18 +++-
 samples/rust/rust_driver_auxiliary.rs |  96 ++++++++++++++------
 12 files changed, 472 insertions(+), 113 deletions(-)


base-commit: 0023a1e8d01a9d400257d30c851bd16a29568809
-- 
2.54.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03 11:59   ` Gary Guo
  2026-06-03  1:10 ` [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt Danilo Krummrich
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Rename ForLt to CovariantForLt to prepare for the introduction of a new
ForLt base trait that does not require covariance.

The existing ForLt trait requires covariance, which enables the safe
cast_ref() method. This rename preserves the same semantics under a more
precise name, making room for a weaker ForLt trait in a subsequent
commit.

No functional change.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 drivers/gpu/nova-core/driver.rs       |  4 +-
 rust/kernel/auxiliary.rs              | 23 +++++-----
 rust/kernel/types.rs                  |  2 +-
 rust/kernel/types/for_lt.rs           | 61 ++++++++++++++-------------
 rust/macros/for_lt.rs                 |  4 +-
 rust/macros/lib.rs                    | 11 +++--
 samples/rust/rust_driver_auxiliary.rs |  8 ++--
 7 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index ade73da68be5..dce8b3b8dc6f 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -15,7 +15,7 @@
         Atomic,
         Relaxed, //
     },
-    types::ForLt,
+    types::CovariantForLt,
 };
 
 use crate::gpu::Gpu;
@@ -29,7 +29,7 @@ pub(crate) struct NovaCore<'bound> {
     pub(crate) gpu: Gpu<'bound>,
     bar: pci::Bar<'bound, BAR0_SIZE>,
     #[allow(clippy::type_complexity)]
-    _reg: auxiliary::Registration<'bound, ForLt!(())>,
+    _reg: auxiliary::Registration<'bound, CovariantForLt!(())>,
 }
 
 pub(crate) struct NovaCoreDriver;
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index c42928d5a239..40a0af74a8e5 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -20,7 +20,7 @@
     },
     prelude::*,
     types::{
-        ForLt,
+        CovariantForLt,
         ForeignOwnable,
         Opaque, //
     },
@@ -272,16 +272,16 @@ pub fn parent(&self) -> &device::Device<device::Bound> {
 
     /// Returns a pinned reference to the registration data set by the registering (parent) driver.
     ///
-    /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned
+    /// `F` is the [`CovariantForLt`](trait@CovariantForLt) encoding of the data type. The returned
     /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via
-    /// [`ForLt::cast_ref`].
+    /// [`CovariantForLt::cast_ref`].
     ///
     /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
     /// [`Registration::new()`].
     ///
     /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
     /// registered by a C driver.
-    pub fn registration_data<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
+    pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
         // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.
         let ptr = unsafe { (*self.as_raw()).registration_data_rust };
         if ptr.is_null() {
@@ -399,8 +399,9 @@ struct RegistrationData<T> {
 /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device
 /// is unbound, the corresponding auxiliary device will be unregistered from the system.
 ///
-/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration
-/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).
+/// The type parameter `F` is a [`CovariantForLt`](trait@CovariantForLt) encoding of the
+/// registration data type. For non-lifetime-parameterized types, use
+/// [`CovariantForLt!(T)`](macro@CovariantForLt).
 /// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].
 ///
 /// # Invariants
@@ -408,12 +409,12 @@ struct RegistrationData<T> {
 /// `self.adev` always holds a valid pointer to an initialized and registered
 /// [`struct auxiliary_device`] whose `registration_data_rust` field points to a
 /// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`.
-pub struct Registration<'a, F: ForLt + 'static> {
+pub struct Registration<'a, F: CovariantForLt + 'static> {
     adev: NonNull<bindings::auxiliary_device>,
     _phantom: PhantomData<F::Of<'a>>,
 }
 
-impl<'a, F: ForLt> Registration<'a, F>
+impl<'a, F: CovariantForLt> Registration<'a, F>
 where
     for<'b> F::Of<'b>: Send + Sync,
 {
@@ -525,7 +526,7 @@ pub fn new<E>(
     }
 }
 
-impl<F: ForLt> Drop for Registration<'_, F> {
+impl<F: CovariantForLt> Drop for Registration<'_, F> {
     fn drop(&mut self) {
         // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered
         // `struct auxiliary_device`.
@@ -547,7 +548,7 @@ fn drop(&mut self) {
 }
 
 // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.
-unsafe impl<F: ForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
+unsafe impl<F: CovariantForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
 
 // SAFETY: `Registration` does not expose any methods or fields that need synchronization.
-unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
+unsafe impl<F: CovariantForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index ac316fd7b538..cbe6907042d3 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -13,7 +13,7 @@
 
 #[doc(hidden)]
 pub mod for_lt;
-pub use for_lt::ForLt;
+pub use for_lt::CovariantForLt;
 
 /// Used to transfer ownership to and from foreign (non-Rust) languages.
 ///
diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
index d44323c28e8d..ef510ab6c092 100644
--- a/rust/kernel/types/for_lt.rs
+++ b/rust/kernel/types/for_lt.rs
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: Apache-2.0 OR MIT
 
-//! Provide implementation and test of the `ForLt` trait and macro.
+//! Provide implementation and test of the `CovariantForLt` trait and macro.
 //!
-//! This module is hidden and user should just use `ForLt!` directly.
+//! This module is hidden and user should just use `CovariantForLt!` directly.
 
 use core::marker::PhantomData;
 
@@ -15,38 +15,39 @@
 ///
 /// # Macro
 ///
-/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
-/// type that implements this trait.
+/// It is not recommended to implement this trait directly. `CovariantForLt!` macro is provided to
+/// obtain a type that implements this trait.
 ///
 /// The full syntax is
 ///
 /// ```
-/// # use kernel::types::ForLt;
-/// # fn expect_lt<F: ForLt>() {}
+/// # use kernel::types::CovariantForLt;
+/// # fn expect_lt<F: CovariantForLt>() {}
 /// # struct TypeThatUse<'a>(&'a ());
 /// # expect_lt::<
-/// ForLt!(for<'a> TypeThatUse<'a>)
+/// CovariantForLt!(for<'a> TypeThatUse<'a>)
 /// # >();
 /// ```
 ///
-/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
+/// which gives a type so that
+/// `<CovariantForLt!(for<'a> TypeThatUse<'a>) as CovariantForLt>::Of<'b>`
 /// is `TypeThatUse<'b>`.
 ///
 /// You may also use a short-hand syntax which works similar to lifetime elision.
 /// The macro also accepts types that do not involve a lifetime at all.
 ///
 /// ```
-/// # use kernel::types::ForLt;
-/// # fn expect_lt<F: ForLt>() {}
+/// # use kernel::types::CovariantForLt;
+/// # fn expect_lt<F: CovariantForLt>() {}
 /// # struct TypeThatUse<'a>(&'a ());
 /// # expect_lt::<
-/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
+/// CovariantForLt!(TypeThatUse<'_>) // Equivalent to `CovariantForLt!(for<'a> TypeThatUse<'a>)`.
 /// # >();
 /// # expect_lt::<
-/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
+/// CovariantForLt!(&u32) // Equivalent to `CovariantForLt!(for<'a> &'a u32)`.
 /// # >();
 /// # expect_lt::<
-/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
+/// CovariantForLt!(u32) // Equivalent to `CovariantForLt!(for<'a> u32)`.
 /// # >();
 /// ```
 ///
@@ -55,10 +56,10 @@
 /// it.
 ///
 /// ```ignore,compile_fail
-/// # use kernel::types::ForLt;
-/// # fn expect_lt<F: ForLt>() {}
+/// # use kernel::types::CovariantForLt;
+/// # fn expect_lt<F: CovariantForLt>() {}
 /// # expect_lt::<
-/// ForLt!(fn(&u32)) // Contravariant, will fail compilation.
+/// CovariantForLt!(fn(&u32)) // Contravariant, will fail compilation.
 /// # >();
 /// ```
 ///
@@ -67,23 +68,23 @@
 /// the generic parameter but is in a separate item.
 ///
 /// ```
-/// # use kernel::types::ForLt;
-/// fn expect_lt<F: ForLt>() {}
+/// # use kernel::types::CovariantForLt;
+/// fn expect_lt<F: CovariantForLt>() {}
 /// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
 /// fn generic_fn<T: 'static>() {
 ///     // Syntactically proven by the macro
-///     expect_lt::<ForLt!(&T)>();
+///     expect_lt::<CovariantForLt!(&T)>();
 ///     // Syntactically proven by the macro
-///     expect_lt::<ForLt!(&KBox<T>)>();
+///     expect_lt::<CovariantForLt!(&KBox<T>)>();
 ///     // Cannot be syntactically proven, need to check covariance of `KBox`
-///     // expect_lt::<ForLt!(&KBox<&T>)>();
+///     // expect_lt::<CovariantForLt!(&KBox<&T>)>();
 /// }
 /// ```
 ///
 /// # Safety
 ///
 /// `Self::Of<'a>` must be covariant over the lifetime `'a`.
-pub unsafe trait ForLt {
+pub unsafe trait CovariantForLt {
     /// The type parameterized by the lifetime.
     type Of<'a>: 'a;
 
@@ -94,11 +95,11 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
         unsafe { core::mem::transmute(long) }
     }
 }
-pub use macros::ForLt;
+pub use macros::CovariantForLt;
 
-/// This is intended to be an "unsafe-to-refer-to" type.
+/// Helper type for the `CovariantForLt!` macro.
 ///
-/// Must only be used by the `ForLt!` macro.
+/// Must only be used by the `CovariantForLt!` macro.
 ///
 /// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
 ///
@@ -107,16 +108,16 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
 /// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
 /// additional properties.
 #[doc(hidden)]
-pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
+pub struct CovariantForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
 
-// This is a helper trait for implementation `ForLt` to be able to use HRTB.
+// This is a helper trait for implementation `CovariantForLt` to be able to use HRTB.
 #[doc(hidden)]
 pub trait WithLt<'a> {
     type Of: 'a;
 }
 
-// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`
-// and it will fail to evaluate if the type is not covariant.
-unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {
+// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated when naming
+// `CovariantForLtImpl` and it will fail to evaluate if the type is not covariant.
+unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for CovariantForLtImpl<T, WF, 0> {
     type Of<'a> = <T as WithLt<'a>>::Of;
 }
diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs
index 364d4113cd10..3cb094d00548 100644
--- a/rust/macros/for_lt.rs
+++ b/rust/macros/for_lt.rs
@@ -176,7 +176,7 @@ fn prove(&mut self, ty: &'a Type) {
     }
 }
 
-pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {
+pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
     let (ty, lifetime) = match input {
         HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),
         HigherRankedType::Implicit { ty } => {
@@ -235,7 +235,7 @@ fn #cov_proof_name<'__short, '__long: '__short>(
     );
 
     quote!(
-        ::kernel::types::for_lt::UnsafeForLtImpl::<
+        ::kernel::types::for_lt::CovariantForLtImpl::<
             dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,
             #ty_static,
             {
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 4a48fabbc268..2167cb270928 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -491,14 +491,13 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
         .into()
 }
 
-/// Obtain a type that implements [`ForLt`] for the given higher-ranked type.
+/// Obtain a type that implements [`CovariantForLt`] for the given higher-ranked type.
 ///
-/// Please refer to the documentation of the [`ForLt`] trait.
+/// Please refer to the documentation of the [`CovariantForLt`] trait.
 ///
-/// [`ForLt`]: trait.ForLt.html
+/// [`CovariantForLt`]: trait.CovariantForLt.html
 #[proc_macro]
-// The macro shares the name with the trait.
 #[allow(non_snake_case)]
-pub fn ForLt(input: TokenStream) -> TokenStream {
-    for_lt::for_lt(parse_macro_input!(input)).into()
+pub fn CovariantForLt(input: TokenStream) -> TokenStream {
+    for_lt::covariant_for_lt(parse_macro_input!(input)).into()
 }
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 2c1351040e45..92ee6a6d348e 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -13,7 +13,7 @@
     driver,
     pci,
     prelude::*,
-    types::ForLt,
+    types::CovariantForLt,
     InPlaceModule, //
 };
 
@@ -60,8 +60,8 @@ struct Data<'bound> {
 
 #[allow(clippy::type_complexity)]
 struct ParentData<'bound> {
-    _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
-    _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
+    _reg0: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
+    _reg1: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
 }
 
 kernel::pci_device_table!(
@@ -115,7 +115,7 @@ fn probe<'bound>(
 
 impl ParentDriver {
     fn connect(adev: &auxiliary::Device<Bound>) -> Result {
-        let data = adev.registration_data::<ForLt!(Data<'_>)>()?;
+        let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
         let pdev = data.parent;
 
         dev_info!(
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03 12:04   ` Gary Guo
  2026-06-03  1:10 ` [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types Danilo Krummrich
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Add a new ForLt trait as a base for CovariantForLt:

  - ForLt (non-unsafe): represents a type generic over a lifetime, with
    no covariance guarantee.  Provides unsafe fn cast_ref_unchecked()
    for callers that can justify lifetime shortening via a round-trip
    safety argument.

  - CovariantForLt (unsafe): becomes a subtrait of ForLt that
    additionally proves the type is covariant over its lifetime
    parameter, providing a safe cast_ref() method.

This split allows non-covariant types (e.g. types behind a Mutex) to
implement ForLt and participate in DevresLt / registration data patterns
where the round-trip argument suffices, without requiring a covariance
proof that would fail to compile.

The internal macro backend is split accordingly: ForLt! emits ForLtImpl
(no covariance proof), CovariantForLt! emits CovariantForLtImpl (with
compile-time covariance proof).

No existing callers change; they all use CovariantForLt.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/types.rs        |   1 +
 rust/kernel/types/for_lt.rs | 101 ++++++++++++++++++++++++++++++------
 rust/macros/for_lt.rs       |  50 ++++++++++++++----
 rust/macros/lib.rs          |  19 ++++++-
 4 files changed, 145 insertions(+), 26 deletions(-)

diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index cbe6907042d3..c1ed05d1046c 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -14,6 +14,7 @@
 #[doc(hidden)]
 pub mod for_lt;
 pub use for_lt::CovariantForLt;
+pub use for_lt::ForLt;
 
 /// Used to transfer ownership to and from foreign (non-Rust) languages.
 ///
diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
index ef510ab6c092..e1774b03dd1f 100644
--- a/rust/kernel/types/for_lt.rs
+++ b/rust/kernel/types/for_lt.rs
@@ -1,17 +1,74 @@
 // SPDX-License-Identifier: Apache-2.0 OR MIT
 
-//! Provide implementation and test of the `CovariantForLt` trait and macro.
+//! Provide implementation and test of the `ForLt` and `CovariantForLt` traits and macros.
 //!
-//! This module is hidden and user should just use `CovariantForLt!` directly.
+//! This module is hidden and users should just use `ForLt!` / `CovariantForLt!` directly.
 
 use core::marker::PhantomData;
 
 /// Representation of types generic over a lifetime.
 ///
-/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter
-/// can be soundly shortened.
+/// # Macro
+///
+/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
+/// type that implements this trait.
+///
+/// The full syntax is
+///
+/// ```
+/// # use kernel::types::ForLt;
+/// # fn expect_lt<F: ForLt>() {}
+/// # struct TypeThatUse<'a>(&'a ());
+/// # expect_lt::<
+/// ForLt!(for<'a> TypeThatUse<'a>)
+/// # >();
+/// ```
+///
+/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
+/// is `TypeThatUse<'b>`.
+///
+/// You may also use a short-hand syntax which works similar to lifetime elision.
+/// The macro also accepts types that do not involve a lifetime at all.
+///
+/// ```
+/// # use kernel::types::ForLt;
+/// # fn expect_lt<F: ForLt>() {}
+/// # struct TypeThatUse<'a>(&'a ());
+/// # expect_lt::<
+/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
+/// # >();
+/// # expect_lt::<
+/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
+/// # >();
+/// # expect_lt::<
+/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
+/// # >();
+/// ```
+pub trait ForLt {
+    /// The type parameterized by the lifetime.
+    type Of<'a>: 'a;
+
+    /// Cast a reference to a shorter lifetime.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the lifetime shortening is sound for their use case,
+    /// e.g. because the `'long` reference originated from a `'short`-to-`'static` transmute
+    /// and this is the reverse leg of that round-trip.
+    #[inline(always)]
+    unsafe fn cast_ref_unchecked<'r, 'short: 'r, 'long: 'short>(
+        long: &'r Self::Of<'long>,
+    ) -> &'r Self::Of<'short> {
+        // SAFETY: Caller guarantees the lifetime shortening is sound.
+        unsafe { core::mem::transmute(long) }
+    }
+}
+pub use macros::ForLt;
+
+/// [`trait@ForLt`] subtrait for types that are covariant over their lifetime parameter.
 ///
-/// The lifetime involved must be covariant.
+/// Provides a safe [`cast_ref`](CovariantForLt::cast_ref) method for types that are proven to be
+/// covariant. The `CovariantForLt!` macro syntax is the same as `ForLt!`.
 ///
 /// # Macro
 ///
@@ -84,10 +141,7 @@
 /// # Safety
 ///
 /// `Self::Of<'a>` must be covariant over the lifetime `'a`.
-pub unsafe trait CovariantForLt {
-    /// The type parameterized by the lifetime.
-    type Of<'a>: 'a;
-
+pub unsafe trait CovariantForLt: ForLt {
     /// Cast a reference to a shorter lifetime.
     #[inline(always)]
     fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {
@@ -97,27 +151,44 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
 }
 pub use macros::CovariantForLt;
 
-/// Helper type for the `CovariantForLt!` macro.
+/// Helper type for the `ForLt!` macro.
 ///
-/// Must only be used by the `CovariantForLt!` macro.
+/// Must only be used by the `ForLt!` macro.
 ///
 /// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
 ///
 /// `WF` is a type that the macro can use to assert some specific type is well-formed.
+#[doc(hidden)]
+pub struct ForLtImpl<T: ?Sized, WF>(PhantomData<(WF, T)>);
+
+/// Helper type for the `CovariantForLt!` macro.
+///
+/// Must only be used by the `CovariantForLt!` macro.
+///
+/// `T` and `WF` are the same as in [`ForLtImpl`].
 ///
 /// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
 /// additional properties.
 #[doc(hidden)]
 pub struct CovariantForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
 
-// This is a helper trait for implementation `CovariantForLt` to be able to use HRTB.
+// This is a helper trait for implementation `ForLt` to be able to use HRTB.
 #[doc(hidden)]
 pub trait WithLt<'a> {
     type Of: 'a;
 }
 
-// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated when naming
-// `CovariantForLtImpl` and it will fail to evaluate if the type is not covariant.
-unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for CovariantForLtImpl<T, WF, 0> {
+impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for ForLtImpl<T, WF> {
+    type Of<'a> = <T as WithLt<'a>>::Of;
+}
+
+impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> ForLt for CovariantForLtImpl<T, WF, N> {
     type Of<'a> = <T as WithLt<'a>>::Of;
 }
+
+// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated in the `N` const generic
+// and it will fail to evaluate if the type is not covariant.
+unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> CovariantForLt
+    for CovariantForLtImpl<T, WF, N>
+{
+}
diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs
index 3cb094d00548..ad9809563fab 100644
--- a/rust/macros/for_lt.rs
+++ b/rust/macros/for_lt.rs
@@ -176,8 +176,10 @@ fn prove(&mut self, ty: &'a Type) {
     }
 }
 
-pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
-    let (ty, lifetime) = match input {
+/// Resolve the higher-ranked type into a concrete `(ty, lifetime)` pair, expanding elided
+/// lifetimes as needed. Shared by both `for_lt` and `covariant_for_lt`.
+fn resolve_hrt(input: HigherRankedType) -> (Type, Lifetime) {
+    match input {
         HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),
         HigherRankedType::Implicit { ty } => {
             // If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime
@@ -188,7 +190,41 @@ pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
             };
             (ty.expand_elided_lifetime(&lifetime), lifetime)
         }
-    };
+    }
+}
+
+/// Produce the `'static`-substituted type for the WF check. Shared by both macros.
+fn ty_static(ty: &Type, lifetime: &Lifetime) -> Type {
+    ty.replace_lifetime(
+        lifetime,
+        &Lifetime {
+            apostrophe: Span::mixed_site(),
+            ident: format_ident!("static"),
+        },
+    )
+}
+
+pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {
+    let (ty, lifetime) = resolve_hrt(input);
+
+    // Make sure that the type is wellformed when substituting lifetime with `'static`.
+    //
+    // Currently the Rust compiler doesn't check this, see the `ProveWf` documentation in
+    // `covariant_for_lt` below.
+    //
+    // We prefer to use this way of proving WF-ness as it can work when generics are involved.
+    let ty_static = ty_static(&ty, &lifetime);
+
+    quote!(
+        ::kernel::types::for_lt::ForLtImpl::<
+            dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,
+            #ty_static,
+        >
+    )
+}
+
+pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
+    let (ty, lifetime) = resolve_hrt(input);
 
     let mut prover = Prover(&lifetime, Vec::new());
     prover.prove(&ty);
@@ -226,13 +262,7 @@ fn #cov_proof_name<'__short, '__long: '__short>(
     // Currently the Rust compiler doesn't check this, see the above `ProveWf` documentation.
     //
     // We prefer to use this way of proving WF-ness as it can work when generics are involved.
-    let ty_static = ty.replace_lifetime(
-        &lifetime,
-        &Lifetime {
-            apostrophe: Span::mixed_site(),
-            ident: format_ident!("static"),
-        },
-    );
+    let ty_static = ty_static(&ty, &lifetime);
 
     quote!(
         ::kernel::types::for_lt::CovariantForLtImpl::<
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 2167cb270928..e970769609f3 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -491,11 +491,28 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
         .into()
 }
 
-/// Obtain a type that implements [`CovariantForLt`] for the given higher-ranked type.
+/// Obtain a type that implements [`ForLt`] for the given higher-ranked type.
+///
+/// Please refer to the documentation of the [`ForLt`] trait.
+///
+/// [`ForLt`]: trait.ForLt.html
+#[proc_macro]
+#[allow(non_snake_case)]
+pub fn ForLt(input: TokenStream) -> TokenStream {
+    for_lt::for_lt(parse_macro_input!(input)).into()
+}
+
+/// Obtain a type that implements [`CovariantForLt`] (and [`ForLt`]) for the given higher-ranked
+/// type.
+///
+/// Unlike [`ForLt!`], this macro additionally proves that the type is covariant over the lifetime,
+/// providing a safe [`CovariantForLt::cast_ref`] method.
 ///
 /// Please refer to the documentation of the [`CovariantForLt`] trait.
 ///
 /// [`CovariantForLt`]: trait.CovariantForLt.html
+/// [`CovariantForLt::cast_ref`]: trait.CovariantForLt.html#method.cast_ref
+/// [`ForLt`]: trait.ForLt.html
 #[proc_macro]
 #[allow(non_snake_case)]
 pub fn CovariantForLt(input: TokenStream) -> TokenStream {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03 12:05   ` Gary Guo
  2026-06-03  1:10 ` [PATCH v2 4/7] rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type Danilo Krummrich
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Add registration_data_with() taking a for<'a> closure that receives
Pin<&'a F::Of<'a>>, which works with any ForLt type. Taking a for<'a>
closure rather than returning a direct reference prevents callers from
choosing a concrete lifetime for the data, which is required for
soundness with non-covariant ForLt types.

Extract the common null-check, TypeId-check and KBox-borrow logic into a
private registration_data_pinned() helper shared by both
registration_data_with() and the existing registration_data().

Relax Registration's bound from CovariantForLt to ForLt so that
non-covariant types can be registered.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/auxiliary.rs | 89 ++++++++++++++++++++++++++++++----------
 1 file changed, 68 insertions(+), 21 deletions(-)

diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 40a0af74a8e5..81549a3e347e 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -21,6 +21,7 @@
     prelude::*,
     types::{
         CovariantForLt,
+        ForLt,
         ForeignOwnable,
         Opaque, //
     },
@@ -270,18 +271,15 @@ pub fn parent(&self) -> &device::Device<device::Bound> {
         unsafe { parent.as_bound() }
     }
 
-    /// Returns a pinned reference to the registration data set by the registering (parent) driver.
+    /// Returns the stored registration data as a pinned `'static` reference.
     ///
-    /// `F` is the [`CovariantForLt`](trait@CovariantForLt) encoding of the data type. The returned
-    /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via
-    /// [`CovariantForLt::cast_ref`].
+    /// Performs null and [`TypeId`] checks, then borrows the stored [`KBox`].
     ///
-    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
-    /// [`Registration::new()`].
+    /// # Safety
     ///
-    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
-    /// registered by a C driver.
-    pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
+    /// The returned `'static` lifetime was transmuted from the device's bound lifetime during
+    /// registration. Callers must shorten it before exposing it.
+    unsafe fn registration_data_pinned<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'static>>> {
         // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.
         let ptr = unsafe { (*self.as_raw()).registration_data_rust };
         if ptr.is_null() {
@@ -306,10 +304,58 @@ pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::O
         let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };
 
         // SAFETY: `data` is a structurally pinned field of `RegistrationData`.
-        let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) };
+        Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })
+    }
+
+    /// Access the registration data set by the registering (parent) driver through a closure.
+    ///
+    /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The closure receives a pinned
+    /// reference to the registration data.
+    ///
+    /// For covariant types that implement [`trait@CovariantForLt`], prefer
+    /// [`registration_data`](Self::registration_data) which returns a direct reference.
+    ///
+    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
+    /// [`Registration::new()`].
+    ///
+    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
+    /// registered by a C driver.
+    pub fn registration_data_with<F: ForLt + 'static, R>(
+        &self,
+        f: impl for<'a> FnOnce(Pin<&'a F::Of<'a>>) -> R,
+    ) -> Result<R> {
+        // SAFETY: The HRTB closure prevents the caller from smuggling in references with a
+        // concrete short lifetime, making the round-trip from `'static` sound regardless of
+        // variance.
+        let pinned = unsafe { self.registration_data_pinned::<F>()? };
+
+        // SAFETY: See above; the closure's HRTB makes the round-trip sound.
+        let short = unsafe { F::cast_ref_unchecked(pinned.get_ref()) };
+
+        // SAFETY: The data was pinned before the lifetime was shortened; pinning is
+        // orthogonal to lifetimes.
+        Ok(f(unsafe { Pin::new_unchecked(short) }))
+    }
 
-        // SAFETY: The data was pinned when stored; `cast_ref` only shortens
-        // the lifetime, so the pinning guarantee is preserved.
+    /// Returns a pinned reference to the registration data set by the registering (parent) driver.
+    ///
+    /// This method is only available when `F` implements [`trait@CovariantForLt`], which guarantees
+    /// safe lifetime shortening via [`CovariantForLt::cast_ref`].
+    ///
+    /// For non-covariant types, use the closure-based [`Self::registration_data_with`].
+    ///
+    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
+    /// [`Registration::new()`].
+    ///
+    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
+    /// registered by a C driver.
+    pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
+        // SAFETY: CovariantForLt guarantees covariance, so cast_ref safely shortens the
+        // `'static` lifetime.
+        let pinned = unsafe { self.registration_data_pinned::<F>()? };
+
+        // SAFETY: The data was pinned before the lifetime was shortened; pinning is orthogonal
+        // to lifetimes.
         Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })
     }
 }
@@ -399,22 +445,23 @@ struct RegistrationData<T> {
 /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device
 /// is unbound, the corresponding auxiliary device will be unregistered from the system.
 ///
-/// The type parameter `F` is a [`CovariantForLt`](trait@CovariantForLt) encoding of the
-/// registration data type. For non-lifetime-parameterized types, use
-/// [`CovariantForLt!(T)`](macro@CovariantForLt).
-/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].
+/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration
+/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).
+///
+/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`] and
+/// [`Device::registration_data_with()`].
 ///
 /// # Invariants
 ///
 /// `self.adev` always holds a valid pointer to an initialized and registered
 /// [`struct auxiliary_device`] whose `registration_data_rust` field points to a
 /// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`.
-pub struct Registration<'a, F: CovariantForLt + 'static> {
+pub struct Registration<'a, F: ForLt + 'static> {
     adev: NonNull<bindings::auxiliary_device>,
     _phantom: PhantomData<F::Of<'a>>,
 }
 
-impl<'a, F: CovariantForLt> Registration<'a, F>
+impl<'a, F: ForLt> Registration<'a, F>
 where
     for<'b> F::Of<'b>: Send + Sync,
 {
@@ -526,7 +573,7 @@ pub fn new<E>(
     }
 }
 
-impl<F: CovariantForLt> Drop for Registration<'_, F> {
+impl<F: ForLt> Drop for Registration<'_, F> {
     fn drop(&mut self) {
         // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered
         // `struct auxiliary_device`.
@@ -548,7 +595,7 @@ fn drop(&mut self) {
 }
 
 // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.
-unsafe impl<F: CovariantForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
+unsafe impl<F: ForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
 
 // SAFETY: `Registration` does not expose any methods or fields that need synchronization.
-unsafe impl<F: CovariantForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
+unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/7] rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
                   ` (2 preceding siblings ...)
  2026-06-03  1:10 ` [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 5/7] rust: devres: add DevresLt for ForLt-aware device resource access Danilo Krummrich
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Extend the auxiliary driver sample to demonstrate both access patterns:

  - registration_data() with CovariantForLt!(Data<'_>) for the covariant
    data type that holds a plain &'bound reference.

  - registration_data_with() with ForLt!(MutexData<'_>) for an invariant
    data type that wraps a Mutex<&'bound Device>. Since Mutex<T> is
    invariant over T, MutexData cannot implement CovariantForLt and must
    use the closure-based accessor.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 samples/rust/rust_driver_auxiliary.rs | 94 +++++++++++++++++++--------
 1 file changed, 68 insertions(+), 26 deletions(-)

diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 92ee6a6d348e..e441ae81fa2c 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -11,14 +11,21 @@
         Core, //
     },
     driver,
+    new_mutex,
     pci,
     prelude::*,
-    types::CovariantForLt,
+    sync::Mutex,
+    types::{
+        CovariantForLt,
+        ForLt, //
+    },
     InPlaceModule, //
 };
 
 const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
 const AUXILIARY_NAME: &CStr = c"auxiliary";
+const COVARIANT_DEV_ID: u32 = 0;
+const INVARIANT_DEV_ID: u32 = 1;
 
 struct AuxiliaryDriver;
 
@@ -56,12 +63,26 @@ struct Data<'bound> {
     parent: &'bound pci::Device<Bound>,
 }
 
+/// Registration data with interior mutability.
+///
+/// `Mutex<&'bound T>` is invariant over `'bound`, so this type cannot implement
+/// [`CovariantForLt`](trait@CovariantForLt). Access must go through the closure-based
+/// [`auxiliary::Device::registration_data_with()`].
+#[pin_data]
+struct MutexData<'bound> {
+    #[pin]
+    parent: Mutex<&'bound pci::Device<Bound>>,
+    index: u32,
+}
+
 struct ParentDriver;
 
 #[allow(clippy::type_complexity)]
+#[pin_data]
 struct ParentData<'bound> {
     _reg0: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
-    _reg1: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
+    #[pin]
+    _reg1: auxiliary::Registration<'bound, ForLt!(MutexData<'_>)>,
 }
 
 kernel::pci_device_table!(
@@ -81,17 +102,17 @@ fn probe<'bound>(
         pdev: &'bound pci::Device<Core<'_>>,
         _info: &'bound Self::IdInfo,
     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
-        Ok(ParentData {
+        try_pin_init!(ParentData {
             // SAFETY: `ParentData` is the driver's private data, which is dropped when the
             // device is unbound; i.e. `mem::forget()` is never called on it.
             _reg0: unsafe {
                 auxiliary::Registration::new_with_lt(
                     pdev.as_ref(),
                     AUXILIARY_NAME,
-                    0,
+                    COVARIANT_DEV_ID,
                     MODULE_NAME,
                     Data {
-                        index: 0,
+                        index: COVARIANT_DEV_ID,
                         parent: pdev,
                     },
                 )?
@@ -101,12 +122,16 @@ fn probe<'bound>(
                 auxiliary::Registration::new_with_lt(
                     pdev.as_ref(),
                     AUXILIARY_NAME,
-                    1,
+                    INVARIANT_DEV_ID,
                     MODULE_NAME,
-                    Data {
-                        index: 1,
-                        parent: pdev,
-                    },
+                    pin_init!(MutexData {
+                        parent <- {
+                            let pdev: &pci::Device<Bound> = pdev;
+
+                            new_mutex!(pdev)
+                        },
+                        index: INVARIANT_DEV_ID,
+                    }),
                 )?
             },
         })
@@ -115,22 +140,39 @@ fn probe<'bound>(
 
 impl ParentDriver {
     fn connect(adev: &auxiliary::Device<Bound>) -> Result {
-        let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
-        let pdev = data.parent;
-
-        dev_info!(
-            pdev,
-            "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
-            adev.id(),
-            pdev.vendor_id(),
-            pdev.device_id()
-        );
-
-        dev_info!(
-            pdev,
-            "Connected to auxiliary device with index {}.\n",
-            data.index
-        );
+        match adev.id() {
+            // CovariantForLt types can use the direct-reference accessor.
+            COVARIANT_DEV_ID => {
+                let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
+                let pdev = data.parent;
+
+                dev_info!(
+                    pdev,
+                    "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
+                    adev.id(),
+                    pdev.vendor_id(),
+                    pdev.device_id()
+                );
+
+                dev_info!(
+                    pdev,
+                    "Connected to auxiliary device with index {}.\n",
+                    data.index
+                );
+            }
+            // Invariant ForLt types (e.g. containing a Mutex) require the closure-based accessor.
+            INVARIANT_DEV_ID => {
+                adev.registration_data_with::<ForLt!(MutexData<'_>), _>(|data| {
+                    let pdev = *data.parent.lock();
+                    dev_info!(
+                        pdev,
+                        "Connected to auxiliary device with index {} (via Mutex).\n",
+                        data.index
+                    );
+                })?;
+            }
+            _ => return Err(EINVAL),
+        }
 
         Ok(())
     }
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 5/7] rust: devres: add DevresLt for ForLt-aware device resource access
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
                   ` (3 preceding siblings ...)
  2026-06-03  1:10 ` [PATCH v2 4/7] rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 6/7] rust: pci: return DevresLt from Bar::into_devres() Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 7/7] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() Danilo Krummrich
  6 siblings, 0 replies; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Devres<T> stores resources as T and returns &'a T from access(). For
lifetime-parameterized types like Bar<'a, 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's lifetime-shortening operations in all access
methods to shorten the stored 'static lifetime to the caller's borrow
lifetime.

DevresLt::new() is unsafe because the caller must guarantee that the
data remains valid for the device's full bound scope; the internal
transmute from F::Of<'a> to F::Of<'static> would otherwise allow
use-after-free.

Two access patterns are provided:

- CovariantForLt types get direct-reference accessors (access,
  try_access) that return shortened references via
  CovariantForLt::cast_ref.

- Plain ForLt types use closure-based accessors (access_with,
  try_access_with) whose universally quantified lifetime prevents
  callers from smuggling in concrete short-lived references.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/devres.rs | 110 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 82cbd8b969fb..23db91377f5e 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -24,6 +24,8 @@
         Arc, //
     },
     types::{
+        CovariantForLt,
+        ForLt,
         ForeignOwnable,
         Opaque, //
     },
@@ -365,6 +367,114 @@ fn drop(&mut self) {
     }
 }
 
+/// Guard returned by [`DevresLt::try_access`].
+///
+/// Dereferences to `F::Of<'a>`, shortening the lifetime of the stored data to the guard's borrow
+/// lifetime.
+pub struct DevresGuard<'a, F: CovariantForLt>(RevocableGuard<'a, F::Of<'static>>);
+
+impl<'a, F: CovariantForLt> core::ops::Deref for DevresGuard<'a, F> {
+    type Target = F::Of<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        F::cast_ref(&*self.0)
+    }
+}
+
+/// Device-managed resource with [`ForLt`](trait@ForLt)-aware access.
+///
+/// `DevresLt` wraps [`Devres`] and shortens the stored `'static` lifetime to the caller's borrow
+/// lifetime in all access methods.
+///
+/// Types that implement [`trait@CovariantForLt`] get direct-reference accessors ([`Self::access`],
+/// [`Self::try_access`]). Plain [`ForLt`](trait@ForLt) types use closure-based accessors
+/// ([`Self::access_with`], [`Self::try_access_with`]).
+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`.
+    ///
+    /// # Safety
+    ///
+    /// The data must remain valid for the device's full bound scope. [`DevresLt`] allows
+    /// access until the device is unbound, which may outlast `'a`.
+    pub unsafe fn new<'a, E>(
+        dev: &'a Device<Bound>,
+        data: impl PinInit<F::Of<'a>, E>,
+    ) -> Result<Self>
+    where
+        Error: From<E>,
+    {
+        // SAFETY: The caller guarantees the data is valid for the device's full bound scope.
+        // Lifetimes do not affect layout, so F::Of<'a> and F::Of<'static> have identical
+        // representation; casting the slot pointer is sound.
+        let data = unsafe {
+            pin_init::pin_init_from_closure::<F::Of<'static>, E>(move |slot| {
+                data.__pinned_init(slot.cast())
+            })
+        };
+
+        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 `&F::Of<'_>`, bypassing the [`Revocable`], through a closure.
+    ///
+    /// This method works like [`DevresLt::access`](DevresLt::access) but accepts any
+    /// [`trait@ForLt`] type, not just [`trait@CovariantForLt`].
+    pub fn access_with<R, G>(&self, dev: &Device<Bound>, f: G) -> Result<R>
+    where
+        G: for<'a> FnOnce(&'a F::Of<'a>) -> R,
+    {
+        self.0.access(dev).map(|data| {
+            // SAFETY: The closure's HRTB `for<'a>` prevents the caller from smuggling in
+            // references with a concrete short lifetime, making the round-trip from `'static`
+            // sound regardless of variance.
+            f(unsafe { F::cast_ref_unchecked(data) })
+        })
+    }
+
+    /// [`DevresLt`] accessor for [`Revocable::try_access_with`].
+    pub fn try_access_with<R, G>(&self, f: G) -> Option<R>
+    where
+        G: for<'a> FnOnce(&'a F::Of<'a>) -> R,
+    {
+        self.0.data().try_access_with(|data| {
+            // SAFETY: The closure's HRTB `for<'a>` prevents the caller from smuggling in
+            // references with a concrete short lifetime, making the round-trip from `'static`
+            // sound regardless of variance.
+            f(unsafe { F::cast_ref_unchecked(data) })
+        })
+    }
+}
+
+impl<F: CovariantForLt> DevresLt<F>
+where
+    F::Of<'static>: Send,
+{
+    /// Obtain `&'a F::Of<'a>`, bypassing the [`Revocable`].
+    ///
+    /// This method works like [`Devres::access`], but shortens the returned reference's lifetime
+    /// from `'static` to `'a` via [`CovariantForLt::cast_ref`].
+    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a F::Of<'a>> {
+        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)
+    }
+}
+
 /// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound.
 fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result
 where
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 6/7] rust: pci: return DevresLt from Bar::into_devres()
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
                   ` (4 preceding siblings ...)
  2026-06-03  1:10 ` [PATCH v2 5/7] rust: devres: add DevresLt for ForLt-aware device resource access Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  2026-06-03  1:10 ` [PATCH v2 7/7] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() Danilo Krummrich
  6 siblings, 0 replies; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Implement ForLt and CovariantForLt for Bar<'static, SIZE> so that
DevresLt can shorten the stored 'static lifetime back to the caller's
borrow lifetime.

CovariantForLt is sound because Bar<'a, SIZE> only holds &'a
Device<Bound>, which is covariant over 'a.

Since DevresLt::new() handles the lifetime transmutation internally,
into_devres() no longer needs an explicit transmute to Bar<'static>.

Add a DevresBar<SIZE> type alias for convenience.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/kernel/pci.rs    |  1 +
 rust/kernel/pci/io.rs | 37 ++++++++++++++++++++++++++-----------
 2 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 5071cae6543f..f783b9d9fa26 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -45,6 +45,7 @@
     ConfigSpace,
     ConfigSpaceKind,
     ConfigSpaceSize,
+    DevresBar,
     Extended,
     Normal, //
 };
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index 0461e01aaa20..7a0d2d74129d 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -6,7 +6,7 @@
 use crate::{
     bindings,
     device,
-    devres::Devres,
+    devres::DevresLt,
     io::{
         Io,
         IoCapable,
@@ -14,7 +14,11 @@
         Mmio,
         MmioRaw, //
     },
-    prelude::*, //
+    prelude::*,
+    types::{
+        CovariantForLt,
+        ForLt, //
+    }, //
 };
 use core::{
     marker::PhantomData,
@@ -151,6 +155,19 @@ pub struct Bar<'a, const SIZE: usize = 0> {
     num: i32,
 }
 
+impl<const SIZE: usize> ForLt for Bar<'static, SIZE> {
+    type Of<'a> = Bar<'a, SIZE>;
+}
+
+// SAFETY: `Bar<'a, SIZE>` is covariant over `'a`; it holds `&'a Device<Bound>`,
+// which is covariant.
+unsafe impl<const SIZE: usize> CovariantForLt for Bar<'static, SIZE> {}
+
+/// A device-managed PCI BAR mapping.
+///
+/// See [`Bar::into_devres`].
+pub type DevresBar<const SIZE: usize> = DevresLt<Bar<'static, SIZE>>;
+
 impl<'a, const SIZE: usize> Bar<'a, SIZE> {
     pub(super) fn new(
         pdev: &'a Device<device::Bound>,
@@ -223,15 +240,13 @@ fn release(&self) {
 
     /// Consume the `Bar` and register it as a device-managed resource.
     ///
-    /// The returned `Devres<Bar<'static, SIZE>>` can outlive the original lifetime `'a`. Access
-    /// to the BAR is revoked when the device is unbound.
-    pub fn into_devres(self) -> Result<Devres<Bar<'static, SIZE>>> {
-        // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `Bar` does not
-        // actually outlive the device -- access is revoked and the resource is released when the
-        // device is unbound.
-        let bar: Bar<'static, SIZE> = unsafe { core::mem::transmute(self) };
-        let pdev = bar.pdev;
-        Devres::new(pdev.as_ref(), bar)
+    /// The returned [`DevresBar`] can outlive the original borrow and be stored in driver data.
+    /// Access to the BAR is revoked automatically when the device is unbound.
+    pub fn into_devres(self) -> Result<DevresBar<SIZE>> {
+        let pdev = self.pdev;
+        // SAFETY: `Bar` only holds a reference to the device and an I/O mapping, both of which
+        // remain valid for the device's full bound scope, not just for `'a`.
+        unsafe { DevresLt::new(pdev.as_ref(), self) }
     }
 }
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 7/7] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres()
  2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
                   ` (5 preceding siblings ...)
  2026-06-03  1:10 ` [PATCH v2 6/7] rust: pci: return DevresLt from Bar::into_devres() Danilo Krummrich
@ 2026-06-03  1:10 ` Danilo Krummrich
  6 siblings, 0 replies; 11+ messages in thread
From: Danilo Krummrich @ 2026-06-03  1:10 UTC (permalink / raw)
  To: gregkh, rafael, dakr, ojeda, boqun, gary, bjorn3_gh, lossin,
	a.hindborg, aliceryhl, tmgross, acourbot, ecourtney, m.wilczynski,
	david.m.ertman, ira.weiny, leon, daniel.almeida, bhelgaas,
	kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

Implement ForLt and CovariantForLt for IoMem<'static, SIZE> and
ExclusiveIoMem<'static, SIZE> so that DevresLt can shorten the stored
'static lifetime back to the caller's borrow lifetime.

CovariantForLt is sound because both types only hold &'a Device<Bound>,
which is covariant over 'a.

Since DevresLt::new() handles the lifetime transmutation internally,
into_devres() no longer needs an explicit transmute to 'static.

Add DevresIoMem<SIZE> and DevresExclusiveIoMem<SIZE> type aliases.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 drivers/pwm/pwm_th1520.rs |  5 ++-
 rust/kernel/io/mem.rs     | 65 +++++++++++++++++++++++++++------------
 2 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index 48808cd80737..7e3a06ed369f 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -24,9 +24,8 @@
 use kernel::{
     clk::Clk,
     device::{Bound, Core, Device},
-    devres,
     io::{
-        mem::IoMem,
+        mem::DevresIoMem,
         Io, //
     },
     of, platform,
@@ -92,7 +91,7 @@ struct Th1520WfHw {
 #[pin_data(PinnedDrop)]
 struct Th1520PwmDriverData {
     #[pin]
-    iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>,
+    iomem: DevresIoMem<TH1520_PWM_REG_SIZE>,
     clk: Clk,
 }
 
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index fc2a3e24f8d5..4691a01a3cf7 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -9,7 +9,7 @@
         Bound,
         Device, //
     },
-    devres::Devres,
+    devres::DevresLt,
     io::{
         self,
         resource::{
@@ -20,6 +20,10 @@
         MmioRaw, //
     },
     prelude::*,
+    types::{
+        CovariantForLt,
+        ForLt, //
+    },
 };
 
 /// An IO request for a specific device and resource.
@@ -172,6 +176,19 @@ pub struct ExclusiveIoMem<'a, const SIZE: usize> {
     _region: Region,
 }
 
+impl<const SIZE: usize> ForLt for ExclusiveIoMem<'static, SIZE> {
+    type Of<'a> = ExclusiveIoMem<'a, SIZE>;
+}
+
+// SAFETY: `ExclusiveIoMem<'a, SIZE>` is covariant over `'a`; it holds an `IoMem<'a, SIZE>`,
+// which holds `&'a Device<Bound>`, which is covariant.
+unsafe impl<const SIZE: usize> CovariantForLt for ExclusiveIoMem<'static, SIZE> {}
+
+/// A device-managed exclusive I/O memory region.
+///
+/// See [`ExclusiveIoMem::into_devres`].
+pub type DevresExclusiveIoMem<const SIZE: usize> = DevresLt<ExclusiveIoMem<'static, SIZE>>;
+
 impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> {
     /// Creates a new `ExclusiveIoMem` instance.
     fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
@@ -198,15 +215,13 @@ fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
 
     /// Consume the `ExclusiveIoMem` and register it as a device-managed resource.
     ///
-    /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime
-    /// `'a`. Access to the I/O memory is revoked when the device is unbound.
-    pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> {
-        // SAFETY: Casting to `'static` is sound because `Devres` guarantees the
-        // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the
-        // resource is released when the device is unbound.
-        let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) };
-        let dev = iomem.iomem.dev;
-        Devres::new(dev, iomem)
+    /// The returned [`DevresExclusiveIoMem`] can outlive the original borrow and be stored in
+    /// driver data. Access to the I/O memory is revoked automatically when the device is unbound.
+    pub fn into_devres(self) -> Result<DevresExclusiveIoMem<SIZE>> {
+        let dev = self.iomem.dev;
+        // SAFETY: `ExclusiveIoMem` only holds a device reference and an I/O mapping, both of
+        // which remain valid for the device's full bound scope, not just for `'a`.
+        unsafe { DevresLt::new(dev, self) }
     }
 }
 
@@ -232,6 +247,19 @@ pub struct IoMem<'a, const SIZE: usize = 0> {
     io: MmioRaw<SIZE>,
 }
 
+impl<const SIZE: usize> ForLt for IoMem<'static, SIZE> {
+    type Of<'a> = IoMem<'a, SIZE>;
+}
+
+// SAFETY: `IoMem<'a, SIZE>` is covariant over `'a`; it holds `&'a Device<Bound>`,
+// which is covariant.
+unsafe impl<const SIZE: usize> CovariantForLt for IoMem<'static, SIZE> {}
+
+/// A device-managed I/O memory region.
+///
+/// See [`IoMem::into_devres`].
+pub type DevresIoMem<const SIZE: usize> = DevresLt<IoMem<'static, SIZE>>;
+
 impl<'a, const SIZE: usize> IoMem<'a, SIZE> {
     fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
         // Note: Some ioremap() implementations use types that depend on the CPU
@@ -271,16 +299,13 @@ fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> {
 
     /// Consume the `IoMem` and register it as a device-managed resource.
     ///
-    /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original
-    /// lifetime `'a`. Access to the I/O memory is revoked when the device
-    /// is unbound.
-    pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> {
-        // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not
-        // actually outlive the device -- access is revoked and the resource is released when the
-        // device is unbound.
-        let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) };
-        let dev = iomem.dev;
-        Devres::new(dev, iomem)
+    /// The returned [`DevresIoMem`] can outlive the original borrow and be stored in driver data.
+    /// Access to the I/O memory is revoked automatically when the device is unbound.
+    pub fn into_devres(self) -> Result<DevresIoMem<SIZE>> {
+        let dev = self.dev;
+        // SAFETY: `IoMem` only holds a device reference and an I/O mapping, both of which
+        // remain valid for the device's full bound scope, not just for `'a`.
+        unsafe { DevresLt::new(dev, self) }
     }
 }
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt
  2026-06-03  1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
@ 2026-06-03 11:59   ` Gary Guo
  0 siblings, 0 replies; 11+ messages in thread
From: Gary Guo @ 2026-06-03 11:59 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, boqun, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, acourbot, ecourtney,
	m.wilczynski, david.m.ertman, ira.weiny, leon, daniel.almeida,
	bhelgaas, kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

On Wed Jun 3, 2026 at 2:10 AM BST, Danilo Krummrich wrote:
> Rename ForLt to CovariantForLt to prepare for the introduction of a new
> ForLt base trait that does not require covariance.
>
> The existing ForLt trait requires covariance, which enables the safe
> cast_ref() method. This rename preserves the same semantics under a more
> precise name, making room for a weaker ForLt trait in a subsequent
> commit.
>
> No functional change.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  drivers/gpu/nova-core/driver.rs       |  4 +-
>  rust/kernel/auxiliary.rs              | 23 +++++-----
>  rust/kernel/types.rs                  |  2 +-
>  rust/kernel/types/for_lt.rs           | 61 ++++++++++++++-------------
>  rust/macros/for_lt.rs                 |  4 +-
>  rust/macros/lib.rs                    | 11 +++--
>  samples/rust/rust_driver_auxiliary.rs |  8 ++--
>  7 files changed, 57 insertions(+), 56 deletions(-)
>
> diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
> index d44323c28e8d..ef510ab6c092 100644
> --- a/rust/kernel/types/for_lt.rs
> +++ b/rust/kernel/types/for_lt.rs
> @@ -1,8 +1,8 @@
>  // SPDX-License-Identifier: Apache-2.0 OR MIT
>  
> -//! Provide implementation and test of the `ForLt` trait and macro.
> +//! Provide implementation and test of the `CovariantForLt` trait and macro.
>  //!
> -//! This module is hidden and user should just use `ForLt!` directly.
> +//! This module is hidden and user should just use `CovariantForLt!` directly.
>  
>  use core::marker::PhantomData;
>  
> @@ -15,38 +15,39 @@
>  ///
>  /// # Macro
>  ///
> -/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
> -/// type that implements this trait.
> +/// It is not recommended to implement this trait directly. `CovariantForLt!` macro is provided to
> +/// obtain a type that implements this trait.
>  ///
>  /// The full syntax is
>  ///
>  /// ```
> -/// # use kernel::types::ForLt;
> -/// # fn expect_lt<F: ForLt>() {}
> +/// # use kernel::types::CovariantForLt;
> +/// # fn expect_lt<F: CovariantForLt>() {}
>  /// # struct TypeThatUse<'a>(&'a ());
>  /// # expect_lt::<
> -/// ForLt!(for<'a> TypeThatUse<'a>)
> +/// CovariantForLt!(for<'a> TypeThatUse<'a>)
>  /// # >();
>  /// ```
>  ///
> -/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
> +/// which gives a type so that
> +/// `<CovariantForLt!(for<'a> TypeThatUse<'a>) as CovariantForLt>::Of<'b>`
>  /// is `TypeThatUse<'b>`.
>  ///
>  /// You may also use a short-hand syntax which works similar to lifetime elision.
>  /// The macro also accepts types that do not involve a lifetime at all.
>  ///
>  /// ```
> -/// # use kernel::types::ForLt;
> -/// # fn expect_lt<F: ForLt>() {}
> +/// # use kernel::types::CovariantForLt;
> +/// # fn expect_lt<F: CovariantForLt>() {}
>  /// # struct TypeThatUse<'a>(&'a ());
>  /// # expect_lt::<
> -/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
> +/// CovariantForLt!(TypeThatUse<'_>) // Equivalent to `CovariantForLt!(for<'a> TypeThatUse<'a>)`.
>  /// # >();
>  /// # expect_lt::<
> -/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
> +/// CovariantForLt!(&u32) // Equivalent to `CovariantForLt!(for<'a> &'a u32)`.
>  /// # >();
>  /// # expect_lt::<
> -/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
> +/// CovariantForLt!(u32) // Equivalent to `CovariantForLt!(for<'a> u32)`.
>  /// # >();
>  /// ```
>  ///
> @@ -55,10 +56,10 @@
>  /// it.
>  ///
>  /// ```ignore,compile_fail
> -/// # use kernel::types::ForLt;
> -/// # fn expect_lt<F: ForLt>() {}
> +/// # use kernel::types::CovariantForLt;
> +/// # fn expect_lt<F: CovariantForLt>() {}
>  /// # expect_lt::<
> -/// ForLt!(fn(&u32)) // Contravariant, will fail compilation.
> +/// CovariantForLt!(fn(&u32)) // Contravariant, will fail compilation.
>  /// # >();
>  /// ```
>  ///
> @@ -67,23 +68,23 @@
>  /// the generic parameter but is in a separate item.
>  ///
>  /// ```
> -/// # use kernel::types::ForLt;
> -/// fn expect_lt<F: ForLt>() {}
> +/// # use kernel::types::CovariantForLt;
> +/// fn expect_lt<F: CovariantForLt>() {}
>  /// # #[allow(clippy::unnecessary_safety_comment, reason = "false positive")]
>  /// fn generic_fn<T: 'static>() {
>  ///     // Syntactically proven by the macro
> -///     expect_lt::<ForLt!(&T)>();
> +///     expect_lt::<CovariantForLt!(&T)>();
>  ///     // Syntactically proven by the macro
> -///     expect_lt::<ForLt!(&KBox<T>)>();
> +///     expect_lt::<CovariantForLt!(&KBox<T>)>();
>  ///     // Cannot be syntactically proven, need to check covariance of `KBox`
> -///     // expect_lt::<ForLt!(&KBox<&T>)>();
> +///     // expect_lt::<CovariantForLt!(&KBox<&T>)>();
>  /// }
>  /// ```
>  ///
>  /// # Safety
>  ///
>  /// `Self::Of<'a>` must be covariant over the lifetime `'a`.
> -pub unsafe trait ForLt {
> +pub unsafe trait CovariantForLt {
>      /// The type parameterized by the lifetime.
>      type Of<'a>: 'a;
>  
> @@ -94,11 +95,11 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
>          unsafe { core::mem::transmute(long) }
>      }
>  }
> -pub use macros::ForLt;
> +pub use macros::CovariantForLt;
>  
> -/// This is intended to be an "unsafe-to-refer-to" type.
> +/// Helper type for the `CovariantForLt!` macro.
>  ///
> -/// Must only be used by the `ForLt!` macro.
> +/// Must only be used by the `CovariantForLt!` macro.
>  ///
>  /// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
>  ///
> @@ -107,16 +108,16 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
>  /// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
>  /// additional properties.
>  #[doc(hidden)]
> -pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
> +pub struct CovariantForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);

I think I prefer this name to be stayed the same (so it has the "Unsafe" in it
and is not too long).

You can actually use this same helper type for both `ForLt!` and
`CovariantForLt!` later in patch 2, by using different `N` based on whether
covariance check has been conducted. So

impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> ForLt for UnsafeForLtImpl<T, WF, N> {
    type Of<'a> = <T as WithLt<'a>>::Of;
}

impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for UnsafeForLtImpl<T, WF, 1> {}

Best,
Gary

>  
> -// This is a helper trait for implementation `ForLt` to be able to use HRTB.
> +// This is a helper trait for implementation `CovariantForLt` to be able to use HRTB.
>  #[doc(hidden)]
>  pub trait WithLt<'a> {
>      type Of: 'a;
>  }
>  
> -// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming `UnsafeForLtImpl`
> -// and it will fail to evaluate if the type is not covariant.
> -unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for UnsafeForLtImpl<T, WF, 0> {
> +// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated when naming
> +// `CovariantForLtImpl` and it will fail to evaluate if the type is not covariant.
> +unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for CovariantForLtImpl<T, WF, 0> {
>      type Of<'a> = <T as WithLt<'a>>::Of;
>  }
> diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs
> index 364d4113cd10..3cb094d00548 100644
> --- a/rust/macros/for_lt.rs
> +++ b/rust/macros/for_lt.rs
> @@ -176,7 +176,7 @@ fn prove(&mut self, ty: &'a Type) {
>      }
>  }
>  
> -pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {
> +pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
>      let (ty, lifetime) = match input {
>          HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),
>          HigherRankedType::Implicit { ty } => {
> @@ -235,7 +235,7 @@ fn #cov_proof_name<'__short, '__long: '__short>(
>      );
>  
>      quote!(
> -        ::kernel::types::for_lt::UnsafeForLtImpl::<
> +        ::kernel::types::for_lt::CovariantForLtImpl::<
>              dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,
>              #ty_static,
>              {
> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
> index 4a48fabbc268..2167cb270928 100644
> --- a/rust/macros/lib.rs
> +++ b/rust/macros/lib.rs
> @@ -491,14 +491,13 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
>          .into()
>  }
>  
> -/// Obtain a type that implements [`ForLt`] for the given higher-ranked type.
> +/// Obtain a type that implements [`CovariantForLt`] for the given higher-ranked type.
>  ///
> -/// Please refer to the documentation of the [`ForLt`] trait.
> +/// Please refer to the documentation of the [`CovariantForLt`] trait.
>  ///
> -/// [`ForLt`]: trait.ForLt.html
> +/// [`CovariantForLt`]: trait.CovariantForLt.html
>  #[proc_macro]
> -// The macro shares the name with the trait.
>  #[allow(non_snake_case)]
> -pub fn ForLt(input: TokenStream) -> TokenStream {
> -    for_lt::for_lt(parse_macro_input!(input)).into()
> +pub fn CovariantForLt(input: TokenStream) -> TokenStream {
> +    for_lt::covariant_for_lt(parse_macro_input!(input)).into()
>  }
> diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
> index 2c1351040e45..92ee6a6d348e 100644
> --- a/samples/rust/rust_driver_auxiliary.rs
> +++ b/samples/rust/rust_driver_auxiliary.rs
> @@ -13,7 +13,7 @@
>      driver,
>      pci,
>      prelude::*,
> -    types::ForLt,
> +    types::CovariantForLt,
>      InPlaceModule, //
>  };
>  
> @@ -60,8 +60,8 @@ struct Data<'bound> {
>  
>  #[allow(clippy::type_complexity)]
>  struct ParentData<'bound> {
> -    _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
> -    _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
> +    _reg0: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
> +    _reg1: auxiliary::Registration<'bound, CovariantForLt!(Data<'_>)>,
>  }
>  
>  kernel::pci_device_table!(
> @@ -115,7 +115,7 @@ fn probe<'bound>(
>  
>  impl ParentDriver {
>      fn connect(adev: &auxiliary::Device<Bound>) -> Result {
> -        let data = adev.registration_data::<ForLt!(Data<'_>)>()?;
> +        let data = adev.registration_data::<CovariantForLt!(Data<'_>)>()?;
>          let pdev = data.parent;
>  
>          dev_info!(



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt
  2026-06-03  1:10 ` [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt Danilo Krummrich
@ 2026-06-03 12:04   ` Gary Guo
  0 siblings, 0 replies; 11+ messages in thread
From: Gary Guo @ 2026-06-03 12:04 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, boqun, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, acourbot, ecourtney,
	m.wilczynski, david.m.ertman, ira.weiny, leon, daniel.almeida,
	bhelgaas, kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

On Wed Jun 3, 2026 at 2:10 AM BST, Danilo Krummrich wrote:
> Add a new ForLt trait as a base for CovariantForLt:
>
>   - ForLt (non-unsafe): represents a type generic over a lifetime, with
>     no covariance guarantee.  Provides unsafe fn cast_ref_unchecked()
>     for callers that can justify lifetime shortening via a round-trip
>     safety argument.
>
>   - CovariantForLt (unsafe): becomes a subtrait of ForLt that
>     additionally proves the type is covariant over its lifetime
>     parameter, providing a safe cast_ref() method.
>
> This split allows non-covariant types (e.g. types behind a Mutex) to
> implement ForLt and participate in DevresLt / registration data patterns
> where the round-trip argument suffices, without requiring a covariance
> proof that would fail to compile.
>
> The internal macro backend is split accordingly: ForLt! emits ForLtImpl
> (no covariance proof), CovariantForLt! emits CovariantForLtImpl (with
> compile-time covariance proof).
>
> No existing callers change; they all use CovariantForLt.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/types.rs        |   1 +
>  rust/kernel/types/for_lt.rs | 101 ++++++++++++++++++++++++++++++------
>  rust/macros/for_lt.rs       |  50 ++++++++++++++----
>  rust/macros/lib.rs          |  19 ++++++-
>  4 files changed, 145 insertions(+), 26 deletions(-)
>
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index cbe6907042d3..c1ed05d1046c 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -14,6 +14,7 @@
>  #[doc(hidden)]
>  pub mod for_lt;
>  pub use for_lt::CovariantForLt;
> +pub use for_lt::ForLt;
>  
>  /// Used to transfer ownership to and from foreign (non-Rust) languages.
>  ///
> diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs
> index ef510ab6c092..e1774b03dd1f 100644
> --- a/rust/kernel/types/for_lt.rs
> +++ b/rust/kernel/types/for_lt.rs
> @@ -1,17 +1,74 @@
>  // SPDX-License-Identifier: Apache-2.0 OR MIT
>  
> -//! Provide implementation and test of the `CovariantForLt` trait and macro.
> +//! Provide implementation and test of the `ForLt` and `CovariantForLt` traits and macros.
>  //!
> -//! This module is hidden and user should just use `CovariantForLt!` directly.
> +//! This module is hidden and users should just use `ForLt!` / `CovariantForLt!` directly.
>  
>  use core::marker::PhantomData;
>  
>  /// Representation of types generic over a lifetime.
>  ///
> -/// The type must be covariant over the generic lifetime, i.e. the lifetime parameter
> -/// can be soundly shortened.
> +/// # Macro
> +///
> +/// It is not recommended to implement this trait directly. `ForLt!` macro is provided to obtain a
> +/// type that implements this trait.
> +///
> +/// The full syntax is
> +///
> +/// ```
> +/// # use kernel::types::ForLt;
> +/// # fn expect_lt<F: ForLt>() {}
> +/// # struct TypeThatUse<'a>(&'a ());
> +/// # expect_lt::<
> +/// ForLt!(for<'a> TypeThatUse<'a>)
> +/// # >();
> +/// ```
> +///
> +/// which gives a type so that `<ForLt!(for<'a> TypeThatUse<'a>) as ForLt>::Of<'b>`
> +/// is `TypeThatUse<'b>`.
> +///
> +/// You may also use a short-hand syntax which works similar to lifetime elision.
> +/// The macro also accepts types that do not involve a lifetime at all.
> +///
> +/// ```
> +/// # use kernel::types::ForLt;
> +/// # fn expect_lt<F: ForLt>() {}
> +/// # struct TypeThatUse<'a>(&'a ());
> +/// # expect_lt::<
> +/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'a>)`.
> +/// # >();
> +/// # expect_lt::<
> +/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)`.
> +/// # >();
> +/// # expect_lt::<
> +/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)`.
> +/// # >();
> +/// ```
> +pub trait ForLt {
> +    /// The type parameterized by the lifetime.
> +    type Of<'a>: 'a;
> +
> +    /// Cast a reference to a shorter lifetime.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The caller must ensure that the lifetime shortening is sound for their use case,
> +    /// e.g. because the `'long` reference originated from a `'short`-to-`'static` transmute
> +    /// and this is the reverse leg of that round-trip.
> +    #[inline(always)]
> +    unsafe fn cast_ref_unchecked<'r, 'short: 'r, 'long: 'short>(
> +        long: &'r Self::Of<'long>,
> +    ) -> &'r Self::Of<'short> {
> +        // SAFETY: Caller guarantees the lifetime shortening is sound.
> +        unsafe { core::mem::transmute(long) }
> +    }

I think this method should just be gone.

> +}
> +pub use macros::ForLt;
> +
> +/// [`trait@ForLt`] subtrait for types that are covariant over their lifetime parameter.
>  ///
> -/// The lifetime involved must be covariant.
> +/// Provides a safe [`cast_ref`](CovariantForLt::cast_ref) method for types that are proven to be
> +/// covariant. The `CovariantForLt!` macro syntax is the same as `ForLt!`.
>  ///
>  /// # Macro
>  ///
> @@ -84,10 +141,7 @@
>  /// # Safety
>  ///
>  /// `Self::Of<'a>` must be covariant over the lifetime `'a`.
> -pub unsafe trait CovariantForLt {
> -    /// The type parameterized by the lifetime.
> -    type Of<'a>: 'a;
> -
> +pub unsafe trait CovariantForLt: ForLt {
>      /// Cast a reference to a shorter lifetime.
>      #[inline(always)]
>      fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Self::Of<'short> {
> @@ -97,27 +151,44 @@ fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) -> &'r Sel
>  }
>  pub use macros::CovariantForLt;
>  
> -/// Helper type for the `CovariantForLt!` macro.
> +/// Helper type for the `ForLt!` macro.
>  ///
> -/// Must only be used by the `CovariantForLt!` macro.
> +/// Must only be used by the `ForLt!` macro.
>  ///
>  /// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
>  ///
>  /// `WF` is a type that the macro can use to assert some specific type is well-formed.
> +#[doc(hidden)]
> +pub struct ForLtImpl<T: ?Sized, WF>(PhantomData<(WF, T)>);

The `N` is still needed for `ForLtImpl` in case there needs to be a
wellformedness check. Currently the macro emits a `struct` to serve
wellformedness-check purpose and a `fn` to check for covariance, and the first
part still needs to be kept (at least until Rust starts checking WF-ness for
`dyn`).

If you follow my suggestion in patch 1, you should be able to share macro impl
for `CovariantForLt` and `ForLt`, and just have a boolean to decide whether to
to emit the function that check for variance.

Best,
Gary

> +
> +/// Helper type for the `CovariantForLt!` macro.
> +///
> +/// Must only be used by the `CovariantForLt!` macro.
> +///
> +/// `T` and `WF` are the same as in [`ForLtImpl`].
>  ///
>  /// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
>  /// additional properties.
>  #[doc(hidden)]
>  pub struct CovariantForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
>  
> -// This is a helper trait for implementation `CovariantForLt` to be able to use HRTB.
> +// This is a helper trait for implementation `ForLt` to be able to use HRTB.
>  #[doc(hidden)]
>  pub trait WithLt<'a> {
>      type Of: 'a;
>  }
>  
> -// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated when naming
> -// `CovariantForLtImpl` and it will fail to evaluate if the type is not covariant.
> -unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF> CovariantForLt for CovariantForLtImpl<T, WF, 0> {
> +impl<T: ?Sized + for<'a> WithLt<'a>, WF> ForLt for ForLtImpl<T, WF> {
> +    type Of<'a> = <T as WithLt<'a>>::Of;
> +}
> +
> +impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> ForLt for CovariantForLtImpl<T, WF, N> {
>      type Of<'a> = <T as WithLt<'a>>::Of;
>  }
> +
> +// SAFETY: In `CovariantForLt!` macro, a covariance proof is generated in the `N` const generic
> +// and it will fail to evaluate if the type is not covariant.
> +unsafe impl<T: ?Sized + for<'a> WithLt<'a>, WF, const N: usize> CovariantForLt
> +    for CovariantForLtImpl<T, WF, N>
> +{
> +}
> diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs
> index 3cb094d00548..ad9809563fab 100644
> --- a/rust/macros/for_lt.rs
> +++ b/rust/macros/for_lt.rs
> @@ -176,8 +176,10 @@ fn prove(&mut self, ty: &'a Type) {
>      }
>  }
>  
> -pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
> -    let (ty, lifetime) = match input {
> +/// Resolve the higher-ranked type into a concrete `(ty, lifetime)` pair, expanding elided
> +/// lifetimes as needed. Shared by both `for_lt` and `covariant_for_lt`.
> +fn resolve_hrt(input: HigherRankedType) -> (Type, Lifetime) {
> +    match input {
>          HigherRankedType::Explicit { lifetime, ty, .. } => (ty, lifetime),
>          HigherRankedType::Implicit { ty } => {
>              // If there's no explicit `for<'a>` binder, inject a synthetic `'__elided` lifetime
> @@ -188,7 +190,41 @@ pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
>              };
>              (ty.expand_elided_lifetime(&lifetime), lifetime)
>          }
> -    };
> +    }
> +}
> +
> +/// Produce the `'static`-substituted type for the WF check. Shared by both macros.
> +fn ty_static(ty: &Type, lifetime: &Lifetime) -> Type {
> +    ty.replace_lifetime(
> +        lifetime,
> +        &Lifetime {
> +            apostrophe: Span::mixed_site(),
> +            ident: format_ident!("static"),
> +        },
> +    )
> +}
> +
> +pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream {
> +    let (ty, lifetime) = resolve_hrt(input);
> +
> +    // Make sure that the type is wellformed when substituting lifetime with `'static`.
> +    //
> +    // Currently the Rust compiler doesn't check this, see the `ProveWf` documentation in
> +    // `covariant_for_lt` below.
> +    //
> +    // We prefer to use this way of proving WF-ness as it can work when generics are involved.
> +    let ty_static = ty_static(&ty, &lifetime);
> +
> +    quote!(
> +        ::kernel::types::for_lt::ForLtImpl::<
> +            dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, Of = #ty>,
> +            #ty_static,
> +        >
> +    )
> +}
> +
> +pub(crate) fn covariant_for_lt(input: HigherRankedType) -> TokenStream {
> +    let (ty, lifetime) = resolve_hrt(input);
>  
>      let mut prover = Prover(&lifetime, Vec::new());
>      prover.prove(&ty);
> @@ -226,13 +262,7 @@ fn #cov_proof_name<'__short, '__long: '__short>(
>      // Currently the Rust compiler doesn't check this, see the above `ProveWf` documentation.
>      //
>      // We prefer to use this way of proving WF-ness as it can work when generics are involved.
> -    let ty_static = ty.replace_lifetime(
> -        &lifetime,
> -        &Lifetime {
> -            apostrophe: Span::mixed_site(),
> -            ident: format_ident!("static"),
> -        },
> -    );
> +    let ty_static = ty_static(&ty, &lifetime);
>  
>      quote!(
>          ::kernel::types::for_lt::CovariantForLtImpl::<
> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
> index 2167cb270928..e970769609f3 100644
> --- a/rust/macros/lib.rs
> +++ b/rust/macros/lib.rs
> @@ -491,11 +491,28 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStream) -> TokenStream {
>          .into()
>  }
>  
> -/// Obtain a type that implements [`CovariantForLt`] for the given higher-ranked type.
> +/// Obtain a type that implements [`ForLt`] for the given higher-ranked type.
> +///
> +/// Please refer to the documentation of the [`ForLt`] trait.
> +///
> +/// [`ForLt`]: trait.ForLt.html
> +#[proc_macro]
> +#[allow(non_snake_case)]
> +pub fn ForLt(input: TokenStream) -> TokenStream {
> +    for_lt::for_lt(parse_macro_input!(input)).into()
> +}
> +
> +/// Obtain a type that implements [`CovariantForLt`] (and [`ForLt`]) for the given higher-ranked
> +/// type.
> +///
> +/// Unlike [`ForLt!`], this macro additionally proves that the type is covariant over the lifetime,
> +/// providing a safe [`CovariantForLt::cast_ref`] method.
>  ///
>  /// Please refer to the documentation of the [`CovariantForLt`] trait.
>  ///
>  /// [`CovariantForLt`]: trait.CovariantForLt.html
> +/// [`CovariantForLt::cast_ref`]: trait.CovariantForLt.html#method.cast_ref
> +/// [`ForLt`]: trait.ForLt.html
>  #[proc_macro]
>  #[allow(non_snake_case)]
>  pub fn CovariantForLt(input: TokenStream) -> TokenStream {



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types
  2026-06-03  1:10 ` [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types Danilo Krummrich
@ 2026-06-03 12:05   ` Gary Guo
  0 siblings, 0 replies; 11+ messages in thread
From: Gary Guo @ 2026-06-03 12:05 UTC (permalink / raw)
  To: Danilo Krummrich, gregkh, rafael, ojeda, boqun, gary, bjorn3_gh,
	lossin, a.hindborg, aliceryhl, tmgross, acourbot, ecourtney,
	m.wilczynski, david.m.ertman, ira.weiny, leon, daniel.almeida,
	bhelgaas, kwilczynski
  Cc: driver-core, linux-kernel, nova-gpu, dri-devel, linux-pwm,
	rust-for-linux

On Wed Jun 3, 2026 at 2:10 AM BST, Danilo Krummrich wrote:
> Add registration_data_with() taking a for<'a> closure that receives
> Pin<&'a F::Of<'a>>, which works with any ForLt type. Taking a for<'a>
> closure rather than returning a direct reference prevents callers from
> choosing a concrete lifetime for the data, which is required for
> soundness with non-covariant ForLt types.
>
> Extract the common null-check, TypeId-check and KBox-borrow logic into a
> private registration_data_pinned() helper shared by both
> registration_data_with() and the existing registration_data().
>
> Relax Registration's bound from CovariantForLt to ForLt so that
> non-covariant types can be registered.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
>  rust/kernel/auxiliary.rs | 89 ++++++++++++++++++++++++++++++----------
>  1 file changed, 68 insertions(+), 21 deletions(-)
>
> diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
> index 40a0af74a8e5..81549a3e347e 100644
> --- a/rust/kernel/auxiliary.rs
> +++ b/rust/kernel/auxiliary.rs
> @@ -21,6 +21,7 @@
>      prelude::*,
>      types::{
>          CovariantForLt,
> +        ForLt,
>          ForeignOwnable,
>          Opaque, //
>      },
> @@ -270,18 +271,15 @@ pub fn parent(&self) -> &device::Device<device::Bound> {
>          unsafe { parent.as_bound() }
>      }
>  
> -    /// Returns a pinned reference to the registration data set by the registering (parent) driver.
> +    /// Returns the stored registration data as a pinned `'static` reference.
>      ///
> -    /// `F` is the [`CovariantForLt`](trait@CovariantForLt) encoding of the data type. The returned
> -    /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via
> -    /// [`CovariantForLt::cast_ref`].
> +    /// Performs null and [`TypeId`] checks, then borrows the stored [`KBox`].
>      ///
> -    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
> -    /// [`Registration::new()`].
> +    /// # Safety
>      ///
> -    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
> -    /// registered by a C driver.
> -    pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
> +    /// The returned `'static` lifetime was transmuted from the device's bound lifetime during
> +    /// registration. Callers must shorten it before exposing it.
> +    unsafe fn registration_data_pinned<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'static>>> {
>          // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.
>          let ptr = unsafe { (*self.as_raw()).registration_data_rust };
>          if ptr.is_null() {
> @@ -306,10 +304,58 @@ pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::O
>          let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };
>  
>          // SAFETY: `data` is a structurally pinned field of `RegistrationData`.
> -        let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) };
> +        Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })
> +    }
> +
> +    /// Access the registration data set by the registering (parent) driver through a closure.
> +    ///
> +    /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The closure receives a pinned
> +    /// reference to the registration data.
> +    ///
> +    /// For covariant types that implement [`trait@CovariantForLt`], prefer
> +    /// [`registration_data`](Self::registration_data) which returns a direct reference.
> +    ///
> +    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
> +    /// [`Registration::new()`].
> +    ///
> +    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
> +    /// registered by a C driver.
> +    pub fn registration_data_with<F: ForLt + 'static, R>(
> +        &self,
> +        f: impl for<'a> FnOnce(Pin<&'a F::Of<'a>>) -> R,
> +    ) -> Result<R> {
> +        // SAFETY: The HRTB closure prevents the caller from smuggling in references with a
> +        // concrete short lifetime, making the round-trip from `'static` sound regardless of
> +        // variance.
> +        let pinned = unsafe { self.registration_data_pinned::<F>()? };
> +
> +        // SAFETY: See above; the closure's HRTB makes the round-trip sound.
> +        let short = unsafe { F::cast_ref_unchecked(pinned.get_ref()) };

This shouldn't be necessary, you can just directly call `f`.

Best,
Gary

> +
> +        // SAFETY: The data was pinned before the lifetime was shortened; pinning is
> +        // orthogonal to lifetimes.
> +        Ok(f(unsafe { Pin::new_unchecked(short) }))
> +    }
>  
> -        // SAFETY: The data was pinned when stored; `cast_ref` only shortens
> -        // the lifetime, so the pinning guarantee is preserved.
> +    /// Returns a pinned reference to the registration data set by the registering (parent) driver.
> +    ///
> +    /// This method is only available when `F` implements [`trait@CovariantForLt`], which guarantees
> +    /// safe lifetime shortening via [`CovariantForLt::cast_ref`].
> +    ///
> +    /// For non-covariant types, use the closure-based [`Self::registration_data_with`].
> +    ///
> +    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
> +    /// [`Registration::new()`].
> +    ///
> +    /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
> +    /// registered by a C driver.
> +    pub fn registration_data<F: CovariantForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
> +        // SAFETY: CovariantForLt guarantees covariance, so cast_ref safely shortens the
> +        // `'static` lifetime.
> +        let pinned = unsafe { self.registration_data_pinned::<F>()? };
> +
> +        // SAFETY: The data was pinned before the lifetime was shortened; pinning is orthogonal
> +        // to lifetimes.
>          Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })
>      }
>  }
> @@ -399,22 +445,23 @@ struct RegistrationData<T> {
>  /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device
>  /// is unbound, the corresponding auxiliary device will be unregistered from the system.
>  ///
> -/// The type parameter `F` is a [`CovariantForLt`](trait@CovariantForLt) encoding of the
> -/// registration data type. For non-lifetime-parameterized types, use
> -/// [`CovariantForLt!(T)`](macro@CovariantForLt).
> -/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].
> +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration
> +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).
> +///
> +/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`] and
> +/// [`Device::registration_data_with()`].
>  ///
>  /// # Invariants
>  ///
>  /// `self.adev` always holds a valid pointer to an initialized and registered
>  /// [`struct auxiliary_device`] whose `registration_data_rust` field points to a
>  /// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`.
> -pub struct Registration<'a, F: CovariantForLt + 'static> {
> +pub struct Registration<'a, F: ForLt + 'static> {
>      adev: NonNull<bindings::auxiliary_device>,
>      _phantom: PhantomData<F::Of<'a>>,
>  }
>  
> -impl<'a, F: CovariantForLt> Registration<'a, F>
> +impl<'a, F: ForLt> Registration<'a, F>
>  where
>      for<'b> F::Of<'b>: Send + Sync,
>  {
> @@ -526,7 +573,7 @@ pub fn new<E>(
>      }
>  }
>  
> -impl<F: CovariantForLt> Drop for Registration<'_, F> {
> +impl<F: ForLt> Drop for Registration<'_, F> {
>      fn drop(&mut self) {
>          // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered
>          // `struct auxiliary_device`.
> @@ -548,7 +595,7 @@ fn drop(&mut self) {
>  }
>  
>  // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.
> -unsafe impl<F: CovariantForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
> +unsafe impl<F: ForLt> Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
>  
>  // SAFETY: `Registration` does not expose any methods or fields that need synchronization.
> -unsafe impl<F: CovariantForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
> +unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-06-03 12:05 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03  1:10 [PATCH v2 0/7] ForLt/CovariantForLt split, auxiliary closure API and DevresLt Danilo Krummrich
2026-06-03  1:10 ` [PATCH v2 1/7] rust: types: rename ForLt to CovariantForLt Danilo Krummrich
2026-06-03 11:59   ` Gary Guo
2026-06-03  1:10 ` [PATCH v2 2/7] rust: types: introduce ForLt base trait for CovariantForLt Danilo Krummrich
2026-06-03 12:04   ` Gary Guo
2026-06-03  1:10 ` [PATCH v2 3/7] rust: auxiliary: add registration_data_with() for ForLt types Danilo Krummrich
2026-06-03 12:05   ` Gary Guo
2026-06-03  1:10 ` [PATCH v2 4/7] rust: auxiliary: sample: demonstrate ForLt with invariant Mutex type Danilo Krummrich
2026-06-03  1:10 ` [PATCH v2 5/7] rust: devres: add DevresLt for ForLt-aware device resource access Danilo Krummrich
2026-06-03  1:10 ` [PATCH v2 6/7] rust: pci: return DevresLt from Bar::into_devres() Danilo Krummrich
2026-06-03  1:10 ` [PATCH v2 7/7] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox