Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: alloc: implement `Cmalloc` in module allocator_test

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.

Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20241004154149.93856-26-dakr@kernel.org
[ Removed the temporary `allow(dead_code)` as discussed in the list and
fixed typo, added backticks. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Danilo Krummrich and committed by
Miguel Ojeda
dd09538f 909037ce

+81 -9
-1
rust/kernel/alloc.rs
··· 215 215 } 216 216 } 217 217 218 - #[allow(dead_code)] 219 218 /// Returns a properly aligned dangling pointer from the given `layout`. 220 219 pub(crate) fn dangling_from_layout(layout: Layout) -> NonNull<u8> { 221 220 let ptr = layout.align() as *mut u8;
+81 -8
rust/kernel/alloc/allocator_test.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 + //! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users 4 + //! of those types (e.g. `CString`) use kernel allocators for instantiation. 5 + //! 6 + //! In order to allow userspace test cases to make use of such types as well, implement the 7 + //! `Cmalloc` allocator within the allocator_test module and type alias all kernel allocators to 8 + //! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend. 9 + 3 10 #![allow(missing_docs)] 4 11 5 - use super::{AllocError, Allocator, Flags}; 12 + use super::{flags::*, AllocError, Allocator, Flags}; 6 13 use core::alloc::Layout; 14 + use core::cmp; 15 + use core::ptr; 7 16 use core::ptr::NonNull; 8 17 9 - pub struct Kmalloc; 18 + /// The userspace allocator based on libc. 19 + pub struct Cmalloc; 20 + 21 + pub type Kmalloc = Cmalloc; 10 22 pub type Vmalloc = Kmalloc; 11 23 pub type KVmalloc = Kmalloc; 12 24 13 - unsafe impl Allocator for Kmalloc { 25 + extern "C" { 26 + #[link_name = "aligned_alloc"] 27 + fn libc_aligned_alloc(align: usize, size: usize) -> *mut core::ffi::c_void; 28 + 29 + #[link_name = "free"] 30 + fn libc_free(ptr: *mut core::ffi::c_void); 31 + } 32 + 33 + // SAFETY: 34 + // - memory remains valid until it is explicitly freed, 35 + // - passing a pointer to a valid memory allocation created by this `Allocator` is always OK, 36 + // - `realloc` provides the guarantees as provided in the `# Guarantees` section. 37 + unsafe impl Allocator for Cmalloc { 14 38 unsafe fn realloc( 15 - _ptr: Option<NonNull<u8>>, 16 - _layout: Layout, 17 - _old_layout: Layout, 18 - _flags: Flags, 39 + ptr: Option<NonNull<u8>>, 40 + layout: Layout, 41 + old_layout: Layout, 42 + flags: Flags, 19 43 ) -> Result<NonNull<[u8]>, AllocError> { 20 - panic!(); 44 + let src = match ptr { 45 + Some(src) => { 46 + if old_layout.size() == 0 { 47 + ptr::null_mut() 48 + } else { 49 + src.as_ptr() 50 + } 51 + } 52 + None => ptr::null_mut(), 53 + }; 54 + 55 + if layout.size() == 0 { 56 + // SAFETY: `src` is either NULL or was previously allocated with this `Allocator` 57 + unsafe { libc_free(src.cast()) }; 58 + 59 + return Ok(NonNull::slice_from_raw_parts( 60 + crate::alloc::dangling_from_layout(layout), 61 + 0, 62 + )); 63 + } 64 + 65 + // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or 66 + // exceeds the given size and alignment requirements. 67 + let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8; 68 + let dst = NonNull::new(dst).ok_or(AllocError)?; 69 + 70 + if flags.contains(__GFP_ZERO) { 71 + // SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new` 72 + // guarantee that `dst` points to memory of at least `layout.size()` bytes. 73 + unsafe { dst.as_ptr().write_bytes(0, layout.size()) }; 74 + } 75 + 76 + if !src.is_null() { 77 + // SAFETY: 78 + // - `src` has previously been allocated with this `Allocator`; `dst` has just been 79 + // newly allocated, hence the memory regions do not overlap. 80 + // - both` src` and `dst` are properly aligned and valid for reads and writes 81 + unsafe { 82 + ptr::copy_nonoverlapping( 83 + src, 84 + dst.as_ptr(), 85 + cmp::min(layout.size(), old_layout.size()), 86 + ) 87 + }; 88 + } 89 + 90 + // SAFETY: `src` is either NULL or was previously allocated with this `Allocator` 91 + unsafe { libc_free(src.cast()) }; 92 + 93 + Ok(NonNull::slice_from_raw_parts(dst, layout.size())) 21 94 } 22 95 }