rust: support large alignments in allocations

Add support for large (> PAGE_SIZE) alignments in Rust allocators.  All
the preparations on the C side are already done, we just need to add
bindings for <alloc>_node_align() functions and start using those.

Link: https://lkml.kernel.org/r/20250806125552.1727073-1-vitaly.wool@konsulko.se
Signed-off-by: Vitaly Wool <vitaly.wool@konsulko.se>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Acked-by: Alice Ryhl <aliceryhl@google.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Jann Horn <jannh@google.com>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Vitaly Wool 2025-08-06 14:55:52 +02:00 committed by Andrew Morton
parent 7760b6421b
commit 1738796994
3 changed files with 18 additions and 27 deletions

View file

@ -3,13 +3,15 @@
#include <linux/slab.h>
void * __must_check __realloc_size(2)
rust_helper_krealloc_node(const void *objp, size_t new_size, gfp_t flags, int node)
rust_helper_krealloc_node_align(const void *objp, size_t new_size, unsigned long align,
gfp_t flags, int node)
{
return krealloc_node(objp, new_size, flags, node);
return krealloc_node_align(objp, new_size, align, flags, node);
}
void * __must_check __realloc_size(2)
rust_helper_kvrealloc_node(const void *p, size_t size, gfp_t flags, int node)
rust_helper_kvrealloc_node_align(const void *p, size_t size, unsigned long align,
gfp_t flags, int node)
{
return kvrealloc_node(p, size, flags, node);
return kvrealloc_node_align(p, size, align, flags, node);
}

View file

@ -3,7 +3,8 @@
#include <linux/vmalloc.h>
void * __must_check __realloc_size(2)
rust_helper_vrealloc_node(const void *p, size_t size, gfp_t flags, int node)
rust_helper_vrealloc_node_align(const void *p, size_t size, unsigned long align,
gfp_t flags, int node)
{
return vrealloc_node(p, size, flags, node);
return vrealloc_node_align(p, size, align, flags, node);
}

View file

@ -15,7 +15,6 @@ use core::ptr::NonNull;
use crate::alloc::{AllocError, Allocator, NumaNode};
use crate::bindings;
use crate::pr_warn;
/// The contiguous kernel allocator.
///
@ -45,25 +44,26 @@ pub struct KVmalloc;
/// # Invariants
///
/// One of the following: `krealloc_node`, `vrealloc_node`, `kvrealloc_node`.
/// One of the following: `krealloc_node_align`, `vrealloc_node_align`, `kvrealloc_node_align`.
struct ReallocFunc(
unsafe extern "C" fn(
*const crate::ffi::c_void,
usize,
crate::ffi::c_ulong,
u32,
crate::ffi::c_int,
) -> *mut crate::ffi::c_void,
);
impl ReallocFunc {
// INVARIANT: `krealloc_node` satisfies the type invariants.
const KREALLOC: Self = Self(bindings::krealloc_node);
// INVARIANT: `krealloc_node_align` satisfies the type invariants.
const KREALLOC: Self = Self(bindings::krealloc_node_align);
// INVARIANT: `vrealloc_node` satisfies the type invariants.
const VREALLOC: Self = Self(bindings::vrealloc_node);
// INVARIANT: `vrealloc_node_align` satisfies the type invariants.
const VREALLOC: Self = Self(bindings::vrealloc_node_align);
// INVARIANT: `kvrealloc_node` satisfies the type invariants.
const KVREALLOC: Self = Self(bindings::kvrealloc_node);
// INVARIANT: `kvrealloc_node_align` satisfies the type invariants.
const KVREALLOC: Self = Self(bindings::kvrealloc_node_align);
/// # Safety
///
@ -105,7 +105,7 @@ impl ReallocFunc {
// - Those functions provide the guarantees of this function.
let raw_ptr = unsafe {
// If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
self.0(ptr.cast(), size, flags.0, nid.0).cast()
self.0(ptr.cast(), size, layout.align(), flags.0, nid.0).cast()
};
let ptr = if size == 0 {
@ -162,12 +162,6 @@ unsafe impl Allocator for Vmalloc {
flags: Flags,
nid: NumaNode,
) -> Result<NonNull<[u8]>, AllocError> {
// TODO: Support alignments larger than PAGE_SIZE.
if layout.align() > bindings::PAGE_SIZE {
pr_warn!("Vmalloc 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::VREALLOC.call(ptr, layout, old_layout, flags, nid) }
@ -191,12 +185,6 @@ unsafe impl Allocator for KVmalloc {
// compatible layout.
let layout = Kmalloc::aligned_layout(layout);
// 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, old_layout, flags, nid) }