mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Alice Ryhl" <aliceryhl@google.com>,
	"Miguel Ojeda" <ojeda@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>,
	"Boqun Feng" <boqun@kernel.org>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Boqun Feng" <boqun@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 v4 2/2] rust: page: add byte-wise atomic memory copy methods
Date: Fri, 05 Jun 2026 12:34:14 +0200	[thread overview]
Message-ID: <20260605-page-volatile-io-v4-2-0e217d9bf11a@kernel.org> (raw)
In-Reply-To: <20260605-page-volatile-io-v4-0-0e217d9bf11a@kernel.org>

When copying data from buffers that are mapped to user space, 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 no special considerations are made.

Add `Page::{read,write}_bytewise_atomic` to read from / write to a
page using byte-wise atomic operations layered on
`atomic_per_byte_memcpy`. The methods are asymmetric: the parameter
buffer must support byte-wise atomic accesses, while the page side
held through `&self` only requires the absence of concurrent writes
(or of concurrent reads or writes for the write variant). This
follows the intended usage where the page is private to the caller
and the parameter buffer may be shared (e.g., with userspace).

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/page.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index adecb200c654..7bb201442679 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -296,6 +296,38 @@ pub unsafe fn read_raw(&self, dst: *mut u8, offset: usize, len: usize) -> Result
         })
     }
 
+    /// Maps the page and reads from it into the given memory region using byte-wise atomic 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`].
+    ///
+    /// This function is guaranteed to perform byte-wise atomic memory writes to `dst`, but it may
+    /// perform only normal (non-atomic) memory reads from the [`Page`] `self`. Accordingly, the
+    /// safety requirements below ask for byte-wise atomic discipline on `dst` and only for absence
+    /// of concurrent writes on the source page.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    ///
+    /// - `dst` is valid for atomic writes for `len` bytes for the duration of the call.
+    /// - This call does not race with a write to the source page that overlaps with this read.
+    pub unsafe fn read_bytewise_atomic(&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.
+            // - By function safety requirements `dst` is valid for writes for `len` bytes.
+            // - By function safety requirements there are no other writes to `src` during this
+            //   call.
+            // - By function safety requirements all other access to `dst` during this call are
+            //   atomic.
+            unsafe { kernel::sync::atomic::atomic_per_byte_memcpy(src, dst, 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
@@ -317,6 +349,44 @@ pub unsafe fn write_raw(&self, src: *const u8, offset: usize, len: usize) -> Res
         })
     }
 
+    /// Maps the page and writes into it from the given memory region using byte-wise atomic 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`].
+    ///
+    /// This function is guaranteed to perform byte-wise atomic memory reads from `src`, but it may
+    /// perform only normal (non-atomic) memory writes to the [`Page`] `self`. Accordingly, the
+    /// safety requirements below ask for byte-wise atomic discipline on `src` and only for absence
+    /// of concurrent reads or writes on the destination page.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    ///
+    /// - `src` is valid for atomic reads for `len` bytes for the duration of the call.
+    /// - This call does not race with a read or write to the destination page that overlaps with
+    ///   this write.
+    pub unsafe fn write_bytewise_atomic(
+        &self,
+        src: *const u8,
+        offset: usize,
+        len: usize,
+    ) -> Result {
+        self.with_pointer_into_page(offset, len, move |dst| {
+            // SAFETY:
+            // - By function safety requirements `src` is valid for writes for `len` bytes.
+            // - 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.
+            // - By function safety requirements there are no other writes to `dst` during this
+            //   call.
+            // - By function safety requirements all other access to `src` during this call are
+            //   atomic.
+            unsafe { kernel::sync::atomic::atomic_per_byte_memcpy(src, dst, 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

-- 
2.51.2



      parent reply	other threads:[~2026-06-05 10:34 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-05 10:34 [PATCH v4 0/2] (no cover subject) Andreas Hindborg
2026-06-05 10:34 ` [PATCH v4 1/2] rust: sync: atomic: add atomic_per_byte_memcpy Andreas Hindborg
2026-06-05 10:34 ` Andreas Hindborg [this message]

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=20260605-page-volatile-io-v4-2-0e217d9bf11a@kernel.org \
    --to=a.hindborg@kernel.org \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=dakr@kernel.org \
    --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=mark.rutland@arm.com \
    --cc=ojeda@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=will@kernel.org \
    /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®