2022-02-11 20:25:34 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
|
|
//! Allocator support.
|
|
|
|
|
|
2024-03-27 22:35:58 -03:00
|
|
|
use super::{flags::*, Flags};
|
2022-02-11 20:25:34 +01:00
|
|
|
use core::alloc::{GlobalAlloc, Layout};
|
|
|
|
|
use core::ptr;
|
|
|
|
|
|
|
|
|
|
struct KernelAllocator;
|
|
|
|
|
|
2023-07-29 18:29:02 -07:00
|
|
|
/// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment.
|
|
|
|
|
///
|
|
|
|
|
/// # Safety
|
|
|
|
|
///
|
|
|
|
|
/// - `ptr` can be either null or a pointer which has been allocated by this allocator.
|
|
|
|
|
/// - `new_layout` must have a non-zero size.
|
2024-03-27 22:35:59 -03:00
|
|
|
pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *mut u8 {
|
2023-07-29 18:29:02 -07:00
|
|
|
// Customized layouts from `Layout::from_size_align()` can have size < align, so pad first.
|
|
|
|
|
let layout = new_layout.pad_to_align();
|
|
|
|
|
|
slab, rust: extend kmalloc() alignment guarantees to remove Rust padding
Slab allocators have been guaranteeing natural alignment for
power-of-two sizes since commit 59bb47985c1d ("mm, sl[aou]b: guarantee
natural alignment for kmalloc(power-of-two)"), while any other sizes are
guaranteed to be aligned only to ARCH_KMALLOC_MINALIGN bytes (although
in practice are aligned more than that in non-debug scenarios).
Rust's allocator API specifies size and alignment per allocation, which
have to satisfy the following rules, per Alice Ryhl [1]:
1. The alignment is a power of two.
2. The size is non-zero.
3. When you round up the size to the next multiple of the alignment,
then it must not overflow the signed type isize / ssize_t.
In order to map this to kmalloc()'s guarantees, some requested
allocation sizes have to be padded to the next power-of-two size [2].
For example, an allocation of size 96 and alignment of 32 will be padded
to an allocation of size 128, because the existing kmalloc-96 bucket
doesn't guarantee alignent above ARCH_KMALLOC_MINALIGN. Without slab
debugging active, the layout of the kmalloc-96 slabs however naturally
align the objects to 32 bytes, so extending the size to 128 bytes is
wasteful.
To improve the situation we can extend the kmalloc() alignment
guarantees in a way that
1) doesn't change the current slab layout (and thus does not increase
internal fragmentation) when slab debugging is not active
2) reduces waste in the Rust allocator use case
3) is a superset of the current guarantee for power-of-two sizes.
The extended guarantee is that alignment is at least the largest
power-of-two divisor of the requested size. For power-of-two sizes the
largest divisor is the size itself, but let's keep this case documented
separately for clarity.
For current kmalloc size buckets, it means kmalloc-96 will guarantee
alignment of 32 bytes and kmalloc-196 will guarantee 64 bytes.
This covers the rules 1 and 2 above of Rust's API as long as the size is
a multiple of the alignment. The Rust layer should now only need to
round up the size to the next multiple if it isn't, while enforcing the
rule 3.
Implementation-wise, this changes the alignment calculation in
create_boot_cache(). While at it also do the calulation only for caches
with the SLAB_KMALLOC flag, because the function is also used to create
the initial kmem_cache and kmem_cache_node caches, where no alignment
guarantee is necessary.
In the Rust allocator's krealloc_aligned(), remove the code that padded
sizes to the next power of two (suggested by Alice Ryhl) as it's no
longer necessary with the new guarantees.
Reported-by: Alice Ryhl <aliceryhl@google.com>
Reported-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/all/CAH5fLggjrbdUuT-H-5vbQfMazjRDpp2%2Bk3%3DYhPyS17ezEqxwcw@mail.gmail.com/ [1]
Link: https://lore.kernel.org/all/CAH5fLghsZRemYUwVvhk77o6y1foqnCeDzW4WZv6ScEWna2+_jw@mail.gmail.com/ [2]
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
2024-07-03 09:25:21 +02:00
|
|
|
// Note that `layout.size()` (after padding) is guaranteed to be a multiple of `layout.align()`
|
|
|
|
|
// which together with the slab guarantees means the `krealloc` will return a properly aligned
|
|
|
|
|
// object (see comments in `kmalloc()` for more information).
|
|
|
|
|
let size = layout.size();
|
2023-07-29 18:29:02 -07:00
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
|
// - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the
|
|
|
|
|
// function safety requirement.
|
slab, rust: extend kmalloc() alignment guarantees to remove Rust padding
Slab allocators have been guaranteeing natural alignment for
power-of-two sizes since commit 59bb47985c1d ("mm, sl[aou]b: guarantee
natural alignment for kmalloc(power-of-two)"), while any other sizes are
guaranteed to be aligned only to ARCH_KMALLOC_MINALIGN bytes (although
in practice are aligned more than that in non-debug scenarios).
Rust's allocator API specifies size and alignment per allocation, which
have to satisfy the following rules, per Alice Ryhl [1]:
1. The alignment is a power of two.
2. The size is non-zero.
3. When you round up the size to the next multiple of the alignment,
then it must not overflow the signed type isize / ssize_t.
In order to map this to kmalloc()'s guarantees, some requested
allocation sizes have to be padded to the next power-of-two size [2].
For example, an allocation of size 96 and alignment of 32 will be padded
to an allocation of size 128, because the existing kmalloc-96 bucket
doesn't guarantee alignent above ARCH_KMALLOC_MINALIGN. Without slab
debugging active, the layout of the kmalloc-96 slabs however naturally
align the objects to 32 bytes, so extending the size to 128 bytes is
wasteful.
To improve the situation we can extend the kmalloc() alignment
guarantees in a way that
1) doesn't change the current slab layout (and thus does not increase
internal fragmentation) when slab debugging is not active
2) reduces waste in the Rust allocator use case
3) is a superset of the current guarantee for power-of-two sizes.
The extended guarantee is that alignment is at least the largest
power-of-two divisor of the requested size. For power-of-two sizes the
largest divisor is the size itself, but let's keep this case documented
separately for clarity.
For current kmalloc size buckets, it means kmalloc-96 will guarantee
alignment of 32 bytes and kmalloc-196 will guarantee 64 bytes.
This covers the rules 1 and 2 above of Rust's API as long as the size is
a multiple of the alignment. The Rust layer should now only need to
round up the size to the next multiple if it isn't, while enforcing the
rule 3.
Implementation-wise, this changes the alignment calculation in
create_boot_cache(). While at it also do the calulation only for caches
with the SLAB_KMALLOC flag, because the function is also used to create
the initial kmem_cache and kmem_cache_node caches, where no alignment
guarantee is necessary.
In the Rust allocator's krealloc_aligned(), remove the code that padded
sizes to the next power of two (suggested by Alice Ryhl) as it's no
longer necessary with the new guarantees.
Reported-by: Alice Ryhl <aliceryhl@google.com>
Reported-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/all/CAH5fLggjrbdUuT-H-5vbQfMazjRDpp2%2Bk3%3DYhPyS17ezEqxwcw@mail.gmail.com/ [1]
Link: https://lore.kernel.org/all/CAH5fLghsZRemYUwVvhk77o6y1foqnCeDzW4WZv6ScEWna2+_jw@mail.gmail.com/ [2]
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
2024-07-03 09:25:21 +02:00
|
|
|
// - `size` is greater than 0 since it's from `layout.size()` (which cannot be zero according
|
|
|
|
|
// to the function safety requirement)
|
2024-03-27 22:35:58 -03:00
|
|
|
unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 }
|
2023-07-29 18:29:02 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 22:43:32 +02:00
|
|
|
// SAFETY: TODO.
|
2022-02-11 20:25:34 +01:00
|
|
|
unsafe impl GlobalAlloc for KernelAllocator {
|
|
|
|
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
2023-07-29 18:29:03 -07:00
|
|
|
// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
|
|
|
|
|
// requirement.
|
2024-03-27 22:35:58 -03:00
|
|
|
unsafe { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL) }
|
2022-02-11 20:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
2024-09-04 22:43:32 +02:00
|
|
|
// SAFETY: TODO.
|
2022-02-11 20:25:34 +01:00
|
|
|
unsafe {
|
|
|
|
|
bindings::kfree(ptr as *const core::ffi::c_void);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-29 18:29:04 -07:00
|
|
|
|
|
|
|
|
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
|
|
|
|
// SAFETY:
|
|
|
|
|
// - `new_size`, when rounded up to the nearest multiple of `layout.align()`, will not
|
|
|
|
|
// overflow `isize` by the function safety requirement.
|
|
|
|
|
// - `layout.align()` is a proper alignment (i.e. not zero and must be a power of two).
|
|
|
|
|
let layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
|
|
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
|
// - `ptr` is either null or a pointer allocated by this allocator by the function safety
|
|
|
|
|
// requirement.
|
|
|
|
|
// - the size of `layout` is not zero because `new_size` is not zero by the function safety
|
|
|
|
|
// requirement.
|
2024-03-27 22:35:58 -03:00
|
|
|
unsafe { krealloc_aligned(ptr, layout, GFP_KERNEL) }
|
2023-07-29 18:29:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
|
|
|
|
// SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
|
|
|
|
|
// requirement.
|
2024-03-27 22:35:58 -03:00
|
|
|
unsafe { krealloc_aligned(ptr::null_mut(), layout, GFP_KERNEL | __GFP_ZERO) }
|
2023-07-29 18:29:04 -07:00
|
|
|
}
|
2022-02-11 20:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[global_allocator]
|
|
|
|
|
static ALLOCATOR: KernelAllocator = KernelAllocator;
|
|
|
|
|
|
rust: upgrade to Rust 1.71.1
This is the second upgrade to the Rust toolchain, from 1.68.2 to 1.71.1
(i.e. the latest).
See the upgrade policy [1] and the comments on the first upgrade in
commit 3ed03f4da06e ("rust: upgrade to Rust 1.68.2").
# Unstable features
No unstable features (that we use) were stabilized.
Therefore, the only unstable feature allowed to be used outside
the `kernel` crate is still `new_uninit`, though other code to be
upstreamed may increase the list.
Please see [2] for details.
# Required changes
For the upgrade, this patch requires the following changes:
- Removal of the `__rust_*` allocator functions, together with
the addition of the `__rust_no_alloc_shim_is_unstable` static.
See [3] for details.
- Some more compiler builtins added due to `<f{32,64}>::midpoint()`
that got added in Rust 1.71 [4].
# `alloc` upgrade and reviewing
The vast majority of changes are due to our `alloc` fork being upgraded
at once.
There are two kinds of changes to be aware of: the ones coming from
upstream, which we should follow as closely as possible, and the updates
needed in our added fallible APIs to keep them matching the newer
infallible APIs coming from upstream.
Instead of taking a look at the diff of this patch, an alternative
approach is reviewing a diff of the changes between upstream `alloc` and
the kernel's. This allows to easily inspect the kernel additions only,
especially to check if the fallible methods we already have still match
the infallible ones in the new version coming from upstream.
Another approach is reviewing the changes introduced in the additions in
the kernel fork between the two versions. This is useful to spot
potentially unintended changes to our additions.
To apply these approaches, one may follow steps similar to the following
to generate a pair of patches that show the differences between upstream
Rust and the kernel (for the subset of `alloc` we use) before and after
applying this patch:
# Get the difference with respect to the old version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > old.patch
git -C linux restore rust/alloc
# Apply this patch.
git -C linux am rust-upgrade.patch
# Get the difference with respect to the new version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > new.patch
git -C linux restore rust/alloc
Now one may check the `new.patch` to take a look at the additions (first
approach) or at the difference between those two patches (second
approach). For the latter, a side-by-side tool is recommended.
Link: https://rust-for-linux.com/rust-version-policy [1]
Link: https://github.com/Rust-for-Linux/linux/issues/2 [2]
Link: https://github.com/rust-lang/rust/pull/86844 [3]
Link: https://github.com/rust-lang/rust/pull/92048 [4]
Closes: https://github.com/Rust-for-Linux/linux/issues/68
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Link: https://lore.kernel.org/r/20230729220317.416771-1-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2023-07-30 00:03:16 +02:00
|
|
|
// See <https://github.com/rust-lang/rust/pull/86844>.
|
2022-02-11 20:25:34 +01:00
|
|
|
#[no_mangle]
|
rust: upgrade to Rust 1.71.1
This is the second upgrade to the Rust toolchain, from 1.68.2 to 1.71.1
(i.e. the latest).
See the upgrade policy [1] and the comments on the first upgrade in
commit 3ed03f4da06e ("rust: upgrade to Rust 1.68.2").
# Unstable features
No unstable features (that we use) were stabilized.
Therefore, the only unstable feature allowed to be used outside
the `kernel` crate is still `new_uninit`, though other code to be
upstreamed may increase the list.
Please see [2] for details.
# Required changes
For the upgrade, this patch requires the following changes:
- Removal of the `__rust_*` allocator functions, together with
the addition of the `__rust_no_alloc_shim_is_unstable` static.
See [3] for details.
- Some more compiler builtins added due to `<f{32,64}>::midpoint()`
that got added in Rust 1.71 [4].
# `alloc` upgrade and reviewing
The vast majority of changes are due to our `alloc` fork being upgraded
at once.
There are two kinds of changes to be aware of: the ones coming from
upstream, which we should follow as closely as possible, and the updates
needed in our added fallible APIs to keep them matching the newer
infallible APIs coming from upstream.
Instead of taking a look at the diff of this patch, an alternative
approach is reviewing a diff of the changes between upstream `alloc` and
the kernel's. This allows to easily inspect the kernel additions only,
especially to check if the fallible methods we already have still match
the infallible ones in the new version coming from upstream.
Another approach is reviewing the changes introduced in the additions in
the kernel fork between the two versions. This is useful to spot
potentially unintended changes to our additions.
To apply these approaches, one may follow steps similar to the following
to generate a pair of patches that show the differences between upstream
Rust and the kernel (for the subset of `alloc` we use) before and after
applying this patch:
# Get the difference with respect to the old version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > old.patch
git -C linux restore rust/alloc
# Apply this patch.
git -C linux am rust-upgrade.patch
# Get the difference with respect to the new version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > new.patch
git -C linux restore rust/alloc
Now one may check the `new.patch` to take a look at the additions (first
approach) or at the difference between those two patches (second
approach). For the latter, a side-by-side tool is recommended.
Link: https://rust-for-linux.com/rust-version-policy [1]
Link: https://github.com/Rust-for-Linux/linux/issues/2 [2]
Link: https://github.com/rust-lang/rust/pull/86844 [3]
Link: https://github.com/rust-lang/rust/pull/92048 [4]
Closes: https://github.com/Rust-for-Linux/linux/issues/68
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Link: https://lore.kernel.org/r/20230729220317.416771-1-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2023-07-30 00:03:16 +02:00
|
|
|
static __rust_no_alloc_shim_is_unstable: u8 = 0;
|