From a9c0b305ddc1d6415506d26d153386f96f7d3a87 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 23 Jul 2024 18:58:41 +0200 Subject: rust: alloc: implement `KVmalloc` allocator Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to allocate memory wth `kmalloc` first and, on failure, falls back to `vmalloc`. All memory allocations made with `KVmalloc` end up in `kvrealloc_noprof()`; all frees in `kvfree()`. Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- rust/helpers.c | 6 ++++++ rust/kernel/alloc/allocator.rs | 27 +++++++++++++++++++++++++++ rust/kernel/alloc/allocator_test.rs | 1 + 3 files changed, 34 insertions(+) diff --git a/rust/helpers.c b/rust/helpers.c index 784fc2a8fd04..91991440d9c3 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -374,6 +374,12 @@ void *rust_helper_vrealloc(const void *p, size_t size, gfp_t flags) } EXPORT_SYMBOL_GPL(rust_helper_vrealloc); +void *rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags) +{ + return kvrealloc(p, size, flags); +} +EXPORT_SYMBOL_GPL(rust_helper_kvrealloc); + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indices. diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index fdda22c6983f..243d8c49a57b 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -23,6 +23,12 @@ pub struct Kmalloc; /// contiguous kernel virtual space. pub struct Vmalloc; +/// The kvmalloc kernel allocator. +/// +/// Attempt to allocate physically contiguous memory, but upon failure, fall back to non-contiguous +/// (vmalloc) allocation. +pub struct KVmalloc; + /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. fn aligned_size(new_layout: Layout) -> usize { // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. @@ -65,6 +71,9 @@ impl ReallocFunc { // INVARIANT: `vrealloc` satisfies the type invariants. const VREALLOC: Self = Self(bindings::vrealloc); + // INVARIANT: `kvrealloc` satisfies the type invariants. + const KVREALLOC: Self = Self(bindings::kvrealloc); + /// # Safety /// /// This method has the same safety requirements as `Allocator::realloc`. @@ -160,6 +169,24 @@ unsafe impl Allocator for Vmalloc { } } +unsafe impl Allocator for KVmalloc { + unsafe fn realloc( + ptr: Option>, + layout: Layout, + flags: Flags, + ) -> Result, AllocError> { + // TODO: Support alignments larger than PAGE_SIZE. + if layout.align() > bindings::PAGE_SIZE { + pr_warn!("KVmalloc does not support alignments larger than PAGE_SIZE yet.\n"); + return Err(AllocError); + } + + // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously + // allocated with this `Allocator`. + unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, flags) } + } +} + #[global_allocator] static ALLOCATOR: Kmalloc = Kmalloc; diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index e7bf2982f68f..1b2642c547ec 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -8,6 +8,7 @@ use core::ptr::NonNull; pub struct Kmalloc; pub type Vmalloc = Kmalloc; +pub type KVmalloc = Kmalloc; unsafe impl Allocator for Kmalloc { unsafe fn realloc( -- cgit v1.2.3-58-ga151