Merge tag 'alloc-next-v6.18-2025-09-04' of https://github.com/Rust-for-Linux/linux into rust-next

Pull alloc and DMA updates from Danilo Krummrich:

  Allocator:
   - Provide information about the minimum alignment guarantees of
     'Kmalloc', 'Vmalloc' and 'KVmalloc'.
   - Take minimum alignment guarantees of allocators for
     'ForeignOwnable' into account.
   - Remove the 'allocator_test' incl. 'Cmalloc'.

  Box:
   - Implement 'Box::pin_slice()', which constructs a pinned slice of
     elements.

  Vec:
   - Simplify KUnit test module name to 'rust_kvec'.
   - Add doc-test for 'Vec::as_slice()'.
   - Constify various methods.

  DMA:
   - Update 'ARef' and 'AlwaysRefCounted' imports.

  MISC:
   - Remove support for unused host '#[test]'s.
   - Constify 'ArrayLayout::new_unchecked()'.

* tag 'alloc-next-v6.18-2025-09-04' of https://github.com/Rust-for-Linux/linux:
  rust: alloc: remove `allocator_test`
  rust: kernel: remove support for unused host `#[test]`s
  rust: alloc: implement Box::pin_slice()
  rust: alloc: add ARCH_KMALLOC_MINALIGN to bindgen blocklist
  rust: dma: Update ARef and AlwaysRefCounted imports from sync::aref
  rust: alloc: take the allocator into account for FOREIGN_ALIGN
  rust: alloc: specify the minimum alignment of each allocator
  rust: make `kvec::Vec` functions `const fn`
  rust: make `ArrayLayout::new_unchecked` a `const fn`
  rust: alloc: kvec: simplify KUnit test module name to "rust_kvec"
  rust: alloc: kvec: add doc example for as_slice method
This commit is contained in:
Miguel Ojeda
2025-09-08 00:09:41 +02:00
14 changed files with 130 additions and 158 deletions
+8
View File
@@ -17,6 +17,8 @@ use crate::alloc::{AllocError, Allocator};
use crate::bindings;
use crate::pr_warn;
const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
/// The contiguous kernel allocator.
///
/// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
@@ -128,6 +130,8 @@ impl Kmalloc {
// - passing a pointer to a valid memory allocation is OK,
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
unsafe impl Allocator for Kmalloc {
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
#[inline]
unsafe fn realloc(
ptr: Option<NonNull<u8>>,
@@ -147,6 +151,8 @@ unsafe impl Allocator for Kmalloc {
// - passing a pointer to a valid memory allocation is OK,
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
unsafe impl Allocator for Vmalloc {
const MIN_ALIGN: usize = kernel::page::PAGE_SIZE;
#[inline]
unsafe fn realloc(
ptr: Option<NonNull<u8>>,
@@ -171,6 +177,8 @@ unsafe impl Allocator for Vmalloc {
// - passing a pointer to a valid memory allocation is OK,
// - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
unsafe impl Allocator for KVmalloc {
const MIN_ALIGN: usize = ARCH_KMALLOC_MINALIGN;
#[inline]
unsafe fn realloc(
ptr: Option<NonNull<u8>>,
-124
View File
@@ -1,124 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
//! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users
//! of those types (e.g. `CString`) use kernel allocators for instantiation.
//!
//! In order to allow userspace test cases to make use of such types as well, implement the
//! `Cmalloc` allocator within the `allocator_test` module and type alias all kernel allocators to
//! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend.
#![allow(missing_docs)]
use super::{flags::*, AllocError, Allocator, Flags};
use core::alloc::Layout;
use core::cmp;
use core::ptr;
use core::ptr::NonNull;
/// The userspace allocator based on libc.
pub struct Cmalloc;
pub type Kmalloc = Cmalloc;
pub type Vmalloc = Kmalloc;
pub type KVmalloc = Kmalloc;
impl Cmalloc {
/// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of
/// `layout`.
pub fn aligned_layout(layout: Layout) -> Layout {
// Note that `layout.size()` (after padding) is guaranteed to be a multiple of
// `layout.align()` which together with the slab guarantees means that `Kmalloc` will return
// a properly aligned object (see comments in `kmalloc()` for more information).
layout.pad_to_align()
}
}
extern "C" {
#[link_name = "aligned_alloc"]
fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;
#[link_name = "free"]
fn libc_free(ptr: *mut crate::ffi::c_void);
}
// SAFETY:
// - memory remains valid until it is explicitly freed,
// - passing a pointer to a valid memory allocation created by this `Allocator` is always OK,
// - `realloc` provides the guarantees as provided in the `# Guarantees` section.
unsafe impl Allocator for Cmalloc {
unsafe fn realloc(
ptr: Option<NonNull<u8>>,
layout: Layout,
old_layout: Layout,
flags: Flags,
) -> Result<NonNull<[u8]>, AllocError> {
let src = match ptr {
Some(src) => {
if old_layout.size() == 0 {
ptr::null_mut()
} else {
src.as_ptr()
}
}
None => ptr::null_mut(),
};
if layout.size() == 0 {
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
unsafe { libc_free(src.cast()) };
return Ok(NonNull::slice_from_raw_parts(
crate::alloc::dangling_from_layout(layout),
0,
));
}
// ISO C (ISO/IEC 9899:2011) defines `aligned_alloc`:
//
// > The value of alignment shall be a valid alignment supported by the implementation
// [...].
//
// As an example of the "supported by the implementation" requirement, POSIX.1-2001 (IEEE
// 1003.1-2001) defines `posix_memalign`:
//
// > The value of alignment shall be a power of two multiple of sizeof (void *).
//
// and POSIX-based implementations of `aligned_alloc` inherit this requirement. At the time
// of writing, this is known to be the case on macOS (but not in glibc).
//
// Satisfy the stricter requirement to avoid spurious test failures on some platforms.
let min_align = core::mem::size_of::<*const crate::ffi::c_void>();
let layout = layout.align_to(min_align).map_err(|_| AllocError)?;
let layout = layout.pad_to_align();
// SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
// exceeds the given size and alignment requirements.
let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>();
let dst = NonNull::new(dst).ok_or(AllocError)?;
if flags.contains(__GFP_ZERO) {
// SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new`
// guarantee that `dst` points to memory of at least `layout.size()` bytes.
unsafe { dst.as_ptr().write_bytes(0, layout.size()) };
}
if !src.is_null() {
// SAFETY:
// - `src` has previously been allocated with this `Allocator`; `dst` has just been
// newly allocated, hence the memory regions do not overlap.
// - both` src` and `dst` are properly aligned and valid for reads and writes
unsafe {
ptr::copy_nonoverlapping(
src,
dst.as_ptr(),
cmp::min(layout.size(), old_layout.size()),
)
};
}
// SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
unsafe { libc_free(src.cast()) };
Ok(NonNull::slice_from_raw_parts(dst, layout.size()))
}
}
+86 -4
View File
@@ -290,6 +290,83 @@ where
Ok(Self::new(x, flags)?.into())
}
/// Construct a pinned slice of elements `Pin<Box<[T], A>>`.
///
/// This is a convenient means for creation of e.g. slices of structrures containing spinlocks
/// or mutexes.
///
/// # Examples
///
/// ```
/// use kernel::sync::{new_spinlock, SpinLock};
///
/// struct Inner {
/// a: u32,
/// b: u32,
/// }
///
/// #[pin_data]
/// struct Example {
/// c: u32,
/// #[pin]
/// d: SpinLock<Inner>,
/// }
///
/// impl Example {
/// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self {
/// c: 10,
/// d <- new_spinlock!(Inner { a: 20, b: 30 }),
/// })
/// }
/// }
///
/// // Allocate a boxed slice of 10 `Example`s.
/// let s = KBox::pin_slice(
/// | _i | Example::new(),
/// 10,
/// GFP_KERNEL
/// )?;
///
/// assert_eq!(s[5].c, 10);
/// assert_eq!(s[3].d.lock().a, 20);
/// # Ok::<(), Error>(())
/// ```
pub fn pin_slice<Func, Item, E>(
mut init: Func,
len: usize,
flags: Flags,
) -> Result<Pin<Box<[T], A>>, E>
where
Func: FnMut(usize) -> Item,
Item: PinInit<T, E>,
E: From<AllocError>,
{
let mut buffer = super::Vec::<T, A>::with_capacity(len, flags)?;
for i in 0..len {
let ptr = buffer.spare_capacity_mut().as_mut_ptr().cast();
// SAFETY:
// - `ptr` is a valid pointer to uninitialized memory.
// - `ptr` is not used if an error is returned.
// - `ptr` won't be moved until it is dropped, i.e. it is pinned.
unsafe { init(i).__pinned_init(ptr)? };
// SAFETY:
// - `i + 1 <= len`, hence we don't exceed the capacity, due to the call to
// `with_capacity()` above.
// - The new value at index buffer.len() + 1 is the only element being added here, and
// it has been initialized above by `init(i).__pinned_init(ptr)`.
unsafe { buffer.inc_len(1) };
}
let (ptr, _, _) = buffer.into_raw_parts();
let slice = core::ptr::slice_from_raw_parts_mut(ptr, len);
// SAFETY: `slice` points to an allocation allocated with `A` (`buffer`) and holds a valid
// `[T]`.
Ok(Pin::from(unsafe { Box::from_raw(slice) }))
}
/// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
/// [`Unpin`], then `x` will be pinned in memory and can't be moved.
pub fn into_pin(this: Self) -> Pin<Self> {
@@ -401,12 +478,17 @@ where
}
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T`.
// pointer to `T` allocated by `A`.
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
where
A: Allocator,
{
const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
const FOREIGN_ALIGN: usize = if core::mem::align_of::<T>() < A::MIN_ALIGN {
A::MIN_ALIGN
} else {
core::mem::align_of::<T>()
};
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;
@@ -435,12 +517,12 @@ where
}
// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T`.
// pointer to `T` allocated by `A`.
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
where
A: Allocator,
{
const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
const FOREIGN_ALIGN: usize = <Box<T, A> as ForeignOwnable>::FOREIGN_ALIGN;
type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>;
+16 -6
View File
@@ -175,7 +175,7 @@ where
/// Returns the number of elements that can be stored within the vector without allocating
/// additional memory.
pub fn capacity(&self) -> usize {
pub const fn capacity(&self) -> usize {
if const { Self::is_zst() } {
usize::MAX
} else {
@@ -185,7 +185,7 @@ where
/// Returns the number of elements stored within the vector.
#[inline]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.len
}
@@ -196,7 +196,7 @@ where
/// - `additional` must be less than or equal to `self.capacity - self.len`.
/// - All elements within the interval [`self.len`,`self.len + additional`) must be initialized.
#[inline]
pub unsafe fn inc_len(&mut self, additional: usize) {
pub const unsafe fn inc_len(&mut self, additional: usize) {
// Guaranteed by the type invariant to never underflow.
debug_assert!(additional <= self.capacity() - self.len());
// INVARIANT: By the safety requirements of this method this represents the exact number of
@@ -224,6 +224,16 @@ where
}
/// Returns a slice of the entire vector.
///
/// # Examples
///
/// ```
/// let mut v = KVec::new();
/// v.push(1, GFP_KERNEL)?;
/// v.push(2, GFP_KERNEL)?;
/// assert_eq!(v.as_slice(), &[1, 2]);
/// # Ok::<(), Error>(())
/// ```
#[inline]
pub fn as_slice(&self) -> &[T] {
self
@@ -245,7 +255,7 @@ where
/// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw
/// pointer.
#[inline]
pub fn as_ptr(&self) -> *const T {
pub const fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
@@ -261,7 +271,7 @@ where
/// assert!(!v.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
@@ -1294,7 +1304,7 @@ impl<'vec, T> Drop for DrainAll<'vec, T> {
}
}
#[macros::kunit_tests(rust_kvec_kunit)]
#[macros::kunit_tests(rust_kvec)]
mod tests {
use super::*;
use crate::prelude::*;
+1 -1
View File
@@ -80,7 +80,7 @@ impl<T> ArrayLayout<T> {
/// # Safety
///
/// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
pub unsafe fn new_unchecked(len: usize) -> Self {
pub const unsafe fn new_unchecked(len: usize) -> Self {
// INVARIANT: By the safety requirements of this function
// `len * size_of::<T>() <= isize::MAX`.
Self {