From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Alice Ryhl" <aliceryhl@google.com>,
"Lorenzo Stoakes" <lorenzo.stoakes@oracle.com>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>
Cc: linux-mm@kvack.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org,
Andreas Hindborg <a.hindborg@kernel.org>
Subject: [PATCH] rust: page: add volatile memory copy methods
Date: Fri, 30 Jan 2026 13:33:38 +0100 [thread overview]
Message-ID: <20260130-page-volatile-io-v1-1-19f3d3e8f265@kernel.org> (raw)
When copying data from buffers that are mapped to user space, or from
buffers that are used for dma, it is impossible to guarantee absence of
concurrent memory operations on those buffers. Copying data to/from `Page`
from/to these buffers would be undefined behavior if regular memcpy
operations are used.
The operation can be made well defined, if the buffers that potentially
observe racy operations can be said to exist outside of any Rust
allocation. For this to be true, the kernel must only interact with the
buffers using raw volatile reads and writes.
Add methods on `Page` to read and write the contents using volatile
operations.
Also improve clarity by specifying additional requirements on
`read_raw`/`write_raw` methods regarding concurrent operations on involved
buffers.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/page.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index 432fc0297d4a8..6568a0d3b3baa 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -7,6 +7,7 @@
bindings,
error::code::*,
error::Result,
+ ffi::c_void,
uaccess::UserSliceReader,
};
use core::{
@@ -260,6 +261,8 @@ fn with_pointer_into_page<T>(
/// # Safety
///
/// * Callers must ensure that `dst` is valid for writing `len` bytes.
+ /// * Callers must ensure that there are no other concurrent reads or writes to/from the
+ /// destination memory region.
/// * Callers must ensure that this call does not race with a write to the same page that
/// overlaps with this read.
pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result {
@@ -274,6 +277,30 @@ pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result
})
}
+ /// Maps the page and reads from it into the given IO memory region using volatile memory
+ /// operations.
+ ///
+ /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
+ /// outside of the page, then this call returns [`EINVAL`].
+ ///
+ /// # Safety
+ /// Callers must ensure that:
+ ///
+ /// * The destination memory region is outside of any Rust memory allocation.
+ /// * The destination memory region is writable.
+ /// * This call does not race with a write to the same source page that overlaps with this read.
+ pub unsafe fn read_raw_toio(&self, dst: *mut u8, offset: usize, len: usize) -> Result {
+ self.with_pointer_into_page(offset, len, move |src| {
+ // SAFETY: If `with_pointer_into_page` calls into this closure, then
+ // it has performed a bounds check and guarantees that `src` is
+ // valid for `len` bytes.
+ //
+ // There caller guarantees that there is no data race at the source.
+ unsafe { bindings::memcpy_toio(dst.cast::<c_void>(), src.cast::<c_void>(), len) };
+ Ok(())
+ })
+ }
+
/// Maps the page and writes into it from the given buffer.
///
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
@@ -282,6 +309,7 @@ pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result
/// # Safety
///
/// * Callers must ensure that `src` is valid for reading `len` bytes.
+ /// * Callers must ensure that there are no concurrent writes to the source memory region.
/// * Callers must ensure that this call does not race with a read or write to the same page
/// that overlaps with this write.
pub unsafe fn write_raw(&self, src: *const u8, offset: usize, len: usize) -> Result {
@@ -295,6 +323,31 @@ pub unsafe fn write_raw(&self, src: *const u8, offset: usize, len: usize) -> Res
})
}
+ /// Maps the page and writes into it from the given IO memory region using volatile memory
+ /// operations.
+ ///
+ /// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
+ /// outside of the page, then this call returns [`EINVAL`].
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that:
+ ///
+ /// * The source memory region is outside of any Rust memory allocation.
+ /// * The source memory region is readable.
+ /// * This call does not race with a read or write to the same destination page that overlaps
+ /// with this write.
+ pub unsafe fn write_raw_fromio(&self, src: *const u8, offset: usize, len: usize) -> Result {
+ self.with_pointer_into_page(offset, len, move |dst| {
+ // SAFETY: If `with_pointer_into_page` calls into this closure, then it has performed a
+ // bounds check and guarantees that `dst` is valid for `len` bytes.
+ //
+ // There caller guarantees that there is no data race at the destination.
+ unsafe { bindings::memcpy_fromio(dst.cast::<c_void>(), src.cast::<c_void>(), len) };
+ Ok(())
+ })
+ }
+
/// Maps the page and zeroes the given slice.
///
/// This method will perform bounds checks on the page offset. If `offset .. offset+len` goes
---
base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
change-id: 20260130-page-volatile-io-05ff595507d3
Best regards,
--
Andreas Hindborg <a.hindborg@kernel.org>
next reply other threads:[~2026-01-30 12:34 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-30 12:33 Andreas Hindborg [this message]
2026-01-30 13:10 ` Gary Guo
2026-01-30 13:48 ` Andreas Hindborg
2026-01-30 14:14 ` Gary Guo
2026-01-30 14:42 ` Andreas Hindborg
2026-01-30 15:04 ` Gary Guo
2026-01-30 15:23 ` Andreas Hindborg
2026-01-30 15:48 ` Gary Guo
2026-01-30 16:20 ` Andreas Hindborg
2026-01-30 21:41 ` Boqun Feng
2026-01-31 7:22 ` Boqun Feng
2026-01-31 13:34 ` Andreas Hindborg
2026-01-31 16:09 ` Gary Guo
2026-01-31 20:30 ` Andreas Hindborg
2026-01-31 20:48 ` Gary Guo
2026-01-31 21:31 ` Andreas Hindborg
2026-02-03 1:07 ` Boqun Feng
2026-02-04 13:16 ` Andreas Hindborg
2026-02-04 13:48 ` Alice Ryhl
2026-02-04 15:58 ` Andreas Hindborg
2026-02-04 16:12 ` Gary Guo
2026-02-12 14:21 ` Andreas Hindborg
2026-01-31 16:26 ` Boqun Feng
2026-01-31 20:14 ` Andreas Hindborg
2026-01-31 13:19 ` Andreas Hindborg
2026-01-31 16:43 ` Boqun Feng
2026-01-31 19:10 ` Andreas Hindborg
2026-01-31 19:30 ` Boqun Feng
2026-01-31 20:20 ` Andreas Hindborg
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=20260130-page-volatile-io-v1-1-19f3d3e8f265@kernel.org \
--to=a.hindborg@kernel.org \
--cc=Liam.Howlett@oracle.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lorenzo.stoakes@oracle.com \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/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