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
511use super :: { flags:: * , Flags } ;
612use core:: alloc:: { GlobalAlloc , Layout } ;
713use core:: ptr;
14+ use core:: ptr:: NonNull ;
815
9- struct Kmalloc ;
16+ use crate :: alloc:: { AllocError , Allocator } ;
17+ use crate :: bindings;
18+
19+ /// The contiguous kernel allocator.
20+ ///
21+ /// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
22+ /// supports larger allocations up to `bindings::KMALLOC_MAX_SIZE`, which is hardware specific.
23+ ///
24+ /// For more details see [self].
25+ pub struct Kmalloc ;
1026
1127/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment.
1228///
@@ -31,6 +47,77 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F
3147 unsafe { bindings:: krealloc ( ptr as * const core:: ffi:: c_void , size, flags. 0 ) as * mut u8 }
3248}
3349
50+ /// # Invariants
51+ ///
52+ /// One of the following `krealloc`, `vrealloc`, `kvrealloc`.
53+ struct ReallocFunc (
54+ unsafe extern "C" fn ( * const core:: ffi:: c_void , usize , u32 ) -> * mut core:: ffi:: c_void ,
55+ ) ;
56+
57+ impl ReallocFunc {
58+ // INVARIANT: `krealloc` satisfies the type invariants.
59+ const KREALLOC : Self = Self ( bindings:: krealloc) ;
60+
61+ /// # Safety
62+ ///
63+ /// This method has the same safety requirements as [`Allocator::realloc`].
64+ ///
65+ /// # Guarantees
66+ ///
67+ /// This method has the same guarantees as `Allocator::realloc`. Additionally
68+ /// - it accepts any pointer to a valid memory allocation allocated by this function.
69+ /// - memory allocated by this function remains valid until it is passed to this function.
70+ unsafe fn call (
71+ & self ,
72+ ptr : Option < NonNull < u8 > > ,
73+ layout : Layout ,
74+ flags : Flags ,
75+ ) -> Result < NonNull < [ u8 ] > , AllocError > {
76+ let size = aligned_size ( layout) ;
77+ let ptr = match ptr {
78+ Some ( ptr) => ptr. as_ptr ( ) ,
79+ None => ptr:: null ( ) ,
80+ } ;
81+
82+ // SAFETY:
83+ // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that
84+ // `ptr` is NULL or valid.
85+ // - `ptr` is either NULL or valid by the safety requirements of this function.
86+ //
87+ // GUARANTEE:
88+ // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`.
89+ // - Those functions provide the guarantees of this function.
90+ let raw_ptr = unsafe {
91+ // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
92+ self . 0 ( ptr. cast ( ) , size, flags. 0 ) . cast ( )
93+ } ;
94+
95+ let ptr = if size == 0 {
96+ NonNull :: dangling ( )
97+ } else {
98+ NonNull :: new ( raw_ptr) . ok_or ( AllocError ) ?
99+ } ;
100+
101+ Ok ( NonNull :: slice_from_raw_parts ( ptr, size) )
102+ }
103+ }
104+
105+ // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
106+ // - memory remains valid until it is explicitly freed,
107+ // - passing a pointer to a valid memory allocation is OK,
108+ // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
109+ unsafe impl Allocator for Kmalloc {
110+ #[ inline]
111+ unsafe fn realloc (
112+ ptr : Option < NonNull < u8 > > ,
113+ layout : Layout ,
114+ flags : Flags ,
115+ ) -> Result < NonNull < [ u8 ] > , AllocError > {
116+ // SAFETY: `ReallocFunc::call` has the same safety requirements as `Allocator::realloc`.
117+ unsafe { ReallocFunc :: KREALLOC . call ( ptr, layout, flags) }
118+ }
119+ }
120+
34121unsafe impl GlobalAlloc for Kmalloc {
35122 unsafe fn alloc ( & self , layout : Layout ) -> * mut u8 {
36123 // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
0 commit comments