Skip to content

Commit 8a79983

Browse files
Danilo Krummrichojeda
authored andcommitted
rust: alloc: implement ReallocFunc
`ReallocFunc` is an abstraction for the kernel's realloc derivates, such as `krealloc`, `vrealloc` and `kvrealloc`. All of the named functions share the same function signature and implement the same semantics. The `ReallocFunc` abstractions provides a generalized wrapper around those, to trivialize the implementation of `Kmalloc`, `Vmalloc` and `KVmalloc` in subsequent patches. 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-5-dakr@kernel.org [ Added temporary `allow(dead_code)` for `dangling_from_layout` to clean warning in `rusttest` target as discussed in the list (but it is needed earlier, i.e. in this patch already). Added colon. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 941e655 commit 8a79983

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

rust/kernel/alloc.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,12 @@ pub unsafe trait Allocator {
187187
let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), layout, Flags(0)) };
188188
}
189189
}
190+
191+
#[allow(dead_code)]
192+
/// Returns a properly aligned dangling pointer from the given `layout`.
193+
pub(crate) fn dangling_from_layout(layout: Layout) -> NonNull<u8> {
194+
let ptr = layout.align() as *mut u8;
195+
196+
// SAFETY: `layout.align()` (and hence `ptr`) is guaranteed to be non-zero.
197+
unsafe { NonNull::new_unchecked(ptr) }
198+
}

rust/kernel/alloc/allocator.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
// SPDX-License-Identifier: GPL-2.0
22

33
//! Allocator support.
4+
//!
5+
//! Documentation for the kernel's memory allocators can found in the "Memory Allocation Guide"
6+
//! linked below. For instance, this includes the concept of "get free page" (GFP) flags and the
7+
//! typical application of the different kernel allocators.
8+
//!
9+
//! Reference: <https://docs.kernel.org/core-api/memory-allocation.html>
410
511
use super::{flags::*, Flags};
612
use core::alloc::{GlobalAlloc, Layout};
713
use core::ptr;
14+
use core::ptr::NonNull;
15+
16+
use crate::alloc::AllocError;
17+
use crate::bindings;
818

919
struct Kmalloc;
1020

@@ -36,6 +46,66 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F
3646
unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 }
3747
}
3848

49+
/// # Invariants
50+
///
51+
/// One of the following: `krealloc`, `vrealloc`, `kvrealloc`.
52+
struct ReallocFunc(
53+
unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
54+
);
55+
56+
#[expect(dead_code)]
57+
impl ReallocFunc {
58+
/// # Safety
59+
///
60+
/// This method has the same safety requirements as [`Allocator::realloc`].
61+
///
62+
/// # Guarantees
63+
///
64+
/// This method has the same guarantees as `Allocator::realloc`. Additionally
65+
/// - it accepts any pointer to a valid memory allocation allocated by this function.
66+
/// - memory allocated by this function remains valid until it is passed to this function.
67+
unsafe fn call(
68+
&self,
69+
ptr: Option<NonNull<u8>>,
70+
layout: Layout,
71+
old_layout: Layout,
72+
flags: Flags,
73+
) -> Result<NonNull<[u8]>, AllocError> {
74+
let size = aligned_size(layout);
75+
let ptr = match ptr {
76+
Some(ptr) => {
77+
if old_layout.size() == 0 {
78+
ptr::null()
79+
} else {
80+
ptr.as_ptr()
81+
}
82+
}
83+
None => ptr::null(),
84+
};
85+
86+
// SAFETY:
87+
// - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that
88+
// `ptr` is NULL or valid.
89+
// - `ptr` is either NULL or valid by the safety requirements of this function.
90+
//
91+
// GUARANTEE:
92+
// - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`.
93+
// - Those functions provide the guarantees of this function.
94+
let raw_ptr = unsafe {
95+
// If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
96+
self.0(ptr.cast(), size, flags.0).cast()
97+
};
98+
99+
let ptr = if size == 0 {
100+
crate::alloc::dangling_from_layout(layout)
101+
} else {
102+
NonNull::new(raw_ptr).ok_or(AllocError)?
103+
};
104+
105+
Ok(NonNull::slice_from_raw_parts(ptr, size))
106+
}
107+
}
108+
39109
// SAFETY: TODO.
40110
unsafe impl GlobalAlloc for Kmalloc {
41111
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {

0 commit comments

Comments
 (0)