2024-03-27 22:35:54 -03:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
2024-10-04 17:41:31 +02:00
|
|
|
//! Implementation of the kernel's memory allocation infrastructure.
|
2024-03-27 22:35:54 -03:00
|
|
|
|
2024-10-04 17:41:11 +02:00
|
|
|
#[cfg(not(any(test, testlib)))]
|
2024-10-04 17:41:09 +02:00
|
|
|
pub mod allocator;
|
2024-10-04 17:41:15 +02:00
|
|
|
pub mod kbox;
|
rust: alloc: implement kernel `Vec` type
`Vec` provides a contiguous growable array type with contents allocated
with the kernel's allocators (e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`).
In contrast to Rust's stdlib `Vec` type, the kernel `Vec` type considers
the kernel's GFP flags for all appropriate functions, always reports
allocation failures through `Result<_, AllocError>` and remains
independent from unstable features.
[ This patch starts using a new unstable feature, `inline_const`, but
it was stabilized in Rust 1.79.0, i.e. the next version after the
minimum one, thus it will not be an issue. - Miguel ]
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20241004154149.93856-17-dakr@kernel.org
[ Cleaned `rustdoc` unescaped backtick warning, added a couple more
backticks elsewhere, fixed typos, sorted `feature`s, rewrapped
documentation lines. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-10-04 17:41:20 +02:00
|
|
|
pub mod kvec;
|
2024-10-04 17:41:19 +02:00
|
|
|
pub mod layout;
|
2024-03-27 22:35:58 -03:00
|
|
|
|
2024-10-04 17:41:11 +02:00
|
|
|
#[cfg(any(test, testlib))]
|
|
|
|
pub mod allocator_test;
|
|
|
|
|
|
|
|
#[cfg(any(test, testlib))]
|
|
|
|
pub use self::allocator_test as allocator;
|
|
|
|
|
2024-10-04 17:41:15 +02:00
|
|
|
pub use self::kbox::Box;
|
|
|
|
pub use self::kbox::KBox;
|
|
|
|
pub use self::kbox::KVBox;
|
|
|
|
pub use self::kbox::VBox;
|
|
|
|
|
2024-10-04 17:41:21 +02:00
|
|
|
pub use self::kvec::IntoIter;
|
rust: alloc: implement kernel `Vec` type
`Vec` provides a contiguous growable array type with contents allocated
with the kernel's allocators (e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`).
In contrast to Rust's stdlib `Vec` type, the kernel `Vec` type considers
the kernel's GFP flags for all appropriate functions, always reports
allocation failures through `Result<_, AllocError>` and remains
independent from unstable features.
[ This patch starts using a new unstable feature, `inline_const`, but
it was stabilized in Rust 1.79.0, i.e. the next version after the
minimum one, thus it will not be an issue. - Miguel ]
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20241004154149.93856-17-dakr@kernel.org
[ Cleaned `rustdoc` unescaped backtick warning, added a couple more
backticks elsewhere, fixed typos, sorted `feature`s, rewrapped
documentation lines. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-10-04 17:41:20 +02:00
|
|
|
pub use self::kvec::KVVec;
|
|
|
|
pub use self::kvec::KVec;
|
|
|
|
pub use self::kvec::VVec;
|
|
|
|
pub use self::kvec::Vec;
|
|
|
|
|
2024-03-27 22:36:03 -03:00
|
|
|
/// Indicates an allocation error.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct AllocError;
|
2024-10-04 17:41:05 +02:00
|
|
|
use core::{alloc::Layout, ptr::NonNull};
|
2024-03-27 22:36:03 -03:00
|
|
|
|
2024-03-27 22:35:58 -03:00
|
|
|
/// Flags to be used when allocating memory.
|
|
|
|
///
|
|
|
|
/// They can be combined with the operators `|`, `&`, and `!`.
|
|
|
|
///
|
|
|
|
/// Values can be used from the [`flags`] module.
|
2024-10-04 17:41:28 +02:00
|
|
|
#[derive(Clone, Copy, PartialEq)]
|
2024-03-27 22:35:58 -03:00
|
|
|
pub struct Flags(u32);
|
|
|
|
|
rust: add abstraction for `struct page`
Adds a new struct called `Page` that wraps a pointer to `struct page`.
This struct is assumed to hold ownership over the page, so that Rust
code can allocate and manage pages directly.
The page type has various methods for reading and writing into the page.
These methods will temporarily map the page to allow the operation. All
of these methods use a helper that takes an offset and length, performs
bounds checks, and returns a pointer to the given offset in the page.
This patch only adds support for pages of order zero, as that is all
Rust Binder needs. However, it is written to make it easy to add support
for higher-order pages in the future. To do that, you would add a const
generic parameter to `Page` that specifies the order. Most of the
methods do not need to be adjusted, as the logic for dealing with
mapping multiple pages at once can be isolated to just the
`with_pointer_into_page` method.
Rust Binder needs to manage pages directly as that is how transactions
are delivered: Each process has an mmap'd region for incoming
transactions. When an incoming transaction arrives, the Binder driver
will choose a region in the mmap, allocate and map the relevant pages
manually, and copy the incoming transaction directly into the page. This
architecture allows the driver to copy transactions directly from the
address space of one process to another, without an intermediate copy
to a kernel buffer.
This code is based on Wedson's page abstractions from the old rust
branch, but it has been modified by Alice by removing the incomplete
support for higher-order pages, by introducing the `with_*` helpers
to consolidate the bounds checking logic into a single place, and
various other changes.
Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240528-alice-mm-v7-4-78222c31b8f4@google.com
[ Fixed typos and added a few intra-doc links. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-05-28 14:58:05 +00:00
|
|
|
impl Flags {
|
|
|
|
/// Get the raw representation of this flag.
|
|
|
|
pub(crate) fn as_raw(self) -> u32 {
|
|
|
|
self.0
|
|
|
|
}
|
2024-10-04 17:41:28 +02:00
|
|
|
|
|
|
|
/// Check whether `flags` is contained in `self`.
|
|
|
|
pub fn contains(self, flags: Flags) -> bool {
|
|
|
|
(self & flags) == flags
|
|
|
|
}
|
rust: add abstraction for `struct page`
Adds a new struct called `Page` that wraps a pointer to `struct page`.
This struct is assumed to hold ownership over the page, so that Rust
code can allocate and manage pages directly.
The page type has various methods for reading and writing into the page.
These methods will temporarily map the page to allow the operation. All
of these methods use a helper that takes an offset and length, performs
bounds checks, and returns a pointer to the given offset in the page.
This patch only adds support for pages of order zero, as that is all
Rust Binder needs. However, it is written to make it easy to add support
for higher-order pages in the future. To do that, you would add a const
generic parameter to `Page` that specifies the order. Most of the
methods do not need to be adjusted, as the logic for dealing with
mapping multiple pages at once can be isolated to just the
`with_pointer_into_page` method.
Rust Binder needs to manage pages directly as that is how transactions
are delivered: Each process has an mmap'd region for incoming
transactions. When an incoming transaction arrives, the Binder driver
will choose a region in the mmap, allocate and map the relevant pages
manually, and copy the incoming transaction directly into the page. This
architecture allows the driver to copy transactions directly from the
address space of one process to another, without an intermediate copy
to a kernel buffer.
This code is based on Wedson's page abstractions from the old rust
branch, but it has been modified by Alice by removing the incomplete
support for higher-order pages, by introducing the `with_*` helpers
to consolidate the bounds checking logic into a single place, and
various other changes.
Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240528-alice-mm-v7-4-78222c31b8f4@google.com
[ Fixed typos and added a few intra-doc links. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-05-28 14:58:05 +00:00
|
|
|
}
|
|
|
|
|
2024-03-27 22:35:58 -03:00
|
|
|
impl core::ops::BitOr for Flags {
|
|
|
|
type Output = Self;
|
|
|
|
fn bitor(self, rhs: Self) -> Self::Output {
|
|
|
|
Self(self.0 | rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::ops::BitAnd for Flags {
|
|
|
|
type Output = Self;
|
|
|
|
fn bitand(self, rhs: Self) -> Self::Output {
|
|
|
|
Self(self.0 & rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::ops::Not for Flags {
|
|
|
|
type Output = Self;
|
|
|
|
fn not(self) -> Self::Output {
|
|
|
|
Self(!self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allocation flags.
|
|
|
|
///
|
|
|
|
/// These are meant to be used in functions that can allocate memory.
|
|
|
|
pub mod flags {
|
|
|
|
use super::Flags;
|
|
|
|
|
|
|
|
/// Zeroes out the allocated memory.
|
|
|
|
///
|
|
|
|
/// This is normally or'd with other flags.
|
|
|
|
pub const __GFP_ZERO: Flags = Flags(bindings::__GFP_ZERO);
|
|
|
|
|
2024-06-07 08:23:41 +00:00
|
|
|
/// Allow the allocation to be in high memory.
|
|
|
|
///
|
|
|
|
/// Allocations in high memory may not be mapped into the kernel's address space, so this can't
|
|
|
|
/// be used with `kmalloc` and other similar methods.
|
|
|
|
///
|
|
|
|
/// This is normally or'd with other flags.
|
|
|
|
pub const __GFP_HIGHMEM: Flags = Flags(bindings::__GFP_HIGHMEM);
|
|
|
|
|
2024-03-27 22:35:58 -03:00
|
|
|
/// Users can not sleep and need the allocation to succeed.
|
|
|
|
///
|
|
|
|
/// A lower watermark is applied to allow access to "atomic reserves". The current
|
|
|
|
/// implementation doesn't support NMI and few other strict non-preemptive contexts (e.g.
|
|
|
|
/// raw_spin_lock). The same applies to [`GFP_NOWAIT`].
|
|
|
|
pub const GFP_ATOMIC: Flags = Flags(bindings::GFP_ATOMIC);
|
|
|
|
|
|
|
|
/// Typical for kernel-internal allocations. The caller requires ZONE_NORMAL or a lower zone
|
|
|
|
/// for direct access but can direct reclaim.
|
|
|
|
pub const GFP_KERNEL: Flags = Flags(bindings::GFP_KERNEL);
|
|
|
|
|
|
|
|
/// The same as [`GFP_KERNEL`], except the allocation is accounted to kmemcg.
|
|
|
|
pub const GFP_KERNEL_ACCOUNT: Flags = Flags(bindings::GFP_KERNEL_ACCOUNT);
|
|
|
|
|
2024-05-29 08:34:52 +00:00
|
|
|
/// For kernel allocations that should not stall for direct reclaim, start physical IO or
|
2024-03-27 22:35:58 -03:00
|
|
|
/// use any filesystem callback. It is very likely to fail to allocate memory, even for very
|
|
|
|
/// small allocations.
|
|
|
|
pub const GFP_NOWAIT: Flags = Flags(bindings::GFP_NOWAIT);
|
2024-10-04 17:41:14 +02:00
|
|
|
|
|
|
|
/// Suppresses allocation failure reports.
|
|
|
|
///
|
|
|
|
/// This is normally or'd with other flags.
|
|
|
|
pub const __GFP_NOWARN: Flags = Flags(bindings::__GFP_NOWARN);
|
2024-03-27 22:35:58 -03:00
|
|
|
}
|
2024-10-04 17:41:05 +02:00
|
|
|
|
|
|
|
/// The kernel's [`Allocator`] trait.
|
|
|
|
///
|
|
|
|
/// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffers described
|
|
|
|
/// via [`Layout`].
|
|
|
|
///
|
|
|
|
/// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
|
|
|
|
/// an object instance.
|
|
|
|
///
|
|
|
|
/// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design
|
|
|
|
/// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind
|
|
|
|
/// of `self` parameter.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// - A memory allocation returned from an allocator must remain valid until it is explicitly freed.
|
|
|
|
///
|
|
|
|
/// - Any pointer to a valid memory allocation must be valid to be passed to any other [`Allocator`]
|
|
|
|
/// function of the same type.
|
|
|
|
///
|
|
|
|
/// - Implementers must ensure that all trait functions abide by the guarantees documented in the
|
|
|
|
/// `# Guarantees` sections.
|
|
|
|
pub unsafe trait Allocator {
|
|
|
|
/// Allocate memory based on `layout` and `flags`.
|
|
|
|
///
|
|
|
|
/// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
|
|
|
|
/// constraints (i.e. minimum size and alignment as specified by `layout`).
|
|
|
|
///
|
|
|
|
/// This function is equivalent to `realloc` when called with `None`.
|
|
|
|
///
|
|
|
|
/// # Guarantees
|
|
|
|
///
|
|
|
|
/// When the return value is `Ok(ptr)`, then `ptr` is
|
|
|
|
/// - valid for reads and writes for `layout.size()` bytes, until it is passed to
|
|
|
|
/// [`Allocator::free`] or [`Allocator::realloc`],
|
|
|
|
/// - aligned to `layout.align()`,
|
|
|
|
///
|
|
|
|
/// Additionally, `Flags` are honored as documented in
|
|
|
|
/// <https://docs.kernel.org/core-api/mm-api.html#mm-api-gfp-flags>.
|
|
|
|
fn alloc(layout: Layout, flags: Flags) -> Result<NonNull<[u8]>, AllocError> {
|
|
|
|
// SAFETY: Passing `None` to `realloc` is valid by its safety requirements and asks for a
|
|
|
|
// new memory allocation.
|
|
|
|
unsafe { Self::realloc(None, layout, Layout::new::<()>(), flags) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Re-allocate an existing memory allocation to satisfy the requested `layout`.
|
|
|
|
///
|
|
|
|
/// If the requested size is zero, `realloc` behaves equivalent to `free`.
|
|
|
|
///
|
|
|
|
/// If the requested size is larger than the size of the existing allocation, a successful call
|
|
|
|
/// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
|
|
|
|
/// may also be larger.
|
|
|
|
///
|
|
|
|
/// If the requested size is smaller than the size of the existing allocation, `realloc` may or
|
|
|
|
/// may not shrink the buffer; this is implementation specific to the allocator.
|
|
|
|
///
|
|
|
|
/// On allocation failure, the existing buffer, if any, remains valid.
|
|
|
|
///
|
|
|
|
/// The buffer is represented as `NonNull<[u8]>`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// - If `ptr == Some(p)`, then `p` must point to an existing and valid memory allocation
|
|
|
|
/// created by this [`Allocator`]; if `old_layout` is zero-sized `p` does not need to be a
|
|
|
|
/// pointer returned by this [`Allocator`].
|
|
|
|
/// - `ptr` is allowed to be `None`; in this case a new memory allocation is created and
|
|
|
|
/// `old_layout` is ignored.
|
|
|
|
/// - `old_layout` must match the `Layout` the allocation has been created with.
|
|
|
|
///
|
|
|
|
/// # Guarantees
|
|
|
|
///
|
|
|
|
/// This function has the same guarantees as [`Allocator::alloc`]. When `ptr == Some(p)`, then
|
|
|
|
/// it additionally guarantees that:
|
|
|
|
/// - the contents of the memory pointed to by `p` are preserved up to the lesser of the new
|
|
|
|
/// and old size, i.e. `ret_ptr[0..min(layout.size(), old_layout.size())] ==
|
|
|
|
/// p[0..min(layout.size(), old_layout.size())]`.
|
|
|
|
/// - when the return value is `Err(AllocError)`, then `ptr` is still valid.
|
|
|
|
unsafe fn realloc(
|
|
|
|
ptr: Option<NonNull<u8>>,
|
|
|
|
layout: Layout,
|
|
|
|
old_layout: Layout,
|
|
|
|
flags: Flags,
|
|
|
|
) -> Result<NonNull<[u8]>, AllocError>;
|
|
|
|
|
|
|
|
/// Free an existing memory allocation.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// - `ptr` must point to an existing and valid memory allocation created by this [`Allocator`];
|
|
|
|
/// if `old_layout` is zero-sized `p` does not need to be a pointer returned by this
|
|
|
|
/// [`Allocator`].
|
|
|
|
/// - `layout` must match the `Layout` the allocation has been created with.
|
|
|
|
/// - The memory allocation at `ptr` must never again be read from or written to.
|
|
|
|
unsafe fn free(ptr: NonNull<u8>, layout: Layout) {
|
|
|
|
// SAFETY: The caller guarantees that `ptr` points at a valid allocation created by this
|
|
|
|
// allocator. We are passing a `Layout` with the smallest possible alignment, so it is
|
|
|
|
// smaller than or equal to the alignment previously used with this allocation.
|
|
|
|
let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), layout, Flags(0)) };
|
|
|
|
}
|
|
|
|
}
|
2024-10-04 17:41:08 +02:00
|
|
|
|
|
|
|
/// Returns a properly aligned dangling pointer from the given `layout`.
|
|
|
|
pub(crate) fn dangling_from_layout(layout: Layout) -> NonNull<u8> {
|
|
|
|
let ptr = layout.align() as *mut u8;
|
|
|
|
|
|
|
|
// SAFETY: `layout.align()` (and hence `ptr`) is guaranteed to be non-zero.
|
|
|
|
unsafe { NonNull::new_unchecked(ptr) }
|
|
|
|
}
|