All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alice Ryhl <aliceryhl@google.com>
To: Andreas Hindborg <a.hindborg@kernel.org>
Cc: "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>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Boqun Feng" <boqun@kernel.org>,
	linux-mm@kvack.org, rust-for-linux@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/2] rust: page: add `SafePage` for race-free page access
Date: Wed, 10 Jun 2026 06:52:17 +0000	[thread overview]
Message-ID: <aikJoacZW5JMEx74@google.com> (raw)
In-Reply-To: <20260605-page-additions-v2-1-03f04c8fdbbf@kernel.org>

On Fri, Jun 05, 2026 at 02:49:14PM +0200, Andreas Hindborg wrote:
> `SafePage` wraps a regular page but adds an invariant that the page data
> area does not incur data races. This means `SafePage` cannot be mapped to
> user space or shared with devices, and it becomes simpler to directly
> reference the contents of the page.
> 
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>

Perhaps it should be called ExclusivePage?

>  rust/kernel/page.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 62 insertions(+), 11 deletions(-)
> 
> diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
> index d56ae597f692..f143b42d1bd6 100644
> --- a/rust/kernel/page.rs
> +++ b/rust/kernel/page.rs
> @@ -8,8 +8,10 @@
>          Flags, //
>      },
>      bindings,
> -    error::code::*,
> -    error::Result,
> +    error::{
> +        code::*,
> +        Result, //
> +    },
>      types::{
>          Opaque,
>          Ownable,
> @@ -20,7 +22,7 @@
>  use core::{
>      marker::PhantomData,
>      mem::ManuallyDrop,
> -    ops::Deref,
> +    ops::{Deref, DerefMut},
>      ptr::{
>          self,
>          NonNull, //
> @@ -193,14 +195,10 @@ impl Page {
>      /// ```
>      #[inline]
>      pub fn alloc_page(flags: Flags) -> Result<Owned<Self>, AllocError> {
> -        // SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
> -        // is always safe to call this method.
> -        let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
> -        let page = NonNull::new(page).ok_or(AllocError)?;
> -        // SAFETY: We just successfully allocated a page, so we now have ownership of the newly
> -        // allocated page. We transfer that ownership to the new `Owned<Page>` object.
> -        // Since `Page` is transparent, we can cast the pointer directly.
> -        Ok(unsafe { Owned::from_raw(page.cast()) })
> +        let page = SafePage::alloc_page(flags)?;
> +        // SAFETY: `SafePage` is `#[repr(transparent)]` over `Page`, so a pointer to a `SafePage`
> +        // with ownership is also a pointer to a `Page` with ownership.
> +        Ok(unsafe { Owned::from_raw(Owned::into_raw(page).cast()) })
>      }
>  
>      /// Returns a raw pointer to the page.
> @@ -401,3 +399,56 @@ unsafe fn release(&mut self) {
>          unsafe { bindings::__free_pages(ptr.cast(), 0) };
>      }
>  }
> +
> +/// A page whose data area follows standard Rust aliasing rules.
> +///
> +/// [`SafePage`] has the same usage constraints as other Rust types. Thus, it cannot be mapped to
> +/// user space or shared with devices. This makes it safe to reference the contents of the page
> +/// while the page is mapped in kernel space.
> +///
> +/// # Invariants
> +///
> +/// The data of this page is accessed only through references to [`SafePage`]. While a shared
> +/// reference to a [`SafePage`] exists, there are no writes to its data. While an exclusive
> +/// reference exists, there are no other reads or writes of its data.
> +#[repr(transparent)]
> +pub struct SafePage(Page);
> +
> +impl SafePage {
> +    /// Allocate a new `SafePage`.
> +    pub fn alloc_page(flags: Flags) -> Result<Owned<Self>, AllocError> {
> +        // SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
> +        // is always safe to call this method.
> +        let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
> +        let page = NonNull::new(page).ok_or(AllocError)?;
> +
> +        // SAFETY: We just successfully allocated a page, so we now have ownership of the newly
> +        // allocated page. We transfer that ownership to the new `Owned<SafePage>` object. Since
> +        // `Page` and `SafePage` are transparent, we can cast to the raw page pointer directly.
> +        Ok(unsafe { Owned::from_raw(page.cast()) })
> +    }
> +}
> +
> +impl Ownable for SafePage {
> +    #[inline]
> +    unsafe fn release(&mut self) {
> +        let ptr: *mut Self = self;
> +        // SAFETY: By the function safety requirements, we have ownership of the page and can free
> +        // it. Since `SafePage` and `Page` are transparent, we can cast the raw pointer directly.
> +        unsafe { bindings::__free_pages(ptr.cast(), 0) };
> +    }
> +}
> +
> +impl Deref for SafePage {
> +    type Target = Page;
> +
> +    fn deref(&self) -> &Self::Target {
> +        &self.0
> +    }
> +}
> +
> +impl DerefMut for SafePage {
> +    fn deref_mut(&mut self) -> &mut Self::Target {
> +        &mut self.0
> +    }
> +}
> 
> -- 
> 2.51.2
> 
> 


  reply	other threads:[~2026-06-10  6:52 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-05 12:49 [PATCH v2 0/2] rust: pages that cannot be racy Andreas Hindborg
2026-06-05 12:49 ` [PATCH v2 1/2] rust: page: add `SafePage` for race-free page access Andreas Hindborg
2026-06-10  6:52   ` Alice Ryhl [this message]
2026-06-10  8:48     ` Andreas Hindborg
2026-06-10  7:24   ` Miguel Ojeda
2026-06-10  8:46     ` Andreas Hindborg
2026-06-05 12:49 ` [PATCH v2 2/2] rust: page: add method to copy data between safe pages 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=aikJoacZW5JMEx74@google.com \
    --to=aliceryhl@google.com \
    --cc=a.hindborg@kernel.org \
    --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=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 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.