|
1 | 1 | // SPDX-License-Identifier: GPL-2.0
|
2 | 2 |
|
3 | 3 | //! 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> |
4 | 10 |
|
5 | 11 | use super::{flags::*, Flags};
|
6 | 12 | use core::alloc::{GlobalAlloc, Layout};
|
7 | 13 | use core::ptr;
|
| 14 | +use core::ptr::NonNull; |
| 15 | + |
| 16 | +use crate::alloc::AllocError; |
| 17 | +use crate::bindings; |
8 | 18 |
|
9 | 19 | struct Kmalloc;
|
10 | 20 |
|
@@ -36,6 +46,66 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F
|
36 | 46 | unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 }
|
37 | 47 | }
|
38 | 48 |
|
| 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 | + |
39 | 109 | // SAFETY: TODO.
|
40 | 110 | unsafe impl GlobalAlloc for Kmalloc {
|
41 | 111 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
|
0 commit comments