From: Gary Guo <[email protected]>
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 <[email protected]>
---
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