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
next prev parent 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