Skip to content

Commit 6c4b546

Browse files
hoshinolinajannau
authored andcommitted
rust: page: Convert to Ownable
This allows Page references to be returned as borrowed references, without necessarily owning the struct page. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent ab536b6 commit 6c4b546

1 file changed

Lines changed: 16 additions & 11 deletions

File tree

rust/kernel/page.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
bindings,
88
error::code::*,
99
error::Result,
10+
types::{Opaque, Ownable, Owned},
1011
uaccess::UserSliceReader,
1112
};
1213
use core::{
@@ -77,7 +78,7 @@ pub const fn page_align(addr: usize) -> usize {
7778
///
7879
/// [`VBox`]: kernel::alloc::VBox
7980
/// [`Vmalloc`]: kernel::alloc::allocator::Vmalloc
80-
pub struct BorrowedPage<'a>(ManuallyDrop<Page>, PhantomData<&'a Page>);
81+
pub struct BorrowedPage<'a>(ManuallyDrop<Owned<Page>>, PhantomData<&'a Page>);
8182

8283
impl<'a> BorrowedPage<'a> {
8384
/// Constructs a [`BorrowedPage`] from a raw pointer to a `struct page`.
@@ -87,7 +88,7 @@ impl<'a> BorrowedPage<'a> {
8788
/// - `ptr` must point to a valid `bindings::page`.
8889
/// - `ptr` must remain valid for the entire lifetime `'a`.
8990
pub unsafe fn from_raw(ptr: NonNull<bindings::page>) -> Self {
90-
let page = Page { page: ptr };
91+
let page = unsafe { Page::from_phys(bindings::page_to_phys(ptr.as_ptr())) };
9192

9293
// INVARIANT: The safety requirements guarantee that `ptr` is valid for the entire lifetime
9394
// `'a`.
@@ -120,8 +121,9 @@ pub trait AsPageIter {
120121
/// # Invariants
121122
///
122123
/// The pointer is valid, and has ownership over the page.
124+
#[repr(transparent)]
123125
pub struct Page {
124-
page: NonNull<bindings::page>,
126+
page: Opaque<bindings::page>,
125127
}
126128

127129
// SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across
@@ -155,19 +157,20 @@ impl Page {
155157
/// # Ok::<(), kernel::alloc::AllocError>(())
156158
/// ```
157159
#[inline]
158-
pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
160+
pub fn alloc_page(flags: Flags) -> Result<Owned<Self>, AllocError> {
159161
// SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
160162
// is always safe to call this method.
161163
let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
162164
let page = NonNull::new(page).ok_or(AllocError)?;
163-
// INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
164-
// allocated page. We transfer that ownership to the new `Page` object.
165-
Ok(Self { page })
165+
// SAFETY: We just successfully allocated a page, so we now have ownership of the newly
166+
// allocated page. We transfer that ownership to the new `Owned<Page>` object.
167+
// Since `Page` is transparent, we can cast the pointer directly.
168+
Ok(unsafe { Owned::from_raw(page.cast()) })
166169
}
167170

168171
/// Returns a raw pointer to the page.
169172
pub fn as_ptr(&self) -> *mut bindings::page {
170-
self.page.as_ptr()
173+
Opaque::cast_into(&self.page)
171174
}
172175

173176
/// Get the node id containing this page.
@@ -342,10 +345,12 @@ impl Page {
342345
}
343346
}
344347

345-
impl Drop for Page {
348+
// SAFETY: See below.
349+
unsafe impl Ownable for Page {
346350
#[inline]
347-
fn drop(&mut self) {
351+
unsafe fn release(this: NonNull<Self>) {
348352
// SAFETY: By the type invariants, we have ownership of the page and can free it.
349-
unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
353+
// Since Page is transparent, we can cast the raw pointer directly.
354+
unsafe { bindings::__free_pages(this.cast().as_ptr(), 0) };
350355
}
351356
}

0 commit comments

Comments
 (0)