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 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.