Skip to content

Commit 2a9bea9

Browse files
committed
rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl
While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation. Link: #68 Signed-off-by: Björn Roy Baron <[email protected]> [boqun: add size adjustment for alignment requirement] Signed-off-by: Boqun Feng <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3712420 commit 2a9bea9

File tree

1 file changed

+54
-5
lines changed

1 file changed

+54
-5
lines changed

rust/kernel/allocator.rs

+54-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,17 @@ use crate::bindings;
99

1010
struct KernelAllocator;
1111

12-
unsafe impl GlobalAlloc for KernelAllocator {
13-
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
12+
impl KernelAllocator {
13+
/// # Safety
14+
///
15+
/// * `ptr` can be either null or a pointer which has been allocated by this allocator.
16+
/// * `layout` must have a non-zero size.
17+
unsafe fn krealloc_with_flags(
18+
&self,
19+
ptr: *mut u8,
20+
layout: Layout,
21+
flags: bindings::gfp_t,
22+
) -> *mut u8 {
1423
// Customized layouts from `Layout::from_size_align()` can have size < align, so pads first.
1524
let layout = layout.pad_to_align();
1625

@@ -26,16 +35,56 @@ unsafe impl GlobalAlloc for KernelAllocator {
2635
size = size.next_power_of_two();
2736
}
2837

29-
// `krealloc()` is used instead of `kmalloc()` because the latter is
30-
// an inline function and cannot be bound to as a result.
31-
unsafe { bindings::krealloc(ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
38+
// SAFETY:
39+
//
40+
// * `ptr` is either null or a pointer returned from a previous k{re}alloc() by the function
41+
// safety requirement.
42+
//
43+
// * `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero
44+
// according to the function safety requirement) or a result from `next_power_of_two()`.
45+
unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags) as *mut u8 }
46+
}
47+
}
48+
49+
unsafe impl GlobalAlloc for KernelAllocator {
50+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
51+
// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
52+
// requirement.
53+
unsafe { self.krealloc_with_flags(ptr::null_mut(), layout, bindings::GFP_KERNEL) }
3254
}
3355

3456
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
3557
unsafe {
3658
bindings::kfree(ptr as *const core::ffi::c_void);
3759
}
3860
}
61+
62+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
63+
// SAFETY:
64+
// * `new_size` when rounded up to the nearest multiple of `layout.align()`, will not
65+
// overflow `isize` by the function safety requirement.
66+
// * `layout.align()` is a proper alignment (i.e. not zero and must be a power of two).
67+
let layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
68+
69+
// SAFETY:
70+
// * `ptr` is either null or a pointer allocated by this allocator by function safety
71+
// requirement.
72+
// * the size of `layout` is not zero because `new_size` is not zero by function safety
73+
// requirement.
74+
unsafe { self.krealloc_with_flags(ptr, layout, bindings::GFP_KERNEL) }
75+
}
76+
77+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
78+
// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
79+
// requirement.
80+
unsafe {
81+
self.krealloc_with_flags(
82+
ptr::null_mut(),
83+
layout,
84+
bindings::GFP_KERNEL | bindings::__GFP_ZERO,
85+
)
86+
}
87+
}
3988
}
4089

4190
#[global_allocator]

0 commit comments

Comments
 (0)