From c3bba9fb3bc46c3ae513b375e45a6923afde3801 Mon Sep 17 00:00:00 2001 From: Ben Gooding Date: Sun, 7 May 2023 17:27:39 +0100 Subject: [PATCH 1/5] rust: lock: Add intra-doc links to the Backend trait Add missing intra-doc links to the Backend trait to make navigating the documentation easier. Suggested-by: Benno Lossin Link: https://lore.kernel.org/rust-for-linux/94625fe6-b87a-a8f0-5b2a-a8152d5f7436@proton.me/ Link: https://github.com/Rust-for-Linux/linux/issues/1001 Signed-off-by: Ben Gooding Link: https://lore.kernel.org/r/20230509202314.8248-1-ben.gooding.dev@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync/lock.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index a2216325632df..70a785f047546 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -72,8 +72,8 @@ pub unsafe trait Backend { /// A mutual exclusion primitive. /// -/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock backend -/// specified as the generic parameter `B`. +/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock +/// [`Backend`] specified as the generic parameter `B`. #[pin_data] pub struct Lock { /// The kernel lock object. @@ -126,7 +126,7 @@ impl Lock { /// A lock guard. /// -/// Allows mutual exclusion primitives that implement the `Backend` trait to automatically unlock +/// Allows mutual exclusion primitives that implement the [`Backend`] trait to automatically unlock /// when a guard goes out of scope. It also provides a safe and convenient way to access the data /// protected by the lock. #[must_use = "the lock unlocks immediately when the guard is unused"] From 341faf2b45ba266d52c1ca886c4ffca52d666786 Mon Sep 17 00:00:00 2001 From: Ariel Miculas Date: Wed, 26 Apr 2023 23:49:23 +0300 Subject: [PATCH 2/5] rust: helpers: sort includes alphabetically in rust/helpers.c Sort the #include directives of rust/helpers.c alphabetically and add a comment specifying this. The reason for this is to improve readability and to be consistent with the other files with a similar approach within 'rust/'. Suggested-by: Miguel Ojeda Link: https://github.com/Rust-for-Linux/linux/issues/1003 Signed-off-by: Ariel Miculas Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo Link: https://lore.kernel.org/r/20230426204923.16195-1-amiculas@cisco.com Signed-off-by: Miguel Ojeda --- rust/helpers.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust/helpers.c b/rust/helpers.c index bb594da56137e..f946f2ea640a3 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -16,16 +16,18 @@ * * All symbols are exported as GPL-only to guarantee no GPL-only feature is * accidentally exposed. + * + * Sorted alphabetically. */ #include #include #include #include -#include #include -#include +#include #include +#include #include __noreturn void rust_helper_BUG(void) From 10a6032595f458862c24a97a06d3a0da6b1186c8 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Sat, 29 Jul 2023 18:29:02 -0700 Subject: [PATCH 3/5] rust: allocator: Prevent mis-aligned allocation Currently the rust allocator simply passes the size of the type Layout to krealloc(), and in theory the alignment requirement from the type Layout may be larger than the guarantee provided by SLAB, which means the allocated object is mis-aligned. Fix this by adjusting the allocation size to the nearest power of two, which SLAB always guarantees a size-aligned allocation. And because Rust guarantees that the original size must be a multiple of alignment and the alignment must be a power of two, then the alignment requirement is satisfied. Suggested-by: Vlastimil Babka Co-developed-by: "Andreas Hindborg (Samsung)" Signed-off-by: "Andreas Hindborg (Samsung)" Signed-off-by: Boqun Feng Cc: stable@vger.kernel.org # v6.1+ Acked-by: Vlastimil Babka Link: https://lore.kernel.org/r/20230730012905.643822-2-boqun.feng@gmail.com [ Applied rewording of comment as discussed in the mailing list. ] Signed-off-by: Miguel Ojeda --- rust/bindings/bindings_helper.h | 1 + rust/kernel/allocator.rs | 74 ++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 3e601ce2548d4..058954961bfc0 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -13,5 +13,6 @@ #include /* `bindgen` gets confused at certain things. */ +const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN; const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL; const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO; diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs index 397a3dd57a9b1..9363b527be664 100644 --- a/rust/kernel/allocator.rs +++ b/rust/kernel/allocator.rs @@ -9,6 +9,36 @@ use crate::bindings; struct KernelAllocator; +/// 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. +unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gfp_t) -> *mut u8 { + // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. + let layout = new_layout.pad_to_align(); + + let mut size = layout.size(); + + if layout.align() > bindings::BINDINGS_ARCH_SLAB_MINALIGN { + // The alignment requirement exceeds the slab guarantee, thus try to enlarge the size + // to use the "power-of-two" size/alignment guarantee (see comments in `kmalloc()` for + // more information). + // + // Note that `layout.size()` (after padding) is guaranteed to be a multiple of + // `layout.align()`, so `next_power_of_two` gives enough alignment guarantee. + size = size.next_power_of_two(); + } + + // SAFETY: + // - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the + // function safety requirement. + // - `size` is greater than 0 since it's either a `layout.size()` (which cannot be zero + // according to the function safety requirement) or a result from `next_power_of_two()`. + unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags) as *mut u8 } +} + unsafe impl GlobalAlloc for KernelAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // `krealloc()` is used instead of `kmalloc()` because the latter is @@ -30,10 +60,20 @@ static ALLOCATOR: KernelAllocator = KernelAllocator; // to extract the object file that has them from the archive. For the moment, // let's generate them ourselves instead. // +// Note: Although these are *safe* functions, they are called by the compiler +// with parameters that obey the same `GlobalAlloc` function safety +// requirements: size and align should form a valid layout, and size is +// greater than 0. +// // Note that `#[no_mangle]` implies exported too, nowadays. #[no_mangle] -fn __rust_alloc(size: usize, _align: usize) -> *mut u8 { - unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 } +fn __rust_alloc(size: usize, align: usize) -> *mut u8 { + // SAFETY: See assumption above. + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; + + // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater + // than 0. + unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } } #[no_mangle] @@ -42,23 +82,27 @@ fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) { } #[no_mangle] -fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 { - unsafe { - bindings::krealloc( - ptr as *const core::ffi::c_void, - new_size, - bindings::GFP_KERNEL, - ) as *mut u8 - } +fn __rust_realloc(ptr: *mut u8, _old_size: usize, align: usize, new_size: usize) -> *mut u8 { + // SAFETY: See assumption above. + let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, align) }; + + // SAFETY: Per assumption above, `ptr` is allocated by `__rust_*` before, and the size of + // `new_layout` is greater than 0. + unsafe { krealloc_aligned(ptr, new_layout, bindings::GFP_KERNEL) } } #[no_mangle] -fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 { +fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + // SAFETY: See assumption above. + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; + + // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater + // than 0. unsafe { - bindings::krealloc( - core::ptr::null(), - size, + krealloc_aligned( + ptr::null_mut(), + layout, bindings::GFP_KERNEL | bindings::__GFP_ZERO, - ) as *mut u8 + ) } } From 3e44cc696842154d1dd88164833c8a4c132acb65 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Sat, 29 Jul 2023 18:29:03 -0700 Subject: [PATCH 4/5] rust: allocator: Use krealloc_aligned() in KernelAllocator::alloc This fixes the potential issue that when KernelAllocator is used, the allocation may be mis-aligned due to SLAB's alignment guarantee. Signed-off-by: Boqun Feng Reviewed-by: Andreas Hindborg Link: https://lore.kernel.org/r/20230730012905.643822-3-boqun.feng@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/allocator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs index 9363b527be664..d4a3670ef4050 100644 --- a/rust/kernel/allocator.rs +++ b/rust/kernel/allocator.rs @@ -41,9 +41,9 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf unsafe impl GlobalAlloc for KernelAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - // `krealloc()` is used instead of `kmalloc()` because the latter is - // an inline function and cannot be bound to as a result. - unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 } + // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety + // requirement. + unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } } unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { From 66084c81211cf754766306b11ae31e186c02278b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= Date: Sat, 29 Jul 2023 18:29:04 -0700 Subject: [PATCH 5/5] rust: alloc: Add realloc and alloc_zeroed to the GlobalAlloc impl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While there are default impls for these methods, using the respective C api's is faster. Currently neither the existing nor these new GlobalAlloc method implementations are actually called. Instead the __rust_* function defined below the GlobalAlloc impl are used. With rustc 1.71 these functions will be gone and all allocation calls will go through the GlobalAlloc implementation. Link: https://github.com/Rust-for-Linux/linux/issues/68 Signed-off-by: Björn Roy Baron [boqun: add size adjustment for alignment requirement] Signed-off-by: Boqun Feng Reviewed-by: Andreas Hindborg Link: https://lore.kernel.org/r/20230730012905.643822-4-boqun.feng@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/allocator.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs index d4a3670ef4050..72d66c23883c1 100644 --- a/rust/kernel/allocator.rs +++ b/rust/kernel/allocator.rs @@ -51,6 +51,33 @@ unsafe impl GlobalAlloc for KernelAllocator { bindings::kfree(ptr as *const core::ffi::c_void); } } + + 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. + unsafe { krealloc_aligned(ptr, layout, bindings::GFP_KERNEL) } + } + + 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. + unsafe { + krealloc_aligned( + ptr::null_mut(), + layout, + bindings::GFP_KERNEL | bindings::__GFP_ZERO, + ) + } + } } #[global_allocator]