diff options
author | Danilo Krummrich <dakr@kernel.org> | 2024-07-23 18:58:41 +0200 |
---|---|---|
committer | Danilo Krummrich <dakr@kernel.org> | 2024-08-13 16:05:08 +0200 |
commit | a9c0b305ddc1d6415506d26d153386f96f7d3a87 (patch) | |
tree | 6f55a5405db8982ed7e588d253d307bc01c05b81 | |
parent | 5fe01f4ab424b366e49cf213e40c0db9ed23c2a1 (diff) |
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 <aliceryhl@google.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-rw-r--r-- | rust/helpers.c | 6 | ||||
-rw-r--r-- | rust/kernel/alloc/allocator.rs | 27 | ||||
-rw-r--r-- | rust/kernel/alloc/allocator_test.rs | 1 |
3 files changed, 34 insertions, 0 deletions
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<NonNull<u8>>, + layout: Layout, + flags: Flags, + ) -> Result<NonNull<[u8]>, 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( |