Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Gary Guo" <gary@garyguo.net>
Cc: linux-pci@vger.kernel.org, "Danilo Krummrich" <dakr@kernel.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	ojeda@kernel.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3 18/19] rust: io: add copying methods
Date: Mon, 08 Jun 2026 20:20:12 +0000	[thread overview]
Message-ID: <20260608202013.34CED1F00898@smtp.kernel.org> (raw)
In-Reply-To: <20260608-io_projection-v3-18-c5cde13a5ec4@garyguo.net>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Safe `copy_from_io_slice` and `copy_to_io_slice` do not handle or prevent overlapping memory slices, leading to Undefined Behavior or silent data corruption.
- [Low] Default implementations of `copy_from_io` and `copy_to_io` use `build_assert!()` on a function parameter but lack the `#[inline(always)]` annotation.
- [Low] The imports in `samples/rust/rust_dma.rs` do not follow the kernel alphabetical sorting style.
--

commit 0d38b02719ddeacdde6e32f8d5c83949c35fd537
Author: Gary Guo <gary@garyguo.net>

rust: io: add copying methods

This commit introduces copying methods for I/O memory in Rust, replacing the
older DMA read/write macros for larger structs. It adds `copy_read`,
`copy_write`, and slice copying methods for various backends, optimizing to
`memcpy` where possible or using a stack buffer fallback.

> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
> index 72f3acc0f50d1..2b238b6256728 100644
> --- a/rust/kernel/io.rs
> +++ b/rust/kernel/io.rs
> @@ -229,6 +230,63 @@ pub trait IoCapable<T>: IoBackend {
>      fn io_write<'a>(view: Self::View<'a, T>, value: T);
>  }
>  
> +/// Trait indicating that an I/O backend supports memory copy operations.
> +///
> +/// # Safety
> +///
> +/// If [`Self::is_mapped`] is overridden, it must be correct per documentation.
> +pub unsafe trait IoCopyable: IoBackend {
> +    /// Whether the pointers for this I/O backend are in the CPU address space, and are coherently
> +    /// mapped.
> +    ///
> +    /// When this returns true, `Self::as_ptr(view)` must return a valid and aligned pointer. The
> +    /// pointer may be accessed with byte-wise atomic memory copy or volatile read/write.
> +    ///
> +    /// This is not an associated constants to support backends where the view may be conditionally
> +    /// mapped. This method should be marked as `#[inline(always)]` if it always returns true, so
> +    /// `build_assert!()` in `copy_{from,to}io` can see it.
> +    #[inline]
> +    fn is_mapped<T: ?Sized + KnownSize>(_view: Self::View<'_, T>) -> bool {
> +        false
> +    }
> +
> +    /// Copy contents of `view` to `buffer`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `buffer` is valid for volatile write for `view.size()` bytes.
> +    #[inline]
> +    unsafe fn copy_from_io(view: Self::View<'_, [u8]>, buffer: *mut u8) {

[Severity: Low]
This isn't a bug, but the Rust subsystem guidelines mandate that functions using
`build_assert!()` that depend on function parameters need to be annotated with
`#[inline(always)]`.

Could these default implementations result in spurious compilation failures if
the compiler chooses not to inline them and attempts to evaluate the assertion
at link-time?

> +        build_assert!(Self::is_mapped(view));
> +
> +        let ptr = Self::as_ptr(view);
> +
> +        // Use `bindings::memcpy` instead of copy_nonoverlapping for volatile.
> +        // SAFETY:
> +        // - `is_mapped` guarantees `ptr` is in CPU address space and valid for read.
> +        // - `buffer` is valid for write for `view.size()` bytes which is equal to `ptr.len()`.
> +        unsafe { bindings::memcpy(buffer.cast(), ptr.cast(), ptr.len()) };
> +    }
> +
> +    /// Copy `size` bytes from `buffer` to `address`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `buffer` is valid for volatile read for `view.size()` bytes.
> +    #[inline]
> +    unsafe fn copy_to_io(view: Self::View<'_, [u8]>, buffer: *const u8) {

[Severity: Low]
This isn't a bug, but the Rust subsystem guidelines mandate that functions using
`build_assert!()` that depend on function parameters need to be annotated with
`#[inline(always)]`.

Could these default implementations result in spurious compilation failures if
the compiler chooses not to inline them and attempts to evaluate the assertion
at link-time?

> +        build_assert!(Self::is_mapped(view));
> +
> +        let ptr = Self::as_ptr(view);
> +
> +        // Use `bindings::memcpy` instead of copy_nonoverlapping for volatile.
> +        // SAFETY:
> +        // - `is_mapped` guarantees `ptr` is in CPU address space and valid for write.
> +        // - `buffer` is valid for read for `view.size()` bytes which is equal to `ptr.len()`.
> +        unsafe { bindings::memcpy(ptr.cast(), buffer.cast(), ptr.len()) };
> +    }
> +}

[ ... ]

> +    fn copy_from_io_slice<'b, T>(self, data: T)
> +    where
> +        Self::Backend: IoCopyable,
> +        Self: Io<'a, Target = [u8]>,
> +        T: Io<'b, Target = [u8], Backend: IoCopyable>,
> +    {
> +        fn copy_from_io_slice_via_buffer<
> +            'a,
> +            'b,
> +            T: Io<'a, Target = [u8], Backend: IoCopyable>,
> +            U: Io<'b, Target = [u8], Backend: IoCopyable>,
> +        >(
> +            dest: T,
> +            src: U,
> +        ) {
> +            let mut buf = MaybeUninit::<[u8; 256]>::uninit();
> +
> +            let mut offset = 0;
> +            let mut len = dest.len();
> +
> +            while len != 0 {
> +                let copy_len = core::cmp::min(len, 256);
> +
> +                // SAFETY: `buf.as_mut_ptr()` is valid for write for `copy_len` bytes as `copy_len
> +                // <= 256`.
> +                unsafe {
> +                    U::Backend::copy_from_io(
> +                        io_project!(src, [panic: offset..][panic: ..copy_len]),
> +                        buf.as_mut_ptr().cast(),
> +                    )
> +                };
> +
> +                // SAFETY: `buf.as_ptr()` is valid for read for `copy_len` bytes as `copy_len <=
> +                // 256`.
> +                unsafe {
> +                    T::Backend::copy_to_io(
> +                        io_project!(dest, [panic: offset..][panic: ..copy_len]),
> +                        buf.as_ptr().cast(),
> +                    )
> +                };
> +
> +                offset += copy_len;
> +                len -= copy_len;
> +            }
> +        }

[Severity: High]
Since `copy_from_io_slice` is a safe function, what prevents a user from
passing overlapping I/O views?

`Io` views implement `Copy` and wrap raw pointers, so a user could safely create
overlapping views of the same memory region and pass them here.

If the backends are CPU-mapped, this eventually delegates to C's
`bindings::memcpy()`. Calling `memcpy` with overlapping pointers is Undefined
Behavior and can trigger crashes under fortified implementations.

For unmapped backends, it falls back to `copy_from_io_slice_via_buffer()` which
processes the copy sequentially forward in 256-byte chunks. If the destination
overlaps and sits ahead of the source, wouldn't an earlier chunk's write
overwrite data that a later chunk's read is supposed to copy, causing silent
data corruption?

Should this method explicitly detect pointer overlap and panic (like
`[T]::copy_from_slice`), or dynamically choose the copy direction?

> +
> +        assert_eq!(self.len(), data.len());
> +
> +        let dst_view = self.as_view();
> +        let src_view = data.as_view();
> +
> +        if T::Backend::is_mapped(src_view) {
> +            // SAFETY: `T::Backend::as_ptr(src_view)` is valid for read for `data.len()`
> +            // bytes.
> +            unsafe {
> +                Self::Backend::copy_to_io(self.as_view(), T::Backend::as_ptr(src_view).cast())
> +            }
> +        } else if Self::Backend::is_mapped(dst_view) {
> +            // SAFETY: `Self::Backend::as_ptr(dst_view)` is valid for write for `data.len()`
> +            // bytes.
> +            unsafe {
> +                T::Backend::copy_from_io(data.as_view(), Self::Backend::as_ptr(dst_view).cast())
> +            }
> +        } else {
> +            copy_from_io_slice_via_buffer(dst_view, src_view)
> +        }
> +    }

[ ... ]

> diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
> index 6727c441658aa..0f2597798ff5b 100644
> --- a/samples/rust/rust_dma.rs
> +++ b/samples/rust/rust_dma.rs
> @@ -12,7 +12,11 @@
>          Device,
>          DmaMask, //
>      },
> -    io::io_read,
> +    io::{
> +        io_project,
> +        io_read,
> +        Io, //
> +    },

[Severity: Low]
This isn't a bug, but the imports do not seem to follow the alphabetical sorting
style expected by the kernel vertical import guidelines. Since uppercase letters
precede lowercase ones in ASCII, shouldn't `Io` be sorted before `io_project`
and `io_read`?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608-io_projection-v3-0-c5cde13a5ec4@garyguo.net?part=18

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

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08 19:58 [PATCH v3 00/19] rust: I/O type generalization and projection Gary Guo
2026-06-08 19:58 ` [PATCH v3 01/19] rust: io: add dynamically-sized `Region` type Gary Guo
2026-06-08 23:52   ` Gary Guo
2026-06-08 19:58 ` [PATCH v3 02/19] rust: io: add missing safety requirement in `IoCapable` methods Gary Guo
2026-06-08 20:13   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 03/19] rust: io: restrict untyped IO access and `register!` to `Region` Gary Guo
2026-06-08 19:59 ` [PATCH v3 04/19] rust: io: implement `Io` on reference types instead Gary Guo
2026-06-08 19:59 ` [PATCH v3 05/19] rust: io: generalize `MmioRaw` to pointer to arbitrary type Gary Guo
2026-06-08 20:14   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 06/19] rust: io: rename `Mmio` to `MmioOwned` Gary Guo
2026-06-08 19:59 ` [PATCH v3 07/19] rust: io: implement `Mmio` as view type Gary Guo
2026-06-08 20:15   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 08/19] rust: pci: io: make `ConfigSpace` a view Gary Guo
2026-06-08 20:11   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 09/19] rust: io: use view types instead of addresses for `Io` Gary Guo
2026-06-08 19:59 ` [PATCH v3 10/19] rust: io: remove `MmioOwned` Gary Guo
2026-06-08 20:12   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 11/19] rust: io: move `Io` methods to extension trait Gary Guo
2026-06-08 19:59 ` [PATCH v3 12/19] rust: io: add projection macro and methods Gary Guo
2026-06-08 20:13   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 13/19] rust: io: add I/O backend for system memory with volatile access Gary Guo
2026-06-08 20:09   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 14/19] rust: io: implement a view type for `Coherent` Gary Guo
2026-06-08 20:18   ` sashiko-bot
2026-06-08 19:59 ` [PATCH v3 15/19] rust: io: add `read_val` and `write_val` function on `Io` Gary Guo
2026-06-08 19:59 ` [PATCH v3 16/19] gpu: nova-core: use I/O projection for cleaner encapsulation Gary Guo
2026-06-08 19:59 ` [PATCH v3 17/19] rust: dma: drop `dma_read!` and `dma_write!` API Gary Guo
2026-06-08 19:59 ` [PATCH v3 18/19] rust: io: add copying methods Gary Guo
2026-06-08 20:20   ` sashiko-bot [this message]
2026-06-08 19:59 ` [PATCH v3 19/19] rust: io: implement `Io` for `Either` Gary Guo
2026-06-08 21:22 ` [PATCH v3 00/19] rust: I/O type generalization and projection Danilo Krummrich

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=20260608202013.34CED1F00898@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=linux-pci@vger.kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox