From: Benno Lossin <benno.lossin@proton.me>
To: Alice Ryhl <aliceryhl@google.com>,
Miguel Ojeda <ojeda@kernel.org>,
Matthew Wilcox <willy@infradead.org>,
Al Viro <viro@zeniv.linux.org.uk>,
Andrew Morton <akpm@linux-foundation.org>,
Kees Cook <keescook@chromium.org>
Cc: "Alex Gaynor" <alex.gaynor@gmail.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@samsung.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Arve Hjønnevåg" <arve@android.com>,
"Todd Kjos" <tkjos@android.com>,
"Martijn Coenen" <maco@android.com>,
"Joel Fernandes" <joel@joelfernandes.org>,
"Carlos Llamas" <cmllamas@google.com>,
"Suren Baghdasaryan" <surenb@google.com>,
"Arnd Bergmann" <arnd@arndb.de>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
rust-for-linux@vger.kernel.org,
"Christian Brauner" <brauner@kernel.org>
Subject: Re: [PATCH v3 4/4] rust: add abstraction for `struct page`
Date: Sat, 16 Mar 2024 20:39:34 +0000 [thread overview]
Message-ID: <baee63d9-273a-48aa-b3cc-f15e3782156b@proton.me> (raw)
In-Reply-To: <20240311-alice-mm-v3-4-cdf7b3a2049c@google.com>
On 3/11/24 11:47, Alice Ryhl wrote:
> +/// A pointer to a page that owns the page allocation.
> +///
> +/// # Invariants
> +///
> +/// The pointer points at a page, and has ownership over the page.
Why not "`page` is valid"?
Do you mean by ownership of the page that `page` has ownership of the
allocation, or does that entail any other property/privilege?
> +pub struct Page {
> + page: NonNull<bindings::page>,
> +}
> +
> +// SAFETY: It is safe to transfer page allocations between threads.
Why?
> +unsafe impl Send for Page {}
> +
> +// SAFETY: As long as the safety requirements for `&self` methods on this type
> +// are followed, there is no problem with calling them in parallel.
Why?
> +unsafe impl Sync for Page {}
> +
> +impl Page {
> + /// Allocates a new page.
> + pub fn alloc_page(gfp_flags: flags::gfp_t) -> Result<Self, AllocError> {
> + // SAFETY: The specified order is zero and we want one page.
This doesn't explain why it is sound to call the function. I expect that
it is always sound to call this function with valid arguments.
> + let page = unsafe { bindings::alloc_pages(gfp_flags, 0) };
> + let page = NonNull::new(page).ok_or(AllocError)?;
> + // INVARIANT: We checked that the allocation succeeded.
Doesn't mention ownership.
> + Ok(Self { page })
> + }
> +
> + /// Returns a raw pointer to the page.
> + pub fn as_ptr(&self) -> *mut bindings::page {
> + self.page.as_ptr()
> + }
> +
> + /// Runs a piece of code with this page mapped to an address.
> + ///
> + /// The page is unmapped when this call returns.
> + ///
> + /// It is up to the caller to use the provided raw pointer correctly.
This says nothing about what 'correctly' means. What I gathered from the
implementation is that the supplied pointer is valid for the execution
of `f` for `PAGE_SIZE` bytes.
What other things are you allowed to rely upon?
Is it really OK for this function to be called from multiple threads?
Could that not result in the same page being mapped multiple times? If
that is fine, what about potential data races when two threads write to
the pointer given to `f`?
> + pub fn with_page_mapped<T>(&self, f: impl FnOnce(*mut u8) -> T) -> T {
> + // SAFETY: `page` is valid due to the type invariants on `Page`.
> + let mapped_addr = unsafe { bindings::kmap_local_page(self.as_ptr()) };
> +
> + let res = f(mapped_addr.cast());
> +
> + // SAFETY: This unmaps the page mapped above.
This doesn't explain why it is sound.
> + //
> + // Since this API takes the user code as a closure, it can only be used
> + // in a manner where the pages are unmapped in reverse order. This is as
> + // required by `kunmap_local`.
> + //
> + // In other words, if this call to `kunmap_local` happens when a
> + // different page should be unmapped first, then there must necessarily
> + // be a call to `kmap_local_page` other than the call just above in
> + // `with_page_mapped` that made that possible. In this case, it is the
> + // unsafe block that wraps that other call that is incorrect.
> + unsafe { bindings::kunmap_local(mapped_addr) };
> +
> + res
> + }
> +
> + /// Runs a piece of code with a raw pointer to a slice of this page, with
> + /// bounds checking.
> + ///
> + /// If `f` is called, then it will be called with a pointer that points at
> + /// `off` bytes into the page, and the pointer will be valid for at least
> + /// `len` bytes. The pointer is only valid on this task, as this method uses
> + /// a local mapping.
This information about the pointer only being valid on this task should
also apply to `with_page_mapped`, right?
> + ///
> + /// If `off` and `len` refers to a region outside of this page, then this
> + /// method returns `EINVAL` and does not call `f`.
> + ///
> + /// It is up to the caller to use the provided raw pointer correctly.
Again, please specify what 'correctly' means.
--
Cheers,
Benno
> + pub fn with_pointer_into_page<T>(
> + &self,
> + off: usize,
> + len: usize,
> + f: impl FnOnce(*mut u8) -> Result<T>,
> + ) -> Result<T> {
> + let bounds_ok = off <= PAGE_SIZE && len <= PAGE_SIZE && (off + len) <= PAGE_SIZE;
> +
> + if bounds_ok {
> + self.with_page_mapped(move |page_addr| {
> + // SAFETY: The `off` integer is at most `PAGE_SIZE`, so this pointer offset will
> + // result in a pointer that is in bounds or one off the end of the page.
> + f(unsafe { page_addr.add(off) })
> + })
> + } else {
> + Err(EINVAL)
> + }
> + }
next prev parent reply other threads:[~2024-03-16 20:40 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-11 10:47 [PATCH v3 0/4] Memory management patches needed by Rust Binder Alice Ryhl
2024-03-11 10:47 ` [PATCH v3 1/4] rust: uaccess: add userspace pointers Alice Ryhl
2024-03-16 14:16 ` Benno Lossin
2024-03-18 18:59 ` Boqun Feng
2024-03-18 19:12 ` Alice Ryhl
2024-03-18 19:33 ` Boqun Feng
2024-03-18 20:10 ` Alice Ryhl
2024-03-18 21:07 ` Boqun Feng
2024-03-20 2:27 ` Boqun Feng
2024-03-20 18:39 ` Boqun Feng
2024-03-11 10:47 ` [PATCH v3 2/4] uaccess: always export _copy_[from|to]_user with CONFIG_RUST Alice Ryhl
2024-03-18 21:16 ` Boqun Feng
2024-03-11 10:47 ` [PATCH v3 3/4] rust: uaccess: add typed accessors for userspace pointers Alice Ryhl
2024-03-16 14:56 ` Benno Lossin
2024-03-19 19:32 ` Boqun Feng
2024-03-11 10:47 ` [PATCH v3 4/4] rust: add abstraction for `struct page` Alice Ryhl
2024-03-11 10:50 ` Alice Ryhl
2024-03-15 8:16 ` Andreas Hindborg
2024-03-16 15:30 ` Matthew Wilcox
2024-03-16 20:39 ` Benno Lossin [this message]
2024-03-20 8:46 ` Alice Ryhl
2024-03-21 13:15 ` Benno Lossin
2024-03-21 13:42 ` Alice Ryhl
2024-03-21 13:56 ` Benno Lossin
2024-03-21 14:11 ` Alice Ryhl
2024-03-21 14:16 ` Alice Ryhl
2024-03-21 14:19 ` Benno Lossin
2024-03-19 22:16 ` Boqun Feng
2024-03-19 22:28 ` Benno Lossin
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=baee63d9-273a-48aa-b3cc-f15e3782156b@proton.me \
--to=benno.lossin@proton.me \
--cc=a.hindborg@samsung.com \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=arnd@arndb.de \
--cc=arve@android.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=brauner@kernel.org \
--cc=cmllamas@google.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=joel@joelfernandes.org \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=maco@android.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=surenb@google.com \
--cc=tkjos@android.com \
--cc=viro@zeniv.linux.org.uk \
--cc=wedsonaf@gmail.com \
--cc=willy@infradead.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;
as well as URLs for NNTP newsgroup(s).