aboutsummaryrefslogtreecommitdiff
path: root/rust/kernel
diff options
context:
space:
mode:
authorDanilo Krummrich <dakr@kernel.org>2026-05-29 00:38:54 +0200
committerDanilo Krummrich <dakr@kernel.org>2026-05-29 00:38:54 +0200
commit2c7c65933600e8db2ec1a78dec5008de876dd3ad (patch)
tree75685a96fdc579cc2b1470efef9f21ced5f9ee41 /rust/kernel
parent557495bc879013c3d5e21d667e987e7ce3a514de (diff)
parentd18f3646184fc805d213fc049fc3b5d9fb9a6a27 (diff)
Merge patch series "rust: device: Higher-Ranked Lifetime Types for device drivers"
Danilo Krummrich <dakr@kernel.org> says: Currently, Rust device drivers access device resources such as PCI BAR mappings and I/O memory regions through Devres<T>. Devres::access() provides zero-overhead access by taking a &Device<Bound> reference as proof that the device is still bound. Since a &Device<Bound> is available in almost all contexts by design, Devres is mostly a type-system level proof that the resource is valid, but it can also be used from scopes without this guarantee through its try_access() accessor. This works well in general, but has a few limitations: - Every access to a device resource goes through Devres::access(), which despite zero cost, adds boilerplate to every access site. - Destructors do not receive a &Device<Bound>, so they must use try_access(), which can fail. In practice the access succeeds if teardown ordering is correct, but the type system can't express this, forcing drivers to handle a failure path that should never be taken. - Sharing a resource across components (e.g. passing a BAR to a sub-component) requires Arc<Devres<T>>. - Device references must be stored as ARef<Device> rather than plain &Device borrows. These limitations stem from the driver's bus device private data being 'static -- the driver struct cannot borrow from the device reference it receives in probe(), even though it structurally cannot outlive the device binding. This series introduces Higher-Ranked Lifetime Types (HRT) for Rust device drivers. An HRT is a type that is generic over a lifetime -- it does not have a fixed lifetime, but can be instantiated with any lifetime chosen by the caller. Bus driver traits use a Generic Associated Type (GAT) type Data<'bound> to introduce the lifetime on the private data, rather than parameterizing the Driver trait itself. This avoids a driver trait global lifetime and avoids the need for ForLt for bus device private data, making the bus implementations much simpler. ForLt is only needed for auxiliary registration data, where the lifetime is not introduced by a trait callback but must be threaded through Registration. With HRT, driver structs carry a lifetime parameter tied to the device binding scope -- the interval of a bus device being bound to a driver. Device resources like pci::Bar<'bound> and IoMem<'bound> are handed out with this lifetime, so the compiler enforces at build time that they do not escape the binding scope. Before: struct MyDriver { pdev: ARef<pci::Device>, bar: Devres<pci::Bar<BAR_SIZE>>, } let io = self.bar.access(dev)?; io.read32(OFFSET); After: struct MyDriver<'bound> { pdev: &'bound pci::Device, bar: pci::Bar<'bound, BAR_SIZE>, } self.bar.read32(OFFSET); Lifetime-parameterized device resources can be put into a Devres at any point via Bar::into_devres() / IoMem::into_devres(), providing the exact same semantics as before. This is useful for resources shared across subsystem boundaries where revocation is needed. This also synergizes with the upcoming self-referential initialization support in pin-init, which allows one field of the driver struct to borrow another during initialization without unsafe code. The same pattern is applied to auxiliary device registration data as a first example beyond bus device private data. Registration<F: ForLt> can hold lifetime-parameterized data tied to the parent driver's binding scope. Since the auxiliary bus guarantees that the parent remains bound while the auxiliary device is registered, the registration data can safely borrow the parent's device resources. More generally, binding resource lifetimes to a registration scope applies to every registration that is scoped to a driver binding -- auxiliary devices, class devices, IRQ handlers, workqueues. A follow-up series extends this to class device registrations, starting with DRM, so that class device callbacks (IOCTLs, etc.) can safely access device resources through the separate registration data bound to the registration's lifetime without Devres indirection. Thanks to Gary for coming up with the ForLt implementation; thanks to Alice for the early discussions around lifetime-parameterized private data that helped shape the direction of this work. Link: https://patch.msgid.link/20260525202921.124698-1-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'rust/kernel')
-rw-r--r--rust/kernel/alloc/kbox.rs24
-rw-r--r--rust/kernel/auxiliary.rs141
-rw-r--r--rust/kernel/cpufreq.rs9
-rw-r--r--rust/kernel/device.rs61
-rw-r--r--rust/kernel/devres.rs2
-rw-r--r--rust/kernel/dma.rs2
-rw-r--r--rust/kernel/driver.rs41
-rw-r--r--rust/kernel/i2c.rs61
-rw-r--r--rust/kernel/io/mem.rs121
-rw-r--r--rust/kernel/pci.rs51
-rw-r--r--rust/kernel/pci/id.rs2
-rw-r--r--rust/kernel/pci/io.rs54
-rw-r--r--rust/kernel/platform.rs52
-rw-r--r--rust/kernel/types.rs12
-rw-r--r--rust/kernel/types/for_lt.rs122
-rw-r--r--rust/kernel/usb.rs57
16 files changed, 554 insertions, 258 deletions
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index c824ed6e1523..2f8c16473c2c 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -477,7 +477,7 @@ where
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T` allocated by `A`.
-unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
+unsafe impl<T, A> ForeignOwnable for Box<T, A>
where
A: Allocator,
{
@@ -487,8 +487,14 @@ where
core::mem::align_of::<T>()
};
- type Borrowed<'a> = &'a T;
- type BorrowedMut<'a> = &'a mut T;
+ type Borrowed<'a>
+ = &'a T
+ where
+ Self: 'a;
+ type BorrowedMut<'a>
+ = &'a mut T
+ where
+ Self: 'a;
fn into_foreign(self) -> *mut c_void {
Box::into_raw(self).cast()
@@ -516,13 +522,19 @@ where
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T` allocated by `A`.
-unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
+unsafe impl<T, A> ForeignOwnable for Pin<Box<T, A>>
where
A: Allocator,
{
const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN;
- type Borrowed<'a> = Pin<&'a T>;
- type BorrowedMut<'a> = Pin<&'a mut T>;
+ type Borrowed<'a>
+ = Pin<&'a T>
+ where
+ Self: 'a;
+ type BorrowedMut<'a>
+ = Pin<&'a mut T>
+ where
+ Self: 'a;
fn into_foreign(self) -> *mut c_void {
// SAFETY: We are still treating the box as pinned.
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 19aec94aa95b..c42928d5a239 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -12,7 +12,7 @@ use crate::{
RawDeviceId,
RawDeviceIdIndex, //
},
- devres::Devres,
+
driver,
error::{
from_result,
@@ -20,6 +20,7 @@ use crate::{
},
prelude::*,
types::{
+ ForLt,
ForeignOwnable,
Opaque, //
},
@@ -41,18 +42,18 @@ pub struct Adapter<T: Driver>(T);
// SAFETY:
// - `bindings::auxiliary_driver` is a C type declared as `repr(C)`.
-// - `T` is the type of the driver's device private data.
+// - `T::Data` is the type of the driver's device private data.
// - `struct auxiliary_driver` embeds a `struct device_driver`.
// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`.
-unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> {
+unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> {
type DriverType = bindings::auxiliary_driver;
- type DriverData = T;
+ type DriverData<'bound> = T::Data<'bound>;
const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
}
// SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if
// a preceding call to `register` has been successful.
-unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
+unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> {
unsafe fn register(
adrv: &Opaque<Self::DriverType>,
name: &'static CStr,
@@ -78,7 +79,7 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
}
}
-impl<T: Driver + 'static> Adapter<T> {
+impl<T: Driver> Adapter<T> {
extern "C" fn probe_callback(
adev: *mut bindings::auxiliary_device,
id: *const bindings::auxiliary_device_id,
@@ -87,7 +88,7 @@ impl<T: Driver + 'static> Adapter<T> {
// `struct auxiliary_device`.
//
// INVARIANT: `adev` is valid for the duration of `probe_callback()`.
- let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() };
+ let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() };
// SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id`
// and does not add additional invariants, so it's safe to transmute.
@@ -107,12 +108,12 @@ impl<T: Driver + 'static> Adapter<T> {
// `struct auxiliary_device`.
//
// INVARIANT: `adev` is valid for the duration of `remove_callback()`.
- let adev = unsafe { &*adev.cast::<Device<device::CoreInternal>>() };
+ let adev = unsafe { &*adev.cast::<Device<device::CoreInternal<'_>>>() };
// SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
- // and stored a `Pin<KBox<T>>`.
- let data = unsafe { adev.as_ref().drvdata_borrow::<T>() };
+ // and stored a `Pin<KBox<T::Data<'_>>>`.
+ let data = unsafe { adev.as_ref().drvdata_borrow::<T::Data<'_>>() };
T::unbind(adev, data);
}
@@ -202,13 +203,19 @@ pub trait Driver {
/// type IdInfo: 'static = ();
type IdInfo: 'static;
+ /// The type of the driver's bus device private data.
+ type Data<'bound>: Send + 'bound;
+
/// The table of device ids supported by the driver.
const ID_TABLE: IdTable<Self::IdInfo>;
/// Auxiliary driver probe.
///
/// Called when an auxiliary device is matches a corresponding driver.
- fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>;
+ fn probe<'bound>(
+ dev: &'bound Device<device::Core<'_>>,
+ id_info: &'bound Self::IdInfo,
+ ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
/// Auxiliary driver unbind.
///
@@ -219,8 +226,8 @@ pub trait Driver {
/// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O
/// operations to gracefully tear down the device.
///
- /// Otherwise, release operations for driver resources should be performed in `Self::drop`.
- fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) {
+ /// Otherwise, release operations for driver resources should be performed in `Drop`.
+ fn unbind<'bound>(dev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) {
let _ = (dev, this);
}
}
@@ -265,12 +272,16 @@ impl Device<device::Bound> {
/// Returns a pinned reference to the registration data set by the registering (parent) driver.
///
- /// Returns [`EINVAL`] if `T` does not match the type used by the parent driver when calling
+ /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned
+ /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via
+ /// [`ForLt::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<T: 'static>(&self) -> Result<Pin<&T>> {
+ pub fn registration_data<F: ForLt + '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() {
@@ -283,18 +294,23 @@ impl Device<device::Bound> {
// SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`;
// `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId`
- // at the start of the allocation is valid regardless of `T`.
+ // at the start of the allocation is valid regardless of `F`.
let type_id = unsafe { ptr.cast::<TypeId>().read() };
- if type_id != TypeId::of::<T>() {
+ if type_id != TypeId::of::<F>() {
return Err(EINVAL);
}
- // SAFETY: The `TypeId` check above confirms that the stored type is `T`; `ptr` remains
- // valid until `Registration::drop()` calls `from_foreign()`.
- let wrapper = unsafe { Pin::<KBox<RegistrationData<T>>>::borrow(ptr) };
+ // SAFETY: The `TypeId` check above confirms that the stored type matches
+ // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls
+ // `from_foreign()`.
+ let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };
// SAFETY: `data` is a structurally pinned field of `RegistrationData`.
- Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })
+ let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) };
+
+ // SAFETY: The data was pinned when stored; `cast_ref` only shortens
+ // the lifetime, so the pinning guarantee is preserved.
+ Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })
}
}
@@ -365,6 +381,10 @@ unsafe impl Send for Device {}
// (i.e. `Device<Normal>) are thread safe.
unsafe impl Sync for Device {}
+// SAFETY: Same as `Device<Normal>` -- the underlying `struct auxiliary_device` is the same;
+// `Bound` is a zero-sized type-state marker that does not affect thread safety.
+unsafe impl Sync for Device<device::Bound> {}
+
/// Wrapper that stores a [`TypeId`] alongside the registration data for runtime type checking.
#[repr(C)]
#[pin_data]
@@ -379,43 +399,60 @@ 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 `T` is the type of the registration data owned by the registering (parent)
-/// driver. It 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()`].
///
/// # 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<T>>>`.
-pub struct Registration<T: 'static> {
+/// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`.
+pub struct Registration<'a, F: ForLt + 'static> {
adev: NonNull<bindings::auxiliary_device>,
- _data: PhantomData<T>,
+ _phantom: PhantomData<F::Of<'a>>,
}
-impl<T: Send + Sync + 'static> Registration<T> {
+impl<'a, F: ForLt> Registration<'a, F>
+where
+ for<'b> F::Of<'b>: Send + Sync,
+{
/// Create and register a new auxiliary device with the given registration data.
///
/// The `data` is owned by the registration and can be accessed through the auxiliary device
/// via [`Device::registration_data()`].
- pub fn new<E>(
- parent: &device::Device<device::Bound>,
+ ///
+ /// # Safety
+ ///
+ /// The caller must not `mem::forget()` the returned [`Registration`] or otherwise prevent its
+ /// [`Drop`] implementation from running, since the registration data may contain borrowed
+ /// references that become invalid after `'a` ends.
+ ///
+ /// If the registration data is `'static`, use the safe [`Registration::new()`] instead.
+ pub unsafe fn new_with_lt<E>(
+ parent: &'a device::Device<device::Bound>,
name: &CStr,
id: u32,
modname: &CStr,
- data: impl PinInit<T, E>,
- ) -> Result<Devres<Self>>
+ data: impl PinInit<F::Of<'a>, E>,
+ ) -> Result<Self>
where
Error: From<E>,
{
let data = KBox::pin_init::<Error>(
try_pin_init!(RegistrationData {
- type_id: TypeId::of::<T>(),
+ type_id: TypeId::of::<F>(),
data <- data,
}),
GFP_KERNEL,
)?;
+ // SAFETY: `'a` is invariant (via `Registration`'s `PhantomData`). Lifetimes do not
+ // affect layout, so RegistrationData<F::Of<'a>> and RegistrationData<F::Of<'static>>
+ // have identical representation.
+ let data: Pin<KBox<RegistrationData<F::Of<'static>>>> =
+ unsafe { core::mem::transmute(data) };
+
let boxed: KBox<Opaque<bindings::auxiliary_device>> = KBox::zeroed(GFP_KERNEL)?;
let adev = boxed.get();
@@ -445,7 +482,9 @@ impl<T: Send + Sync + 'static> Registration<T> {
if ret != 0 {
// SAFETY: `registration_data` was set above via `into_foreign()`.
drop(unsafe {
- Pin::<KBox<RegistrationData<T>>>::from_foreign((*adev).registration_data_rust)
+ Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(
+ (*adev).registration_data_rust,
+ )
});
// SAFETY: `adev` is guaranteed to be a valid pointer to a
@@ -457,18 +496,36 @@ impl<T: Send + Sync + 'static> Registration<T> {
// INVARIANT: The device will remain registered until `auxiliary_device_delete()` is
// called, which happens in `Self::drop()`.
- let reg = Self {
+ Ok(Self {
// SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated
// successfully.
adev: unsafe { NonNull::new_unchecked(adev) },
- _data: PhantomData,
- };
+ _phantom: PhantomData,
+ })
+ }
- Devres::new::<core::convert::Infallible>(parent, reg)
+ /// Create and register a new auxiliary device with `'static` registration data.
+ ///
+ /// Safe variant of [`Registration::new_with_lt()`] for registration data that does not contain
+ /// borrowed references.
+ pub fn new<E>(
+ parent: &'a device::Device<device::Bound>,
+ name: &CStr,
+ id: u32,
+ modname: &CStr,
+ data: impl PinInit<F::Of<'a>, E>,
+ ) -> Result<Self>
+ where
+ F::Of<'a>: 'static,
+ Error: From<E>,
+ {
+ // SAFETY: `F::Of<'a>: 'static` guarantees the data contains no borrowed references,
+ // so forgetting the `Registration` cannot cause use-after-free.
+ unsafe { Self::new_with_lt(parent, name, id, modname, data) }
}
}
-impl<T: 'static> Drop for Registration<T> {
+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`.
@@ -476,7 +533,7 @@ impl<T: 'static> Drop for Registration<T> {
// SAFETY: `registration_data` was set in `new()` via `into_foreign()`.
drop(unsafe {
- Pin::<KBox<RegistrationData<T>>>::from_foreign(
+ Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(
(*self.adev.as_ptr()).registration_data_rust,
)
});
@@ -490,7 +547,7 @@ impl<T: 'static> Drop for Registration<T> {
}
// SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.
-unsafe impl<T: Send + Sync> Send for Registration<T> {}
+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<T: Send + Sync> Sync for Registration<T> {}
+unsafe impl<F: ForLt> Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {}
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index d8d26870bea2..d94c6cdbc45a 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -888,12 +888,13 @@ pub trait Driver {
///
/// impl platform::Driver for SampleDriver {
/// type IdInfo = ();
+/// type Data<'bound> = Self;
/// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
///
-/// fn probe(
-/// pdev: &platform::Device<Core>,
-/// _id_info: Option<&Self::IdInfo>,
-/// ) -> impl PinInit<Self, Error> {
+/// fn probe<'bound>(
+/// pdev: &'bound platform::Device<Core<'_>>,
+/// _id_info: Option<&'bound Self::IdInfo>,
+/// ) -> impl PinInit<Self, Error> + 'bound {
/// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?;
/// Ok(Self {})
/// }
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index fd50399aadea..645afc49a27d 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -201,9 +201,9 @@ impl Device {
}
}
-impl Device<CoreInternal> {
+impl<'a> Device<CoreInternal<'a>> {
/// Store a pointer to the bound driver's private data.
- pub fn set_drvdata<T: 'static>(&self, data: impl PinInit<T, Error>) -> Result {
+ pub fn set_drvdata<T>(&self, data: impl PinInit<T, Error>) -> Result {
let data = KBox::pin_init(data, GFP_KERNEL)?;
// SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`.
@@ -218,7 +218,7 @@ impl Device<CoreInternal> {
///
/// - The type `T` must match the type of the `ForeignOwnable` previously stored by
/// [`Device::set_drvdata`].
- pub(crate) unsafe fn drvdata_obtain<T: 'static>(&self) -> Option<Pin<KBox<T>>> {
+ pub(crate) unsafe fn drvdata_obtain<T>(&self) -> Option<Pin<KBox<T>>> {
// SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`.
let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) };
@@ -244,7 +244,7 @@ impl Device<CoreInternal> {
/// device is fully unbound.
/// - The type `T` must match the type of the `ForeignOwnable` previously stored by
/// [`Device::set_drvdata`].
- pub unsafe fn drvdata_borrow<T: 'static>(&self) -> Pin<&T> {
+ pub unsafe fn drvdata_borrow<T>(&self) -> Pin<&T> {
// SAFETY: `drvdata_unchecked()` has the exact same safety requirements as the ones
// required by this method.
unsafe { self.drvdata_unchecked() }
@@ -260,7 +260,7 @@ impl Device<Bound> {
/// the device is fully unbound.
/// - The type `T` must match the type of the `ForeignOwnable` previously stored by
/// [`Device::set_drvdata`].
- unsafe fn drvdata_unchecked<T: 'static>(&self) -> Pin<&T> {
+ unsafe fn drvdata_unchecked<T>(&self) -> Pin<&T> {
// SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`.
let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) };
@@ -467,6 +467,10 @@ unsafe impl Send for Device {}
// synchronization in `struct device`.
unsafe impl Sync for Device {}
+// SAFETY: Same as `Device<Normal>` -- the underlying `struct device` is the same; `Bound` is a
+// zero-sized type-state marker that does not affect thread safety.
+unsafe impl Sync for Device<Bound> {}
+
/// Marker trait for the context or scope of a bus specific device.
///
/// [`DeviceContext`] is a marker trait for types representing the context of a bus specific
@@ -507,7 +511,7 @@ pub struct Normal;
/// 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;
+pub struct Core<'a>(PhantomData<&'a ()>);
/// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus
/// abstraction.
@@ -518,7 +522,7 @@ pub struct Core;
///
/// 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;
+pub struct CoreInternal<'a>(PhantomData<&'a ()>);
/// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to
/// be bound to a driver.
@@ -542,14 +546,14 @@ mod private {
pub trait Sealed {}
impl Sealed for super::Bound {}
- impl Sealed for super::Core {}
- impl Sealed for super::CoreInternal {}
+ impl<'a> Sealed for super::Core<'a> {}
+ impl<'a> Sealed for super::CoreInternal<'a> {}
impl Sealed for super::Normal {}
}
impl DeviceContext for Bound {}
-impl DeviceContext for Core {}
-impl DeviceContext for CoreInternal {}
+impl<'a> DeviceContext for Core<'a> {}
+impl<'a> DeviceContext for CoreInternal<'a> {}
impl DeviceContext for Normal {}
impl<Ctx: DeviceContext> AsRef<Device<Ctx>> for Device<Ctx> {
@@ -599,6 +603,22 @@ pub unsafe trait AsBusDevice<Ctx: DeviceContext>: AsRef<Device<Ctx>> {
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_device_context_deref {
+ (unsafe { $device:ident, <$lt:lifetime> $src:ty => $dst:ty }) => {
+ impl<$lt> ::core::ops::Deref for $device<$src> {
+ type Target = $device<$dst>;
+
+ fn deref(&self) -> &Self::Target {
+ let ptr: *const Self = self;
+
+ // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the
+ // safety requirement of the macro.
+ let ptr = ptr.cast::<Self::Target>();
+
+ // SAFETY: `ptr` was derived from `&self`.
+ unsafe { &*ptr }
+ }
+ }
+ };
(unsafe { $device:ident, $src:ty => $dst:ty }) => {
impl ::core::ops::Deref for $device<$src> {
type Target = $device<$dst>;
@@ -631,14 +651,14 @@ macro_rules! impl_device_context_deref {
// `__impl_device_context_deref!`.
::kernel::__impl_device_context_deref!(unsafe {
$device,
- $crate::device::CoreInternal => $crate::device::Core
+ <'a> $crate::device::CoreInternal<'a> => $crate::device::Core<'a>
});
// SAFETY: This macro has the exact same safety requirement as
// `__impl_device_context_deref!`.
::kernel::__impl_device_context_deref!(unsafe {
$device,
- $crate::device::Core => $crate::device::Bound
+ <'a> $crate::device::Core<'a> => $crate::device::Bound
});
// SAFETY: This macro has the exact same safety requirement as
@@ -653,6 +673,13 @@ macro_rules! impl_device_context_deref {
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_device_context_into_aref {
+ (<$lt:lifetime> $src:ty, $device:tt) => {
+ impl<$lt> ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> {
+ fn from(dev: &$device<$src>) -> Self {
+ (&**dev).into()
+ }
+ }
+ };
($src:ty, $device:tt) => {
impl ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> {
fn from(dev: &$device<$src>) -> Self {
@@ -667,8 +694,12 @@ macro_rules! __impl_device_context_into_aref {
#[macro_export]
macro_rules! impl_device_context_into_aref {
($device:tt) => {
- ::kernel::__impl_device_context_into_aref!($crate::device::CoreInternal, $device);
- ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device);
+ ::kernel::__impl_device_context_into_aref!(
+ <'a> $crate::device::CoreInternal<'a>, $device
+ );
+ ::kernel::__impl_device_context_into_aref!(
+ <'a> $crate::device::Core<'a>, $device
+ );
::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device);
};
}
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 9e5f93aed20c..82cbd8b969fb 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -304,7 +304,7 @@ impl<T: Send> Devres<T> {
/// pci, //
/// };
///
- /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result {
+ /// fn from_core(dev: &pci::Device<Core<'_>>, devres: Devres<pci::Bar<'_, 0x4>>) -> Result {
/// let bar = devres.access(dev.as_ref())?;
///
/// let _ = bar.read32(0x0);
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 4995ee5dc689..8f97916e0688 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -47,7 +47,7 @@ pub type DmaAddress = bindings::dma_addr_t;
/// where the underlying bus is DMA capable, such as:
#[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")]
/// * [`platform::Device`](::kernel::platform::Device)
-pub trait Device: AsRef<device::Device<Core>> {
+pub trait Device<'a>: AsRef<device::Device<Core<'a>>> {
/// Set up the device's DMA streaming addressing capabilities.
///
/// This method is usually called once from `probe()` as soon as the device capabilities are
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index 93e5dd6ae371..bf5ba0d27553 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -13,10 +13,13 @@
//! The main driver interface is defined by a bus specific driver trait. For instance:
//!
//! ```ignore
-//! pub trait Driver: Send {
+//! pub trait Driver {
//! /// The type holding information about each device ID supported by the driver.
//! type IdInfo: 'static;
//!
+//! /// The type of the driver's bus device private data.
+//! type Data<'bound>: Send + 'bound;
+//!
//! /// The table of OF device ids supported by the driver.
//! const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
//!
@@ -24,10 +27,16 @@
//! const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
//!
//! /// Driver probe.
-//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>;
+//! fn probe<'bound>(
+//! dev: &'bound Device<device::Core<'_>>,
+//! id_info: &'bound Self::IdInfo,
+//! ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
//!
//! /// Driver unbind (optional).
-//! fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) {
+//! fn unbind<'bound>(
+//! dev: &'bound Device<device::Core<'_>>,
+//! this: Pin<&Self::Data<'bound>>,
+//! ) {
//! let _ = (dev, this);
//! }
//! }
@@ -42,8 +51,9 @@
)]
#![cfg_attr(CONFIG_PCI, doc = "* [`pci::Driver`](kernel::pci::Driver)")]
//!
-//! The `probe()` callback should return a `impl PinInit<Self, Error>`, i.e. the driver's private
-//! data. The bus abstraction should store the pointer in the corresponding bus device. The generic
+//! The `probe()` callback should return a
+//! `impl PinInit<Self::Data<'bound>, Error>`, i.e. the driver's private data. The bus
+//! abstraction should store the pointer in the corresponding bus device. The generic
//! [`Device`] infrastructure provides common helpers for this purpose on its
//! [`Device<CoreInternal>`] implementation.
//!
@@ -118,8 +128,8 @@ pub unsafe trait DriverLayout {
/// The specific driver type embedding a `struct device_driver`.
type DriverType: Default;
- /// The type of the driver's device private data.
- type DriverData;
+ /// The type of the driver's bus device private data.
+ type DriverData<'bound>;
/// Byte offset of the embedded `struct device_driver` within `DriverType`.
///
@@ -181,20 +191,20 @@ unsafe impl<T: RegistrationOps> Sync for Registration<T> {}
// any thread, so `Registration` is `Send`.
unsafe impl<T: RegistrationOps> Send for Registration<T> {}
-impl<T: RegistrationOps + 'static> Registration<T> {
+impl<T: RegistrationOps> Registration<T> {
extern "C" fn post_unbind_callback(dev: *mut bindings::device) {
// SAFETY: The driver core only ever calls the post unbind callback with a valid pointer to
// a `struct device`.
//
// INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`.
- let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal>>() };
+ let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal<'_>>>() };
- // `remove()` and all devres callbacks have been completed at this point, hence drop the
- // driver's device private data.
+ // `remove()` has been completed at this point; devres resources are still valid and will
+ // be released after the driver's bus device private data is dropped.
//
// SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the
- // driver's device private data type.
- drop(unsafe { dev.drvdata_obtain::<T::DriverData>() });
+ // driver's bus device private data type.
+ drop(unsafe { dev.drvdata_obtain::<T::DriverData<'_>>() });
}
/// Attach generic `struct device_driver` callbacks.
@@ -215,7 +225,10 @@ impl<T: RegistrationOps + 'static> Registration<T> {
}
/// Creates a new in