xref: /linux-6.15/rust/kernel/alloc/allocator.rs (revision 41b6a812)
131d94d8fSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0
231d94d8fSWedson Almeida Filho 
331d94d8fSWedson Almeida Filho //! Allocator support.
48a799831SDanilo Krummrich //!
58a799831SDanilo Krummrich //! Documentation for the kernel's memory allocators can found in the "Memory Allocation Guide"
68a799831SDanilo Krummrich //! linked below. For instance, this includes the concept of "get free page" (GFP) flags and the
78a799831SDanilo Krummrich //! typical application of the different kernel allocators.
88a799831SDanilo Krummrich //!
98a799831SDanilo Krummrich //! Reference: <https://docs.kernel.org/core-api/memory-allocation.html>
1031d94d8fSWedson Almeida Filho 
11392e34b6SDanilo Krummrich use super::Flags;
12392e34b6SDanilo Krummrich use core::alloc::Layout;
1331d94d8fSWedson Almeida Filho use core::ptr;
148a799831SDanilo Krummrich use core::ptr::NonNull;
158a799831SDanilo Krummrich 
16a34822d1SDanilo Krummrich use crate::alloc::{AllocError, Allocator};
178a799831SDanilo Krummrich use crate::bindings;
1861c00478SDanilo Krummrich use crate::pr_warn;
1931d94d8fSWedson Almeida Filho 
20a34822d1SDanilo Krummrich /// The contiguous kernel allocator.
21a34822d1SDanilo Krummrich ///
22a34822d1SDanilo Krummrich /// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
23a34822d1SDanilo Krummrich /// supports larger allocations up to `bindings::KMALLOC_MAX_SIZE`, which is hardware specific.
24a34822d1SDanilo Krummrich ///
25a34822d1SDanilo Krummrich /// For more details see [self].
26a34822d1SDanilo Krummrich pub struct Kmalloc;
2731d94d8fSWedson Almeida Filho 
2861c00478SDanilo Krummrich /// The virtually contiguous kernel allocator.
2961c00478SDanilo Krummrich ///
3061c00478SDanilo Krummrich /// `Vmalloc` allocates pages from the page level allocator and maps them into the contiguous kernel
3161c00478SDanilo Krummrich /// virtual space. It is typically used for large allocations. The memory allocated with this
3261c00478SDanilo Krummrich /// allocator is not physically contiguous.
3361c00478SDanilo Krummrich ///
3461c00478SDanilo Krummrich /// For more details see [self].
3561c00478SDanilo Krummrich pub struct Vmalloc;
3661c00478SDanilo Krummrich 
378362c260SDanilo Krummrich /// The kvmalloc kernel allocator.
388362c260SDanilo Krummrich ///
398362c260SDanilo Krummrich /// `KVmalloc` attempts to allocate memory with `Kmalloc` first, but falls back to `Vmalloc` upon
408362c260SDanilo Krummrich /// failure. This allocator is typically used when the size for the requested allocation is not
418362c260SDanilo Krummrich /// known and may exceed the capabilities of `Kmalloc`.
428362c260SDanilo Krummrich ///
438362c260SDanilo Krummrich /// For more details see [self].
448362c260SDanilo Krummrich pub struct KVmalloc;
458362c260SDanilo Krummrich 
46a654a6e0SDanilo Krummrich /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment.
aligned_size(new_layout: Layout) -> usize47a654a6e0SDanilo Krummrich fn aligned_size(new_layout: Layout) -> usize {
48a654a6e0SDanilo Krummrich     // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
49a654a6e0SDanilo Krummrich     let layout = new_layout.pad_to_align();
50a654a6e0SDanilo Krummrich 
51a654a6e0SDanilo Krummrich     // Note that `layout.size()` (after padding) is guaranteed to be a multiple of `layout.align()`
52a654a6e0SDanilo Krummrich     // which together with the slab guarantees means the `krealloc` will return a properly aligned
53a654a6e0SDanilo Krummrich     // object (see comments in `kmalloc()` for more information).
54a654a6e0SDanilo Krummrich     layout.size()
55a654a6e0SDanilo Krummrich }
56a654a6e0SDanilo Krummrich 
578a799831SDanilo Krummrich /// # Invariants
588a799831SDanilo Krummrich ///
598a799831SDanilo Krummrich /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`.
608a799831SDanilo Krummrich struct ReallocFunc(
61d072acdaSGary Guo     unsafe extern "C" fn(*const crate::ffi::c_void, usize, u32) -> *mut crate::ffi::c_void,
628a799831SDanilo Krummrich );
638a799831SDanilo Krummrich 
648a799831SDanilo Krummrich impl ReallocFunc {
65a34822d1SDanilo Krummrich     // INVARIANT: `krealloc` satisfies the type invariants.
66a34822d1SDanilo Krummrich     const KREALLOC: Self = Self(bindings::krealloc);
67a34822d1SDanilo Krummrich 
6861c00478SDanilo Krummrich     // INVARIANT: `vrealloc` satisfies the type invariants.
6961c00478SDanilo Krummrich     const VREALLOC: Self = Self(bindings::vrealloc);
7061c00478SDanilo Krummrich 
718362c260SDanilo Krummrich     // INVARIANT: `kvrealloc` satisfies the type invariants.
728362c260SDanilo Krummrich     const KVREALLOC: Self = Self(bindings::kvrealloc);
738362c260SDanilo Krummrich 
748a799831SDanilo Krummrich     /// # Safety
758a799831SDanilo Krummrich     ///
768a799831SDanilo Krummrich     /// This method has the same safety requirements as [`Allocator::realloc`].
778a799831SDanilo Krummrich     ///
788a799831SDanilo Krummrich     /// # Guarantees
798a799831SDanilo Krummrich     ///
808a799831SDanilo Krummrich     /// This method has the same guarantees as `Allocator::realloc`. Additionally
818a799831SDanilo Krummrich     /// - it accepts any pointer to a valid memory allocation allocated by this function.
828a799831SDanilo Krummrich     /// - memory allocated by this function remains valid until it is passed to this function.
83*41b6a812SGary Guo     #[inline]
call( &self, ptr: Option<NonNull<u8>>, layout: Layout, old_layout: Layout, flags: Flags, ) -> Result<NonNull<[u8]>, AllocError>848a799831SDanilo Krummrich     unsafe fn call(
858a799831SDanilo Krummrich         &self,
868a799831SDanilo Krummrich         ptr: Option<NonNull<u8>>,
878a799831SDanilo Krummrich         layout: Layout,
888a799831SDanilo Krummrich         old_layout: Layout,
898a799831SDanilo Krummrich         flags: Flags,
908a799831SDanilo Krummrich     ) -> Result<NonNull<[u8]>, AllocError> {
918a799831SDanilo Krummrich         let size = aligned_size(layout);
928a799831SDanilo Krummrich         let ptr = match ptr {
938a799831SDanilo Krummrich             Some(ptr) => {
948a799831SDanilo Krummrich                 if old_layout.size() == 0 {
958a799831SDanilo Krummrich                     ptr::null()
968a799831SDanilo Krummrich                 } else {
978a799831SDanilo Krummrich                     ptr.as_ptr()
988a799831SDanilo Krummrich                 }
998a799831SDanilo Krummrich             }
1008a799831SDanilo Krummrich             None => ptr::null(),
1018a799831SDanilo Krummrich         };
1028a799831SDanilo Krummrich 
1038a799831SDanilo Krummrich         // SAFETY:
1048a799831SDanilo Krummrich         // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that
1058a799831SDanilo Krummrich         //   `ptr` is NULL or valid.
1068a799831SDanilo Krummrich         // - `ptr` is either NULL or valid by the safety requirements of this function.
1078a799831SDanilo Krummrich         //
1088a799831SDanilo Krummrich         // GUARANTEE:
1098a799831SDanilo Krummrich         // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`.
1108a799831SDanilo Krummrich         // - Those functions provide the guarantees of this function.
1118a799831SDanilo Krummrich         let raw_ptr = unsafe {
1128a799831SDanilo Krummrich             // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
1138a799831SDanilo Krummrich             self.0(ptr.cast(), size, flags.0).cast()
1148a799831SDanilo Krummrich         };
1158a799831SDanilo Krummrich 
1168a799831SDanilo Krummrich         let ptr = if size == 0 {
1178a799831SDanilo Krummrich             crate::alloc::dangling_from_layout(layout)
1188a799831SDanilo Krummrich         } else {
1198a799831SDanilo Krummrich             NonNull::new(raw_ptr).ok_or(AllocError)?
1208a799831SDanilo Krummrich         };
1218a799831SDanilo Krummrich 
1228a799831SDanilo Krummrich         Ok(NonNull::slice_from_raw_parts(ptr, size))
1238a799831SDanilo Krummrich     }
1248a799831SDanilo Krummrich }
1258a799831SDanilo Krummrich 
126a34822d1SDanilo Krummrich // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
127a34822d1SDanilo Krummrich // - memory remains valid until it is explicitly freed,
128a34822d1SDanilo Krummrich // - passing a pointer to a valid memory allocation is OK,
129a34822d1SDanilo Krummrich // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
130a34822d1SDanilo Krummrich unsafe impl Allocator for Kmalloc {
131a34822d1SDanilo Krummrich     #[inline]
realloc( ptr: Option<NonNull<u8>>, layout: Layout, old_layout: Layout, flags: Flags, ) -> Result<NonNull<[u8]>, AllocError>132a34822d1SDanilo Krummrich     unsafe fn realloc(
133a34822d1SDanilo Krummrich         ptr: Option<NonNull<u8>>,
134a34822d1SDanilo Krummrich         layout: Layout,
135a34822d1SDanilo Krummrich         old_layout: Layout,
136a34822d1SDanilo Krummrich         flags: Flags,
137a34822d1SDanilo Krummrich     ) -> Result<NonNull<[u8]>, AllocError> {
138a34822d1SDanilo Krummrich         // SAFETY: `ReallocFunc::call` has the same safety requirements as `Allocator::realloc`.
139a34822d1SDanilo Krummrich         unsafe { ReallocFunc::KREALLOC.call(ptr, layout, old_layout, flags) }
140a34822d1SDanilo Krummrich     }
141a34822d1SDanilo Krummrich }
142a34822d1SDanilo Krummrich 
14361c00478SDanilo Krummrich // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
14461c00478SDanilo Krummrich // - memory remains valid until it is explicitly freed,
14561c00478SDanilo Krummrich // - passing a pointer to a valid memory allocation is OK,
14661c00478SDanilo Krummrich // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
14761c00478SDanilo Krummrich unsafe impl Allocator for Vmalloc {
14861c00478SDanilo Krummrich     #[inline]
realloc( ptr: Option<NonNull<u8>>, layout: Layout, old_layout: Layout, flags: Flags, ) -> Result<NonNull<[u8]>, AllocError>14961c00478SDanilo Krummrich     unsafe fn realloc(
15061c00478SDanilo Krummrich         ptr: Option<NonNull<u8>>,
15161c00478SDanilo Krummrich         layout: Layout,
15261c00478SDanilo Krummrich         old_layout: Layout,
15361c00478SDanilo Krummrich         flags: Flags,
15461c00478SDanilo Krummrich     ) -> Result<NonNull<[u8]>, AllocError> {
15561c00478SDanilo Krummrich         // TODO: Support alignments larger than PAGE_SIZE.
15661c00478SDanilo Krummrich         if layout.align() > bindings::PAGE_SIZE {
15761c00478SDanilo Krummrich             pr_warn!("Vmalloc does not support alignments larger than PAGE_SIZE yet.\n");
15861c00478SDanilo Krummrich             return Err(AllocError);
15961c00478SDanilo Krummrich         }
16061c00478SDanilo Krummrich 
16161c00478SDanilo Krummrich         // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
16261c00478SDanilo Krummrich         // allocated with this `Allocator`.
16361c00478SDanilo Krummrich         unsafe { ReallocFunc::VREALLOC.call(ptr, layout, old_layout, flags) }
16461c00478SDanilo Krummrich     }
16561c00478SDanilo Krummrich }
16661c00478SDanilo Krummrich 
1678362c260SDanilo Krummrich // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
1688362c260SDanilo Krummrich // - memory remains valid until it is explicitly freed,
1698362c260SDanilo Krummrich // - passing a pointer to a valid memory allocation is OK,
1708362c260SDanilo Krummrich // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
1718362c260SDanilo Krummrich unsafe impl Allocator for KVmalloc {
1728362c260SDanilo Krummrich     #[inline]
realloc( ptr: Option<NonNull<u8>>, layout: Layout, old_layout: Layout, flags: Flags, ) -> Result<NonNull<[u8]>, AllocError>1738362c260SDanilo Krummrich     unsafe fn realloc(
1748362c260SDanilo Krummrich         ptr: Option<NonNull<u8>>,
1758362c260SDanilo Krummrich         layout: Layout,
1768362c260SDanilo Krummrich         old_layout: Layout,
1778362c260SDanilo Krummrich         flags: Flags,
1788362c260SDanilo Krummrich     ) -> Result<NonNull<[u8]>, AllocError> {
1798362c260SDanilo Krummrich         // TODO: Support alignments larger than PAGE_SIZE.
1808362c260SDanilo Krummrich         if layout.align() > bindings::PAGE_SIZE {
1818362c260SDanilo Krummrich             pr_warn!("KVmalloc does not support alignments larger than PAGE_SIZE yet.\n");
1828362c260SDanilo Krummrich             return Err(AllocError);
1838362c260SDanilo Krummrich         }
1848362c260SDanilo Krummrich 
1858362c260SDanilo Krummrich         // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
1868362c260SDanilo Krummrich         // allocated with this `Allocator`.
1878362c260SDanilo Krummrich         unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) }
1888362c260SDanilo Krummrich     }
1898362c260SDanilo Krummrich }
190