All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Maurice Hieronymus" <mhi@mailbox.org>
Cc: ojeda@kernel.org, "Danilo Krummrich" <dakr@kernel.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 2/3] rust: dma: add abstraction for the single-buffer streaming DMA API
Date: Wed, 05 Aug 2026 22:06:27 +0000	[thread overview]
Message-ID: <20260805220628.4CF241F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260805-dma-streaming-v1-2-03974c86b141@mailbox.org>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] StreamingCpuGuard unconditionally implements DerefMut, allowing safe Rust code to mutate DMA_FROM_DEVICE buffers.
- [High] Safe Rust code can bypass dma_sync_single_for_device by leaking StreamingCpuGuard, causing a hardware data race.
- [Medium] Panic in ContiguousBuffer::data() leaves the DMA buffer synced for the CPU without creating a guard.
- [Low] Missing #[inline] annotations on small/forwarding methods in abstractions.
--

--- Patch [2]: [PATCH 2/3] rust: dma: add abstraction for the single-buffer streaming DMA API ---
commit 5deae1f6c89c43e53f36e40c370843d948aa3422
Author: Maurice Hieronymus <mhi@mailbox.org>

rust: dma: add abstraction for the single-buffer streaming DMA API

Add Streaming, a safe abstraction around dma_map_single_attrs(). Between
map and unmap the buffer belongs to the device, and the CPU may only access
it in between a dma_sync_single_for_cpu() / dma_sync_single_for_device()
pair.

> diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
> index 8a8af5ab7feb8..cbaf30a2de864 100644
> --- a/rust/kernel/dma.rs
> +++ b/rust/kernel/dma.rs
> @@ -621,6 +630,389 @@ fn data(&mut self) -> &mut Self::Data {

[ ... ]

> +    pub fn for_cpu(&mut self) -> StreamingCpuGuard<'_, C::Data> {
> +        let dev = self.dev;
> +        let dma_addr = self.dma_addr;
> +        let direction = self.direction;
> +        let size = self.container.size();
> +
> +        // SAFETY: By the type invariants, `dev` is bound and `dma_addr` denotes a live mapping of
> +        // `size` bytes established with `direction`, which is the range synced here.
> +        unsafe {
> +            bindings::dma_sync_single_for_cpu(dev.as_raw(), dma_addr, size, direction.into())
> +        };
> +
> +        // INVARIANT: The buffer is now owned by the CPU, and dropping the guard hands it back.
> +        StreamingCpuGuard {
> +            data: self.container.data(),

[Severity: Medium]
If the custom ContiguousBuffer::data() implementation panics, does this
leave the DMA buffer synced for the CPU without creating the guard? While
the kernel currently uses panic=abort, this sequence mutates global state
(the DMA cache mapping) before a potentially panicking safe trait method
call, which could violate panic safety guarantees. Could data() be
evaluated before calling dma_sync_single_for_cpu()?

> +            dev,
> +            dma_addr,
> +            size,
> +            direction,
> +        }
> +    }

[ ... ]

> +    fn unmap(&mut self) {

[Severity: Low]
This isn't a bug, but according to the Rust kernel coding guidelines,
functions in abstractions that are small or directly forward to a C
binding should be annotated with #[inline]. Should this method have
an #[inline] annotation?

> +        // SAFETY: By the type invariants, `self.dev` is bound and the mapping is still live, with
> +        // exactly the address, size, direction and attributes it was created with. Both callers
> +        // run this at most once, so the mapping cannot be torn down twice.
> +        unsafe {
> +            bindings::dma_unmap_single_attrs(
> +                self.dev.as_raw(),
> +                self.dma_addr,
> +                self.container.size(),
> +                self.direction.into(),
> +                self.dma_attrs.as_raw(),
> +            )
> +        };
> +    }

[ ... ]

> +impl<T: ?Sized> Drop for StreamingCpuGuard<'_, T> {
> +    fn drop(&mut self) {

[Severity: High]
Does relying on Drop to run dma_sync_single_for_device() allow safe Rust
code to bypass the synchronization? If a driver calls for_cpu() and then
passes the guard to core::mem::forget(), the mutable borrow ends without
Drop ever being called. The driver could then safely call submit(),
causing the device to interact with an unsynchronized buffer and breaking
the explicit type invariant.

> +        // SAFETY: By the type invariants, `self.dev` is bound and `self.dma_addr` denotes a live
> +        // mapping of `self.size` bytes established with `self.direction`, which is the range
> +        // synced here.
> +        unsafe {
> +            bindings::dma_sync_single_for_device(
> +                self.dev.as_raw(),
> +                self.dma_addr,
> +                self.size,
> +                self.direction.into(),
> +            )
> +        };
> +    }
> +}
> +
> +impl<T: ?Sized> Deref for StreamingCpuGuard<'_, T> {
> +    type Target = T;
> +
> +    fn deref(&self) -> &Self::Target {

[Severity: Low]
This isn't a bug, but this small trait implementation in an abstraction
might benefit from an #[inline] annotation to follow the Rust kernel
coding guidelines.

> +        self.data
> +    }
> +}
> +
> +impl<T: ?Sized> DerefMut for StreamingCpuGuard<'_, T> {
> +    fn deref_mut(&mut self) -> &mut Self::Target {

[Severity: Low]
This isn't a bug, but this trait implementation could also use an
#[inline] annotation.

[Severity: High]
Does this unconditional DerefMut implementation permit safe code to mutate
buffers mapped with DataDirection::FromDevice? According to the DMA API,
memory mapped with DMA_FROM_DEVICE must be treated as read-only by the CPU
to avoid dirtying cache lines, which could asynchronously evict and
overwrite the device's DMA writes in physical memory.

> +        self.data
> +    }
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260805-dma-streaming-v1-0-03974c86b141@mailbox.org?part=2

  reply	other threads:[~2026-08-05 22:06 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05 21:54 [PATCH 0/3] rust: dma: add the single-buffer streaming DMA API Maurice Hieronymus
2026-08-05 21:54 ` [PATCH 1/3] rust: dma: add ContiguousBuffer trait for streaming DMA storage Maurice Hieronymus
2026-08-05 22:05   ` sashiko-bot
2026-08-05 21:54 ` [PATCH 2/3] rust: dma: add abstraction for the single-buffer streaming DMA API Maurice Hieronymus
2026-08-05 22:06   ` sashiko-bot [this message]
2026-08-06 13:06   ` Robin Murphy
2026-08-05 21:54 ` [PATCH 3/3] gpu: nova-core: gsp: map the WPR meta for streaming DMA Maurice Hieronymus
2026-08-05 22:06   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260805220628.4CF241F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=mhi@mailbox.org \
    --cc=ojeda@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.