[PATCH 2/4] rust: dma: tie CoherentHandle to the device's bound lifetime
From: Danilo Krummrich
Date: Sun Aug 30 2026 - 15:40:25 EST
Add a lifetime parameter to CoherentHandle that ties the DMA allocation
to the device's bound scope, ensuring it is freed before the device is
unbound.
DMA allocations carry device resources (e.g. IOMMU mappings) that must
not outlive the device's bound lifetime. Without a lifetime parameter,
there was no compile-time enforcement that a CoherentHandle is dropped
before the device is unbound.
Signed-off-by: Danilo Krummrich <dakr@xxxxxxxxxx>
---
drivers/gpu/nova-core/fb.rs | 2 +-
rust/kernel/dma.rs | 20 ++++++++++----------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 1576399389b1..9ef232a73dee 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -49,7 +49,7 @@ pub(crate) struct SysmemFlush<'sys> {
device: &'sys device::Device,
bar: Bar0<'sys>,
/// Keep the page alive as long as we need it.
- page: CoherentHandle,
+ page: CoherentHandle<'sys>,
}
impl<'sys> SysmemFlush<'sys> {
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 2ce09f8e90c6..79f453e9ec0b 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -996,15 +996,15 @@ fn write_to_slice(
/// - `size` is the allocation size in bytes as passed to `dma_alloc_attrs`.
/// - `dma_attrs` contains the attributes used for the allocation, always including
/// `DMA_ATTR_NO_KERNEL_MAPPING`.
-pub struct CoherentHandle {
- dev: ARef<device::Device>,
+pub struct CoherentHandle<'a> {
+ dev: &'a device::Device<Bound>,
dma_addr: DmaAddress,
cpu_handle: NonNull<c_void>,
size: usize,
dma_attrs: Attrs,
}
-impl CoherentHandle {
+impl<'a> CoherentHandle<'a> {
/// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
///
/// Additional DMA attributes may be passed via `dma_attrs`; `DMA_ATTR_NO_KERNEL_MAPPING` is
@@ -1012,7 +1012,7 @@ impl CoherentHandle {
///
/// Returns `EINVAL` if `size` is zero, `ENOMEM` if the allocation fails.
pub fn alloc_with_attrs(
- dev: &device::Device<Bound>,
+ dev: &'a device::Device<Bound>,
size: usize,
gfp_flags: kernel::alloc::Flags,
dma_attrs: Attrs,
@@ -1038,9 +1038,9 @@ pub fn alloc_with_attrs(
// INVARIANT: `cpu_handle` is the opaque handle from a successful `dma_alloc_attrs` call
// with `DMA_ATTR_NO_KERNEL_MAPPING`, `dma_addr` is the corresponding DMA address,
- // and we hold a refcounted reference to the device.
+ // and `dev` is a valid reference to a bound device that outlives this allocation.
Ok(Self {
- dev: dev.into(),
+ dev,
dma_addr,
cpu_handle,
size,
@@ -1051,7 +1051,7 @@ pub fn alloc_with_attrs(
/// Allocates `size` bytes of coherent DMA memory without creating a kernel virtual mapping.
#[inline]
pub fn alloc(
- dev: &device::Device<Bound>,
+ dev: &'a device::Device<Bound>,
size: usize,
gfp_flags: kernel::alloc::Flags,
) -> Result<Self> {
@@ -1073,7 +1073,7 @@ pub fn size(&self) -> usize {
}
}
-impl Drop for CoherentHandle {
+impl Drop for CoherentHandle<'_> {
fn drop(&mut self) {
// SAFETY: All values are valid by the type invariants on `CoherentHandle`.
// `cpu_handle` is the opaque handle from `dma_alloc_attrs` and is passed back unchanged.
@@ -1091,12 +1091,12 @@ fn drop(&mut self) {
// SAFETY: `CoherentHandle` only holds a device reference, a DMA address, an opaque CPU handle,
// and a size. None of these are tied to a specific thread.
-unsafe impl Send for CoherentHandle {}
+unsafe impl Send for CoherentHandle<'_> {}
// SAFETY: `CoherentHandle` provides no CPU access to the underlying allocation. The only
// operations on `&CoherentHandle` are reading the DMA address and size, both of which are
// plain `Copy` values.
-unsafe impl Sync for CoherentHandle {}
+unsafe impl Sync for CoherentHandle<'_> {}
/// View type for `Coherent`.
///
--
2.55.0