From: Abdiel Janulgue <abdiel.janulgue@gmail.com>
To: rust-for-linux@vger.kernel.org
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Valentin Obst" <kernel@valentinobst.de>,
linux-kernel@vger.kernel.org (open list),
"Andrew Morton" <akpm@linux-foundation.org>,
linux-mm@kvack.org (open list:MEMORY MANAGEMENT),
airlied@redhat.com, "Abdiel Janulgue" <abdiel.janulgue@gmail.com>
Subject: [PATCH v3 1/2] rust: page: use the page's reference count to decide when to free the allocation
Date: Tue, 19 Nov 2024 13:24:02 +0200 [thread overview]
Message-ID: <20241119112408.779243-2-abdiel.janulgue@gmail.com> (raw)
In-Reply-To: <20241119112408.779243-1-abdiel.janulgue@gmail.com>
Ensure pages returned by the constructor are always reference counted.
This requires that we replace the page pointer wrapper with Opaque instead
of NonNull to make it possible to cast to a Page pointer from a raw struct
page pointer which is needed to create an ARef instance.
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@gmail.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/helpers/page.c | 10 +++++++++
rust/kernel/page.rs | 38 ++++++++++++++++++++++-----------
3 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index a80783fcbe04..daa3225a185f 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -15,6 +15,7 @@
#include <linux/firmware.h>
#include <linux/jiffies.h>
#include <linux/mdio.h>
+#include <linux/mm.h>
#include <linux/phy.h>
#include <linux/refcount.h>
#include <linux/sched.h>
diff --git a/rust/helpers/page.c b/rust/helpers/page.c
index b3f2b8fbf87f..48d4481c1e33 100644
--- a/rust/helpers/page.c
+++ b/rust/helpers/page.c
@@ -17,3 +17,13 @@ void rust_helper_kunmap_local(const void *addr)
{
kunmap_local(addr);
}
+
+void rust_helper_put_page(struct page *page)
+{
+ put_page(page);
+}
+
+void rust_helper_get_page(struct page *page)
+{
+ get_page(page);
+}
diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index fdac6c375fe4..fdf7ee203597 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -8,6 +8,7 @@
error::code::*,
error::Result,
uaccess::UserSliceReader,
+ types::{Opaque, ARef},
};
use core::ptr::{self, NonNull};
@@ -30,13 +31,14 @@ pub const fn page_align(addr: usize) -> usize {
(addr + (PAGE_SIZE - 1)) & PAGE_MASK
}
-/// A pointer to a page that owns the page allocation.
+/// A pointer to a reference-counted page.
///
/// # Invariants
///
-/// The pointer is valid, and has ownership over the page.
+/// The pointer is valid.
+#[repr(transparent)]
pub struct Page {
- page: NonNull<bindings::page>,
+ page: Opaque<bindings::page>,
}
// SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across
@@ -71,19 +73,23 @@ impl Page {
/// let page = Page::alloc_page(GFP_KERNEL | __GFP_ZERO)?;
/// # Ok(()) }
/// ```
- pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
+ pub fn alloc_page(flags: Flags) -> Result<ARef<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)?;
- // INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
- // allocated page. We transfer that ownership to the new `Page` object.
- Ok(Self { page })
+ if page.is_null() {
+ return Err(AllocError);
+ }
+ // CAST: Self` is a `repr(transparent)` wrapper around `bindings::page`.
+ let ptr = page.cast::<Self>();
+ // INVARIANT: We just successfully allocated a page, ptr points to the new `Page` object.
+ // SAFETY: According to invariant above ptr is valid.
+ Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(ptr)) })
}
/// Returns a raw pointer to the page.
pub fn as_ptr(&self) -> *mut bindings::page {
- self.page.as_ptr()
+ self.page.get()
}
/// Runs a piece of code with this page mapped to an address.
@@ -252,9 +258,15 @@ pub unsafe fn copy_from_user_slice_raw(
}
}
-impl Drop for Page {
- fn drop(&mut self) {
- // SAFETY: By the type invariants, we have ownership of the page and can free it.
- unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
+// SAFETY: Instances of `Page` are always reference-counted.
+unsafe impl crate::types::AlwaysRefCounted for Page {
+ fn inc_ref(&self) {
+ // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
+ unsafe { bindings::get_page(self.as_ptr()) };
+ }
+
+ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+ // SAFETY: The safety requirements guarantee that the refcount is non-zero.
+ unsafe { bindings::put_page(obj.cast().as_ptr()) }
}
}
--
2.43.0
next prev parent reply other threads:[~2024-11-19 11:24 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-19 11:24 [PATCH v3 0/2] rust: page: Add support for existing struct page mappings Abdiel Janulgue
2024-11-19 11:24 ` Abdiel Janulgue [this message]
2024-11-19 11:45 ` [PATCH v3 1/2] rust: page: use the page's reference count to decide when to free the allocation Alice Ryhl
2024-11-19 12:06 ` Abdiel Janulgue
2024-11-19 12:11 ` Alice Ryhl
2024-11-19 11:24 ` [PATCH v3 2/2] rust: page: Extend support to existing struct page mappings Abdiel Janulgue
2024-11-19 17:07 ` Jann Horn
2024-11-20 22:56 ` Abdiel Janulgue
2024-11-21 20:17 ` Jann Horn
2024-11-22 7:55 ` Alice Ryhl
2024-11-22 8:36 ` Abdiel Janulgue
2024-11-22 8:50 ` Alice Ryhl
2024-11-22 8:09 ` Abdiel Janulgue
2024-11-20 4:57 ` [PATCH v3 0/2] rust: page: Add support for " Matthew Wilcox
2024-11-20 9:10 ` Alice Ryhl
2024-11-20 16:20 ` Boqun Feng
2024-11-20 17:02 ` Matthew Wilcox
2024-11-20 17:25 ` Boqun Feng
2024-11-20 22:56 ` Abdiel Janulgue
2024-11-21 0:24 ` Boqun Feng
2024-11-21 9:19 ` Alice Ryhl
2024-11-21 9:30 ` Abdiel Janulgue
2024-11-21 19:10 ` Boqun Feng
2024-11-21 19:12 ` Boqun Feng
2024-11-21 22:01 ` Matthew Wilcox
2024-11-21 23:18 ` Abdiel Janulgue
2024-11-22 1:24 ` Matthew Wilcox
2024-11-22 6:58 ` David Airlie
2024-11-22 12:37 ` Paolo Bonzini
2024-11-26 20:31 ` Jann Horn
2024-11-26 20:43 ` Jann Horn
2024-12-02 12:03 ` Asahi Lina
2024-12-03 9:08 ` Alice Ryhl
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=20241119112408.779243-2-abdiel.janulgue@gmail.com \
--to=abdiel.janulgue@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=kernel@valentinobst.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=wedsonaf@gmail.com \
/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