From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Alice Ryhl" <aliceryhl@google.com>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "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>,
"Will Deacon" <will@kernel.org>,
"Peter Zijlstra" <peterz@infradead.org>,
"Mark Rutland" <mark.rutland@arm.com>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Lyude Paul" <lyude@redhat.com>
Cc: linux-mm@kvack.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org, driver-core@lists.linux.dev,
Andreas Hindborg <a.hindborg@kernel.org>
Subject: [PATCH v5 1/4] rust: io: require freedom from plain accesses for `SysMem`
Date: Tue, 10 Nov 2026 15:44:19 +0100 [thread overview]
Message-ID: <20261110-page-volatile-io-v5-1-a91ef252c24b@kernel.org> (raw)
In-Reply-To: <20261110-page-volatile-io-v5-0-a91ef252c24b@kernel.org>
`SysMem` accesses memory with volatile loads and stores and with the
kernel's `memcpy()`. Both are well-defined when racing with hardware or
user space, and when racing with atomic or volatile accesses from other
kernel code. However, if they race with plain, non-atomic accesses from
kernel code, they are considered a data race, and therefore undefined
behavior.
The invariants of `SysMem` only require the region to be valid and
aligned kernel accessible memory. Nothing stops a caller from creating
a `SysMem` over memory that other kernel code accesses with plain loads
and stores at the same time.
Make the requirement explicit. Require that no plain access to the
region is performed for the lifetime of the view, define what a plain
access is, and update the safety comments on the backend implementation
to rely on the new invariant.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/io.rs | 46 ++++++++++++++++++++++++++++++----------------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index a877df11a03e..3bc4be35e355 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -1452,7 +1452,7 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
ptr: *mut U,
) -> Self::View<'a, U> {
// INVARIANT: Per safety requirement, `ptr` is projection from `view`, so it is also a valid
- // kernel accessible memory region.
+ // kernel accessible memory region that is free of plain accesses.
SysMem {
ptr,
phantom: PhantomData,
@@ -1470,8 +1470,9 @@ fn io_read(view: SysMem<'_, $ty>) -> $ty {
// SAFETY:
// - Per type invariant, `ptr` is valid and aligned.
// - Using read_volatile() here so that race with hardware is well-defined.
- // - Using read_volatile() here is not sound if it races with other CPU per Rust
- // rules, but this is allowed per LKMM.
+ // - Per type invariant, no plain access races with this read. Racing with atomic
+ // or volatile accesses from other CPUs is not sound per Rust rules, but this is
+ // allowed per LKMM.
// - The macro is only used on primitives so all bit patterns are valid.
unsafe { view.ptr.read_volatile() }
}
@@ -1481,8 +1482,9 @@ fn io_write(view: SysMem<'_, $ty>, value: $ty) {
// SAFETY:
// - Per type invariant, `ptr` is valid and aligned.
// - Using write_volatile() here so that race with hardware is well-defined.
- // - Using write_volatile() here is not sound if it races with other CPU per Rust
- // rules, but this is allowed per LKMM.
+ // - Per type invariant, no plain access races with this write. Racing with atomic
+ // or volatile accesses from other CPUs is not sound per Rust rules, but this is
+ // allowed per LKMM.
unsafe { view.ptr.write_volatile(value) }
}
}
@@ -1519,8 +1521,9 @@ fn copy_read<T: FromBytes>(view: Self::View<'_, T>) -> T {
// SAFETY:
// - Per type invariant, `ptr` is valid and aligned.
// - Using read_volatile() here so that race with hardware is well-defined.
- // - Using read_volatile() here is not sound if it races with other CPU per Rust
- // rules, but this is allowed per LKMM.
+ // - Per type invariant, no plain access races with this read. Racing with atomic or
+ // volatile accesses from other CPUs is not sound per Rust rules, but this is allowed
+ // per LKMM.
// - `T: FromBytes` so all bit patterns are valid.
unsafe { view.ptr.read_volatile() }
}
@@ -1530,22 +1533,31 @@ fn copy_write<T: IntoBytes>(view: Self::View<'_, T>, value: T) {
// SAFETY:
// - Per type invariant, `ptr` is valid and aligned.
// - Using write_volatile() here so that race with hardware is well-defined.
- // - Using write_volatile() here is not sound if it races with other CPU per Rust
- // rules, but this is allowed per LKMM.
+ // - Per type invariant, no plain access races with this write. Racing with atomic or
+ // volatile accesses from other CPUs is not sound per Rust rules, but this is allowed
+ // per LKMM.
unsafe { view.ptr.write_volatile(value) }
}
}
/// A view of a system memory region.
///
-/// Provides `Io` trait implementation for kernel virtual address ranges,
-/// using volatile read/write to safely access shared memory that may be
-/// concurrently accessed by external hardware.
+/// Provides `Io` trait implementation for kernel virtual address ranges, using volatile or
+/// byte-wise atomic accesses to safely access shared memory that may be concurrently accessed by
+/// external actors, such as hardware or user space threads, or by other kernel code using atomic or
+/// volatile accesses.
+///
+/// Accesses through a `SysMem` are never plain accesses. A plain access is a non-atomic,
+/// non-volatile access performed by kernel code, whether in C or in Rust. A plain access that
+/// races with any other access to the same memory is a data race, and therefore undefined
+/// behavior. Accesses performed by hardware or by user space are not plain accesses in this sense.
+/// Racing with them is well-defined, but the data observed may be arbitrary.
///
/// # Invariants
///
-/// `self.ptr.addr() .. self.ptr.addr() + KnownSize::size(self.ptr)` is valid and aligned kernel
-/// accessible memory region for the lifetime `'a`.
+/// - `self.ptr.addr() .. self.ptr.addr() + KnownSize::size(self.ptr)` is valid and aligned kernel
+/// accessible memory region for the lifetime `'a`.
+/// - No plain access to that memory region is performed for the lifetime `'a`.
pub struct SysMem<'a, T: ?Sized> {
ptr: *mut T,
phantom: PhantomData<&'a ()>,
@@ -1570,8 +1582,10 @@ impl<'a, T: ?Sized> SysMem<'a, T> {
///
/// # Safety
///
- /// `ptr.addr() .. ptr.addr() + KnownSize::size(ptr)` must be valid and aligned kernel
- /// accessible memory region for the lifetime `'a`.
+ /// - `ptr.addr() .. ptr.addr() + KnownSize::size(ptr)` must be valid and aligned kernel
+ /// accessible memory region for the lifetime `'a`.
+ /// - No plain access (see [`SysMem`]) to that memory region may be performed for the lifetime
+ /// `'a`.
#[inline]
pub unsafe fn new(ptr: *mut T) -> Self {
// INVARIANT: Per safety requirement.
--
2.54.0
next prev parent reply other threads:[~2026-11-10 14:45 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 14:44 [PATCH v5 0/4] rust: byte-wise atomic copies between `Page` and shared memory Andreas Hindborg
2026-11-10 14:44 ` Andreas Hindborg [this message]
2026-11-10 14:44 ` [PATCH v5 2/4] rust: sync: atomic: add atomic_per_byte_memcpy Andreas Hindborg
2026-11-10 14:44 ` [PATCH v5 3/4] rust: io: copy `SysMem` with `atomic_per_byte_memcpy` Andreas Hindborg
2026-11-10 14:44 ` [PATCH v5 4/4] rust: page: add byte-wise atomic copy methods for `SysMem` 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=20261110-page-volatile-io-v5-1-a91ef252c24b@kernel.org \
--to=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=mark.rutland@arm.com \
--cc=ojeda@kernel.org \
--cc=peterz@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=will@kernel.org \
--cc=work@onurozkan.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
all inboxes | Powered by JetHome®