From: Danilo Krummrich <dakr@kernel.org>
To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
benno.lossin@proton.me, a.hindborg@samsung.com,
aliceryhl@google.com, akpm@linux-foundation.org
Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com,
boris.brezillon@collabora.com, lina@asahilina.net,
mcanal@igalia.com, zhiw@nvidia.com, cjia@nvidia.com,
jhubbard@nvidia.com, airlied@redhat.com, ajanulgu@redhat.com,
lyude@redhat.com, linux-kernel@vger.kernel.org,
rust-for-linux@vger.kernel.org, linux-mm@kvack.org,
Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH v6 22/26] rust: alloc: implement `Cmalloc` in module allocator_test
Date: Fri, 16 Aug 2024 02:11:04 +0200 [thread overview]
Message-ID: <20240816001216.26575-23-dakr@kernel.org> (raw)
In-Reply-To: <20240816001216.26575-1-dakr@kernel.org>
So far the kernel's `Box` and `Vec` types can't be used by userspace
test cases, since all users of those types (e.g. `CString`) use kernel
allocators for instantiation.
In order to allow userspace test cases to make use of such types as
well, implement the `Cmalloc` allocator within the allocator_test module
and type alias all kernel allocators to `Cmalloc`. The `Cmalloc`
allocator uses libc's realloc() function as allocator backend.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/alloc/allocator_test.rs | 178 ++++++++++++++++++++++++++--
1 file changed, 171 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
index 1b2642c547ec..7fff308d02dc 100644
--- a/rust/kernel/alloc/allocator_test.rs
+++ b/rust/kernel/alloc/allocator_test.rs
@@ -2,20 +2,184 @@
#![allow(missing_docs)]
-use super::{AllocError, Allocator, Flags};
+use super::{flags::*, AllocError, Allocator, Flags};
use core::alloc::Layout;
+use core::cmp;
+use core::mem;
+use core::ptr;
use core::ptr::NonNull;
-pub struct Kmalloc;
+pub struct Cmalloc;
+pub type Kmalloc = Cmalloc;
pub type Vmalloc = Kmalloc;
pub type KVmalloc = Kmalloc;
-unsafe impl Allocator for Kmalloc {
+extern "C" {
+ #[link_name = "aligned_alloc"]
+ fn libc_aligned_alloc(align: usize, size: usize) -> *mut core::ffi::c_void;
+
+ #[link_name = "free"]
+ fn libc_free(ptr: *mut core::ffi::c_void);
+}
+
+struct CmallocData {
+ // The actual size as requested through `Cmalloc::alloc` or `Cmalloc::realloc`.
+ size: usize,
+ // The offset from the pointer returned to the caller of `Cmalloc::alloc` or `Cmalloc::realloc`
+ // to the actual base address of the allocation.
+ offset: usize,
+}
+
+impl Cmalloc {
+ /// Adjust the size and alignment such that we can additionally store `CmallocData` right
+ /// before the actual data described by `layout`.
+ ///
+ /// Example:
+ ///
+ /// For `CmallocData` assume an alignment of 8 and a size of 16.
+ /// For `layout` assume and alignment of 16 and a size of 64.
+ ///
+ /// 0 16 32 96
+ /// |----------------|----------------|------------------------------------------------|
+ /// empty CmallocData data
+ ///
+ /// For this example the returned `Layout` has an alignment of 32 and a size of 96.
+ fn layout_adjust(layout: Layout) -> Result<Layout, AllocError> {
+ let layout = layout.pad_to_align();
+
+ // Ensure that `CmallocData` fits into half the alignment. Additionally, this guarantees
+ // that advancing a pointer aligned to `align` by `align / 2` we still satisfy or exceed
+ // the alignment requested through `layout`.
+ let align = cmp::max(
+ layout.align(),
+ mem::size_of::<CmallocData>().next_power_of_two(),
+ ) * 2;
+
+ // Add the additional space required for `CmallocData`.
+ let size = layout.size() + mem::size_of::<CmallocData>();
+
+ Ok(Layout::from_size_align(size, align)
+ .map_err(|_| AllocError)?
+ .pad_to_align())
+ }
+
+ fn alloc_store_data(layout: Layout) -> Result<NonNull<u8>, AllocError> {
+ let requested_size = layout.size();
+
+ let layout = Self::layout_adjust(layout)?;
+ let min_align = layout.align() / 2;
+
+ // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
+ // exceeds the given size and alignment requirements.
+ let raw_ptr = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8;
+
+ let priv_ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
+
+ // SAFETY: Advance the pointer by `min_align`. The adjustments from `Self::layout_adjust`
+ // ensure that after this operation the original size and alignment requirements are still
+ // satisfied or exceeded.
+ let ptr = unsafe { priv_ptr.as_ptr().add(min_align) };
+
+ // SAFETY: `min_align` is greater than or equal to the size of `CmallocData`, hence we
+ // don't exceed the allocation boundaries.
+ let data_ptr: *mut CmallocData = unsafe { ptr.sub(mem::size_of::<CmallocData>()) }.cast();
+
+ let data = CmallocData {
+ size: requested_size,
+ offset: min_align,
+ };
+
+ // SAFETY: `data_ptr` is properly aligned and within the allocation boundaries reserved for
+ // `CmallocData`.
+ unsafe { data_ptr.write(data) };
+
+ NonNull::new(ptr).ok_or(AllocError)
+ }
+
+ /// # Safety
+ ///
+ /// `ptr` must have been previously allocated with `Self::alloc_store_data`.
+ unsafe fn data<'a>(ptr: NonNull<u8>) -> &'a CmallocData {
+ // SAFETY: `Self::alloc_store_data` stores the `CmallocData` right before the address
+ // returned to callers of `Self::alloc_store_data`.
+ let data_ptr: *mut CmallocData =
+ unsafe { ptr.as_ptr().sub(mem::size_of::<CmallocData>()) }.cast();
+
+ // SAFETY: The `CmallocData` has been previously stored at this offset with
+ // `Self::alloc_store_data`.
+ unsafe { &*data_ptr }
+ }
+
+ /// # Safety
+ ///
+ /// This function must not be called more than once for the same allocation.
+ ///
+ /// `ptr` must have been previously allocated with `Self::alloc_store_data`.
+ unsafe fn free_read_data(ptr: NonNull<u8>) {
+ // SAFETY: `ptr` has been created by `Self::alloc_store_data`.
+ let data = unsafe { Self::data(ptr) };
+
+ // SAFETY: `ptr` has been created by `Self::alloc_store_data`.
+ let priv_ptr = unsafe { ptr.as_ptr().sub(data.offset) };
+
+ // SAFETY: `priv_ptr` has previously been allocatored with this `Allocator`.
+ unsafe { libc_free(priv_ptr.cast()) };
+ }
+}
+
+unsafe impl Allocator for Cmalloc {
+ fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
+ if layout.size() == 0 {
+ return Ok(NonNull::slice_from_raw_parts(NonNull::dangling(), 0));
+ }
+
+ let ptr = Self::alloc_store_data(layout)?;
+
+ if flags.contains(__GFP_ZERO) {
+ // SAFETY: `Self::alloc_store_data` guarantees that `ptr` points to memory of at least
+ // `layout.size()` bytes.
+ unsafe { ptr.as_ptr().write_bytes(0, layout.size()) };
+ }
+
+ Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
+ }
+
unsafe fn realloc(
- _ptr: Option<NonNull<u8>>,
- _layout: Layout,
- _flags: Flags,
+ ptr: Option<NonNull<u8>>,
+ layout: Layout,
+ flags: Flags,
) -> Result<NonNull<[u8]>, AllocError> {
- panic!();
+ let src: NonNull<u8> = if let Some(src) = ptr {
+ src.cast()
+ } else {
+ return Self::alloc(layout, flags);
+ };
+
+ if layout.size() == 0 {
+ // SAFETY: `src` has been created by `Self::alloc_store_data`.
+ unsafe { Self::free_read_data(src) };
+
+ return Ok(NonNull::slice_from_raw_parts(NonNull::dangling(), 0));
+ }
+
+ let dst = Self::alloc(layout, flags)?;
+
+ // SAFETY: `src` has been created by `Self::alloc_store_data`.
+ let data = unsafe { Self::data(src) };
+
+ // SAFETY: `src` has previously been allocated with this `Allocator`; `dst` has just been
+ // newly allocated. Copy up to the smaller of both sizes.
+ unsafe {
+ ptr::copy_nonoverlapping(
+ src.as_ptr(),
+ dst.as_ptr().cast(),
+ cmp::min(layout.size(), data.size),
+ )
+ };
+
+ // SAFETY: `src` has been created by `Self::alloc_store_data`.
+ unsafe { Self::free_read_data(src) };
+
+ Ok(dst)
}
}
--
2.46.0
next prev parent reply other threads:[~2024-08-16 0:14 UTC|newest]
Thread overview: 100+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-16 0:10 [PATCH v6 00/26] Generic `Allocator` support for Rust Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 01/26] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-08-29 18:19 ` Benno Lossin
2024-08-29 21:56 ` Danilo Krummrich
2024-08-30 13:06 ` Benno Lossin
2024-09-03 11:56 ` Danilo Krummrich
2024-09-10 13:03 ` Benno Lossin
2024-09-10 13:23 ` Danilo Krummrich
2024-09-10 19:37 ` Benno Lossin
2024-08-30 13:44 ` Benno Lossin
2024-08-31 12:01 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 02/26] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-08-31 12:16 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 03/26] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 04/26] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-08-29 18:32 ` Benno Lossin
2024-08-29 22:04 ` Danilo Krummrich
2024-08-30 14:45 ` Benno Lossin
2024-09-03 11:48 ` Danilo Krummrich
2024-09-10 13:11 ` Benno Lossin
2024-09-10 13:37 ` Danilo Krummrich
2024-09-10 19:42 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 05/26] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-08-31 12:18 ` Gary Guo
2024-08-16 0:10 ` [PATCH v6 06/26] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-08-31 5:21 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 07/26] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 08/26] rust: alloc: add __GFP_NOWARN to `Flags` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 09/26] rust: alloc: implement kernel `Box` Danilo Krummrich
2024-08-20 9:47 ` Alice Ryhl
2024-08-20 15:26 ` Danilo Krummrich
2024-08-27 19:21 ` Boqun Feng
2024-08-31 5:39 ` Benno Lossin
2024-09-10 17:40 ` Danilo Krummrich
2024-09-10 19:49 ` Benno Lossin
2024-09-10 23:25 ` Danilo Krummrich
2024-09-11 8:36 ` Benno Lossin
2024-09-11 11:02 ` Danilo Krummrich
2024-09-11 13:26 ` Benno Lossin
2024-09-11 13:27 ` Alice Ryhl
2024-09-11 14:50 ` Danilo Krummrich
2024-09-12 8:03 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 10/26] rust: treewide: switch to our kernel `Box` type Danilo Krummrich
2024-08-29 18:35 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 11/26] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-08-29 18:38 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 12/26] rust: alloc: add `Box` to prelude Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 13/26] rust: alloc: implement kernel `Vec` type Danilo Krummrich
2024-09-03 19:08 ` Boqun Feng
2024-09-10 18:26 ` Danilo Krummrich
2024-09-10 19:33 ` Benno Lossin
2024-09-10 19:32 ` Benno Lossin
2024-09-11 0:18 ` Danilo Krummrich
2024-09-11 8:46 ` Benno Lossin
2024-09-10 20:07 ` Benno Lossin
2024-09-11 21:59 ` Danilo Krummrich
2024-09-23 9:24 ` Alice Ryhl
2024-08-16 0:10 ` [PATCH v6 14/26] rust: alloc: implement `IntoIterator` for `Vec` Danilo Krummrich
2024-09-04 10:29 ` Alice Ryhl
2024-09-10 20:04 ` Benno Lossin
2024-09-10 23:39 ` Danilo Krummrich
2024-09-11 8:52 ` Benno Lossin
2024-09-11 11:32 ` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 15/26] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-09-10 20:12 ` Benno Lossin
2024-09-11 0:22 ` Danilo Krummrich
2024-09-11 8:53 ` Benno Lossin
2024-09-11 11:33 ` Danilo Krummrich
2024-08-16 0:10 ` [PATCH v6 16/26] rust: treewide: switch to the kernel `Vec` type Danilo Krummrich
2024-08-29 18:41 ` Benno Lossin
2024-08-16 0:10 ` [PATCH v6 17/26] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 18/26] rust: alloc: add `Vec` to prelude Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 19/26] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 20/26] rust: error: check for config `test` in `Error::name` Danilo Krummrich
2024-08-29 18:41 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 21/26] rust: alloc: implement `contains` for `Flags` Danilo Krummrich
2024-08-29 18:42 ` Benno Lossin
2024-08-16 0:11 ` Danilo Krummrich [this message]
2024-08-29 19:14 ` [PATCH v6 22/26] rust: alloc: implement `Cmalloc` in module allocator_test Benno Lossin
2024-08-29 22:25 ` Danilo Krummrich
2024-08-30 12:56 ` Benno Lossin
2024-09-11 12:31 ` Danilo Krummrich
2024-09-11 13:32 ` Benno Lossin
2024-09-11 14:37 ` Danilo Krummrich
2024-09-12 8:18 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 23/26] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-08-29 18:43 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 24/26] rust: alloc: update module comment of alloc.rs Danilo Krummrich
2024-08-16 0:11 ` [PATCH v6 25/26] kbuild: rust: remove the `alloc` crate and `GlobalAlloc` Danilo Krummrich
2024-08-21 21:34 ` Benno Lossin
2024-08-16 0:11 ` [PATCH v6 26/26] MAINTAINERS: add entry for the Rust `alloc` module Danilo Krummrich
2024-08-31 12:57 ` Gary Guo
2024-09-03 12:03 ` Danilo Krummrich
2024-09-04 10:15 ` Alice Ryhl
2024-09-04 12:51 ` Benno Lossin
2024-09-04 12:57 ` Miguel Ojeda
2024-09-10 13:26 ` Benno Lossin
2024-09-10 13:42 ` Danilo Krummrich
2024-09-10 14:27 ` Benno Lossin
2024-08-27 19:17 ` [PATCH v6 00/26] Generic `Allocator` support for Rust Boqun Feng
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=20240816001216.26575-23-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@samsung.com \
--cc=airlied@redhat.com \
--cc=ajanulgu@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=boris.brezillon@collabora.com \
--cc=cjia@nvidia.com \
--cc=daniel.almeida@collabora.com \
--cc=faith.ekstrand@collabora.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lyude@redhat.com \
--cc=mcanal@igalia.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
--cc=zhiw@nvidia.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 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.