NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
* [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
@ 2026-07-13 20:14 Gary Guo
  2026-07-13 20:23 ` Gary Guo
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Gary Guo @ 2026-07-13 20:14 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Greg Kroah-Hartman, Rafael J. Wysocki,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Daniel Almeida,
	Tamir Duberstein, Onur Özkan, Eliot Courtney
  Cc: nova-gpu, dri-devel, linux-kernel, driver-core, rust-for-linux

From: Gary Guo <gary@garyguo.net>

Currently the lifetime on `Core` and `CoreInternal` is covariant. This
means that they can be coerced into shorter living lifetimes. On `probe`
function, signature has `&'bound Device<Core<'a>>`; the type's wellformness
would imply `'a: 'bound` and thus the type can be coerced `&'bound
Device<Core<'bound>>`, defeating the purpose of having the lifetime bound
to prevent users of the `Core` type to escape the function.

Fix this by making the lifetime invariant, so the coercion is impossible.
The lifetime here only needs to be "branded" so it does not coerce or unify
with other lifetimes, so we do not need to ensure `'bound: 'a`.

This requires modifying `nova-core` which relies on this implied bound due
to pre-2024 capture rule. The "use" bound can be removed if built with
edition 2024.

Fixes: 24799831d631 ("rust: device: make Core and CoreInternal lifetime-parameterized")
Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/gpu/nova-core/gpu.rs |  6 +++---
 rust/kernel/device.rs        | 10 ++++++++--
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index b3c91731db45..b603b0bd2692 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> {
 }
 
 impl<'gpu> Gpu<'gpu> {
-    pub(crate) fn new(
-        pdev: &'gpu pci::Device<device::Core<'_>>,
+    pub(crate) fn new<'a>(
+        pdev: &'gpu pci::Device<device::Core<'a>>,
         bar: Bar0<'gpu>,
-    ) -> impl PinInit<Self, Error> + 'gpu {
+    ) -> impl PinInit<Self, Error> + use<'gpu, 'a> {
         try_pin_init!(Self {
             device: pdev.as_ref(),
             spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 645afc49a27d..db25ed1ae8e5 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -511,7 +511,11 @@ pub trait DeviceContext: private::Sealed {}
 /// callback it appears in. It is intended to be used for synchronization purposes. Bus device
 /// implementations can implement methods for [`Device<Core>`], such that they can only be called
 /// from bus callbacks.
-pub struct Core<'a>(PhantomData<&'a ()>);
+///
+/// The lifetime `'a` is for "lifetime branding" purpose. Callbacks need to polymorphic over this
+/// lifetime so the `&'bound Device<Core<'_>>` provided to them cannot outlive the scope of the
+/// function. For this reason, it needs to be invariant.
+pub struct Core<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
 
 /// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus
 /// abstraction.
@@ -522,7 +526,9 @@ pub trait DeviceContext: private::Sealed {}
 ///
 /// This context mainly exists to share generic [`Device`] infrastructure that should only be called
 /// from bus callbacks with bus abstractions, but without making them accessible for drivers.
-pub struct CoreInternal<'a>(PhantomData<&'a ()>);
+///
+/// Lifetime `'a` is invariant for the same reason as [`Core`].
+pub struct CoreInternal<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
 
 /// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to
 /// be bound to a driver.

base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
-- 
2.54.0


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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 20:14 [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant Gary Guo
@ 2026-07-13 20:23 ` Gary Guo
  2026-07-13 20:55   ` Danilo Krummrich
  2026-07-13 20:29 ` Danilo Krummrich
  2026-07-14 13:47 ` kernel test robot
  2 siblings, 1 reply; 7+ messages in thread
From: Gary Guo @ 2026-07-13 20:23 UTC (permalink / raw)
  To: Gary Guo, Danilo Krummrich, Alice Ryhl, Alexandre Courbot,
	David Airlie, Simona Vetter, Greg Kroah-Hartman,
	Rafael J. Wysocki, Miguel Ojeda, Boqun Feng, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Daniel Almeida,
	Tamir Duberstein, Onur Özkan, Eliot Courtney
  Cc: nova-gpu, dri-devel, linux-kernel, driver-core, rust-for-linux

On Mon Jul 13, 2026 at 9:14 PM BST, Gary Guo wrote:
> From: Gary Guo <gary@garyguo.net>
>
> Currently the lifetime on `Core` and `CoreInternal` is covariant. This
> means that they can be coerced into shorter living lifetimes. On `probe`
> function, signature has `&'bound Device<Core<'a>>`; the type's wellformness
> would imply `'a: 'bound` and thus the type can be coerced `&'bound
> Device<Core<'bound>>`, defeating the purpose of having the lifetime bound
> to prevent users of the `Core` type to escape the function.
>
> Fix this by making the lifetime invariant, so the coercion is impossible.
> The lifetime here only needs to be "branded" so it does not coerce or unify
> with other lifetimes, so we do not need to ensure `'bound: 'a`.
>
> This requires modifying `nova-core` which relies on this implied bound due
> to pre-2024 capture rule. The "use" bound can be removed if built with
> edition 2024.

Actually, a more proper fix is to make `Device` invariant over their
context. It would require touching all `Device`, though.

Danilo, let me know if you'd prefer that approach instead.

Best,
Gary

>
> Fixes: 24799831d631 ("rust: device: make Core and CoreInternal lifetime-parameterized")
> Signed-off-by: Gary Guo <gary@garyguo.net>
> ---
>  drivers/gpu/nova-core/gpu.rs |  6 +++---
>  rust/kernel/device.rs        | 10 ++++++++--
>  2 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index b3c91731db45..b603b0bd2692 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> {
>  }
>  
>  impl<'gpu> Gpu<'gpu> {
> -    pub(crate) fn new(
> -        pdev: &'gpu pci::Device<device::Core<'_>>,
> +    pub(crate) fn new<'a>(
> +        pdev: &'gpu pci::Device<device::Core<'a>>,
>          bar: Bar0<'gpu>,
> -    ) -> impl PinInit<Self, Error> + 'gpu {
> +    ) -> impl PinInit<Self, Error> + use<'gpu, 'a> {
>          try_pin_init!(Self {
>              device: pdev.as_ref(),
>              spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
> diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
> index 645afc49a27d..db25ed1ae8e5 100644
> --- a/rust/kernel/device.rs
> +++ b/rust/kernel/device.rs
> @@ -511,7 +511,11 @@ pub trait DeviceContext: private::Sealed {}
>  /// callback it appears in. It is intended to be used for synchronization purposes. Bus device
>  /// implementations can implement methods for [`Device<Core>`], such that they can only be called
>  /// from bus callbacks.
> -pub struct Core<'a>(PhantomData<&'a ()>);
> +///
> +/// The lifetime `'a` is for "lifetime branding" purpose. Callbacks need to polymorphic over this
> +/// lifetime so the `&'bound Device<Core<'_>>` provided to them cannot outlive the scope of the
> +/// function. For this reason, it needs to be invariant.
> +pub struct Core<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
>  
>  /// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus
>  /// abstraction.
> @@ -522,7 +526,9 @@ pub trait DeviceContext: private::Sealed {}
>  ///
>  /// This context mainly exists to share generic [`Device`] infrastructure that should only be called
>  /// from bus callbacks with bus abstractions, but without making them accessible for drivers.
> -pub struct CoreInternal<'a>(PhantomData<&'a ()>);
> +///
> +/// Lifetime `'a` is invariant for the same reason as [`Core`].
> +pub struct CoreInternal<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
>  
>  /// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to
>  /// be bound to a driver.
>
> base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa



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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 20:14 [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant Gary Guo
  2026-07-13 20:23 ` Gary Guo
@ 2026-07-13 20:29 ` Danilo Krummrich
  2026-07-13 21:03   ` Gary Guo
  2026-07-14 13:47 ` kernel test robot
  2 siblings, 1 reply; 7+ messages in thread
From: Danilo Krummrich @ 2026-07-13 20:29 UTC (permalink / raw)
  To: Gary Guo
  Cc: Gary Guo, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Greg Kroah-Hartman, Rafael J. Wysocki,
	Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, Eliot Courtney, nova-gpu, dri-devel,
	linux-kernel, driver-core, rust-for-linux

On Mon Jul 13, 2026 at 10:14 PM CEST, Gary Guo wrote:
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index b3c91731db45..b603b0bd2692 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> {
>  }
>  
>  impl<'gpu> Gpu<'gpu> {
> -    pub(crate) fn new(
> -        pdev: &'gpu pci::Device<device::Core<'_>>,
> +    pub(crate) fn new<'a>(
> +        pdev: &'gpu pci::Device<device::Core<'a>>,
>          bar: Bar0<'gpu>,
> -    ) -> impl PinInit<Self, Error> + 'gpu {
> +    ) -> impl PinInit<Self, Error> + use<'gpu, 'a> {

Isn't that edition 2024 only?

>          try_pin_init!(Self {
>              device: pdev.as_ref(),
>              spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {

I think you also need this hunk:

diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
index 1f59e08aaa4b..6fe94a73c52a 100644
--- a/samples/rust/rust_debugfs.rs
+++ b/samples/rust/rust_debugfs.rs
@@ -147,7 +147,7 @@ fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ {
         dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 }))
     }

-    fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a {
+    fn new<'a, 'b>(pdev: &'a platform::Device<Core<'b>>) -> impl PinInit<Self, Error> + use<'a, 'b> {
         let debugfs = Dir::new(c"sample_debugfs");
         let dev = pdev.as_ref();

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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 20:23 ` Gary Guo
@ 2026-07-13 20:55   ` Danilo Krummrich
  0 siblings, 0 replies; 7+ messages in thread
From: Danilo Krummrich @ 2026-07-13 20:55 UTC (permalink / raw)
  To: Gary Guo
  Cc: Alice Ryhl, Alexandre Courbot, David Airlie, Simona Vetter,
	Greg Kroah-Hartman, Rafael J. Wysocki, Miguel Ojeda, Boqun Feng,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan,
	Eliot Courtney, nova-gpu, dri-devel, linux-kernel, driver-core,
	rust-for-linux

On Mon Jul 13, 2026 at 10:23 PM CEST, Gary Guo wrote:
> Actually, a more proper fix is to make `Device` invariant over their
> context. It would require touching all `Device`, though.
>
> Danilo, let me know if you'd prefer that approach instead.

The bigger change is not a concern, but requiring every bus device implementor
to consider this is a bit of a concern. If we can enforce it in the driver core
code I'd prefer that.

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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 20:29 ` Danilo Krummrich
@ 2026-07-13 21:03   ` Gary Guo
  2026-07-13 21:09     ` Danilo Krummrich
  0 siblings, 1 reply; 7+ messages in thread
From: Gary Guo @ 2026-07-13 21:03 UTC (permalink / raw)
  To: Danilo Krummrich, Gary Guo
  Cc: Gary Guo, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Greg Kroah-Hartman, Rafael J. Wysocki,
	Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, Eliot Courtney, nova-gpu, dri-devel,
	linux-kernel, driver-core, rust-for-linux

On Mon Jul 13, 2026 at 9:29 PM BST, Danilo Krummrich wrote:
> On Mon Jul 13, 2026 at 10:14 PM CEST, Gary Guo wrote:
>> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
>> index b3c91731db45..b603b0bd2692 100644
>> --- a/drivers/gpu/nova-core/gpu.rs
>> +++ b/drivers/gpu/nova-core/gpu.rs
>> @@ -285,10 +285,10 @@ pub(crate) struct Gpu<'gpu> {
>>  }
>>  
>>  impl<'gpu> Gpu<'gpu> {
>> -    pub(crate) fn new(
>> -        pdev: &'gpu pci::Device<device::Core<'_>>,
>> +    pub(crate) fn new<'a>(
>> +        pdev: &'gpu pci::Device<device::Core<'a>>,
>>          bar: Bar0<'gpu>,
>> -    ) -> impl PinInit<Self, Error> + 'gpu {
>> +    ) -> impl PinInit<Self, Error> + use<'gpu, 'a> {
>
> Isn't that edition 2024 only?

The syntax is available to all editions. Pre-2024 only type parameters are
captured, so the `use` would be needed to capture `'a`.

In 2024 the capture rule is changed so that all lifetimes are captured by
default, removing the inconsistency between lifetime and type parameters, so
this can just be 

    pub(crate) fn new(
        pdev: &'gpu pci::Device<device::Core<'_>>,
        bar: Bar0<'gpu>,
    ) -> impl PinInit<Self, Error> {

The equivalent code without using `use` is

    pub(crate) fn new<'init, 'a>(
        pdev: &'gpu pci::Device<device::Core<'a>>,
        bar: Bar0<'gpu>,
    ) -> impl PinInit<Self, Error> + 'init where 'init: 'gpu, 'init: 'a {

but `use` is stable in 1.82+ so we can just use it instead.

>
>>          try_pin_init!(Self {
>>              device: pdev.as_ref(),
>>              spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| {
>
> I think you also need this hunk:
>
> diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
> index 1f59e08aaa4b..6fe94a73c52a 100644
> --- a/samples/rust/rust_debugfs.rs
> +++ b/samples/rust/rust_debugfs.rs
> @@ -147,7 +147,7 @@ fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ {
>          dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 }))
>      }
>
> -    fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a {
> +    fn new<'a, 'b>(pdev: &'a platform::Device<Core<'b>>) -> impl PinInit<Self, Error> + use<'a, 'b> {
>          let debugfs = Dir::new(c"sample_debugfs");
>          let dev = pdev.as_ref();

Right, somehow debugfs is disabled in my test build that I didn't notice.

Best,
Gary


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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 21:03   ` Gary Guo
@ 2026-07-13 21:09     ` Danilo Krummrich
  0 siblings, 0 replies; 7+ messages in thread
From: Danilo Krummrich @ 2026-07-13 21:09 UTC (permalink / raw)
  To: Gary Guo
  Cc: Gary Guo, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Greg Kroah-Hartman, Rafael J. Wysocki,
	Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, Daniel Almeida, Tamir Duberstein,
	Onur Özkan, Eliot Courtney, nova-gpu, dri-devel,
	linux-kernel, driver-core, rust-for-linux

On Mon Jul 13, 2026 at 11:03 PM CEST, Gary Guo wrote:
> but `use` is stable in 1.82+ so we can just use it instead.

Ah, right. I was confusing this with the situation before the version bump up
from 1.78.

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

* Re: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
  2026-07-13 20:14 [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant Gary Guo
  2026-07-13 20:23 ` Gary Guo
  2026-07-13 20:29 ` Danilo Krummrich
@ 2026-07-14 13:47 ` kernel test robot
  2 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2026-07-14 13:47 UTC (permalink / raw)
  To: Gary Guo, Danilo Krummrich, Alice Ryhl, Alexandre Courbot,
	David Airlie, Simona Vetter, Greg Kroah-Hartman,
	Rafael J. Wysocki, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, Daniel Almeida, Tamir Duberstein, Onur Özkan,
	Eliot Courtney
  Cc: llvm, oe-kbuild-all, nova-gpu, dri-devel, linux-kernel,
	driver-core, rust-for-linux

Hi Gary,

kernel test robot noticed the following build errors:

[auto build test ERROR on a13c140cc289c0b7b3770bce5b3ad42ab35074aa]

url:    https://github.com/intel-lab-lkp/linux/commits/Gary-Guo/rust-device-make-lifetime-on-Core-and-CoreInternal-invariant/20260714-041724
base:   a13c140cc289c0b7b3770bce5b3ad42ab35074aa
patch link:    https://lore.kernel.org/r/20260713201455.640151-1-gary%40kernel.org
patch subject: [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant
config: x86_64-buildonly-randconfig-002-20260714 (https://download.01.org/0day-ci/archive/20260714/202607142146.1EoHdPGy-lkp@intel.com/config)
compiler: clang version 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211)
rustc: rustc 1.96.0 (ac68faa20 2026-05-25)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260714/202607142146.1EoHdPGy-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202607142146.1EoHdPGy-lkp@intel.com/

All errors (new ones prefixed by >>):

>> error[E0700]: hidden type for `impl pin_init::PinInit<RustDebugFs, kernel::error::Error> + 'a` captures lifetime that does not appear in bounds
   --> samples/rust/rust_debugfs.rs:154:9
   |
   150 |       fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a {
   |                                             --------      ------------------------------ opaque type defined here
   |                                             |
>> |                                             hidden type `impl pin_init::PinInit<RustDebugFs, kernel::error::Error>` captures the anonymous lifetime defined here
   ...
   154 | /         try_pin_init! {
   155 | |             Self {
   156 | |                 _compatible <- debugfs.read_only_file(
   157 | |                     c"compatible",
   ...   |
   176 | |         }
   | |_________^
   |
   = note: this error originates in the macro `::pin_init::pin_init` which comes from the expansion of the macro `try_pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
   help: add a `use<...>` bound to explicitly capture `'_`
   |
   150 |     fn new<'a>(pdev: &'a platform::Device<Core<'_>>) -> impl PinInit<Self, Error> + 'a + use<'a, '_> {
   |                                                                                        +++++++++++++

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

end of thread, other threads:[~2026-07-14 13:47 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 20:14 [PATCH] rust: device: make lifetime on `Core` and `CoreInternal` invariant Gary Guo
2026-07-13 20:23 ` Gary Guo
2026-07-13 20:55   ` Danilo Krummrich
2026-07-13 20:29 ` Danilo Krummrich
2026-07-13 21:03   ` Gary Guo
2026-07-13 21:09     ` Danilo Krummrich
2026-07-14 13:47 ` kernel test robot

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