Hi Greg, Sasha,
Please consider this series for 6.12.y. It should apply cleanly on top of v6.12.18.
These are the patches to backport the `alloc` series for Rust, which will be useful for Rust Android Binder and others. It also means that, with this applied, we will not rely on the standard library `alloc` (and the unstable `cfg` option we used) anymore in any stable kernel that supports several Rust versions, so e.g. upstream Rust could consider removing that `cfg` if they needed.
The entire series of cherry-picks apply almost cleanly (only 2 trivial conflicts) -- to achieve that, I included the `#[expect]` support, which will make future backports that use that feature easier anyway. That series also enabled some Clippy warnings. We could reduce the series, but the end result is warning-free and Clippy is opt-in anyway. Out-of-tree code could, of course, see some warnings if they use it.
I also included a bunch of Clippy warnings cleanups for the DRM QR Code to have this series clean up to Rust 1.85.0 (the latest stable), but I could send them separately if needed.
Finally, I included the "Custom FFI" series backport, which in turn solves the arm64 + Rust 1.85.0 + `CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y` issue. It will also make future patches easier to backport, since we will have the same `ffi::` types.
I tested that the entire series builds between every commit for x86_64 `LLVM=1` with the latest stable and minimum supported Rust compiler versions. I also ran my usual stable kernel tests on the end result; that is, boot-tested in QEMU for several architectures etc. In v6.12.18 for loongarch there is an unrelated error that was not there in v6.12.17 when I did a previous test run -- reported separately.
Things could still break, so extra tests on the next -rc from users in Cc here would be welcome -- thanks!
Cheers, Miguel
Asahi Lina (1): rust: alloc: Fix `ArrayLayout` allocations
Benno Lossin (1): rust: alloc: introduce `ArrayLayout`
Danilo Krummrich (28): rust: alloc: add `Allocator` trait rust: alloc: separate `aligned_size` from `krealloc_aligned` rust: alloc: rename `KernelAllocator` to `Kmalloc` rust: alloc: implement `ReallocFunc` rust: alloc: make `allocator` module public rust: alloc: implement `Allocator` for `Kmalloc` rust: alloc: add module `allocator_test` rust: alloc: implement `Vmalloc` allocator rust: alloc: implement `KVmalloc` allocator rust: alloc: add __GFP_NOWARN to `Flags` rust: alloc: implement kernel `Box` rust: treewide: switch to our kernel `Box` type rust: alloc: remove extension of std's `Box` rust: alloc: add `Box` to prelude rust: alloc: implement kernel `Vec` type rust: alloc: implement `IntoIterator` for `Vec` rust: alloc: implement `collect` for `IntoIter` rust: treewide: switch to the kernel `Vec` type rust: alloc: remove `VecExt` extension rust: alloc: add `Vec` to prelude rust: error: use `core::alloc::LayoutError` rust: error: check for config `test` in `Error::name` rust: alloc: implement `contains` for `Flags` rust: alloc: implement `Cmalloc` in module allocator_test rust: str: test: replace `alloc::format` rust: alloc: update module comment of alloc.rs kbuild: rust: remove the `alloc` crate and `GlobalAlloc` MAINTAINERS: add entry for the Rust `alloc` module
Ethan D. Twardy (1): rust: kbuild: expand rusttest target for macros
Filipe Xavier (2): rust: error: make conversion functions public rust: error: optimize error type to use nonzero
Gary Guo (3): rust: fix size_t in bindgen prototypes of C builtins rust: map `__kernel_size_t` and friends also to usize/isize rust: use custom FFI integer types
Miguel Ojeda (17): rust: workqueue: remove unneeded ``#[allow(clippy::new_ret_no_self)]` rust: sort global Rust flags rust: types: avoid repetition in `{As,From}Bytes` impls rust: enable `clippy::undocumented_unsafe_blocks` lint rust: enable `clippy::unnecessary_safety_comment` lint rust: enable `clippy::unnecessary_safety_doc` lint rust: enable `clippy::ignored_unit_patterns` lint rust: enable `rustdoc::unescaped_backticks` lint rust: init: remove unneeded `#[allow(clippy::disallowed_names)]` rust: sync: remove unneeded `#[allow(clippy::non_send_fields_in_send_ty)]` rust: introduce `.clippy.toml` rust: replace `clippy::dbg_macro` with `disallowed_macros` rust: provide proper code documentation titles rust: enable Clippy's `check-private-items` Documentation: rust: add coding guidelines on lints rust: start using the `#[expect(...)]` attribute Documentation: rust: discuss `#[expect(...)]` in the guidelines
Thomas Böhler (7): drm/panic: avoid reimplementing Iterator::find drm/panic: remove unnecessary borrow in alignment_pattern drm/panic: prefer eliding lifetimes drm/panic: remove redundant field when assigning value drm/panic: correctly indent continuation of line in list item drm/panic: allow verbose boolean for clarity drm/panic: allow verbose version check
.clippy.toml | 9 + .gitignore | 1 + Documentation/rust/coding-guidelines.rst | 148 ++++ MAINTAINERS | 8 + Makefile | 15 +- drivers/block/rnull.rs | 4 +- drivers/gpu/drm/drm_panic_qr.rs | 23 +- mm/kasan/kasan_test_rust.rs | 3 +- rust/Makefile | 92 +-- rust/bindgen_parameters | 5 + rust/bindings/bindings_helper.h | 1 + rust/bindings/lib.rs | 6 + rust/exports.c | 1 - rust/ffi.rs | 13 + rust/helpers/helpers.c | 1 + rust/helpers/slab.c | 6 + rust/helpers/vmalloc.c | 9 + rust/kernel/alloc.rs | 150 +++- rust/kernel/alloc/allocator.rs | 208 ++++-- rust/kernel/alloc/allocator_test.rs | 95 +++ rust/kernel/alloc/box_ext.rs | 89 --- rust/kernel/alloc/kbox.rs | 456 +++++++++++ rust/kernel/alloc/kvec.rs | 913 +++++++++++++++++++++++ rust/kernel/alloc/layout.rs | 91 +++ rust/kernel/alloc/vec_ext.rs | 185 ----- rust/kernel/block/mq/operations.rs | 18 +- rust/kernel/block/mq/raw_writer.rs | 2 +- rust/kernel/block/mq/tag_set.rs | 2 +- rust/kernel/error.rs | 79 +- rust/kernel/init.rs | 127 ++-- rust/kernel/init/__internal.rs | 13 +- rust/kernel/init/macros.rs | 18 +- rust/kernel/ioctl.rs | 2 +- rust/kernel/lib.rs | 5 +- rust/kernel/list.rs | 1 + rust/kernel/list/arc_field.rs | 2 +- rust/kernel/net/phy.rs | 16 +- rust/kernel/prelude.rs | 5 +- rust/kernel/print.rs | 5 +- rust/kernel/rbtree.rs | 49 +- rust/kernel/std_vendor.rs | 12 +- rust/kernel/str.rs | 46 +- rust/kernel/sync/arc.rs | 25 +- rust/kernel/sync/arc/std_vendor.rs | 2 + rust/kernel/sync/condvar.rs | 7 +- rust/kernel/sync/lock.rs | 8 +- rust/kernel/sync/lock/mutex.rs | 4 +- rust/kernel/sync/lock/spinlock.rs | 4 +- rust/kernel/sync/locked_by.rs | 2 +- rust/kernel/task.rs | 8 +- rust/kernel/time.rs | 4 +- rust/kernel/types.rs | 140 ++-- rust/kernel/uaccess.rs | 23 +- rust/kernel/workqueue.rs | 29 +- rust/macros/lib.rs | 14 +- rust/macros/module.rs | 8 +- rust/uapi/lib.rs | 6 + samples/rust/rust_minimal.rs | 4 +- samples/rust/rust_print.rs | 1 + scripts/Makefile.build | 4 +- scripts/generate_rust_analyzer.py | 11 +- 61 files changed, 2482 insertions(+), 756 deletions(-) create mode 100644 .clippy.toml create mode 100644 rust/ffi.rs create mode 100644 rust/helpers/vmalloc.c create mode 100644 rust/kernel/alloc/allocator_test.rs delete mode 100644 rust/kernel/alloc/box_ext.rs create mode 100644 rust/kernel/alloc/kbox.rs create mode 100644 rust/kernel/alloc/kvec.rs create mode 100644 rust/kernel/alloc/layout.rs delete mode 100644 rust/kernel/alloc/vec_ext.rs
-- 2.48.1
commit 024f9676a6d236132119832a90fb9a1a9115b41a upstream.
Perform the same clean commit b2516f7af9d2 ("rust: kernel: remove `#[allow(clippy::new_ret_no_self)]`") did for a case that appeared in workqueue in parallel in commit 7324b88975c5 ("rust: workqueue: add helper for defining work_struct fields"):
Clippy triggered a false positive on its `new_ret_no_self` lint when using the `pin_init!` macro. Since Rust 1.67.0, that does not happen anymore, since Clippy learnt to not warn about `-> impl Trait<Self>` [1][2].
The kernel nowadays uses Rust 1.72.1, thus remove the `#[allow]`.
Link: https://github.com/rust-lang/rust-clippy/issues/7344 [1] Link: https://github.com/rust-lang/rust-clippy/pull/9733 [2]
Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/workqueue.rs | 1 - 1 file changed, 1 deletion(-)
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 553a5cba2adc..493288dc1de0 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -366,7 +366,6 @@ unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {} impl<T: ?Sized, const ID: u64> Work<T, ID> { /// Creates a new instance of [`Work`]. #[inline] - #[allow(clippy::new_ret_no_self)] pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> where T: WorkItem<ID>,
commit a135aa3d30d28f26eb28a0ff5d48b387b0e0755f upstream.
Sort the global Rust flags so that it is easier to follow along when we have more, like this patch series does.
Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-3-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile index 17dfe0a8ca8f..6fbdb2e8ffff 100644 --- a/Makefile +++ b/Makefile @@ -446,19 +446,19 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS) export rust_common_flags := --edition=2021 \ -Zbinary_dep_depinfo=y \ -Astable_features \ - -Dunsafe_op_in_unsafe_fn \ -Dnon_ascii_idents \ + -Dunsafe_op_in_unsafe_fn \ + -Wmissing_docs \ -Wrust_2018_idioms \ -Wunreachable_pub \ - -Wmissing_docs \ - -Wrustdoc::missing_crate_level_docs \ -Wclippy::all \ + -Wclippy::dbg_macro \ -Wclippy::mut_mut \ -Wclippy::needless_bitwise_bool \ -Wclippy::needless_continue \ -Aclippy::needless_lifetimes \ -Wclippy::no_mangle_with_rust_abi \ - -Wclippy::dbg_macro + -Wrustdoc::missing_crate_level_docs
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \ $(HOSTCFLAGS) -I $(srctree)/scripts/include
commit 567cdff53e71de56ae67eaf4309db38778b7bcd3 upstream.
In order to provide `// SAFETY` comments for every `unsafe impl`, we would need to repeat them, which is not very useful and would be harder to read.
We could perhaps allow the lint (ideally within a small module), but we can take the chance to avoid the repetition of the `impl`s themselves too by using a small local macro, like in other places where we have had to do this sort of thing.
Thus add the straightforward `impl_{from,as}bytes!` macros and use them to implement `FromBytes`.
This, in turn, will allow us in the next patch to place a `// SAFETY` comment that defers to the actual invocation of the macro.
Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-4-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/types.rs | 68 +++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9e7ca066355c..70e173f15d87 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -481,21 +481,22 @@ pub enum Either<L, R> { /// All bit-patterns must be valid for this type. This type must not have interior mutability. pub unsafe trait FromBytes {}
-// SAFETY: All bit patterns are acceptable values of the types below. -unsafe impl FromBytes for u8 {} -unsafe impl FromBytes for u16 {} -unsafe impl FromBytes for u32 {} -unsafe impl FromBytes for u64 {} -unsafe impl FromBytes for usize {} -unsafe impl FromBytes for i8 {} -unsafe impl FromBytes for i16 {} -unsafe impl FromBytes for i32 {} -unsafe impl FromBytes for i64 {} -unsafe impl FromBytes for isize {} -// SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit -// patterns are also acceptable for arrays of that type. -unsafe impl<T: FromBytes> FromBytes for [T] {} -unsafe impl<T: FromBytes, const N: usize> FromBytes for [T; N] {} +macro_rules! impl_frombytes { + ($($({$($generics:tt)*})? $t:ty, )*) => { + $(unsafe impl$($($generics)*)? FromBytes for $t {})* + }; +} + +impl_frombytes! { + // SAFETY: All bit patterns are acceptable values of the types below. + u8, u16, u32, u64, usize, + i8, i16, i32, i64, isize, + + // SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit + // patterns are also acceptable for arrays of that type. + {<T: FromBytes>} [T], + {<T: FromBytes, const N: usize>} [T; N], +}
/// Types that can be viewed as an immutable slice of initialized bytes. /// @@ -514,21 +515,22 @@ unsafe impl<T: FromBytes> FromBytes for [T] {} /// mutability. pub unsafe trait AsBytes {}
-// SAFETY: Instances of the following types have no uninitialized portions. -unsafe impl AsBytes for u8 {} -unsafe impl AsBytes for u16 {} -unsafe impl AsBytes for u32 {} -unsafe impl AsBytes for u64 {} -unsafe impl AsBytes for usize {} -unsafe impl AsBytes for i8 {} -unsafe impl AsBytes for i16 {} -unsafe impl AsBytes for i32 {} -unsafe impl AsBytes for i64 {} -unsafe impl AsBytes for isize {} -unsafe impl AsBytes for bool {} -unsafe impl AsBytes for char {} -unsafe impl AsBytes for str {} -// SAFETY: If individual values in an array have no uninitialized portions, then the array itself -// does not have any uninitialized portions either. -unsafe impl<T: AsBytes> AsBytes for [T] {} -unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {} +macro_rules! impl_asbytes { + ($($({$($generics:tt)*})? $t:ty, )*) => { + $(unsafe impl$($($generics)*)? AsBytes for $t {})* + }; +} + +impl_asbytes! { + // SAFETY: Instances of the following types have no uninitialized portions. + u8, u16, u32, u64, usize, + i8, i16, i32, i64, isize, + bool, + char, + str, + + // SAFETY: If individual values in an array have no uninitialized portions, then the array + // itself does not have any uninitialized portions either. + {<T: AsBytes>} [T], + {<T: AsBytes, const N: usize>} [T; N], +}
commit db4f72c904cb116e2bf56afdd67fc5167a607a7b upstream.
Checking that we are not missing any `// SAFETY` comments in our `unsafe` blocks is something we have wanted to do for a long time, as well as cleaning up the remaining cases that were not documented [1].
Back when Rust for Linux started, this was something that could have been done via a script, like Rust's `tidy`. Soon after, in Rust 1.58.0, Clippy implemented the `undocumented_unsafe_blocks` lint [2].
Even though the lint has a few false positives, e.g. in some cases where attributes appear between the comment and the `unsafe` block [3], there are workarounds and the lint seems quite usable already.
Thus enable the lint now.
We still have a few cases to clean up, so just allow those for the moment by writing a `TODO` comment -- some of those may be good candidates for new contributors.
Link: https://github.com/Rust-for-Linux/linux/issues/351 [1] Link: https://rust-lang.github.io/rust-clippy/master/#/undocumented_unsafe_blocks [2] Link: https://github.com/rust-lang/rust-clippy/issues/13189 [3] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-5-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 1 + mm/kasan/kasan_test_rust.rs | 1 + rust/bindings/lib.rs | 1 + rust/kernel/alloc/allocator.rs | 2 ++ rust/kernel/error.rs | 9 ++++++--- rust/kernel/init.rs | 5 +++++ rust/kernel/init/__internal.rs | 2 ++ rust/kernel/init/macros.rs | 9 +++++++++ rust/kernel/list.rs | 1 + rust/kernel/print.rs | 2 ++ rust/kernel/str.rs | 7 ++++--- rust/kernel/sync/condvar.rs | 2 +- rust/kernel/sync/lock.rs | 6 +++--- rust/kernel/types.rs | 4 ++++ rust/kernel/workqueue.rs | 4 ++++ rust/uapi/lib.rs | 1 + 16 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile index 6fbdb2e8ffff..a491ba904601 100644 --- a/Makefile +++ b/Makefile @@ -458,6 +458,7 @@ export rust_common_flags := --edition=2021 \ -Wclippy::needless_continue \ -Aclippy::needless_lifetimes \ -Wclippy::no_mangle_with_rust_abi \ + -Wclippy::undocumented_unsafe_blocks \ -Wrustdoc::missing_crate_level_docs
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \ diff --git a/mm/kasan/kasan_test_rust.rs b/mm/kasan/kasan_test_rust.rs index caa7175964ef..47bcf033dd4f 100644 --- a/mm/kasan/kasan_test_rust.rs +++ b/mm/kasan/kasan_test_rust.rs @@ -17,5 +17,6 @@ pub extern "C" fn kasan_test_rust_uaf() -> u8 { } let ptr: *mut u8 = addr_of_mut!(v[2048]); drop(v); + // SAFETY: Incorrect, on purpose. unsafe { *ptr } } diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs index 93a1a3fc97bc..d6da3011281a 100644 --- a/rust/bindings/lib.rs +++ b/rust/bindings/lib.rs @@ -25,6 +25,7 @@ )]
#[allow(dead_code)] +#[allow(clippy::undocumented_unsafe_blocks)] mod bindings_raw { // Use glob import here to expose all helpers. // Symbols defined within the module will take precedence to the glob import. diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index e6ea601f38c6..91216b36af69 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -31,6 +31,7 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 } }
+// SAFETY: TODO. unsafe impl GlobalAlloc for KernelAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety @@ -39,6 +40,7 @@ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { }
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + // SAFETY: TODO. unsafe { bindings::kfree(ptr as *const core::ffi::c_void); } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 6f1587a2524e..639bc7572f90 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -171,9 +171,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.name() { // Print out number if no name can be found. None => f.debug_tuple("Error").field(&-self.0).finish(), - // SAFETY: These strings are ASCII-only. Some(name) => f - .debug_tuple(unsafe { core::str::from_utf8_unchecked(name) }) + .debug_tuple( + // SAFETY: These strings are ASCII-only. + unsafe { core::str::from_utf8_unchecked(name) }, + ) .finish(), } } @@ -277,6 +279,8 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { if unsafe { bindings::IS_ERR(const_ptr) } { // SAFETY: The FFI function does not deref the pointer. let err = unsafe { bindings::PTR_ERR(const_ptr) }; + + #[allow(clippy::unnecessary_cast)] // CAST: If `IS_ERR()` returns `true`, // then `PTR_ERR()` is guaranteed to return a // negative value greater-or-equal to `-bindings::MAX_ERRNO`, @@ -286,7 +290,6 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { // // SAFETY: `IS_ERR()` ensures `err` is a // negative value greater-or-equal to `-bindings::MAX_ERRNO`. - #[allow(clippy::unnecessary_cast)] return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) }); } Ok(ptr) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 789f80f71ca7..a5857883e044 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -541,6 +541,7 @@ macro_rules! stack_try_pin_init { /// } /// pin_init!(&this in Buf { /// buf: [0; 64], +/// // SAFETY: TODO. /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, /// pin: PhantomPinned, /// }); @@ -875,6 +876,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { /// } /// /// let foo = pin_init!(Foo { + /// // SAFETY: TODO. /// raw <- unsafe { /// Opaque::ffi_init(|s| { /// init_foo(s); @@ -1162,6 +1164,7 @@ pub fn pin_init_array_from_fn<I, const N: usize, T, E>( // SAFETY: Every type can be initialized by-value. unsafe impl<T, E> Init<T, E> for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: TODO. unsafe { slot.write(self) }; Ok(()) } @@ -1170,6 +1173,7 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. unsafe impl<T, E> PinInit<T, E> for T { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: TODO. unsafe { self.__init(slot) } } } @@ -1411,6 +1415,7 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {
macro_rules! impl_zeroable { ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. $(unsafe impl$($($generics)*)? Zeroable for $t {})* }; } diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 13cefd37512f..29f4fd00df3d 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -112,10 +112,12 @@ fn clone(&self) -> Self {
impl<T: ?Sized> Copy for AllData<T> {}
+// SAFETY: TODO. unsafe impl<T: ?Sized> InitData for AllData<T> { type Datee = T; }
+// SAFETY: TODO. unsafe impl<T: ?Sized> HasInitData for T { type InitData = AllData<T>;
diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 9a0c4650ef67..736fe0ce0cd9 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -513,6 +513,7 @@ fn drop($($sig:tt)*) { } ), ) => { + // SAFETY: TODO. unsafe $($impl_sig)* { // Inherit all attributes and the type/ident tokens for the signature. $(#[$($attr)*])* @@ -872,6 +873,7 @@ unsafe fn __pin_data() -> Self::PinData { } }
+ // SAFETY: TODO. unsafe impl<$($impl_generics)*> $crate::init::__internal::PinData for __ThePinData<$($ty_generics)*> where $($whr)* @@ -997,6 +999,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> slot: *mut $p_type, init: impl $crate::init::PinInit<$p_type, E>, ) -> ::core::result::Result<(), E> { + // SAFETY: TODO. unsafe { $crate::init::PinInit::__pinned_init(init, slot) } } )* @@ -1007,6 +1010,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> slot: *mut $type, init: impl $crate::init::Init<$type, E>, ) -> ::core::result::Result<(), E> { + // SAFETY: TODO. unsafe { $crate::init::Init::__init(init, slot) } } )* @@ -1121,6 +1125,8 @@ macro_rules! __init_internal { // no possibility of returning without `unsafe`. struct __InitOk; // Get the data about fields from the supplied type. + // + // SAFETY: TODO. let data = unsafe { use $crate::init::__internal::$has_data; // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal @@ -1176,6 +1182,7 @@ fn assert_zeroable<T: $crate::init::Zeroable>(_: *mut T) {} let init = move |slot| -> ::core::result::Result<(), $err> { init(slot).map(|__InitOk| ()) }; + // SAFETY: TODO. let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) }; init }}; @@ -1324,6 +1331,8 @@ fn assert_zeroable<T: $crate::init::Zeroable>(_: *mut T) {} // Endpoint, nothing more to munch, create the initializer. // Since we are in the closure that is never called, this will never get executed. // We abuse `slot` to get the correct type inference here: + // + // SAFETY: TODO. unsafe { // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal // information that is associated to already parsed fragments, so a path fragment diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs index 5b4aec29eb67..fb93330f4af4 100644 --- a/rust/kernel/list.rs +++ b/rust/kernel/list.rs @@ -354,6 +354,7 @@ pub fn pop_front(&mut self) -> Option<ListArc<T, ID>> { /// /// `item` must not be in a different linked list (with the same id). pub unsafe fn remove(&mut self, item: &T) -> Option<ListArc<T, ID>> { + // SAFETY: TODO. let mut item = unsafe { ListLinks::fields(T::view_links(item)) }; // SAFETY: The user provided a reference, and reference are never dangling. // diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 508b0221256c..fe53fc469c4f 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -23,6 +23,7 @@ use fmt::Write; // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`. let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) }; + // SAFETY: TODO. let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) }); w.pos().cast() } @@ -102,6 +103,7 @@ pub unsafe fn call_printk( ) { // `_printk` does not seem to fail in any path. #[cfg(CONFIG_PRINTK)] + // SAFETY: TODO. unsafe { bindings::_printk( format_string.as_ptr() as _, diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index bb8d4f41475b..66d4527f6c6f 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -162,10 +162,10 @@ pub const fn len(&self) -> usize { /// Returns the length of this string with `NUL`. #[inline] pub const fn len_with_nul(&self) -> usize { - // SAFETY: This is one of the invariant of `CStr`. - // We add a `unreachable_unchecked` here to hint the optimizer that - // the value returned from this function is non-zero. if self.0.is_empty() { + // SAFETY: This is one of the invariant of `CStr`. + // We add a `unreachable_unchecked` here to hint the optimizer that + // the value returned from this function is non-zero. unsafe { core::hint::unreachable_unchecked() }; } self.0.len() @@ -301,6 +301,7 @@ pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { /// ``` #[inline] pub unsafe fn as_str_unchecked(&self) -> &str { + // SAFETY: TODO. unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } }
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 2b306afbe56d..7e00048bf4b1 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -92,8 +92,8 @@ pub struct CondVar { _pin: PhantomPinned, }
-// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread. #[allow(clippy::non_send_fields_in_send_ty)] +// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread. unsafe impl Send for CondVar {}
// SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index f6c34ca4d819..07fcf2d8efc6 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -150,9 +150,9 @@ pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U { // SAFETY: The caller owns the lock, so it is safe to unlock it. unsafe { B::unlock(self.lock.state.get(), &self.state) };
- // SAFETY: The lock was just unlocked above and is being relocked now. - let _relock = - ScopeGuard::new(|| unsafe { B::relock(self.lock.state.get(), &mut self.state) }); + let _relock = ScopeGuard::new(|| + // SAFETY: The lock was just unlocked above and is being relocked now. + unsafe { B::relock(self.lock.state.get(), &mut self.state) });
cb() } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 70e173f15d87..6c2d5fa9bce3 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -410,6 +410,7 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { /// /// struct Empty {} /// + /// # // SAFETY: TODO. /// unsafe impl AlwaysRefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull<Self>) {} @@ -417,6 +418,7 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { /// /// let mut data = Empty {}; /// let ptr = NonNull::<Empty>::new(&mut data as *mut _).unwrap(); + /// # // SAFETY: TODO. /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref); /// @@ -483,6 +485,7 @@ pub unsafe trait FromBytes {}
macro_rules! impl_frombytes { ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. $(unsafe impl$($($generics)*)? FromBytes for $t {})* }; } @@ -517,6 +520,7 @@ pub unsafe trait AsBytes {}
macro_rules! impl_asbytes { ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. $(unsafe impl$($($generics)*)? AsBytes for $t {})* }; } diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 493288dc1de0..3b3f1dbe8192 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -519,6 +519,7 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_typ impl{T} HasWork<Self> for ClosureWork<T> { self.work } }
+// SAFETY: TODO. unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T> where T: WorkItem<ID, Pointer = Self>, @@ -536,6 +537,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T> } }
+// SAFETY: TODO. unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T> where T: WorkItem<ID, Pointer = Self>, @@ -564,6 +566,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput } }
+// SAFETY: TODO. unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> where T: WorkItem<ID, Pointer = Self>, @@ -583,6 +586,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> } }
+// SAFETY: TODO. unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>> where T: WorkItem<ID, Pointer = Self>, diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs index 80a00260e3e7..fea2de330d19 100644 --- a/rust/uapi/lib.rs +++ b/rust/uapi/lib.rs @@ -14,6 +14,7 @@ #![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))] #![allow( clippy::all, + clippy::undocumented_unsafe_blocks, dead_code, missing_docs, non_camel_case_types,
commit c28bfe76e4ba707775a205b0274710de7aa1e31c upstream.
In Rust 1.67.0, Clippy added the `unnecessary_safety_comment` lint [1], which is the "inverse" of `undocumented_unsafe_blocks`: it finds places where safe code has a `// SAFETY` comment attached.
The lint currently finds 3 places where we had such mistakes, thus it seems already quite useful.
Thus clean those and enable it.
Link: https://rust-lang.github.io/rust-clippy/master/index.html#/unnecessary_safet... [1] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Vincenzo Palazzo vincenzopalazzodev@gmail.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-6-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 1 + rust/kernel/sync/arc.rs | 2 +- rust/kernel/workqueue.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile index a491ba904601..295d52b677f8 100644 --- a/Makefile +++ b/Makefile @@ -459,6 +459,7 @@ export rust_common_flags := --edition=2021 \ -Aclippy::needless_lifetimes \ -Wclippy::no_mangle_with_rust_abi \ -Wclippy::undocumented_unsafe_blocks \ + -Wclippy::unnecessary_safety_comment \ -Wrustdoc::missing_crate_level_docs
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \ diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 28743a7c74a8..9325cc5a16a4 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -338,7 +338,7 @@ fn into_foreign(self) -> *const core::ffi::c_void { }
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> { - // SAFETY: By the safety requirement of this function, we know that `ptr` came from + // By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`. let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap();
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 3b3f1dbe8192..10d2bc62e2cf 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -526,7 +526,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T> T: HasWork<T, ID>, { unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { - // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. + // The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. let ptr = ptr as *mut Work<T, ID>; // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. let ptr = unsafe { T::work_container_of(ptr) }; @@ -573,7 +573,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> T: HasWork<T, ID>, { unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { - // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. + // The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. let ptr = ptr as *mut Work<T, ID>; // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. let ptr = unsafe { T::work_container_of(ptr) };
commit 23f42dc054b3c550373eae0c9ae97f1ce1501e0a upstream.
In Rust 1.67.0, Clippy added the `unnecessary_safety_doc` lint [1], which is similar to `unnecessary_safety_comment`, but for `# Safety` sections, i.e. safety preconditions in the documentation.
This is something that should not happen with our coding guidelines in mind. Thus enable the lint to have it machine-checked.
Link: https://rust-lang.github.io/rust-clippy/master/index.html#/unnecessary_safet... [1] Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-7-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 1 + 1 file changed, 1 insertion(+)
diff --git a/Makefile b/Makefile index 295d52b677f8..13d8aa4a41d3 100644 --- a/Makefile +++ b/Makefile @@ -460,6 +460,7 @@ export rust_common_flags := --edition=2021 \ -Wclippy::no_mangle_with_rust_abi \ -Wclippy::undocumented_unsafe_blocks \ -Wclippy::unnecessary_safety_comment \ + -Wclippy::unnecessary_safety_doc \ -Wrustdoc::missing_crate_level_docs
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
commit 3fcc23397628c2357dbe66df59644e09f72ac725 upstream.
In Rust 1.73.0, Clippy introduced the `ignored_unit_patterns` lint [1]:
Matching with `()` explicitly instead of `_` outlines the fact that the pattern contains no data. Also it would detect a type change that `_` would ignore.
There is only a single case that requires a change:
error: matching over `()` is more explicit --> rust/kernel/types.rs:176:45 | 176 | ScopeGuard::new_with_data((), move |_| cleanup()) | ^ help: use `()` instead of `_`: `()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patte... = note: requested on the command line with `-D clippy::ignored-unit-patterns`
Thus clean it up and enable the lint -- no functional change intended.
Link: https://rust-lang.github.io/rust-clippy/master/index.html#/ignored_unit_patt... [1] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-8-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 1 + rust/kernel/types.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 13d8aa4a41d3..7433df4d22f9 100644 --- a/Makefile +++ b/Makefile @@ -453,6 +453,7 @@ export rust_common_flags := --edition=2021 \ -Wunreachable_pub \ -Wclippy::all \ -Wclippy::dbg_macro \ + -Wclippy::ignored_unit_patterns \ -Wclippy::mut_mut \ -Wclippy::needless_bitwise_bool \ -Wclippy::needless_continue \ diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 6c2d5fa9bce3..4e03df725f3f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -225,7 +225,7 @@ pub fn dismiss(mut self) -> T { impl ScopeGuard<(), fn(())> { /// Creates a new guarded object with the given cleanup function. pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> { - ScopeGuard::new_with_data((), move |_| cleanup()) + ScopeGuard::new_with_data((), move |()| cleanup()) } }
commit bef83245f5ed434932aaf07f890142b576dc5d85 upstream.
In Rust 1.71.0, `rustdoc` added the `unescaped_backticks` lint, which detects what are typically typos in Markdown formatting regarding inline code [1], e.g. from the Rust standard library:
/// ... to `deref`/`deref_mut`` must ...
/// ... use [`from_mut`]`. Specifically, ...
It does not seem to have almost any false positives, from the experience of enabling it in the Rust standard library [2], which will be checked starting with Rust 1.82.0. The maintainers also confirmed it is ready to be used.
Thus enable it.
Link: https://doc.rust-lang.org/rustdoc/lints.html#unescaped_backticks [1] Link: https://github.com/rust-lang/rust/pull/128307 [2] Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-9-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Makefile | 3 ++- rust/Makefile | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile index 7433df4d22f9..8748aa1b2f79 100644 --- a/Makefile +++ b/Makefile @@ -462,7 +462,8 @@ export rust_common_flags := --edition=2021 \ -Wclippy::undocumented_unsafe_blocks \ -Wclippy::unnecessary_safety_comment \ -Wclippy::unnecessary_safety_doc \ - -Wrustdoc::missing_crate_level_docs + -Wrustdoc::missing_crate_level_docs \ + -Wrustdoc::unescaped_backticks
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \ $(HOSTCFLAGS) -I $(srctree)/scripts/include diff --git a/rust/Makefile b/rust/Makefile index 45779a064fa4..b16456ac5d77 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -61,7 +61,7 @@ alloc-cfgs = \ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< cmd_rustdoc = \ OBJTREE=$(abspath $(objtree)) \ - $(RUSTDOC) $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags)) \ + $(RUSTDOC) $(filter-out $(skip_flags),$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \ $(rustc_target_flags) -L$(objtree)/$(obj) \ -Zunstable-options --generate-link-to-definition \ --output $(rustdoc_output) \ @@ -98,6 +98,9 @@ rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \ rustdoc-macros: $(src)/macros/lib.rs FORCE +$(call if_changed,rustdoc)
+# Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should +# not be needed -- see https://github.com/rust-lang/rust/pull/128307. +rustdoc-core: private skip_flags = -Wrustdoc::unescaped_backticks rustdoc-core: private rustc_target_flags = $(core-cfgs) rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE +$(call if_changed,rustdoc)
commit d5cc7ab0a0a99496de1bd933dac242699a417809 upstream.
These few cases, unlike others in the same file, did not need the `allow`.
Thus clean them up.
Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-10-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/init.rs | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index a5857883e044..0330a8756fa5 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -87,7 +87,6 @@ //! To declare an init macro/function you just return an [`impl PinInit<T, E>`]: //! //! ```rust -//! # #![allow(clippy::disallowed_names)] //! # use kernel::{sync::Mutex, new_mutex, init::PinInit, try_pin_init}; //! #[pin_data] //! struct DriverData { @@ -368,7 +367,6 @@ macro_rules! stack_try_pin_init { /// The syntax is almost identical to that of a normal `struct` initializer: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// #[pin_data] @@ -413,7 +411,6 @@ macro_rules! stack_try_pin_init { /// To create an initializer function, simply declare it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -468,7 +465,6 @@ macro_rules! stack_try_pin_init { /// They can also easily embed it into their own `struct`s: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data]
commit 5e7c9b84ad08cc7a41b2ddbbbaccb60057da3860 upstream.
Rust 1.58.0 (before Rust was merged into the kernel) made Clippy's `non_send_fields_in_send_ty` lint part of the `suspicious` lint group for a brief window of time [1] until the minor version 1.58.1 got released a week after, where the lint was moved back to `nursery`.
By that time, we had already upgraded to that Rust version, and thus we had `allow`ed the lint here for `CondVar`.
Nowadays, Clippy's `non_send_fields_in_send_ty` would still trigger here if it were enabled.
Moreover, if enabled, `Lock<T, B>` and `Task` would also require an `allow`. Therefore, it does not seem like someone is actually enabling it (in, e.g., a custom flags build).
Finally, the lint does not appear to have had major improvements since then [2].
Thus remove the `allow` since it is unneeded.
Link: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1581-2022-... [1] Link: https://github.com/rust-lang/rust-clippy/issues/8045 [2] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-11-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/sync/condvar.rs | 1 - 1 file changed, 1 deletion(-)
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 7e00048bf4b1..dec2e5ffc919 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -92,7 +92,6 @@ pub struct CondVar { _pin: PhantomPinned, }
-#[allow(clippy::non_send_fields_in_send_ty)] // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread. unsafe impl Send for CondVar {}
commit 7d56786edcbdf58b6367fd7f01d5861214ad1c95 upstream.
Some Clippy lints can be configured/tweaked. We will use these knobs to our advantage in later commits.
This is done via a configuration file, `.clippy.toml` [1]. The file is currently unstable. This may be a problem in the future, but we can adapt as needed. In addition, we proposed adding Clippy to the Rust CI's RFL job [2], so we should be able to catch issues pre-merge.
Thus introduce the file.
Link: https://doc.rust-lang.org/clippy/configuration.html [1] Link: https://github.com/rust-lang/rust/pull/128928 [2] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-12-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- .clippy.toml | 1 + .gitignore | 1 + MAINTAINERS | 1 + Makefile | 3 +++ 4 files changed, 6 insertions(+) create mode 100644 .clippy.toml
diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 000000000000..f66554cd5c45 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0 diff --git a/.gitignore b/.gitignore index 56972adb5031..a61e4778d011 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ modules.order # We don't want to ignore the following even if they are dot-files # !.clang-format +!.clippy.toml !.cocciconfig !.editorconfig !.get_maintainer.ignore diff --git a/MAINTAINERS b/MAINTAINERS index 6bb4ec0c162a..f4e08a0851bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20175,6 +20175,7 @@ B: https://github.com/Rust-for-Linux/linux/issues C: zulip://rust-for-linux.zulipchat.com P: https://rust-for-linux.com/contributing T: git https://github.com/Rust-for-Linux/linux.git rust-next +F: .clippy.toml F: Documentation/rust/ F: rust/ F: samples/rust/ diff --git a/Makefile b/Makefile index 8748aa1b2f79..43cc17c514dc 100644 --- a/Makefile +++ b/Makefile @@ -588,6 +588,9 @@ endif # Allows the usage of unstable features in stable compilers. export RUSTC_BOOTSTRAP := 1
+# Allows finding `.clippy.toml` in out-of-srctree builds. +export CLIPPY_CONF_DIR := $(srctree) + export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
commit 8577c9dca799bd74377f7c30015d8cdc53a53ca2 upstream.
Back when we used Rust 1.60.0 (before Rust was merged in the kernel), we added `-Wclippy::dbg_macro` to the compilation flags. This worked great with our custom `dbg!` macro (vendored from `std`, but slightly modified to use the kernel printing facilities).
However, in the very next version, 1.61.0, it stopped working [1] since the lint started to use a Rust diagnostic item rather than a path to find the `dbg!` macro [1]. This behavior remains until the current nightly (1.83.0).
Therefore, currently, the `dbg_macro` is not doing anything, which explains why we can invoke `dbg!` in samples/rust/rust_print.rs`, as well as why changing the `#[allow()]`s to `#[expect()]`s in `std_vendor.rs` doctests does not work since they are not fulfilled.
One possible workaround is using `rustc_attrs` like the standard library does. However, this is intended to be internal, and we just started supporting several Rust compiler versions, so it is best to avoid it.
Therefore, instead, use `disallowed_macros`. It is a stable lint and is more flexible (in that we can provide different macros), although its diagnostic message(s) are not as nice as the specialized one (yet), and does not allow to set different lint levels per macro/path [2].
In turn, this requires allowing the (intentional) `dbg!` use in the sample, as one would have expected.
Finally, in a single case, the `allow` is fixed to be an inner attribute, since otherwise it was not being applied.
Link: https://github.com/rust-lang/rust-clippy/issues/11303 [1] Link: https://github.com/rust-lang/rust-clippy/issues/11307 [2] Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-13-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- .clippy.toml | 6 ++++++ Makefile | 1 - rust/kernel/std_vendor.rs | 10 +++++----- samples/rust/rust_print.rs | 1 + 4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/.clippy.toml b/.clippy.toml index f66554cd5c45..ad9f804fb677 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 + +disallowed-macros = [ + # The `clippy::dbg_macro` lint only works with `std::dbg!`, thus we simulate + # it here, see: https://github.com/rust-lang/rust-clippy/issues/11303. + { path = "kernel::dbg", reason = "the `dbg!` macro is intended as a debugging tool" }, +] diff --git a/Makefile b/Makefile index 43cc17c514dc..d005a439a67c 100644 --- a/Makefile +++ b/Makefile @@ -452,7 +452,6 @@ export rust_common_flags := --edition=2021 \ -Wrust_2018_idioms \ -Wunreachable_pub \ -Wclippy::all \ - -Wclippy::dbg_macro \ -Wclippy::ignored_unit_patterns \ -Wclippy::mut_mut \ -Wclippy::needless_bitwise_bool \ diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs index 67bf9d37ddb5..085b23312c65 100644 --- a/rust/kernel/std_vendor.rs +++ b/rust/kernel/std_vendor.rs @@ -14,7 +14,7 @@ /// /// ```rust /// let a = 2; -/// # #[allow(clippy::dbg_macro)] +/// # #[allow(clippy::disallowed_macros)] /// let b = dbg!(a * 2) + 1; /// // ^-- prints: [src/main.rs:2] a * 2 = 4 /// assert_eq!(b, 5); @@ -52,7 +52,7 @@ /// With a method call: /// /// ```rust -/// # #[allow(clippy::dbg_macro)] +/// # #[allow(clippy::disallowed_macros)] /// fn foo(n: usize) { /// if dbg!(n.checked_sub(4)).is_some() { /// // ... @@ -71,7 +71,7 @@ /// Naive factorial implementation: /// /// ```rust -/// # #[allow(clippy::dbg_macro)] +/// # #[allow(clippy::disallowed_macros)] /// # { /// fn factorial(n: u32) -> u32 { /// if dbg!(n <= 1) { @@ -118,7 +118,7 @@ /// a tuple (and return it, too): /// /// ``` -/// # #[allow(clippy::dbg_macro)] +/// # #![allow(clippy::disallowed_macros)] /// assert_eq!(dbg!(1usize, 2u32), (1, 2)); /// ``` /// @@ -127,7 +127,7 @@ /// invocations. You can use a 1-tuple directly if you need one: /// /// ``` -/// # #[allow(clippy::dbg_macro)] +/// # #[allow(clippy::disallowed_macros)] /// # { /// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored /// assert_eq!((1,), dbg!((1u32,))); // 1-tuple diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs index 6eabb0d79ea3..ed1137ab2018 100644 --- a/samples/rust/rust_print.rs +++ b/samples/rust/rust_print.rs @@ -15,6 +15,7 @@
struct RustPrint;
+#[allow(clippy::disallowed_macros)] fn arc_print() -> Result { use kernel::sync::*;
commit 2f390cc589433dfcfedc307a141e103929a6fd4d upstream.
Rust 1.82.0's Clippy is introducing [1][2] a new warn-by-default lint, `too_long_first_doc_paragraph` [3], which is intended to catch titles of code documentation items that are too long (likely because no title was provided and the item documentation starts with a paragraph).
This lint does not currently trigger anywhere, but it does detect a couple cases if checking for private items gets enabled (which we will do in the next commit):
error: first doc comment paragraph is too long --> rust/kernel/init/__internal.rs:18:1 | 18 | / /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this 19 | | /// type, since the closure needs to fulfill the same safety requirement as the 20 | | /// `__pinned_init`/`__init` functions. | |_ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#too_long_first_doc... = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]`
error: first doc comment paragraph is too long --> rust/kernel/sync/arc/std_vendor.rs:3:1 | 3 | / //! The contents of this file come from the Rust standard library, hosted in 4 | | //! the https://github.com/rust-lang/rust repository, licensed under 5 | | //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details, 6 | | //! see https://github.com/rust-lang/rust/blob/master/COPYRIGHT. | |_ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#too_long_first_doc...
Thus clean those two instances.
In addition, since we have a second `std_vendor.rs` file with a similar header, do the same there too (even if that one does not trigger the lint, because it is `doc(hidden)`).
Link: https://github.com/rust-lang/rust/pull/129531 [1] Link: https://github.com/rust-lang/rust-clippy/pull/12993 [2] Link: https://rust-lang.github.io/rust-clippy/master/index.html#/too_long_first_do... [3] Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-15-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/init/__internal.rs | 7 ++++--- rust/kernel/std_vendor.rs | 2 ++ rust/kernel/sync/arc/std_vendor.rs | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 29f4fd00df3d..163eb072f296 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -15,9 +15,10 @@ /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-pat... pub(super) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>;
-/// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this -/// type, since the closure needs to fulfill the same safety requirement as the -/// `__pinned_init`/`__init` functions. +/// Module-internal type implementing `PinInit` and `Init`. +/// +/// It is unsafe to create this type, since the closure needs to fulfill the same safety +/// requirement as the `__pinned_init`/`__init` functions. pub(crate) struct InitClosure<F, T: ?Sized, E>(pub(crate) F, pub(crate) Invariant<(E, T)>);
// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs index 085b23312c65..d59e4cf4b252 100644 --- a/rust/kernel/std_vendor.rs +++ b/rust/kernel/std_vendor.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT
+//! Rust standard library vendored code. +//! //! The contents of this file come from the Rust standard library, hosted in //! the https://github.com/rust-lang/rust repository, licensed under //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details, diff --git a/rust/kernel/sync/arc/std_vendor.rs b/rust/kernel/sync/arc/std_vendor.rs index a66a0c2831b3..11b3f4ecca5f 100644 --- a/rust/kernel/sync/arc/std_vendor.rs +++ b/rust/kernel/sync/arc/std_vendor.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT
+//! Rust standard library vendored code. +//! //! The contents of this file come from the Rust standard library, hosted in //! the https://github.com/rust-lang/rust repository, licensed under //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
commit 624063b9ac97f40cadca32a896aafeb28b1220fd upstream.
In Rust 1.76.0, Clippy added the `check-private-items` lint configuration option. When turned on (the default is off), it makes several lints check private items as well.
In our case, it affects two lints we have enabled [1]: `missing_safety_doc` and `unnecessary_safety_doc`.
It also seems to affect the new `too_long_first_doc_paragraph` lint [2], even though the documentation does not mention it.
Thus allow the few instances remaining we currently hit and enable the lint.
Link: https://doc.rust-lang.org/nightly/clippy/lint_configuration.html#check-priva... [1] Link: https://rust-lang.github.io/rust-clippy/master/index.html#/too_long_first_do... [2] Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-16-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- .clippy.toml | 2 ++ rust/kernel/init.rs | 1 + rust/kernel/init/__internal.rs | 2 ++ rust/kernel/init/macros.rs | 1 + rust/kernel/print.rs | 1 + 5 files changed, 7 insertions(+)
diff --git a/.clippy.toml b/.clippy.toml index ad9f804fb677..e4c4eef10b28 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0
+check-private-items = true + disallowed-macros = [ # The `clippy::dbg_macro` lint only works with `std::dbg!`, thus we simulate # it here, see: https://github.com/rust-lang/rust-clippy/issues/11303. diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 0330a8756fa5..fdbf0857ba20 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -125,6 +125,7 @@ //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { //! # #![allow(non_camel_case_types)] +//! # #![allow(clippy::missing_safety_doc)] //! # pub struct foo; //! # pub unsafe fn init_foo(_ptr: *mut foo) {} //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 163eb072f296..549ae227c2ea 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -54,6 +54,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { pub unsafe trait HasPinData { type PinData: PinData;
+ #[allow(clippy::missing_safety_doc)] unsafe fn __pin_data() -> Self::PinData; }
@@ -83,6 +84,7 @@ fn make_closure<F, O, E>(self, f: F) -> F pub unsafe trait HasInitData { type InitData: InitData;
+ #[allow(clippy::missing_safety_doc)] unsafe fn __init_data() -> Self::InitData; }
diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 736fe0ce0cd9..193d39886b1f 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -989,6 +989,7 @@ fn drop(&mut self) { // // The functions are `unsafe` to prevent accidentally calling them. #[allow(dead_code)] + #[allow(clippy::missing_safety_doc)] impl<$($impl_generics)*> $pin_data<$($ty_generics)*> where $($whr)* { diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index fe53fc469c4f..45af17095a24 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -14,6 +14,7 @@ use crate::str::RawFormatter;
// Called from `vsprintf` with format specifier `%pA`. +#[allow(clippy::missing_safety_doc)] #[no_mangle] unsafe extern "C" fn rust_fmt_argument( buf: *mut c_char,
commit 139d396572ec4ba6e8cc5c02f5c8d5d1139be4b7 upstream.
In the C side, disabling diagnostics locally, i.e. within the source code, is rare (at least in the kernel). Sometimes warnings are manipulated via the flags at the translation unit level, but that is about it.
In Rust, it is easier to change locally the "level" of lints (e.g. allowing them locally). In turn, this means it is easier to globally enable more lints that may trigger a few false positives here and there that need to be allowed locally, but that generally can spot issues or bugs.
Thus document this.
Reviewed-by: Trevor Gross tmgross@umich.edu Reviewed-by: Alice Ryhl aliceryhl@google.com Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-17-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Documentation/rust/coding-guidelines.rst | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/Documentation/rust/coding-guidelines.rst b/Documentation/rust/coding-guidelines.rst index 329b070a1d47..6db0420f0cea 100644 --- a/Documentation/rust/coding-guidelines.rst +++ b/Documentation/rust/coding-guidelines.rst @@ -227,3 +227,41 @@ The equivalent in Rust may look like (ignoring documentation): That is, the equivalent of ``GPIO_LINE_DIRECTION_IN`` would be referred to as ``gpio::LineDirection::In``. In particular, it should not be named ``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN``. + + +Lints +----- + +In Rust, it is possible to ``allow`` particular warnings (diagnostics, lints) +locally, making the compiler ignore instances of a given warning within a given +function, module, block, etc. + +It is similar to ``#pragma GCC diagnostic push`` + ``ignored`` + ``pop`` in C +[#]_: + +.. code-block:: c + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-function" + static void f(void) {} + #pragma GCC diagnostic pop + +.. [#] In this particular case, the kernel's ``__{always,maybe}_unused`` + attributes (C23's ``[[maybe_unused]]``) may be used; however, the example + is meant to reflect the equivalent lint in Rust discussed afterwards. + +But way less verbose: + +.. code-block:: rust + + #[allow(dead_code)] + fn f() {} + +By that virtue, it makes it possible to comfortably enable more diagnostics by +default (i.e. outside ``W=`` levels). In particular, those that may have some +false positives but that are otherwise quite useful to keep enabled to catch +potential mistakes. + +For more information about diagnostics in Rust, please see: + + https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
commit 1f9ed172545687e5c04c77490a45896be6d2e459 upstream.
In Rust, it is possible to `allow` particular warnings (diagnostics, lints) locally, making the compiler ignore instances of a given warning within a given function, module, block, etc.
It is similar to `#pragma GCC diagnostic push` + `ignored` + `pop` in C:
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static void f(void) {} #pragma GCC diagnostic pop
But way less verbose:
#[allow(dead_code)] fn f() {}
By that virtue, it makes it possible to comfortably enable more diagnostics by default (i.e. outside `W=` levels) that may have some false positives but that are otherwise quite useful to keep enabled to catch potential mistakes.
The `#[expect(...)]` attribute [1] takes this further, and makes the compiler warn if the diagnostic was _not_ produced. For instance, the following will ensure that, when `f()` is called somewhere, we will have to remove the attribute:
#[expect(dead_code)] fn f() {}
If we do not, we get a warning from the compiler:
warning: this lint expectation is unfulfilled --> x.rs:3:10 | 3 | #[expect(dead_code)] | ^^^^^^^^^ | = note: `#[warn(unfulfilled_lint_expectations)]` on by default
This means that `expect`s do not get forgotten when they are not needed.
See the next commit for more details, nuances on its usage and documentation on the feature.
The attribute requires the `lint_reasons` [2] unstable feature, but it is becoming stable in 1.81.0 (to be released on 2024-09-05) and it has already been useful to clean things up in this patch series, finding cases where the `allow`s should not have been there.
Thus, enable `lint_reasons` and convert some of our `allow`s to `expect`s where possible.
This feature was also an example of the ongoing collaboration between Rust and the kernel -- we tested it in the kernel early on and found an issue that was quickly resolved [3].
Cc: Fridtjof Stoldt xfrednet@gmail.com Cc: Urgau urgau@numericable.fr Link: https://rust-lang.github.io/rfcs/2383-lint-reasons.html#expect-lint-attribut... [1] Link: https://github.com/rust-lang/rust/issues/54503 [2] Link: https://github.com/rust-lang/rust/issues/114557 [3] Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-18-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/error.rs | 2 +- rust/kernel/init.rs | 22 +++++++++++----------- rust/kernel/init/__internal.rs | 4 ++-- rust/kernel/init/macros.rs | 10 +++++----- rust/kernel/ioctl.rs | 2 +- rust/kernel/lib.rs | 1 + rust/kernel/list/arc_field.rs | 2 +- rust/kernel/print.rs | 4 ++-- rust/kernel/std_vendor.rs | 10 +++++----- samples/rust/rust_print.rs | 2 +- scripts/Makefile.build | 2 +- 11 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 639bc7572f90..a681acda87ce 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -133,7 +133,7 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { }
/// Returns the error encoded as a pointer. - #[allow(dead_code)] + #[expect(dead_code)] pub(crate) fn to_ptr<T>(self) -> *mut T { #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index fdbf0857ba20..44e829b61243 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -35,7 +35,7 @@ //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. //! //! ```rust -//! # #![allow(clippy::disallowed_names)] +//! # #![expect(clippy::disallowed_names)] //! use kernel::sync::{new_mutex, Mutex}; //! # use core::pin::Pin; //! #[pin_data] @@ -55,7 +55,7 @@ //! (or just the stack) to actually initialize a `Foo`: //! //! ```rust -//! # #![allow(clippy::disallowed_names)] +//! # #![expect(clippy::disallowed_names)] //! # use kernel::sync::{new_mutex, Mutex}; //! # use core::pin::Pin; //! # #[pin_data] @@ -120,12 +120,12 @@ //! `slot` gets called. //! //! ```rust -//! # #![allow(unreachable_pub, clippy::disallowed_names)] +//! # #![expect(unreachable_pub, clippy::disallowed_names)] //! use kernel::{init, types::Opaque}; //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { -//! # #![allow(non_camel_case_types)] -//! # #![allow(clippy::missing_safety_doc)] +//! # #![expect(non_camel_case_types)] +//! # #![expect(clippy::missing_safety_doc)] //! # pub struct foo; //! # pub unsafe fn init_foo(_ptr: *mut foo) {} //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} @@ -238,7 +238,7 @@ /// # Examples /// /// ```rust -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; /// # use core::pin::Pin; /// #[pin_data] @@ -290,7 +290,7 @@ macro_rules! stack_pin_init { /// # Examples /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -316,7 +316,7 @@ macro_rules! stack_pin_init { /// ``` /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init { /// Users of `Foo` can now create it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -852,7 +852,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { /// # Examples /// /// ```rust - /// # #![allow(clippy::disallowed_names)] + /// # #![expect(clippy::disallowed_names)] /// use kernel::{types::Opaque, init::pin_init_from_closure}; /// #[repr(C)] /// struct RawFoo([u8; 16]); @@ -964,7 +964,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { /// # Examples /// /// ```rust - /// # #![allow(clippy::disallowed_names)] + /// # #![expect(clippy::disallowed_names)] /// use kernel::{types::Opaque, init::{self, init_from_closure}}; /// struct Foo { /// buf: [u8; 1_000_000], diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 549ae227c2ea..44431fba7aab 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -54,7 +54,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { pub unsafe trait HasPinData { type PinData: PinData;
- #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] unsafe fn __pin_data() -> Self::PinData; }
@@ -84,7 +84,7 @@ fn make_closure<F, O, E>(self, f: F) -> F pub unsafe trait HasInitData { type InitData: InitData;
- #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] unsafe fn __init_data() -> Self::InitData; }
diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 193d39886b1f..1fd146a83241 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -182,13 +182,13 @@ //! // Normally `Drop` bounds do not have the correct semantics, but for this purpose they do //! // (normally people want to know if a type has any kind of drop glue at all, here we want //! // to know if it has any kind of custom drop glue, which is exactly what this bound does). -//! #[allow(drop_bounds)] +//! #[expect(drop_bounds)] //! impl<T: ::core::ops::Drop> MustNotImplDrop for T {} //! impl<T> MustNotImplDrop for Bar<T> {} //! // Here comes a convenience check, if one implemented `PinnedDrop`, but forgot to add it to //! // `#[pin_data]`, then this will error with the same mechanic as above, this is not needed //! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`. -//! #[allow(non_camel_case_types)] +//! #[expect(non_camel_case_types)] //! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} //! impl< //! T: ::kernel::init::PinnedDrop, @@ -925,14 +925,14 @@ impl<'__pin, $($impl_generics)*> ::core::marker::Unpin for $name<$($ty_generics) // `Drop`. Additionally we will implement this trait for the struct leading to a conflict, // if it also implements `Drop` trait MustNotImplDrop {} - #[allow(drop_bounds)] + #[expect(drop_bounds)] impl<T: ::core::ops::Drop> MustNotImplDrop for T {} impl<$($impl_generics)*> MustNotImplDrop for $name<$($ty_generics)*> where $($whr)* {} // We also take care to prevent users from writing a useless `PinnedDrop` implementation. // They might implement `PinnedDrop` correctly for the struct, but forget to give // `PinnedDrop` as the parameter to `#[pin_data]`. - #[allow(non_camel_case_types)] + #[expect(non_camel_case_types)] trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} impl<T: $crate::init::PinnedDrop> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} @@ -989,7 +989,7 @@ fn drop(&mut self) { // // The functions are `unsafe` to prevent accidentally calling them. #[allow(dead_code)] - #[allow(clippy::missing_safety_doc)] + #[expect(clippy::missing_safety_doc)] impl<$($impl_generics)*> $pin_data<$($ty_generics)*> where $($whr)* { diff --git a/rust/kernel/ioctl.rs b/rust/kernel/ioctl.rs index cfa7d080b531..2fc7662339e5 100644 --- a/rust/kernel/ioctl.rs +++ b/rust/kernel/ioctl.rs @@ -4,7 +4,7 @@ //! //! C header: [`include/asm-generic/ioctl.h`](srctree/include/asm-generic/ioctl.h)
-#![allow(non_snake_case)] +#![expect(non_snake_case)]
use crate::build_assert;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index e936254531fd..b6395b4209d7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -15,6 +15,7 @@ #![feature(arbitrary_self_types)] #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] +#![feature(lint_reasons)] #![feature(new_uninit)] #![feature(unsize)]
diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs index 2330f673427a..c4b9dd503982 100644 --- a/rust/kernel/list/arc_field.rs +++ b/rust/kernel/list/arc_field.rs @@ -56,7 +56,7 @@ pub unsafe fn assert_ref(&self) -> &T { /// /// The caller must have mutable access to the `ListArc<ID>` containing the struct with this /// field for the duration of the returned reference. - #[allow(clippy::mut_from_ref)] + #[expect(clippy::mut_from_ref)] pub unsafe fn assert_mut(&self) -> &mut T { // SAFETY: The caller has exclusive access to the `ListArc`, so they also have exclusive // access to this field. diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 45af17095a24..a28077a7cb30 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -14,7 +14,7 @@ use crate::str::RawFormatter;
// Called from `vsprintf` with format specifier `%pA`. -#[allow(clippy::missing_safety_doc)] +#[expect(clippy::missing_safety_doc)] #[no_mangle] unsafe extern "C" fn rust_fmt_argument( buf: *mut c_char, @@ -140,7 +140,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) { #[doc(hidden)] #[cfg(not(testlib))] #[macro_export] -#[allow(clippy::crate_in_macro_def)] +#[expect(clippy::crate_in_macro_def)] macro_rules! print_macro ( // The non-continuation cases (most of them, e.g. `INFO`). ($format_string:path, false, $($arg:tt)+) => ( diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs index d59e4cf4b252..8b4872b48e97 100644 --- a/rust/kernel/std_vendor.rs +++ b/rust/kernel/std_vendor.rs @@ -16,7 +16,7 @@ /// /// ```rust /// let a = 2; -/// # #[allow(clippy::disallowed_macros)] +/// # #[expect(clippy::disallowed_macros)] /// let b = dbg!(a * 2) + 1; /// // ^-- prints: [src/main.rs:2] a * 2 = 4 /// assert_eq!(b, 5); @@ -54,7 +54,7 @@ /// With a method call: /// /// ```rust -/// # #[allow(clippy::disallowed_macros)] +/// # #[expect(clippy::disallowed_macros)] /// fn foo(n: usize) { /// if dbg!(n.checked_sub(4)).is_some() { /// // ... @@ -73,7 +73,7 @@ /// Naive factorial implementation: /// /// ```rust -/// # #[allow(clippy::disallowed_macros)] +/// # #[expect(clippy::disallowed_macros)] /// # { /// fn factorial(n: u32) -> u32 { /// if dbg!(n <= 1) { @@ -120,7 +120,7 @@ /// a tuple (and return it, too): /// /// ``` -/// # #![allow(clippy::disallowed_macros)] +/// # #![expect(clippy::disallowed_macros)] /// assert_eq!(dbg!(1usize, 2u32), (1, 2)); /// ``` /// @@ -129,7 +129,7 @@ /// invocations. You can use a 1-tuple directly if you need one: /// /// ``` -/// # #[allow(clippy::disallowed_macros)] +/// # #[expect(clippy::disallowed_macros)] /// # { /// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored /// assert_eq!((1,), dbg!((1u32,))); // 1-tuple diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs index ed1137ab2018..ba1606bdbd75 100644 --- a/samples/rust/rust_print.rs +++ b/samples/rust/rust_print.rs @@ -15,7 +15,7 @@
struct RustPrint;
-#[allow(clippy::disallowed_macros)] +#[expect(clippy::disallowed_macros)] fn arc_print() -> Result { use kernel::sync::*;
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 880785b52c04..64518c2f3d9c 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -248,7 +248,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # Compile Rust sources (.rs) # ---------------------------------------------------------------------------
-rust_allowed_features := arbitrary_self_types,new_uninit +rust_allowed_features := arbitrary_self_types,lint_reasons,new_uninit
# `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree
commit 04866494e936d041fd196d3a36aecd979e4ef078 upstream.
Discuss `#[expect(...)]` in the Lints sections of the coding guidelines document, which is an upcoming feature in Rust 1.81.0, and explain that it is generally to be preferred over `allow` unless there is a reason not to use it (e.g. conditional compilation being involved).
Tested-by: Gary Guo gary@garyguo.net Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240904204347.168520-19-ojeda@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- Documentation/rust/coding-guidelines.rst | 110 +++++++++++++++++++++++ 1 file changed, 110 insertions(+)
diff --git a/Documentation/rust/coding-guidelines.rst b/Documentation/rust/coding-guidelines.rst index 6db0420f0cea..f7194f7124b0 100644 --- a/Documentation/rust/coding-guidelines.rst +++ b/Documentation/rust/coding-guidelines.rst @@ -262,6 +262,116 @@ default (i.e. outside ``W=`` levels). In particular, those that may have some false positives but that are otherwise quite useful to keep enabled to catch potential mistakes.
+On top of that, Rust provides the ``expect`` attribute which takes this further. +It makes the compiler warn if the warning was not produced. For instance, the +following will ensure that, when ``f()`` is called somewhere, we will have to +remove the attribute: + +.. code-block:: rust + + #[expect(dead_code)] + fn f() {} + +If we do not, we get a warning from the compiler:: + + warning: this lint expectation is unfulfilled + --> x.rs:3:10 + | + 3 | #[expect(dead_code)] + | ^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +This means that ``expect``\ s do not get forgotten when they are not needed, which +may happen in several situations, e.g.: + +- Temporary attributes added while developing. + +- Improvements in lints in the compiler, Clippy or custom tools which may + remove a false positive. + +- When the lint is not needed anymore because it was expected that it would be + removed at some point, such as the ``dead_code`` example above. + +It also increases the visibility of the remaining ``allow``\ s and reduces the +chance of misapplying one. + +Thus prefer ``except`` over ``allow`` unless: + +- The lint attribute is intended to be temporary, e.g. while developing. + +- Conditional compilation triggers the warning in some cases but not others. + + If there are only a few cases where the warning triggers (or does not + trigger) compared to the total number of cases, then one may consider using + a conditional ``expect`` (i.e. ``cfg_attr(..., expect(...))``). Otherwise, + it is likely simpler to just use ``allow``. + +- Inside macros, when the different invocations may create expanded code that + triggers the warning in some cases but not in others. + +- When code may trigger a warning for some architectures but not others, such + as an ``as`` cast to a C FFI type. + +As a more developed example, consider for instance this program: + +.. code-block:: rust + + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +Here, function ``g()`` is dead code if ``CONFIG_X`` is not set. Can we use +``expect`` here? + +.. code-block:: rust + + #[expect(dead_code)] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +This would emit a lint if ``CONFIG_X`` is set, since it is not dead code in that +configuration. Therefore, in cases like this, we cannot use ``expect`` as-is. + +A simple possibility is using ``allow``: + +.. code-block:: rust + + #[allow(dead_code)] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +An alternative would be using a conditional ``expect``: + +.. code-block:: rust + + #[cfg_attr(not(CONFIG_X), expect(dead_code))] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +This would ensure that, if someone introduces another call to ``g()`` somewhere +(e.g. unconditionally), then it would be spotted that it is not dead code +anymore. However, the ``cfg_attr`` is more complex than a simple ``allow``. + +Therefore, it is likely that it is not worth using conditional ``expect``\ s when +more than one or two configurations are involved or when the lint may be +triggered due to non-local changes (such as ``dead_code``). + For more information about diagnostics in Rust, please see:
https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
From: Filipe Xavier felipe_life@live.com
commit 5ed147473458f8c20f908a03227d8f5bb3cb8f7d upstream.
Change visibility to public of functions in error.rs: from_err_ptr, from_errno, from_result and to_ptr. Additionally, remove dead_code annotations.
Link: https://github.com/Rust-for-Linux/linux/issues/1105 Reviewed-by: Alice Ryhl aliceryhl@google.com Signed-off-by: Filipe Xavier felipe_life@live.com Reviewed-by: Benno Lossin benno.lossin@proton.me Reviewed-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/DM4PR14MB7276E6948E67B3B23D8EA847E9652@DM4PR14MB72... Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/error.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index a681acda87ce..2f1e4b783bfb 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -95,7 +95,7 @@ impl Error { /// /// It is a bug to pass an out-of-range `errno`. `EINVAL` would /// be returned in such a case. - pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error { + pub fn from_errno(errno: core::ffi::c_int) -> Error { if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { // TODO: Make it a `WARN_ONCE` once available. crate::pr_warn!( @@ -133,8 +133,7 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { }
/// Returns the error encoded as a pointer. - #[expect(dead_code)] - pub(crate) fn to_ptr<T>(self) -> *mut T { + pub fn to_ptr<T>(self) -> *mut T { #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. unsafe { @@ -270,9 +269,7 @@ pub fn to_result(err: core::ffi::c_int) -> Result { /// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) }) /// } /// ``` -// TODO: Remove `dead_code` marker once an in-kernel client is available. -#[allow(dead_code)] -pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { +pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid. let const_ptr: *const core::ffi::c_void = ptr.cast(); // SAFETY: The FFI function does not deref the pointer. @@ -318,9 +315,7 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { /// }) /// } /// ``` -// TODO: Remove `dead_code` marker once an in-kernel client is available. -#[allow(dead_code)] -pub(crate) fn from_result<T, F>(f: F) -> T +pub fn from_result<T, F>(f: F) -> T where T: From<i16>, F: FnOnce() -> Result<T>,
From: Filipe Xavier felipe_life@live.com
commit e9759c5b9ea555d09f426c70c880e9522e9b0576 upstream.
Optimize `Result<(), Error>` size by changing `Error` type to `NonZero*` for niche optimization.
This reduces the space used by the `Result` type, as the `NonZero*` type enables the compiler to apply more efficient memory layout. For example, the `Result<(), Error>` changes size from 8 to 4 bytes.
Link: https://github.com/Rust-for-Linux/linux/issues/1120 Signed-off-by: Filipe Xavier felipe_life@live.com Reviewed-by: Gary Guo gary@garyguo.net Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Fiona Behrens me@kloenk.dev Link: https://lore.kernel.org/r/BL0PR02MB4914B9B088865CF237731207E9732@BL0PR02MB49... [ Removed unneeded block around `match`, added backticks in panic message and added intra-doc link. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/error.rs | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 2f1e4b783bfb..be6509d5f4a4 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -9,6 +9,7 @@ use alloc::alloc::LayoutError;
use core::fmt; +use core::num::NonZeroI32; use core::num::TryFromIntError; use core::str::Utf8Error;
@@ -20,7 +21,11 @@ macro_rules! declare_err { $( #[doc = $doc] )* - pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32)); + pub const $err: super::Error = + match super::Error::try_from_errno(-(crate::bindings::$err as i32)) { + Some(err) => err, + None => panic!("Invalid errno in `declare_err!`"), + }; }; }
@@ -88,7 +93,7 @@ macro_rules! declare_err { /// /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`). #[derive(Clone, Copy, PartialEq, Eq)] -pub struct Error(core::ffi::c_int); +pub struct Error(NonZeroI32);
impl Error { /// Creates an [`Error`] from a kernel error code. @@ -107,7 +112,20 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error {
// INVARIANT: The check above ensures the type invariant // will hold. - Error(errno) + // SAFETY: `errno` is checked above to be in a valid range. + unsafe { Error::from_errno_unchecked(errno) } + } + + /// Creates an [`Error`] from a kernel error code. + /// + /// Returns [`None`] if `errno` is out-of-range. + const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> { + if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { + return None; + } + + // SAFETY: `errno` is checked above to be in a valid range. + Some(unsafe { Error::from_errno_unchecked(errno) }) }
/// Creates an [`Error`] from a kernel error code. @@ -115,21 +133,22 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error { /// # Safety /// /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`). - unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error { + const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error { // INVARIANT: The contract ensures the type invariant // will hold. - Error(errno) + // SAFETY: The caller guarantees `errno` is non-zero. + Error(unsafe { NonZeroI32::new_unchecked(errno) }) }
/// Returns the kernel error code. pub fn to_errno(self) -> core::ffi::c_int { - self.0 + self.0.get() }
#[cfg(CONFIG_BLOCK)] pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { bindings::errno_to_blk_status(self.0) } + unsafe { bindings::errno_to_blk_status(self.0.get()) } }
/// Returns the error encoded as a pointer. @@ -137,7 +156,7 @@ pub fn to_ptr<T>(self) -> *mut T { #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. unsafe { - bindings::ERR_PTR(self.0.into()) as *mut _ + bindings::ERR_PTR(self.0.get().into()) as *mut _ } }
@@ -145,7 +164,7 @@ pub fn to_ptr<T>(self) -> *mut T { #[cfg(not(testlib))] pub fn name(&self) -> Option<&'static CStr> { // SAFETY: Just an FFI call, there are no extra safety requirements. - let ptr = unsafe { bindings::errname(-self.0) }; + let ptr = unsafe { bindings::errname(-self.0.get()) }; if ptr.is_null() { None } else {
From: Danilo Krummrich dakr@kernel.org
commit b7a084ba4fbb8f416ce8d19c93a3a2bee63c9c89 upstream.
Add a kernel specific `Allocator` trait, that in contrast to the one in Rust's core library doesn't require unstable features and supports GFP flags.
Subsequent patches add the following trait implementors: `Kmalloc`, `Vmalloc` and `KVmalloc`.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-2-dakr@kernel.org [ Fixed typo. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 1966bd407017..998779cc6976 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -11,6 +11,7 @@ /// Indicates an allocation error. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; +use core::{alloc::Layout, ptr::NonNull};
/// Flags to be used when allocating memory. /// @@ -86,3 +87,103 @@ pub mod flags { /// small allocations. pub const GFP_NOWAIT: Flags = Flags(bindings::GFP_NOWAIT); } + +/// 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)) }; + } +}
From: Danilo Krummrich dakr@kernel.org
commit a654a6e09644266e38ac05415ef7737d299c4497 upstream.
Separate `aligned_size` from `krealloc_aligned`.
Subsequent patches implement `Allocator` derivates, such as `Kmalloc`, that require `aligned_size` and replace the original `krealloc_aligned`.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-3-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc/allocator.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index 91216b36af69..765f72d5bc21 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -8,6 +8,17 @@
struct KernelAllocator;
+/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. +fn aligned_size(new_layout: Layout) -> usize { + // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. + let layout = new_layout.pad_to_align(); + + // 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). + layout.size() +} + /// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment. /// /// # Safety @@ -15,13 +26,7 @@ /// - `ptr` can be either null or a pointer which has been allocated by this allocator. /// - `new_layout` must have a non-zero size. pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *mut u8 { - // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. - let layout = new_layout.pad_to_align(); - - // 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(); + let size = aligned_size(new_layout);
// SAFETY: // - `ptr` is either null or a pointer returned from a previous `k{re}alloc()` by the
From: Danilo Krummrich dakr@kernel.org
commit 941e65531446c1eb5d573c5d30172117ebe96112 upstream.
Subsequent patches implement `Vmalloc` and `KVmalloc` allocators, hence align `KernelAllocator` to this naming scheme.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-4-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc/allocator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index 765f72d5bc21..3b1c735ba409 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -6,7 +6,7 @@ use core::alloc::{GlobalAlloc, Layout}; use core::ptr;
-struct KernelAllocator; +struct Kmalloc;
/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. fn aligned_size(new_layout: Layout) -> usize { @@ -37,7 +37,7 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F }
// SAFETY: TODO. -unsafe impl GlobalAlloc for KernelAllocator { +unsafe impl GlobalAlloc for Kmalloc { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety // requirement. @@ -74,7 +74,7 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { }
#[global_allocator] -static ALLOCATOR: KernelAllocator = KernelAllocator; +static ALLOCATOR: Kmalloc = Kmalloc;
// See https://github.com/rust-lang/rust/pull/86844. #[no_mangle]
From: Danilo Krummrich dakr@kernel.org
commit 8a799831fc63c988eec90d334fdd68ff5f2c7eb5 upstream.
`ReallocFunc` is an abstraction for the kernel's realloc derivates, such as `krealloc`, `vrealloc` and `kvrealloc`.
All of the named functions share the same function signature and implement the same semantics. The `ReallocFunc` abstractions provides a generalized wrapper around those, to trivialize the implementation of `Kmalloc`, `Vmalloc` and `KVmalloc` in subsequent patches.
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-5-dakr@kernel.org [ Added temporary `allow(dead_code)` for `dangling_from_layout` to clean warning in `rusttest` target as discussed in the list (but it is needed earlier, i.e. in this patch already). Added colon. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 9 +++++ rust/kernel/alloc/allocator.rs | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 998779cc6976..95d402feb6ff 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -187,3 +187,12 @@ unsafe fn free(ptr: NonNull<u8>, layout: Layout) { let _ = unsafe { Self::realloc(Some(ptr), Layout::new::<()>(), layout, Flags(0)) }; } } + +#[allow(dead_code)] +/// 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) } +} diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index 3b1c735ba409..9ed122401e8a 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -1,10 +1,20 @@ // SPDX-License-Identifier: GPL-2.0
//! Allocator support. +//! +//! Documentation for the kernel's memory allocators can found in the "Memory Allocation Guide" +//! linked below. For instance, this includes the concept of "get free page" (GFP) flags and the +//! typical application of the different kernel allocators. +//! +//! Reference: https://docs.kernel.org/core-api/memory-allocation.html
use super::{flags::*, Flags}; use core::alloc::{GlobalAlloc, Layout}; use core::ptr; +use core::ptr::NonNull; + +use crate::alloc::AllocError; +use crate::bindings;
struct Kmalloc;
@@ -36,6 +46,66 @@ pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: F unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 } }
+/// # Invariants +/// +/// One of the following: `krealloc`, `vrealloc`, `kvrealloc`. +struct ReallocFunc( + unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void, +); + +#[expect(dead_code)] +impl ReallocFunc { + /// # Safety + /// + /// This method has the same safety requirements as [`Allocator::realloc`]. + /// + /// # Guarantees + /// + /// This method has the same guarantees as `Allocator::realloc`. Additionally + /// - it accepts any pointer to a valid memory allocation allocated by this function. + /// - memory allocated by this function remains valid until it is passed to this function. + unsafe fn call( + &self, + ptr: Option<NonNull<u8>>, + layout: Layout, + old_layout: Layout, + flags: Flags, + ) -> Result<NonNull<[u8]>, AllocError> { + let size = aligned_size(layout); + let ptr = match ptr { + Some(ptr) => { + if old_layout.size() == 0 { + ptr::null() + } else { + ptr.as_ptr() + } + } + None => ptr::null(), + }; + + // SAFETY: + // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that + // `ptr` is NULL or valid. + // - `ptr` is either NULL or valid by the safety requirements of this function. + // + // GUARANTEE: + // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`. + // - 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).cast() + }; + + let ptr = if size == 0 { + crate::alloc::dangling_from_layout(layout) + } else { + NonNull::new(raw_ptr).ok_or(AllocError)? + }; + + Ok(NonNull::slice_from_raw_parts(ptr, size)) + } +} + // SAFETY: TODO. unsafe impl GlobalAlloc for Kmalloc { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
From: Danilo Krummrich dakr@kernel.org
commit a87a36f0bf517dae22f3e3790b05c979070f776a upstream.
Subsequent patches implement allocators such as `Kmalloc`, `Vmalloc`, `KVmalloc`; we need them to be available outside of the kernel crate as well.
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-6-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 95d402feb6ff..2203852c3712 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -4,7 +4,7 @@
#[cfg(not(test))] #[cfg(not(testlib))] -mod allocator; +pub mod allocator; pub mod box_ext; pub mod vec_ext;
From: Danilo Krummrich dakr@kernel.org
commit a34822d1c4c93085f635b922441a017bd7e959b0 upstream.
Implement `Allocator` for `Kmalloc`, the kernel's default allocator, typically used for objects smaller than page size.
All memory allocations made with `Kmalloc` end up in `krealloc()`.
It serves as allocator for the subsequently introduced types `KBox` and `KVec`.
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-7-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc/allocator.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index 9ed122401e8a..272c581e24a0 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -13,10 +13,16 @@ use core::ptr; use core::ptr::NonNull;
-use crate::alloc::AllocError; +use crate::alloc::{AllocError, Allocator}; use crate::bindings;
-struct Kmalloc; +/// The contiguous kernel allocator. +/// +/// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also +/// supports larger allocations up to `bindings::KMALLOC_MAX_SIZE`, which is hardware specific. +/// +/// For more details see [self]. +pub struct Kmalloc;
/// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. fn aligned_size(new_layout: Layout) -> usize { @@ -53,8 +59,10 @@ struct ReallocFunc( unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void, );
-#[expect(dead_code)] impl ReallocFunc { + // INVARIANT: `krealloc` satisfies the type invariants. + const KREALLOC: Self = Self(bindings::krealloc); + /// # Safety /// /// This method has the same safety requirements as [`Allocator::realloc`]. @@ -106,6 +114,23 @@ unsafe fn call( } }
+// SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that +// - memory remains valid until it is explicitly freed, +// - 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 { + #[inline] + unsafe fn realloc( + ptr: Option<NonNull<u8>>, + layout: Layout, + old_layout: Layout, + flags: Flags, + ) -> Result<NonNull<[u8]>, AllocError> { + // SAFETY: `ReallocFunc::call` has the same safety requirements as `Allocator::realloc`. + unsafe { ReallocFunc::KREALLOC.call(ptr, layout, old_layout, flags) } + } +} + // SAFETY: TODO. unsafe impl GlobalAlloc for Kmalloc { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
From: Danilo Krummrich dakr@kernel.org
commit 5a888c28e3b4ff6f54a53fca33951537d135e7f1 upstream.
`Allocator`s, such as `Kmalloc`, will be used by e.g. `Box` and `Vec` in subsequent patches, and hence this dependency propagates throughout the whole kernel.
Add the `allocator_test` module that provides an empty implementation for all `Allocator`s in the kernel, such that we don't break the `rusttest` make target in subsequent patches.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-8-dakr@kernel.org [ Added missing `_old_layout` parameter as discussed. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 9 +++++++-- rust/kernel/alloc/allocator_test.rs | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 rust/kernel/alloc/allocator_test.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 2203852c3712..b5605aab182d 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -2,12 +2,17 @@
//! Extensions to the [`alloc`] crate.
-#[cfg(not(test))] -#[cfg(not(testlib))] +#[cfg(not(any(test, testlib)))] pub mod allocator; pub mod box_ext; pub mod vec_ext;
+#[cfg(any(test, testlib))] +pub mod allocator_test; + +#[cfg(any(test, testlib))] +pub use self::allocator_test as allocator; + /// Indicates an allocation error. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs new file mode 100644 index 000000000000..c5d325506f0c --- /dev/null +++ b/rust/kernel/alloc/allocator_test.rs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +#![allow(missing_docs)] + +use super::{AllocError, Allocator, Flags}; +use core::alloc::Layout; +use core::ptr::NonNull; + +pub struct Kmalloc; + +unsafe impl Allocator for Kmalloc { + unsafe fn realloc( + _ptr: Option<NonNull<u8>>, + _layout: Layout, + _old_layout: Layout, + _flags: Flags, + ) -> Result<NonNull<[u8]>, AllocError> { + panic!(); + } +}
From: Danilo Krummrich dakr@kernel.org
commit 61c004781d6b928443052e7a6cf84b35d4f61401 upstream.
Implement `Allocator` for `Vmalloc`, the kernel's virtually contiguous allocator, typically used for larger objects, (much) larger than page size.
All memory allocations made with `Vmalloc` end up in `vrealloc()`.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-9-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/helpers/helpers.c | 1 + rust/helpers/vmalloc.c | 9 +++++++ rust/kernel/alloc/allocator.rs | 37 +++++++++++++++++++++++++++++ rust/kernel/alloc/allocator_test.rs | 1 + 4 files changed, 48 insertions(+) create mode 100644 rust/helpers/vmalloc.c
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 30f40149f3a9..20a0c69d5cc7 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -22,5 +22,6 @@ #include "spinlock.c" #include "task.c" #include "uaccess.c" +#include "vmalloc.c" #include "wait.c" #include "workqueue.c" diff --git a/rust/helpers/vmalloc.c b/rust/helpers/vmalloc.c new file mode 100644 index 000000000000..80d34501bbc0 --- /dev/null +++ b/rust/helpers/vmalloc.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/vmalloc.h> + +void * __must_check __realloc_size(2) +rust_helper_vrealloc(const void *p, size_t size, gfp_t flags) +{ + return vrealloc(p, size, flags); +} diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index 272c581e24a0..ee4c828cbd58 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -15,6 +15,7 @@
use crate::alloc::{AllocError, Allocator}; use crate::bindings; +use crate::pr_warn;
/// The contiguous kernel allocator. /// @@ -24,6 +25,15 @@ /// For more details see [self]. pub struct Kmalloc;
+/// The virtually contiguous kernel allocator. +/// +/// `Vmalloc` allocates pages from the page level allocator and maps them into the contiguous kernel +/// virtual space. It is typically used for large allocations. The memory allocated with this +/// allocator is not physically contiguous. +/// +/// For more details see [self]. +pub struct Vmalloc; + /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. fn aligned_size(new_layout: Layout) -> usize { // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. @@ -63,6 +73,9 @@ impl ReallocFunc { // INVARIANT: `krealloc` satisfies the type invariants. const KREALLOC: Self = Self(bindings::krealloc);
+ // INVARIANT: `vrealloc` satisfies the type invariants. + const VREALLOC: Self = Self(bindings::vrealloc); + /// # Safety /// /// This method has the same safety requirements as [`Allocator::realloc`]. @@ -168,6 +181,30 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { } }
+// SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that +// - memory remains valid until it is explicitly freed, +// - 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 { + #[inline] + unsafe fn realloc( + ptr: Option<NonNull<u8>>, + layout: Layout, + old_layout: Layout, + flags: Flags, + ) -> 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) } + } +} + #[global_allocator] static ALLOCATOR: Kmalloc = Kmalloc;
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index c5d325506f0c..32a1450c4d39 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -7,6 +7,7 @@ use core::ptr::NonNull;
pub struct Kmalloc; +pub type Vmalloc = Kmalloc;
unsafe impl Allocator for Kmalloc { unsafe fn realloc(
From: Danilo Krummrich dakr@kernel.org
commit 8362c2608ba1be635ffa22a256dfcfe51c6238cc upstream.
Implement `Allocator` for `KVmalloc`, an `Allocator` that tries to allocate memory with `kmalloc` first and, on failure, falls back to `vmalloc`.
All memory allocations made with `KVmalloc` end up in `kvrealloc_noprof()`; all frees in `kvfree()`.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-10-dakr@kernel.org [ Reworded typo. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/helpers/slab.c | 6 +++++ rust/kernel/alloc/allocator.rs | 36 +++++++++++++++++++++++++++++ rust/kernel/alloc/allocator_test.rs | 1 + 3 files changed, 43 insertions(+)
diff --git a/rust/helpers/slab.c b/rust/helpers/slab.c index f043e087f9d6..a842bfbddcba 100644 --- a/rust/helpers/slab.c +++ b/rust/helpers/slab.c @@ -7,3 +7,9 @@ rust_helper_krealloc(const void *objp, size_t new_size, gfp_t flags) { return krealloc(objp, new_size, flags); } + +void * __must_check __realloc_size(2) +rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags) +{ + return kvrealloc(p, size, flags); +} diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index ee4c828cbd58..f8a1f0feb25d 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -34,6 +34,15 @@ /// For more details see [self]. pub struct Vmalloc;
+/// The kvmalloc kernel allocator. +/// +/// `KVmalloc` attempts to allocate memory with `Kmalloc` first, but falls back to `Vmalloc` upon +/// failure. This allocator is typically used when the size for the requested allocation is not +/// known and may exceed the capabilities of `Kmalloc`. +/// +/// For more details see [self]. +pub struct KVmalloc; + /// Returns a proper size to alloc a new object aligned to `new_layout`'s alignment. fn aligned_size(new_layout: Layout) -> usize { // Customized layouts from `Layout::from_size_align()` can have size < align, so pad first. @@ -76,6 +85,9 @@ impl ReallocFunc { // INVARIANT: `vrealloc` satisfies the type invariants. const VREALLOC: Self = Self(bindings::vrealloc);
+ // INVARIANT: `kvrealloc` satisfies the type invariants. + const KVREALLOC: Self = Self(bindings::kvrealloc); + /// # Safety /// /// This method has the same safety requirements as [`Allocator::realloc`]. @@ -205,6 +217,30 @@ unsafe fn realloc( } }
+// SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that +// - memory remains valid until it is explicitly freed, +// - 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 { + #[inline] + unsafe fn realloc( + ptr: Option<NonNull<u8>>, + layout: Layout, + old_layout: Layout, + flags: Flags, + ) -> Result<NonNull<[u8]>, AllocError> { + // 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) } + } +} + #[global_allocator] static ALLOCATOR: Kmalloc = Kmalloc;
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index 32a1450c4d39..bd0cbcd93e52 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -8,6 +8,7 @@
pub struct Kmalloc; pub type Vmalloc = Kmalloc; +pub type KVmalloc = Kmalloc;
unsafe impl Allocator for Kmalloc { unsafe fn realloc(
From: Danilo Krummrich dakr@kernel.org
commit 01b2196e5aac8af9343282d0044fa0d6b07d484c upstream.
Some test cases in subsequent patches provoke allocation failures. Add `__GFP_NOWARN` to enable test cases to silence unpleasant warnings.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-11-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/bindings/bindings_helper.h | 1 + rust/kernel/alloc.rs | 5 +++++ 2 files changed, 6 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index ae82e9c941af..a80783fcbe04 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -31,4 +31,5 @@ const gfp_t RUST_CONST_HELPER_GFP_KERNEL_ACCOUNT = GFP_KERNEL_ACCOUNT; const gfp_t RUST_CONST_HELPER_GFP_NOWAIT = GFP_NOWAIT; const gfp_t RUST_CONST_HELPER___GFP_ZERO = __GFP_ZERO; const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM = ___GFP_HIGHMEM; +const gfp_t RUST_CONST_HELPER___GFP_NOWARN = ___GFP_NOWARN; const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL; diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index b5605aab182d..8172106a1423 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -91,6 +91,11 @@ pub mod flags { /// 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); + + /// Suppresses allocation failure reports. + /// + /// This is normally or'd with other flags. + pub const __GFP_NOWARN: Flags = Flags(bindings::__GFP_NOWARN); }
/// The kernel's [`Allocator`] trait.
From: Danilo Krummrich dakr@kernel.org
commit c8cfa8d0c0b10be216861fe904ea68978b1dcc97 upstream.
`Box` provides the simplest way to allocate memory for a generic type with one of the kernel's allocators, e.g. `Kmalloc`, `Vmalloc` or `KVmalloc`.
In contrast to Rust's `Box` type, the kernel `Box` type considers the kernel's GFP flags for all appropriate functions, always reports allocation failures through `Result<_, AllocError>` and remains independent from unstable features.
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-12-dakr@kernel.org [ Added backticks, fixed typos. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 6 + rust/kernel/alloc/kbox.rs | 456 ++++++++++++++++++++++++++++++++++++++ rust/kernel/prelude.rs | 2 +- 3 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/alloc/kbox.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 8172106a1423..3628e16240a6 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -5,6 +5,7 @@ #[cfg(not(any(test, testlib)))] pub mod allocator; pub mod box_ext; +pub mod kbox; pub mod vec_ext;
#[cfg(any(test, testlib))] @@ -13,6 +14,11 @@ #[cfg(any(test, testlib))] pub use self::allocator_test as allocator;
+pub use self::kbox::Box; +pub use self::kbox::KBox; +pub use self::kbox::KVBox; +pub use self::kbox::VBox; + /// Indicates an allocation error. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs new file mode 100644 index 000000000000..d69c32496b86 --- /dev/null +++ b/rust/kernel/alloc/kbox.rs @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Implementation of [`Box`]. + +#[allow(unused_imports)] // Used in doc comments. +use super::allocator::{KVmalloc, Kmalloc, Vmalloc}; +use super::{AllocError, Allocator, Flags}; +use core::alloc::Layout; +use core::fmt; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr::NonNull; +use core::result::Result; + +use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit}; +use crate::types::ForeignOwnable; + +/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`. +/// +/// This is the kernel's version of the Rust stdlib's `Box`. There are several differences, +/// for example no `noalias` attribute is emitted and partially moving out of a `Box` is not +/// supported. There are also several API differences, e.g. `Box` always requires an [`Allocator`] +/// implementation to be passed as generic, page [`Flags`] when allocating memory and all functions +/// that may allocate memory are fallible. +/// +/// `Box` works with any of the kernel's allocators, e.g. [`Kmalloc`], [`Vmalloc`] or [`KVmalloc`]. +/// There are aliases for `Box` with these allocators ([`KBox`], [`VBox`], [`KVBox`]). +/// +/// When dropping a [`Box`], the value is also dropped and the heap memory is automatically freed. +/// +/// # Examples +/// +/// ``` +/// let b = KBox::<u64>::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +/// +/// ``` +/// # use kernel::bindings; +/// const SIZE: usize = bindings::KMALLOC_MAX_SIZE as usize + 1; +/// struct Huge([u8; SIZE]); +/// +/// assert!(KBox::<Huge>::new_uninit(GFP_KERNEL | __GFP_NOWARN).is_err()); +/// ``` +/// +/// ``` +/// # use kernel::bindings; +/// const SIZE: usize = bindings::KMALLOC_MAX_SIZE as usize + 1; +/// struct Huge([u8; SIZE]); +/// +/// assert!(KVBox::<Huge>::new_uninit(GFP_KERNEL).is_ok()); +/// ``` +/// +/// # Invariants +/// +/// `self.0` is always properly aligned and either points to memory allocated with `A` or, for +/// zero-sized types, is a dangling, well aligned pointer. +#[repr(transparent)] +pub struct Box<T: ?Sized, A: Allocator>(NonNull<T>, PhantomData<A>); + +/// Type alias for [`Box`] with a [`Kmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = KBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type KBox<T> = Box<T, super::allocator::Kmalloc>; + +/// Type alias for [`Box`] with a [`Vmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = VBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type VBox<T> = Box<T, super::allocator::Vmalloc>; + +/// Type alias for [`Box`] with a [`KVmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = KVBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type KVBox<T> = Box<T, super::allocator::KVmalloc>; + +// SAFETY: `Box` is `Send` if `T` is `Send` because the `Box` owns a `T`. +unsafe impl<T, A> Send for Box<T, A> +where + T: Send + ?Sized, + A: Allocator, +{ +} + +// SAFETY: `Box` is `Sync` if `T` is `Sync` because the `Box` owns a `T`. +unsafe impl<T, A> Sync for Box<T, A> +where + T: Sync + ?Sized, + A: Allocator, +{ +} + +impl<T, A> Box<T, A> +where + T: ?Sized, + A: Allocator, +{ + /// Creates a new `Box<T, A>` from a raw pointer. + /// + /// # Safety + /// + /// For non-ZSTs, `raw` must point at an allocation allocated with `A` that is sufficiently + /// aligned for and holds a valid `T`. The caller passes ownership of the allocation to the + /// `Box`. + /// + /// For ZSTs, `raw` must be a dangling, well aligned pointer. + #[inline] + pub const unsafe fn from_raw(raw: *mut T) -> Self { + // INVARIANT: Validity of `raw` is guaranteed by the safety preconditions of this function. + // SAFETY: By the safety preconditions of this function, `raw` is not a NULL pointer. + Self(unsafe { NonNull::new_unchecked(raw) }, PhantomData) + } + + /// Consumes the `Box<T, A>` and returns a raw pointer. + /// + /// This will not run the destructor of `T` and for non-ZSTs the allocation will stay alive + /// indefinitely. Use [`Box::from_raw`] to recover the [`Box`], drop the value and free the + /// allocation, if any. + /// + /// # Examples + /// + /// ``` + /// let x = KBox::new(24, GFP_KERNEL)?; + /// let ptr = KBox::into_raw(x); + /// // SAFETY: `ptr` comes from a previous call to `KBox::into_raw`. + /// let x = unsafe { KBox::from_raw(ptr) }; + /// + /// assert_eq!(*x, 24); + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + pub fn into_raw(b: Self) -> *mut T { + ManuallyDrop::new(b).0.as_ptr() + } + + /// Consumes and leaks the `Box<T, A>` and returns a mutable reference. + /// + /// See [`Box::into_raw`] for more details. + #[inline] + pub fn leak<'a>(b: Self) -> &'a mut T { + // SAFETY: `Box::into_raw` always returns a properly aligned and dereferenceable pointer + // which points to an initialized instance of `T`. + unsafe { &mut *Box::into_raw(b) } + } +} + +impl<T, A> Box<MaybeUninit<T>, A> +where + A: Allocator, +{ + /// Converts a `Box<MaybeUninit<T>, A>` to a `Box<T, A>`. + /// + /// It is undefined behavior to call this function while the value inside of `b` is not yet + /// fully initialized. + /// + /// # Safety + /// + /// Callers must ensure that the value inside of `b` is in an initialized state. + pub unsafe fn assume_init(self) -> Box<T, A> { + let raw = Self::into_raw(self); + + // SAFETY: `raw` comes from a previous call to `Box::into_raw`. By the safety requirements + // of this function, the value inside the `Box` is in an initialized state. Hence, it is + // safe to reconstruct the `Box` as `Box<T, A>`. + unsafe { Box::from_raw(raw.cast()) } + } + + /// Writes the value and converts to `Box<T, A>`. + pub fn write(mut self, value: T) -> Box<T, A> { + (*self).write(value); + + // SAFETY: We've just initialized `b`'s value. + unsafe { self.assume_init() } + } +} + +impl<T, A> Box<T, A> +where + A: Allocator, +{ + /// Creates a new `Box<T, A>` and initializes its contents with `x`. + /// + /// New memory is allocated with `A`. The allocation may fail, in which case an error is + /// returned. For ZSTs no memory is allocated. + pub fn new(x: T, flags: Flags) -> Result<Self, AllocError> { + let b = Self::new_uninit(flags)?; + Ok(Box::write(b, x)) + } + + /// Creates a new `Box<T, A>` with uninitialized contents. + /// + /// New memory is allocated with `A`. The allocation may fail, in which case an error is + /// returned. For ZSTs no memory is allocated. + /// + /// # Examples + /// + /// ``` + /// let b = KBox::<u64>::new_uninit(GFP_KERNEL)?; + /// let b = KBox::write(b, 24); + /// + /// assert_eq!(*b, 24_u64); + /// # Ok::<(), Error>(()) + /// ``` + pub fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>, A>, AllocError> { + let layout = Layout::new::<MaybeUninit<T>>(); + let ptr = A::alloc(layout, flags)?; + + // INVARIANT: `ptr` is either a dangling pointer or points to memory allocated with `A`, + // which is sufficient in size and alignment for storing a `T`. + Ok(Box(ptr.cast(), PhantomData)) + } + + /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then `x` will be + /// pinned in memory and can't be moved. + #[inline] + pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError> + where + A: 'static, + { + Ok(Self::new(x, flags)?.into()) + } + + /// Forgets the contents (does not run the destructor), but keeps the allocation. + fn forget_contents(this: Self) -> Box<MaybeUninit<T>, A> { + let ptr = Self::into_raw(this); + + // SAFETY: `ptr` is valid, because it came from `Box::into_raw`. + unsafe { Box::from_raw(ptr.cast()) } + } + + /// Drops the contents, but keeps the allocation. + /// + /// # Examples + /// + /// ``` + /// let value = KBox::new([0; 32], GFP_KERNEL)?; + /// assert_eq!(*value, [0; 32]); + /// let value = KBox::drop_contents(value); + /// // Now we can re-use `value`: + /// let value = KBox::write(value, [1; 32]); + /// assert_eq!(*value, [1; 32]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn drop_contents(this: Self) -> Box<MaybeUninit<T>, A> { + let ptr = this.0.as_ptr(); + + // SAFETY: `ptr` is valid, because it came from `this`. After this call we never access the + // value stored in `this` again. + unsafe { core::ptr::drop_in_place(ptr) }; + + Self::forget_contents(this) + } + + /// Moves the `Box`'s value out of the `Box` and consumes the `Box`. + pub fn into_inner(b: Self) -> T { + // SAFETY: By the type invariant `&*b` is valid for `read`. + let value = unsafe { core::ptr::read(&*b) }; + let _ = Self::forget_contents(b); + value + } +} + +impl<T, A> From<Box<T, A>> for Pin<Box<T, A>> +where + T: ?Sized, + A: Allocator, +{ + /// Converts a `Box<T, A>` into a `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then + /// `*b` will be pinned in memory and can't be moved. + /// + /// This moves `b` into `Pin` without moving `*b` or allocating and copying any memory. + fn from(b: Box<T, A>) -> Self { + // SAFETY: The value wrapped inside a `Pin<Box<T, A>>` cannot be moved or replaced as long + // as `T` does not implement `Unpin`. + unsafe { Pin::new_unchecked(b) } + } +} + +impl<T, A> InPlaceWrite<T> for Box<MaybeUninit<T>, A> +where + A: Allocator + 'static, +{ + type Initialized = Box<T, A>; + + fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid. + unsafe { init.__init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { Box::assume_init(self) }) + } + + fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<PinSelf::Initialized, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { Box::assume_init(self) }.into()) + } +} + +impl<T, A> InPlaceInit<T> for Box<T, A> +where + A: Allocator + 'static, +{ + type PinnedSelf = Pin<Self>; + + #[inline] + fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E> + where + E: From<AllocError>, + { + Box::<_, A>::new_uninit(flags)?.write_pin_init(init) + } + + #[inline] + fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> + where + E: From<AllocError>, + { + Box::<_, A>::new_uninit(flags)?.write_init(init) + } +} + +impl<T: 'static, A> ForeignOwnable for Box<T, A> +where + A: Allocator, +{ + type Borrowed<'a> = &'a T; + + fn into_foreign(self) -> *const core::ffi::c_void { + Box::into_raw(self) as _ + } + + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + unsafe { Box::from_raw(ptr as _) } + } + + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T { + // SAFETY: The safety requirements of this method ensure that the object remains alive and + // immutable for the duration of 'a. + unsafe { &*ptr.cast() } + } +} + +impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> +where + A: Allocator, +{ + type Borrowed<'a> = Pin<&'a T>; + + fn into_foreign(self) -> *const core::ffi::c_void { + // SAFETY: We are still treating the box as pinned. + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ + } + + unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } + } + + unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Pin<&'a T> { + // SAFETY: The safety requirements for this function ensure that the object is still alive, + // so it is safe to dereference the raw pointer. + // The safety requirements of `from_foreign` also ensure that the object remains alive for + // the lifetime of the returned value. + let r = unsafe { &*ptr.cast() }; + + // SAFETY: This pointer originates from a `Pin<Box<T>>`. + unsafe { Pin::new_unchecked(r) } + } +} + +impl<T, A> Deref for Box<T, A> +where + T: ?Sized, + A: Allocator, +{ + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized + // instance of `T`. + unsafe { self.0.as_ref() } + } +} + +impl<T, A> DerefMut for Box<T, A> +where + T: ?Sized, + A: Allocator, +{ + fn deref_mut(&mut self) -> &mut T { + // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized + // instance of `T`. + unsafe { self.0.as_mut() } + } +} + +impl<T, A> fmt::Debug for Box<T, A> +where + T: ?Sized + fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<T, A> Drop for Box<T, A> +where + T: ?Sized, + A: Allocator, +{ + fn drop(&mut self) { + let layout = Layout::for_value::<T>(self); + + // SAFETY: The pointer in `self.0` is guaranteed to be valid by the type invariant. + unsafe { core::ptr::drop_in_place::<T>(self.deref_mut()) }; + + // SAFETY: + // - `self.0` was previously allocated with `A`. + // - `layout` is equal to the `Layout´ `self.0` was allocated with. + unsafe { A::free(self.0.cast(), layout) }; + } +} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 4571daec0961..a9210634a8c3 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,7 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt}; +pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
#[doc(no_inline)] pub use alloc::{boxed::Box, vec::Vec};
From: Danilo Krummrich dakr@kernel.org
commit 8373147ce4961665c5700016b1c76299e962d077 upstream.
Now that we got the kernel `Box` type in place, convert all existing `Box` users to make use of it.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-13-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/block/rnull.rs | 4 +-- rust/kernel/init.rs | 51 ++++++++++++++++--------------- rust/kernel/init/__internal.rs | 2 +- rust/kernel/rbtree.rs | 49 ++++++++++++++++------------- rust/kernel/sync/arc.rs | 17 +++++------ rust/kernel/sync/condvar.rs | 4 +-- rust/kernel/sync/lock/mutex.rs | 2 +- rust/kernel/sync/lock/spinlock.rs | 2 +- rust/kernel/workqueue.rs | 20 ++++++------ rust/macros/lib.rs | 6 ++-- 10 files changed, 81 insertions(+), 76 deletions(-)
diff --git a/drivers/block/rnull.rs b/drivers/block/rnull.rs index b0227cf9ddd3..5de7223beb4d 100644 --- a/drivers/block/rnull.rs +++ b/drivers/block/rnull.rs @@ -32,7 +32,7 @@ }
struct NullBlkModule { - _disk: Pin<Box<Mutex<GenDisk<NullBlkDevice>>>>, + _disk: Pin<KBox<Mutex<GenDisk<NullBlkDevice>>>>, }
impl kernel::Module for NullBlkModule { @@ -47,7 +47,7 @@ fn init(_module: &'static ThisModule) -> Result<Self> { .rotational(false) .build(format_args!("rnullb{}", 0), tagset)?;
- let disk = Box::pin_init(new_mutex!(disk, "nullb:disk"), flags::GFP_KERNEL)?; + let disk = KBox::pin_init(new_mutex!(disk, "nullb:disk"), flags::GFP_KERNEL)?;
Ok(Self { _disk: disk }) } diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 44e829b61243..9b63fd8e82da 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -13,7 +13,7 @@ //! To initialize a `struct` with an in-place constructor you will need two things: //! - an in-place constructor, //! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`], -//! [`UniqueArc<T>`], [`Box<T>`] or any other smart pointer that implements [`InPlaceInit`]). +//! [`UniqueArc<T>`], [`KBox<T>`] or any other smart pointer that implements [`InPlaceInit`]). //! //! To get an in-place constructor there are generally three options: //! - directly creating an in-place constructor using the [`pin_init!`] macro, @@ -68,7 +68,7 @@ //! # a <- new_mutex!(42, "Foo::a"), //! # b: 24, //! # }); -//! let foo: Result<Pin<Box<Foo>>> = Box::pin_init(foo, GFP_KERNEL); +//! let foo: Result<Pin<KBox<Foo>>> = KBox::pin_init(foo, GFP_KERNEL); //! ``` //! //! For more information see the [`pin_init!`] macro. @@ -92,14 +92,14 @@ //! struct DriverData { //! #[pin] //! status: Mutex<i32>, -//! buffer: Box<[u8; 1_000_000]>, +//! buffer: KBox<[u8; 1_000_000]>, //! } //! //! impl DriverData { //! fn new() -> impl PinInit<Self, Error> { //! try_pin_init!(Self { //! status <- new_mutex!(0, "DriverData::status"), -//! buffer: Box::init(kernel::init::zeroed(), GFP_KERNEL)?, +//! buffer: KBox::init(kernel::init::zeroed(), GFP_KERNEL)?, //! }) //! } //! } @@ -211,7 +211,7 @@ //! [`pin_init!`]: crate::pin_init!
use crate::{ - alloc::{box_ext::BoxExt, AllocError, Flags}, + alloc::{box_ext::BoxExt, AllocError, Flags, KBox}, error::{self, Error}, sync::Arc, sync::UniqueArc, @@ -298,7 +298,7 @@ macro_rules! stack_pin_init { /// struct Foo { /// #[pin] /// a: Mutex<usize>, -/// b: Box<Bar>, +/// b: KBox<Bar>, /// } /// /// struct Bar { @@ -307,7 +307,7 @@ macro_rules! stack_pin_init { /// /// stack_try_pin_init!(let foo: Result<Pin<&mut Foo>, AllocError> = pin_init!(Foo { /// a <- new_mutex!(42), -/// b: Box::new(Bar { +/// b: KBox::new(Bar { /// x: 64, /// }, GFP_KERNEL)?, /// })); @@ -324,7 +324,7 @@ macro_rules! stack_pin_init { /// struct Foo { /// #[pin] /// a: Mutex<usize>, -/// b: Box<Bar>, +/// b: KBox<Bar>, /// } /// /// struct Bar { @@ -333,7 +333,7 @@ macro_rules! stack_pin_init { /// /// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo { /// a <- new_mutex!(42), -/// b: Box::new(Bar { +/// b: KBox::new(Bar { /// x: 64, /// }, GFP_KERNEL)?, /// })); @@ -391,7 +391,7 @@ macro_rules! stack_try_pin_init { /// }, /// }); /// # initializer } -/// # Box::pin_init(demo(), GFP_KERNEL).unwrap(); +/// # KBox::pin_init(demo(), GFP_KERNEL).unwrap(); /// ``` /// /// Arbitrary Rust expressions can be used to set the value of a variable. @@ -460,7 +460,7 @@ macro_rules! stack_try_pin_init { /// # }) /// # } /// # } -/// let foo = Box::pin_init(Foo::new(), GFP_KERNEL); +/// let foo = KBox::pin_init(Foo::new(), GFP_KERNEL); /// ``` /// /// They can also easily embed it into their own `struct`s: @@ -592,7 +592,7 @@ macro_rules! pin_init { /// use kernel::{init::{self, PinInit}, error::Error}; /// #[pin_data] /// struct BigBuf { -/// big: Box<[u8; 1024 * 1024 * 1024]>, +/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// small: [u8; 1024 * 1024], /// ptr: *mut u8, /// } @@ -600,7 +600,7 @@ macro_rules! pin_init { /// impl BigBuf { /// fn new() -> impl PinInit<Self, Error> { /// try_pin_init!(Self { -/// big: Box::init(init::zeroed(), GFP_KERNEL)?, +/// big: KBox::init(init::zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// ptr: core::ptr::null_mut(), /// }? Error) @@ -692,16 +692,16 @@ macro_rules! init { /// # Examples /// /// ```rust -/// use kernel::{init::{PinInit, zeroed}, error::Error}; +/// use kernel::{alloc::KBox, init::{PinInit, zeroed}, error::Error}; /// struct BigBuf { -/// big: Box<[u8; 1024 * 1024 * 1024]>, +/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// small: [u8; 1024 * 1024], /// } /// /// impl BigBuf { /// fn new() -> impl Init<Self, Error> { /// try_init!(Self { -/// big: Box::init(zeroed(), GFP_KERNEL)?, +/// big: KBox::init(zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// }? Error) /// } @@ -812,8 +812,8 @@ macro_rules! assert_pinned { /// A pin-initializer for the type `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the -/// [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this. +/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use +/// the [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this. /// /// Also see the [module description](self). /// @@ -893,7 +893,7 @@ fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E> }
/// An initializer returned by [`PinInit::pin_chain`]. -pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>); +pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, KBox<T>)>);
// SAFETY: The `__pinned_init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -919,8 +919,8 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { /// An initializer for `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the -/// [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because +/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use +/// the [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because /// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well. /// /// Also see the [module description](self). @@ -992,7 +992,7 @@ fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E> }
/// An initializer returned by [`Init::chain`]. -pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>); +pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, KBox<T>)>);
// SAFETY: The `__init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -1076,8 +1076,9 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { /// # Examples /// /// ```rust -/// use kernel::{error::Error, init::init_array_from_fn}; -/// let array: Box<[usize; 1_000]> = Box::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); +/// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn}; +/// let array: KBox<[usize; 1_000]> = +/// KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); /// assert_eq!(array.len(), 1_000); /// ``` pub fn init_array_from_fn<I, const N: usize, T, E>( @@ -1453,7 +1454,7 @@ macro_rules! impl_zeroable { // // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant. {<T: ?Sized>} Option<NonNull<T>>, - {<T: ?Sized>} Option<Box<T>>, + {<T: ?Sized>} Option<KBox<T>>,
// SAFETY: `null` pointer is valid. // diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 44431fba7aab..74329cc3262c 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -105,7 +105,7 @@ fn make_closure<F, O, E>(self, f: F) -> F } }
-pub struct AllData<T: ?Sized>(PhantomData<fn(Box<T>) -> Box<T>>); +pub struct AllData<T: ?Sized>(PhantomData<fn(KBox<T>) -> KBox<T>>);
impl<T: ?Sized> Clone for AllData<T> { fn clone(&self) -> Self { diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index 7543378d3729..571e27efe544 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -7,7 +7,6 @@ //! Reference: https://docs.kernel.org/core-api/rbtree.html
use crate::{alloc::Flags, bindings, container_of, error::Result, prelude::*}; -use alloc::boxed::Box; use core::{ cmp::{Ord, Ordering}, marker::PhantomData, @@ -497,7 +496,7 @@ fn drop(&mut self) { // but it is not observable. The loop invariant is still maintained.
// SAFETY: `this` is valid per the loop invariant. - unsafe { drop(Box::from_raw(this.cast_mut())) }; + unsafe { drop(KBox::from_raw(this.cast_mut())) }; } } } @@ -764,7 +763,7 @@ pub fn remove_current(self) -> (Option<Self>, RBTreeNode<K, V>) { // point to the links field of `Node<K, V>` objects. let this = unsafe { container_of!(self.current.as_ptr(), Node<K, V>, links) }.cast_mut(); // SAFETY: `this` is valid by the type invariants as described above. - let node = unsafe { Box::from_raw(this) }; + let node = unsafe { KBox::from_raw(this) }; let node = RBTreeNode { node }; // SAFETY: The reference to the tree used to create the cursor outlives the cursor, so // the tree cannot change. By the tree invariant, all nodes are valid. @@ -809,7 +808,7 @@ fn remove_neighbor(&mut self, direction: Direction) -> Option<RBTreeNode<K, V>> // point to the links field of `Node<K, V>` objects. let this = unsafe { container_of!(neighbor, Node<K, V>, links) }.cast_mut(); // SAFETY: `this` is valid by the type invariants as described above. - let node = unsafe { Box::from_raw(this) }; + let node = unsafe { KBox::from_raw(this) }; return Some(RBTreeNode { node }); } None @@ -1038,7 +1037,7 @@ fn next(&mut self) -> OptionSelf::Item { /// It contains the memory needed to hold a node that can be inserted into a red-black tree. One /// can be obtained by directly allocating it ([`RBTreeNodeReservation::new`]). pub struct RBTreeNodeReservation<K, V> { - node: Box<MaybeUninit<Node<K, V>>>, + node: KBox<MaybeUninit<Node<K, V>>>, }
impl<K, V> RBTreeNodeReservation<K, V> { @@ -1046,7 +1045,7 @@ impl<K, V> RBTreeNodeReservation<K, V> { /// call to [`RBTree::insert`]. pub fn new(flags: Flags) -> Result<RBTreeNodeReservation<K, V>> { Ok(RBTreeNodeReservation { - node: <Box<_> as BoxExt<_>>::new_uninit(flags)?, + node: KBox::new_uninit(flags)?, }) } } @@ -1062,14 +1061,15 @@ impl<K, V> RBTreeNodeReservation<K, V> { /// Initialises a node reservation. /// /// It then becomes an [`RBTreeNode`] that can be inserted into a tree. - pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> { - self.node.write(Node { - key, - value, - links: bindings::rb_node::default(), - }); - // SAFETY: We just wrote to it. - let node = unsafe { self.node.assume_init() }; + pub fn into_node(self, key: K, value: V) -> RBTreeNode<K, V> { + let node = KBox::write( + self.node, + Node { + key, + value, + links: bindings::rb_node::default(), + }, + ); RBTreeNode { node } } } @@ -1079,7 +1079,7 @@ pub fn into_node(mut self, key: K, value: V) -> RBTreeNode<K, V> { /// The node is fully initialised (with key and value) and can be inserted into a tree without any /// extra allocations or failure paths. pub struct RBTreeNode<K, V> { - node: Box<Node<K, V>>, + node: KBox<Node<K, V>>, }
impl<K, V> RBTreeNode<K, V> { @@ -1091,7 +1091,9 @@ pub fn new(key: K, value: V, flags: Flags) -> Result<RBTreeNode<K, V>> {
/// Get the key and value from inside the node. pub fn to_key_value(self) -> (K, V) { - (self.node.key, self.node.value) + let node = KBox::into_inner(self.node); + + (node.key, node.value) } }
@@ -1113,7 +1115,7 @@ impl<K, V> RBTreeNode<K, V> { /// may be freed (but only for the key/value; memory for the node itself is kept for reuse). pub fn into_reservation(self) -> RBTreeNodeReservation<K, V> { RBTreeNodeReservation { - node: Box::drop_contents(self.node), + node: KBox::drop_contents(self.node), } } } @@ -1164,7 +1166,7 @@ impl<'a, K, V> RawVacantEntry<'a, K, V> { /// The `node` must have a key such that inserting it here does not break the ordering of this /// [`RBTree`]. fn insert(self, node: RBTreeNode<K, V>) -> &'a mut V { - let node = Box::into_raw(node.node); + let node = KBox::into_raw(node.node);
// SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when // the node is removed or replaced. @@ -1238,21 +1240,24 @@ pub fn remove_node(self) -> RBTreeNode<K, V> { // SAFETY: The node was a node in the tree, but we removed it, so we can convert it // back into a box. node: unsafe { - Box::from_raw(container_of!(self.node_links, Node<K, V>, links).cast_mut()) + KBox::from_raw(container_of!(self.node_links, Node<K, V>, links).cast_mut()) }, } }
/// Takes the value of the entry out of the map, and returns it. pub fn remove(self) -> V { - self.remove_node().node.value + let rb_node = self.remove_node(); + let node = KBox::into_inner(rb_node.node); + + node.value }
/// Swap the current node for the provided node. /// /// The key of both nodes must be equal. fn replace(self, node: RBTreeNode<K, V>) -> RBTreeNode<K, V> { - let node = Box::into_raw(node.node); + let node = KBox::into_raw(node.node);
// SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when // the node is removed or replaced. @@ -1268,7 +1273,7 @@ fn replace(self, node: RBTreeNode<K, V>) -> RBTreeNode<K, V> { // - `self.node_ptr` produces a valid pointer to a node in the tree. // - Now that we removed this entry from the tree, we can convert the node to a box. let old_node = - unsafe { Box::from_raw(container_of!(self.node_links, Node<K, V>, links).cast_mut()) }; + unsafe { KBox::from_raw(container_of!(self.node_links, Node<K, V>, links).cast_mut()) };
RBTreeNode { node: old_node } } diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 9325cc5a16a4..db9da352d588 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -17,13 +17,12 @@ //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
use crate::{ - alloc::{box_ext::BoxExt, AllocError, Flags}, + alloc::{AllocError, Flags, KBox}, bindings, init::{self, InPlaceInit, Init, PinInit}, try_init, types::{ForeignOwnable, Opaque}, }; -use alloc::boxed::Box; use core::{ alloc::Layout, fmt, @@ -201,11 +200,11 @@ pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> { data: contents, };
- let inner = <Box<_> as BoxExt<_>>::new(value, flags)?; + let inner = KBox::new(value, flags)?;
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new // `Arc` object. - Ok(unsafe { Self::from_inner(Box::leak(inner).into()) }) + Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) }) } }
@@ -398,8 +397,8 @@ fn drop(&mut self) { if is_zero { // The count reached zero, we must free the memory. // - // SAFETY: The pointer was initialised from the result of `Box::leak`. - unsafe { drop(Box::from_raw(self.ptr.as_ptr())) }; + // SAFETY: The pointer was initialised from the result of `KBox::leak`. + unsafe { drop(KBox::from_raw(self.ptr.as_ptr())) }; } } } @@ -641,7 +640,7 @@ pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> { /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> { // INVARIANT: The refcount is initialised to a non-zero value. - let inner = Box::try_init::<AllocError>( + let inner = KBox::try_init::<AllocError>( try_init!(ArcInner { // SAFETY: There are no safety requirements for this FFI call. refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), @@ -651,8 +650,8 @@ pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> )?; Ok(UniqueArc { // INVARIANT: The newly-created object has a refcount of 1. - // SAFETY: The pointer from the `Box` is valid. - inner: unsafe { Arc::from_inner(Box::leak(inner).into()) }, + // SAFETY: The pointer from the `KBox` is valid. + inner: unsafe { Arc::from_inner(KBox::leak(inner).into()) }, }) } } diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index dec2e5ffc919..a1a29c0bdb3a 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -70,8 +70,8 @@ macro_rules! new_condvar { /// } /// /// /// Allocates a new boxed `Example`. -/// fn new_example() -> Result<Pin<Box<Example>>> { -/// Box::pin_init(pin_init!(Example { +/// fn new_example() -> Result<Pin<KBox<Example>>> { +/// KBox::pin_init(pin_init!(Example { /// value <- new_mutex!(0), /// value_changed <- new_condvar!(), /// }), GFP_KERNEL) diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 30632070ee67..f8f6d530db7d 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -58,7 +58,7 @@ macro_rules! new_mutex { /// } /// /// // Allocate a boxed `Example`. -/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?; +/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?; /// assert_eq!(e.c, 10); /// assert_eq!(e.d.lock().a, 20); /// assert_eq!(e.d.lock().b, 30); diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index ea5c5bc1ce12..a9096a4dc42a 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -56,7 +56,7 @@ macro_rules! new_spinlock { /// } /// /// // Allocate a boxed `Example`. -/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?; +/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?; /// assert_eq!(e.c, 10); /// assert_eq!(e.d.lock().a, 20); /// assert_eq!(e.d.lock().b, 30); diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 10d2bc62e2cf..4d1d2062f6eb 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -216,7 +216,7 @@ pub fn try_spawn<T: 'static + Send + FnOnce()>( func: Some(func), });
- self.enqueue(Box::pin_init(init, flags).map_err(|_| AllocError)?); + self.enqueue(KBox::pin_init(init, flags).map_err(|_| AllocError)?); Ok(()) } } @@ -239,9 +239,9 @@ fn project(self: Pin<&mut Self>) -> &mut Option<T> { }
impl<T: FnOnce()> WorkItem for ClosureWork<T> { - type Pointer = Pin<Box<Self>>; + type Pointer = Pin<KBox<Self>>;
- fn run(mut this: Pin<Box<Self>>) { + fn run(mut this: Pin<KBox<Self>>) { if let Some(func) = this.as_mut().project().take() { (func)() } @@ -297,7 +297,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
/// Defines the method that should be called directly when a work item is executed. /// -/// This trait is implemented by `Pin<Box<T>>` and [`Arc<T>`], and is mainly intended to be +/// This trait is implemented by `Pin<KBox<T>>` and [`Arc<T>`], and is mainly intended to be /// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`] /// instead. The [`run`] method on this trait will usually just perform the appropriate /// `container_of` translation and then call into the [`run`][WorkItem::run] method from the @@ -329,7 +329,7 @@ pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> { /// This trait is used when the `work_struct` field is defined using the [`Work`] helper. pub trait WorkItem<const ID: u64 = 0> { /// The pointer type that this struct is wrapped in. This will typically be `Arc<Self>` or - /// `Pin<Box<Self>>`. + /// `Pin<KBox<Self>>`. type Pointer: WorkItemPointer<ID>;
/// The method that should be called when this work item is executed. @@ -567,7 +567,7 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput }
// SAFETY: TODO. -unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> +unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<KBox<T>> where T: WorkItem<ID, Pointer = Self>, T: HasWork<T, ID>, @@ -578,7 +578,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. let ptr = unsafe { T::work_container_of(ptr) }; // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. - let boxed = unsafe { Box::from_raw(ptr) }; + let boxed = unsafe { KBox::from_raw(ptr) }; // SAFETY: The box was already pinned when it was enqueued. let pinned = unsafe { Pin::new_unchecked(boxed) };
@@ -587,7 +587,7 @@ unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>> }
// SAFETY: TODO. -unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>> +unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<KBox<T>> where T: WorkItem<ID, Pointer = Self>, T: HasWork<T, ID>, @@ -601,9 +601,9 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput // SAFETY: We're not going to move `self` or any of its fields, so its okay to temporarily // remove the `Pin` wrapper. let boxed = unsafe { Pin::into_inner_unchecked(self) }; - let ptr = Box::into_raw(boxed); + let ptr = KBox::into_raw(boxed);
- // SAFETY: Pointers into a `Box` point at a valid value. + // SAFETY: Pointers into a `KBox` point at a valid value. let work_ptr = unsafe { T::raw_get_work(ptr) }; // SAFETY: `raw_get_work` returns a pointer to a valid value. let work_ptr = unsafe { Work::raw_get(work_ptr) }; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 90e2202ba4d5..1f1d3a28032c 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -243,7 +243,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// struct DriverData { /// #[pin] /// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, +/// buf: KBox<[u8; 1024 * 1024]>, /// } /// ``` /// @@ -252,7 +252,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// struct DriverData { /// #[pin] /// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, +/// buf: KBox<[u8; 1024 * 1024]>, /// raw_info: *mut Info, /// } /// @@ -282,7 +282,7 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { /// struct DriverData { /// #[pin] /// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, +/// buf: KBox<[u8; 1024 * 1024]>, /// raw_info: *mut Info, /// } ///
From: Danilo Krummrich dakr@kernel.org
commit e8c6ccdbcaaf31f26c0fffd4073edd0b0147cdc6 upstream.
Now that all existing `Box` users were moved to the kernel `Box` type, remove the `BoxExt` extension and all other related extensions.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-14-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 1 - rust/kernel/alloc/box_ext.rs | 89 ------------------------------------ rust/kernel/init.rs | 46 +------------------ rust/kernel/lib.rs | 1 - rust/kernel/prelude.rs | 4 +- rust/kernel/types.rs | 50 -------------------- 6 files changed, 3 insertions(+), 188 deletions(-) delete mode 100644 rust/kernel/alloc/box_ext.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 3628e16240a6..94f4de5e0cdc 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -4,7 +4,6 @@
#[cfg(not(any(test, testlib)))] pub mod allocator; -pub mod box_ext; pub mod kbox; pub mod vec_ext;
diff --git a/rust/kernel/alloc/box_ext.rs b/rust/kernel/alloc/box_ext.rs deleted file mode 100644 index 7009ad78d4e0..000000000000 --- a/rust/kernel/alloc/box_ext.rs +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Extensions to [`Box`] for fallible allocations. - -use super::{AllocError, Flags}; -use alloc::boxed::Box; -use core::{mem::MaybeUninit, ptr, result::Result}; - -/// Extensions to [`Box`]. -pub trait BoxExt<T>: Sized { - /// Allocates a new box. - /// - /// The allocation may fail, in which case an error is returned. - fn new(x: T, flags: Flags) -> Result<Self, AllocError>; - - /// Allocates a new uninitialised box. - /// - /// The allocation may fail, in which case an error is returned. - fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>; - - /// Drops the contents, but keeps the allocation. - /// - /// # Examples - /// - /// ``` - /// use kernel::alloc::{flags, box_ext::BoxExt}; - /// let value = Box::new([0; 32], flags::GFP_KERNEL)?; - /// assert_eq!(*value, [0; 32]); - /// let mut value = Box::drop_contents(value); - /// // Now we can re-use `value`: - /// value.write([1; 32]); - /// // SAFETY: We just wrote to it. - /// let value = unsafe { value.assume_init() }; - /// assert_eq!(*value, [1; 32]); - /// # Ok::<(), Error>(()) - /// ``` - fn drop_contents(this: Self) -> Box<MaybeUninit<T>>; -} - -impl<T> BoxExt<T> for Box<T> { - fn new(x: T, flags: Flags) -> Result<Self, AllocError> { - let mut b = <Self as BoxExt<_>>::new_uninit(flags)?; - b.write(x); - // SAFETY: We just wrote to it. - Ok(unsafe { b.assume_init() }) - } - - #[cfg(any(test, testlib))] - fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { - Ok(Box::new_uninit()) - } - - #[cfg(not(any(test, testlib)))] - fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { - let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 { - core::ptr::NonNull::<_>::dangling().as_ptr() - } else { - let layout = core::alloc::Layout::new::<MaybeUninit<T>>(); - - // SAFETY: Memory is being allocated (first arg is null). The only other source of - // safety issues is sleeping on atomic context, which is addressed by klint. Lastly, - // the type is not a SZT (checked above). - let ptr = - unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) }; - if ptr.is_null() { - return Err(AllocError); - } - - ptr.cast::<MaybeUninit<T>>() - }; - - // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For - // zero-sized types, we use `NonNull::dangling`. - Ok(unsafe { Box::from_raw(ptr) }) - } - - fn drop_contents(this: Self) -> Box<MaybeUninit<T>> { - let ptr = Box::into_raw(this); - // SAFETY: `ptr` is valid, because it came from `Box::into_raw`. - unsafe { ptr::drop_in_place(ptr) }; - - // CAST: `MaybeUninit<T>` is a transparent wrapper of `T`. - let ptr = ptr.cast::<MaybeUninit<T>>(); - - // SAFETY: `ptr` is valid for writes, because it came from `Box::into_raw` and it is valid for - // reads, since the pointer came from `Box::into_raw` and the type is `MaybeUninit<T>`. - unsafe { Box::from_raw(ptr) } - } -} diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 9b63fd8e82da..812ae1d06077 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -211,13 +211,12 @@ //! [`pin_init!`]: crate::pin_init!
use crate::{ - alloc::{box_ext::BoxExt, AllocError, Flags, KBox}, + alloc::{AllocError, Flags, KBox}, error::{self, Error}, sync::Arc, sync::UniqueArc, types::{Opaque, ScopeGuard}, }; -use alloc::boxed::Box; use core::{ cell::UnsafeCell, convert::Infallible, @@ -588,7 +587,6 @@ macro_rules! pin_init { /// # Examples /// /// ```rust -/// # #![feature(new_uninit)] /// use kernel::{init::{self, PinInit}, error::Error}; /// #[pin_data] /// struct BigBuf { @@ -1245,26 +1243,6 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> } }
-impl<T> InPlaceInit<T> for Box<T> { - type PinnedSelf = Pin<Self>; - - #[inline] - fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E> - where - E: From<AllocError>, - { - <Box<_> as BoxExt<_>>::new_uninit(flags)?.write_pin_init(init) - } - - #[inline] - fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> - where - E: From<AllocError>, - { - <Box<_> as BoxExt<_>>::new_uninit(flags)?.write_init(init) - } -} - impl<T> InPlaceInit<T> for UniqueArc<T> { type PinnedSelf = Pin<Self>;
@@ -1301,28 +1279,6 @@ pub trait InPlaceWrite<T> { fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<PinSelf::Initialized, E>; }
-impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> { - type Initialized = Box<T>; - - fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { - let slot = self.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid. - unsafe { init.__init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { self.assume_init() }) - } - - fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<PinSelf::Initialized, E> { - let slot = self.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid and will not be moved, because we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { self.assume_init() }.into()) - } -} - impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> { type Initialized = UniqueArc<T>;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index b6395b4209d7..5bbaf6282265 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -16,7 +16,6 @@ #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] #![feature(lint_reasons)] -#![feature(new_uninit)] #![feature(unsize)]
// Ensure conditional compilation based on the kernel configuration works; diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index a9210634a8c3..c1f8e5c832e2 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,10 +14,10 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt, KBox, KVBox, VBox}; +pub use crate::alloc::{flags::*, vec_ext::VecExt, KBox, KVBox, VBox};
#[doc(no_inline)] -pub use alloc::{boxed::Box, vec::Vec}; +pub use alloc::vec::Vec;
#[doc(no_inline)] pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 4e03df725f3f..c426c36a4db7 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -3,13 +3,11 @@ //! Kernel types.
use crate::init::{self, PinInit}; -use alloc::boxed::Box; use core::{ cell::UnsafeCell, marker::{PhantomData, PhantomPinned}, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, - pin::Pin, ptr::NonNull, };
@@ -71,54 +69,6 @@ unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> { } }
-impl<T: 'static> ForeignOwnable for Box<T> { - type Borrowed<'a> = &'a T; - - fn into_foreign(self) -> *const core::ffi::c_void { - Box::into_raw(self) as _ - } - - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T { - // SAFETY: The safety requirements for this function ensure that the object is still alive, - // so it is safe to dereference the raw pointer. - // The safety requirements of `from_foreign` also ensure that the object remains alive for - // the lifetime of the returned value. - unsafe { &*ptr.cast() } - } - - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { - // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous - // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr as _) } - } -} - -impl<T: 'static> ForeignOwnable for Pin<Box<T>> { - type Borrowed<'a> = Pin<&'a T>; - - fn into_foreign(self) -> *const core::ffi::c_void { - // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ - } - - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Pin<&'a T> { - // SAFETY: The safety requirements for this function ensure that the object is still alive, - // so it is safe to dereference the raw pointer. - // The safety requirements of `from_foreign` also ensure that the object remains alive for - // the lifetime of the returned value. - let r = unsafe { &*ptr.cast() }; - - // SAFETY: This pointer originates from a `Pin<Box<T>>`. - unsafe { Pin::new_unchecked(r) } - } - - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { - // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous - // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } - } -} - impl ForeignOwnable for () { type Borrowed<'a> = ();
From: Danilo Krummrich dakr@kernel.org
commit e1044c2238f54ae5bd902cac6d12e48835df418b upstream.
Now that we removed `BoxExt` and the corresponding includes in prelude.rs, add the new kernel `Box` type instead.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-15-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/prelude.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index c1f8e5c832e2..d5f2fe42d093 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,7 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{flags::*, vec_ext::VecExt, KBox, KVBox, VBox}; +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox};
#[doc(no_inline)] pub use alloc::vec::Vec;
From: Benno Lossin benno.lossin@proton.me
commit 9e7bbfa182767f638ba61dba3518ff78da9f31ff upstream.
When allocating memory for arrays using allocators, the `Layout::array` function is typically used. It returns a result, since the given size might be too big. However, `Vec` and its iterators store their allocated capacity and thus they already did check that the size is not too big.
The `ArrayLayout` type provides this exact behavior, as it can be infallibly converted into a `Layout`. Instead of a `usize` capacity, `Vec` and other similar array-storing types can use `ArrayLayout` instead.
Reviewed-by: Gary Guo gary@garyguo.net Signed-off-by: Benno Lossin benno.lossin@proton.me Signed-off-by: Danilo Krummrich dakr@kernel.org Link: https://lore.kernel.org/r/20241004154149.93856-16-dakr@kernel.org [ Formatted a few comments. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 1 + rust/kernel/alloc/layout.rs | 91 +++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 rust/kernel/alloc/layout.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 94f4de5e0cdc..c679d93b0523 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -5,6 +5,7 @@ #[cfg(not(any(test, testlib)))] pub mod allocator; pub mod kbox; +pub mod layout; pub mod vec_ext;
#[cfg(any(test, testlib))] diff --git a/rust/kernel/alloc/layout.rs b/rust/kernel/alloc/layout.rs new file mode 100644 index 000000000000..7e0c2f46157b --- /dev/null +++ b/rust/kernel/alloc/layout.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Memory layout. +//! +//! Custom layout types extending or improving [`Layout`]. + +use core::{alloc::Layout, marker::PhantomData}; + +/// Error when constructing an [`ArrayLayout`]. +pub struct LayoutError; + +/// A layout for an array `[T; n]`. +/// +/// # Invariants +/// +/// - `len * size_of::<T>() <= isize::MAX`. +pub struct ArrayLayout<T> { + len: usize, + _phantom: PhantomData<fn() -> T>, +} + +impl<T> Clone for ArrayLayout<T> { + fn clone(&self) -> Self { + *self + } +} +impl<T> Copy for ArrayLayout<T> {} + +const ISIZE_MAX: usize = isize::MAX as usize; + +impl<T> ArrayLayout<T> { + /// Creates a new layout for `[T; 0]`. + pub const fn empty() -> Self { + // INVARIANT: `0 * size_of::<T>() <= isize::MAX`. + Self { + len: 0, + _phantom: PhantomData, + } + } + + /// Creates a new layout for `[T; len]`. + /// + /// # Errors + /// + /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. + pub const fn new(len: usize) -> Result<Self, LayoutError> { + match len.checked_mul(core::mem::size_of::<T>()) { + Some(len) if len <= ISIZE_MAX => { + // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. + Ok(Self { + len, + _phantom: PhantomData, + }) + } + _ => Err(LayoutError), + } + } + + /// Creates a new layout for `[T; len]`. + /// + /// # Safety + /// + /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. + pub unsafe fn new_unchecked(len: usize) -> Self { + // INVARIANT: By the safety requirements of this function + // `len * size_of::<T>() <= isize::MAX`. + Self { + len, + _phantom: PhantomData, + } + } + + /// Returns the number of array elements represented by this layout. + pub const fn len(&self) -> usize { + self.len + } + + /// Returns `true` when no array elements are represented by this layout. + pub const fn is_empty(&self) -> bool { + self.len == 0 + } +} + +impl<T> From<ArrayLayout<T>> for Layout { + fn from(value: ArrayLayout<T>) -> Self { + let res = Layout::array::<T>(value.len); + // SAFETY: By the type invariant of `ArrayLayout` we have + // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. + unsafe { res.unwrap_unchecked() } + } +}
From: Danilo Krummrich dakr@kernel.org
commit 2aac4cd7dae3d7bb0e0ddec2561b2ee4cbe6c8f6 upstream.
`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 --- rust/kernel/alloc.rs | 6 + rust/kernel/alloc/kvec.rs | 648 ++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + rust/kernel/prelude.rs | 2 +- 4 files changed, 656 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/alloc/kvec.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index c679d93b0523..7f654b214ec2 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -5,6 +5,7 @@ #[cfg(not(any(test, testlib)))] pub mod allocator; pub mod kbox; +pub mod kvec; pub mod layout; pub mod vec_ext;
@@ -19,6 +20,11 @@ pub use self::kbox::KVBox; pub use self::kbox::VBox;
+pub use self::kvec::KVVec; +pub use self::kvec::KVec; +pub use self::kvec::VVec; +pub use self::kvec::Vec; + /// Indicates an allocation error. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs new file mode 100644 index 000000000000..8a1d8f414955 --- /dev/null +++ b/rust/kernel/alloc/kvec.rs @@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Implementation of [`Vec`]. + +use super::{ + allocator::{KVmalloc, Kmalloc, Vmalloc}, + layout::ArrayLayout, + AllocError, Allocator, Box, Flags, +}; +use core::{ + fmt, + marker::PhantomData, + mem::{ManuallyDrop, MaybeUninit}, + ops::Deref, + ops::DerefMut, + ops::Index, + ops::IndexMut, + ptr, + ptr::NonNull, + slice, + slice::SliceIndex, +}; + +/// Create a [`KVec`] containing the arguments. +/// +/// New memory is allocated with `GFP_KERNEL`. +/// +/// # Examples +/// +/// ``` +/// let mut v = kernel::kvec![]; +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(v, [1]); +/// +/// let mut v = kernel::kvec![1; 3]?; +/// v.push(4, GFP_KERNEL)?; +/// assert_eq!(v, [1, 1, 1, 4]); +/// +/// let mut v = kernel::kvec![1, 2, 3]?; +/// v.push(4, GFP_KERNEL)?; +/// assert_eq!(v, [1, 2, 3, 4]); +/// +/// # Ok::<(), Error>(()) +/// ``` +#[macro_export] +macro_rules! kvec { + () => ( + $crate::alloc::KVec::new() + ); + ($elem:expr; $n:expr) => ( + $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL) + ); + ($($x:expr),+ $(,)?) => ( + match $crate::alloc::KBox::new_uninit(GFP_KERNEL) { + Ok(b) => Ok($crate::alloc::KVec::from($crate::alloc::KBox::write(b, [$($x),+]))), + Err(e) => Err(e), + } + ); +} + +/// The kernel's [`Vec`] type. +/// +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g. +/// [`Kmalloc`], [`Vmalloc`] or [`KVmalloc`]), written `Vec<T, A>`. +/// +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For +/// the most common allocators the type aliases [`KVec`], [`VVec`] and [`KVVec`] exist. +/// +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::<T>`; no memory is allocated. +/// +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the +/// capacity of the vector (the number of elements that currently fit into the vector), its length +/// (the number of elements that are currently stored in the vector) and the `Allocator` type used +/// to allocate (and free) the backing buffer. +/// +/// A [`Vec`] can be deconstructed into and (re-)constructed from its previously named raw parts +/// and manually modified. +/// +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements +/// are added to the vector. +/// +/// # Invariants +/// +/// - `self.ptr` is always properly aligned and either points to memory allocated with `A` or, for +/// zero-sized types, is a dangling, well aligned pointer. +/// +/// - `self.len` always represents the exact number of elements stored in the vector. +/// +/// - `self.layout` represents the absolute number of elements that can be stored within the vector +/// without re-allocation. For ZSTs `self.layout`'s capacity is zero. However, it is legal for the +/// backing buffer to be larger than `layout`. +/// +/// - The `Allocator` type `A` of the vector is the exact same `Allocator` type the backing buffer +/// was allocated with (and must be freed with). +pub struct Vec<T, A: Allocator> { + ptr: NonNull<T>, + /// Represents the actual buffer size as `cap` times `size_of::<T>` bytes. + /// + /// Note: This isn't quite the same as `Self::capacity`, which in contrast returns the number of + /// elements we can still store without reallocating. + layout: ArrayLayout<T>, + len: usize, + _p: PhantomData<A>, +} + +/// Type alias for [`Vec`] with a [`Kmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = KVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type KVec<T> = Vec<T, Kmalloc>; + +/// Type alias for [`Vec`] with a [`Vmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = VVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type VVec<T> = Vec<T, Vmalloc>; + +/// Type alias for [`Vec`] with a [`KVmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = KVVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type KVVec<T> = Vec<T, KVmalloc>; + +// SAFETY: `Vec` is `Send` if `T` is `Send` because `Vec` owns its elements. +unsafe impl<T, A> Send for Vec<T, A> +where + T: Send, + A: Allocator, +{ +} + +// SAFETY: `Vec` is `Sync` if `T` is `Sync` because `Vec` owns its elements. +unsafe impl<T, A> Sync for Vec<T, A> +where + T: Sync, + A: Allocator, +{ +} + +impl<T, A> Vec<T, A> +where + A: Allocator, +{ + #[inline] + const fn is_zst() -> bool { + core::mem::size_of::<T>() == 0 + } + + /// Returns the number of elements that can be stored within the vector without allocating + /// additional memory. + pub fn capacity(&self) -> usize { + if const { Self::is_zst() } { + usize::MAX + } else { + self.layout.len() + } + } + + /// Returns the number of elements stored within the vector. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Forcefully sets `self.len` to `new_len`. + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to [`Self::capacity`]. + /// - If `new_len` is greater than `self.len`, all elements within the interval + /// [`self.len`,`new_len`) must be initialized. + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + self.len = new_len; + } + + /// Returns a slice of the entire vector. + #[inline] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Returns a mutable slice of the entire vector. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + /// Returns a mutable raw pointer to the vector's backing buffer, or, if `T` is a ZST, a + /// dangling raw pointer. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self.ptr.as_ptr() + } + + /// 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 { + self.ptr.as_ptr() + } + + /// Returns `true` if the vector contains no elements, `false` otherwise. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// assert!(v.is_empty()); + /// + /// v.push(1, GFP_KERNEL); + /// assert!(!v.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Creates a new, empty `Vec<T, A>`. + /// + /// This method does not allocate by itself. + #[inline] + pub const fn new() -> Self { + // INVARIANT: Since this is a new, empty `Vec` with no backing memory yet, + // - `ptr` is a properly aligned dangling pointer for type `T`, + // - `layout` is an empty `ArrayLayout` (zero capacity) + // - `len` is zero, since no elements can be or have been stored, + // - `A` is always valid. + Self { + ptr: NonNull::dangling(), + layout: ArrayLayout::empty(), + len: 0, + _p: PhantomData::<A>, + } + } + + /// Returns a slice of `MaybeUninit<T>` for the remaining spare capacity of the vector. + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] { + // SAFETY: + // - `self.len` is smaller than `self.capacity` and hence, the resulting pointer is + // guaranteed to be part of the same allocated object. + // - `self.len` can not overflow `isize`. + let ptr = unsafe { self.as_mut_ptr().add(self.len) } as *mut MaybeUninit<T>; + + // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated + // and valid, but uninitialized. + unsafe { slice::from_raw_parts_mut(ptr, self.capacity() - self.len) } + } + + /// Appends an element to the back of the [`Vec`] instance. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// assert_eq!(&v, &[1]); + /// + /// v.push(2, GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 2]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { + self.reserve(1, flags)?; + + // SAFETY: + // - `self.len` is smaller than `self.capacity` and hence, the resulting pointer is + // guaranteed to be part of the same allocated object. + // - `self.len` can not overflow `isize`. + let ptr = unsafe { self.as_mut_ptr().add(self.len) }; + + // SAFETY: + // - `ptr` is properly aligned and valid for writes. + unsafe { core::ptr::write(ptr, v) }; + + // SAFETY: We just initialised the first spare entry, so it is safe to increase the length + // by 1. We also know that the new length is <= capacity because of the previous call to + // `reserve` above. + unsafe { self.set_len(self.len() + 1) }; + Ok(()) + } + + /// Creates a new [`Vec`] instance with at least the given capacity. + /// + /// # Examples + /// + /// ``` + /// let v = KVec::<u32>::with_capacity(20, GFP_KERNEL)?; + /// + /// assert!(v.capacity() >= 20); + /// # Ok::<(), Error>(()) + /// ``` + pub fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> { + let mut v = Vec::new(); + + v.reserve(capacity, flags)?; + + Ok(v) + } + + /// Creates a `Vec<T, A>` from a pointer, a length and a capacity using the allocator `A`. + /// + /// # Examples + /// + /// ``` + /// let mut v = kernel::kvec![1, 2, 3]?; + /// v.reserve(1, GFP_KERNEL)?; + /// + /// let (mut ptr, mut len, cap) = v.into_raw_parts(); + /// + /// // SAFETY: We've just reserved memory for another element. + /// unsafe { ptr.add(len).write(4) }; + /// len += 1; + /// + /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and + /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it + /// // from the exact same raw parts. + /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) }; + /// + /// assert_eq!(v, [1, 2, 3, 4]); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// # Safety + /// + /// If `T` is a ZST: + /// + /// - `ptr` must be a dangling, well aligned pointer. + /// + /// Otherwise: + /// + /// - `ptr` must have been allocated with the allocator `A`. + /// - `ptr` must satisfy or exceed the alignment requirements of `T`. + /// - `ptr` must point to memory with a size of at least `size_of::<T>() * capacity` bytes. + /// - The allocated size in bytes must not be larger than `isize::MAX`. + /// - `length` must be less than or equal to `capacity`. + /// - The first `length` elements must be initialized values of type `T`. + /// + /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for + /// `cap` and `len`. + pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { + let layout = if Self::is_zst() { + ArrayLayout::empty() + } else { + // SAFETY: By the safety requirements of this function, `capacity * size_of::<T>()` is + // smaller than `isize::MAX`. + unsafe { ArrayLayout::new_unchecked(capacity) } + }; + + // INVARIANT: For ZSTs, we store an empty `ArrayLayout`, all other type invariants are + // covered by the safety requirements of this function. + Self { + // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid + // memory allocation, allocated with `A`. + ptr: unsafe { NonNull::new_unchecked(ptr) }, + layout, + len: length, + _p: PhantomData::<A>, + } + } + + /// Consumes the `Vec<T, A>` and returns its raw components `pointer`, `length` and `capacity`. + /// + /// This will not run the destructor of the contained elements and for non-ZSTs the allocation + /// will stay alive indefinitely. Use [`Vec::from_raw_parts`] to recover the [`Vec`], drop the + /// elements and free the allocation, if any. + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + let len = me.len(); + let capacity = me.capacity(); + let ptr = me.as_mut_ptr(); + (ptr, len, capacity) + } + + /// Ensures that the capacity exceeds the length by at least `additional` elements. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// + /// v.reserve(10, GFP_KERNEL)?; + /// let cap = v.capacity(); + /// assert!(cap >= 10); + /// + /// v.reserve(10, GFP_KERNEL)?; + /// let new_cap = v.capacity(); + /// assert_eq!(new_cap, cap); + /// + /// # Ok::<(), Error>(()) + /// ``` + pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { + let len = self.len(); + let cap = self.capacity(); + + if cap - len >= additional { + return Ok(()); + } + + if Self::is_zst() { + // The capacity is already `usize::MAX` for ZSTs, we can't go higher. + return Err(AllocError); + } + + // We know that `cap <= isize::MAX` because of the type invariants of `Self`. So the + // multiplication by two won't overflow. + let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); + let layout = ArrayLayout::new(new_cap).map_err(|_| AllocError)?; + + // SAFETY: + // - `ptr` is valid because it's either `None` or comes from a previous call to + // `A::realloc`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + let ptr = unsafe { + A::realloc( + Some(self.ptr.cast()), + layout.into(), + self.layout.into(), + flags, + )? + }; + + // INVARIANT: + // - `layout` is some `ArrayLayout::<T>`, + // - `ptr` has been created by `A::realloc` from `layout`. + self.ptr = ptr.cast(); + self.layout = layout; + + Ok(()) + } +} + +impl<T: Clone, A: Allocator> Vec<T, A> { + /// Extend the vector by `n` clones of `value`. + pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> { + if n == 0 { + return Ok(()); + } + + self.reserve(n, flags)?; + + let spare = self.spare_capacity_mut(); + + for item in spare.iter_mut().take(n - 1) { + item.write(value.clone()); + } + + // We can write the last element directly without cloning needlessly. + spare[n - 1].write(value); + + // SAFETY: + // - `self.len() + n < self.capacity()` due to the call to reserve above, + // - the loop and the line above initialized the next `n` elements. + unsafe { self.set_len(self.len() + n) }; + + Ok(()) + } + + /// Pushes clones of the elements of slice into the [`Vec`] instance. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// + /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 20, 30, 40]); + /// + /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> { + self.reserve(other.len(), flags)?; + for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { + slot.write(item.clone()); + } + + // SAFETY: + // - `other.len()` spare entries have just been initialized, so it is safe to increase + // the length by the same number. + // - `self.len() + other.len() <= self.capacity()` is guaranteed by the preceding `reserve` + // call. + unsafe { self.set_len(self.len() + other.len()) }; + Ok(()) + } + + /// Create a new `Vec<T, A>` and extend it by `n` clones of `value`. + pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> { + let mut v = Self::with_capacity(n, flags)?; + + v.extend_with(n, value, flags)?; + + Ok(v) + } +} + +impl<T, A> Drop for Vec<T, A> +where + A: Allocator, +{ + fn drop(&mut self) { + // SAFETY: `self.as_mut_ptr` is guaranteed to be valid by the type invariant. + unsafe { + ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( + self.as_mut_ptr(), + self.len, + )) + }; + + // SAFETY: + // - `self.ptr` was previously allocated with `A`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + unsafe { A::free(self.ptr.cast(), self.layout.into()) }; + } +} + +impl<T, A, const N: usize> From<Box<[T; N], A>> for Vec<T, A> +where + A: Allocator, +{ + fn from(b: Box<[T; N], A>) -> Vec<T, A> { + let len = b.len(); + let ptr = Box::into_raw(b); + + // SAFETY: + // - `b` has been allocated with `A`, + // - `ptr` fulfills the alignment requirements for `T`, + // - `ptr` points to memory with at least a size of `size_of::<T>() * len`, + // - all elements within `b` are initialized values of `T`, + // - `len` does not exceed `isize::MAX`. + unsafe { Vec::from_raw_parts(ptr as _, len, len) } + } +} + +impl<T> Default for KVec<T> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Vec<T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<T, A> Deref for Vec<T, A> +where + A: Allocator, +{ + type Target = [T]; + + #[inline] + fn deref(&self) -> &[T] { + // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len` + // initialized elements of type `T`. + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + } +} + +impl<T, A> DerefMut for Vec<T, A> +where + A: Allocator, +{ + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len` + // initialized elements of type `T`. + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + } +} + +impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {} + +impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A> +where + A: Allocator, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(&**self, index) + } +} + +impl<T, I: SliceIndex<[T]>, A> IndexMut<I> for Vec<T, A> +where + A: Allocator, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut **self, index) + } +} + +macro_rules! impl_slice_eq { + ($([$($vars:tt)*] $lhs:ty, $rhs:ty,)*) => { + $( + impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs + where + T: PartialEq<U>, + { + #[inline] + fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } + } + )* + } +} + +impl_slice_eq! { + [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2>, + [A: Allocator] Vec<T, A>, &[U], + [A: Allocator] Vec<T, A>, &mut [U], + [A: Allocator] &[T], Vec<U, A>, + [A: Allocator] &mut [T], Vec<U, A>, + [A: Allocator] Vec<T, A>, [U], + [A: Allocator] [T], Vec<U, A>, + [A: Allocator, const N: usize] Vec<T, A>, [U; N], + [A: Allocator, const N: usize] Vec<T, A>, &[U; N], +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 5bbaf6282265..40c903515586 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -15,6 +15,7 @@ #![feature(arbitrary_self_types)] #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] +#![feature(inline_const)] #![feature(lint_reasons)] #![feature(unsize)]
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index d5f2fe42d093..80223cdaa485 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,7 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, VBox}; +pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
#[doc(no_inline)] pub use alloc::vec::Vec;
From: Danilo Krummrich dakr@kernel.org
commit 1d1d223aa3b37c34271aefc2706340d0843bfcb2 upstream.
Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as `Iterator` for `IntoIter`.
`Vec::into_iter` disassembles the `Vec` into its raw parts; additionally, `IntoIter` keeps track of a separate pointer, which is incremented correspondingly as the iterator advances, while the length, or the count of elements, is decremented.
This also means that `IntoIter` takes the ownership of the backing buffer and is responsible to drop the remaining elements and free the backing buffer, if it's dropped.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-18-dakr@kernel.org [ Fixed typos. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 1 + rust/kernel/alloc/kvec.rs | 170 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 7f654b214ec2..86d2077a8e64 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -20,6 +20,7 @@ pub use self::kbox::KVBox; pub use self::kbox::VBox;
+pub use self::kvec::IntoIter; pub use self::kvec::KVVec; pub use self::kvec::KVec; pub use self::kvec::VVec; diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 8a1d8f414955..4ddc2ca6cd32 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -646,3 +646,173 @@ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } [A: Allocator, const N: usize] Vec<T, A>, [U; N], [A: Allocator, const N: usize] Vec<T, A>, &[U; N], } + +impl<'a, T, A> IntoIterator for &'a Vec<T, A> +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector. +/// +/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the +/// [`IntoIterator`] trait). +/// +/// # Examples +/// +/// ``` +/// let v = kernel::kvec![0, 1, 2]?; +/// let iter = v.into_iter(); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub struct IntoIter<T, A: Allocator> { + ptr: *mut T, + buf: NonNull<T>, + len: usize, + layout: ArrayLayout<T>, + _p: PhantomData<A>, +} + +impl<T, A> Iterator for IntoIter<T, A> +where + A: Allocator, +{ + type Item = T; + + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2, 3]?; + /// let mut it = v.into_iter(); + /// + /// assert_eq!(it.next(), Some(1)); + /// assert_eq!(it.next(), Some(2)); + /// assert_eq!(it.next(), Some(3)); + /// assert_eq!(it.next(), None); + /// + /// # Ok::<(), Error>(()) + /// ``` + fn next(&mut self) -> Option<T> { + if self.len == 0 { + return None; + } + + let current = self.ptr; + + // SAFETY: We can't overflow; decreasing `self.len` by one every time we advance `self.ptr` + // by one guarantees that. + unsafe { self.ptr = self.ptr.add(1) }; + + self.len -= 1; + + // SAFETY: `current` is guaranteed to point at a valid element within the buffer. + Some(unsafe { current.read() }) + } + + /// # Examples + /// + /// ``` + /// let v: KVec<u32> = kernel::kvec![1, 2, 3]?; + /// let mut iter = v.into_iter(); + /// let size = iter.size_hint().0; + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 1); + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 2); + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 3); + /// + /// # Ok::<(), Error>(()) + /// ``` + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len, Some(self.len)) + } +} + +impl<T, A> Drop for IntoIter<T, A> +where + A: Allocator, +{ + fn drop(&mut self) { + // SAFETY: `self.ptr` is guaranteed to be valid by the type invariant. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) }; + + // SAFETY: + // - `self.buf` was previously allocated with `A`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + unsafe { A::free(self.buf.cast(), self.layout.into()) }; + } +} + +impl<T, A> IntoIterator for Vec<T, A> +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter<T, A>; + + /// Consumes the `Vec<T, A>` and creates an `Iterator`, which moves each value out of the + /// vector (from start to end). + /// + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2]?; + /// let mut v_iter = v.into_iter(); + /// + /// let first_element: Option<u32> = v_iter.next(); + /// + /// assert_eq!(first_element, Some(1)); + /// assert_eq!(v_iter.next(), Some(2)); + /// assert_eq!(v_iter.next(), None); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// ``` + /// let v = kernel::kvec![]; + /// let mut v_iter = v.into_iter(); + /// + /// let first_element: Option<u32> = v_iter.next(); + /// + /// assert_eq!(first_element, None); + /// + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + fn into_iter(self) -> Self::IntoIter { + let buf = self.ptr; + let layout = self.layout; + let (ptr, len, _) = self.into_raw_parts(); + + IntoIter { + ptr, + buf, + len, + layout, + _p: PhantomData::<A>, + } + } +}
From: Danilo Krummrich dakr@kernel.org
commit 93e602310f87b7b515b86a8f919cc0799387e5c3 upstream.
Currently, we can't implement `FromIterator`. There are a couple of issues with this trait in the kernel, namely:
- Rust's specialization feature is unstable. This prevents us to optimize for the special case where `I::IntoIter` equals `Vec`'s `IntoIter` type. - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` doesn't require this type to be `'static`. - `FromIterator::from_iter` does return `Self` instead of `Result<Self, AllocError>`, hence we can't properly handle allocation failures. - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation flags.
Instead, provide `IntoIter::collect`, such that we can at least convert `IntoIter` into a `Vec` again.
Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Benno Lossin benno.lossin@proton.me Signed-off-by: Danilo Krummrich dakr@kernel.org Link: https://lore.kernel.org/r/20241004154149.93856-19-dakr@kernel.org [ Added newline in documentation, changed case of section to be consistent with an existing one, fixed typo. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc/kvec.rs | 95 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+)
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index 4ddc2ca6cd32..ae9d072741ce 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -692,6 +692,101 @@ pub struct IntoIter<T, A: Allocator> { _p: PhantomData<A>, }
+impl<T, A> IntoIter<T, A> +where + A: Allocator, +{ + fn into_raw_parts(self) -> (*mut T, NonNull<T>, usize, usize) { + let me = ManuallyDrop::new(self); + let ptr = me.ptr; + let buf = me.buf; + let len = me.len; + let cap = me.layout.len(); + (ptr, buf, len, cap) + } + + /// Same as `Iterator::collect` but specialized for `Vec`'s `IntoIter`. + /// + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2, 3]?; + /// let mut it = v.into_iter(); + /// + /// assert_eq!(it.next(), Some(1)); + /// + /// let v = it.collect(GFP_KERNEL); + /// assert_eq!(v, [2, 3]); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// # Implementation details + /// + /// Currently, we can't implement `FromIterator`. There are a couple of issues with this trait + /// in the kernel, namely: + /// + /// - Rust's specialization feature is unstable. This prevents us to optimize for the special + /// case where `I::IntoIter` equals `Vec`'s `IntoIter` type. + /// - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` + /// doesn't require this type to be `'static`. + /// - `FromIterator::from_iter` does return `Self` instead of `Result<Self, AllocError>`, hence + /// we can't properly handle allocation failures. + /// - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation + /// flags. + /// + /// Instead, provide `IntoIter::collect`, such that we can at least convert a `IntoIter` into a + /// `Vec` again. + /// + /// Note that `IntoIter::collect` doesn't require `Flags`, since it re-uses the existing backing + /// buffer. However, this backing buffer may be shrunk to the actual count of elements. + pub fn collect(self, flags: Flags) -> Vec<T, A> { + let old_layout = self.layout; + let (mut ptr, buf, len, mut cap) = self.into_raw_parts(); + let has_advanced = ptr != buf.as_ptr(); + + if has_advanced { + // Copy the contents we have advanced to at the beginning of the buffer. + // + // SAFETY: + // - `ptr` is valid for reads of `len * size_of::<T>()` bytes, + // - `buf.as_ptr()` is valid for writes of `len * size_of::<T>()` bytes, + // - `ptr` and `buf.as_ptr()` are not be subject to aliasing restrictions relative to + // each other, + // - both `ptr` and `buf.ptr()` are properly aligned. + unsafe { ptr::copy(ptr, buf.as_ptr(), len) }; + ptr = buf.as_ptr(); + + // SAFETY: `len` is guaranteed to be smaller than `self.layout.len()`. + let layout = unsafe { ArrayLayout::<T>::new_unchecked(len) }; + + // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be + // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves + // it as it is. + ptr = match unsafe { + A::realloc(Some(buf.cast()), layout.into(), old_layout.into(), flags) + } { + // If we fail to shrink, which likely can't even happen, continue with the existing + // buffer. + Err(_) => ptr, + Ok(ptr) => { + cap = len; + ptr.as_ptr().cast() + } + }; + } + + // SAFETY: If the iterator has been advanced, the advanced elements have been copied to + // the beginning of the buffer and `len` has been adjusted accordingly. + // + // - `ptr` is guaranteed to point to the start of the backing buffer. + // - `cap` is either the original capacity or, after shrinking the buffer, equal to `len`. + // - `alloc` is guaranteed to be unchanged since `into_iter` has been called on the original + // `Vec`. + unsafe { Vec::from_raw_parts(ptr, len, cap) } + } +} + impl<T, A> Iterator for IntoIter<T, A> where A: Allocator,
From: Danilo Krummrich dakr@kernel.org
commit 58eff8e872bd04ccb3adcf99aec7334ffad06cfd upstream.
Now that we got the kernel `Vec` in place, convert all existing `Vec` users to make use of it.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-20-dakr@kernel.org [ Converted `kasan_test_rust.rs` too, as discussed. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- mm/kasan/kasan_test_rust.rs | 2 +- rust/kernel/str.rs | 12 +++++------- rust/kernel/sync/locked_by.rs | 2 +- rust/kernel/types.rs | 2 +- rust/kernel/uaccess.rs | 17 +++++++---------- rust/macros/lib.rs | 6 +++--- samples/rust/rust_minimal.rs | 4 ++-- 7 files changed, 20 insertions(+), 25 deletions(-)
diff --git a/mm/kasan/kasan_test_rust.rs b/mm/kasan/kasan_test_rust.rs index 47bcf033dd4f..5b34edf30e72 100644 --- a/mm/kasan/kasan_test_rust.rs +++ b/mm/kasan/kasan_test_rust.rs @@ -11,7 +11,7 @@ /// drop the vector, and touch it. #[no_mangle] pub extern "C" fn kasan_test_rust_uaf() -> u8 { - let mut v: Vec<u8> = Vec::new(); + let mut v: KVec<u8> = KVec::new(); for _ in 0..4096 { v.push(0x42, GFP_KERNEL).unwrap(); } diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 66d4527f6c6f..6053bc7a98d1 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,8 +2,7 @@
//! String representations.
-use crate::alloc::{flags::*, vec_ext::VecExt, AllocError}; -use alloc::vec::Vec; +use crate::alloc::{flags::*, AllocError, KVec}; use core::fmt::{self, Write}; use core::ops::{self, Deref, DerefMut, Index};
@@ -791,7 +790,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result { /// assert_eq!(s.is_ok(), false); /// ``` pub struct CString { - buf: Vec<u8>, + buf: KVec<u8>, }
impl CString { @@ -804,7 +803,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> { let size = f.bytes_written();
// Allocate a vector with the required number of bytes, and write to it. - let mut buf = <Vec<_> as VecExt<_>>::with_capacity(size, GFP_KERNEL)?; + let mut buf = KVec::with_capacity(size, GFP_KERNEL)?; // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; f.write_fmt(args)?; @@ -851,10 +850,9 @@ impl<'a> TryFrom<&'a CStr> for CString { type Error = AllocError;
fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> { - let mut buf = Vec::new(); + let mut buf = KVec::new();
- <Vec<_> as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL) - .map_err(|_| AllocError)?; + buf.extend_from_slice(cstr.as_bytes_with_nul(), GFP_KERNEL)?;
// INVARIANT: The `CStr` and `CString` types have the same invariants for // the string data, and we copied it over without changes. diff --git a/rust/kernel/sync/locked_by.rs b/rust/kernel/sync/locked_by.rs index ce2ee8d87865..a7b244675c2b 100644 --- a/rust/kernel/sync/locked_by.rs +++ b/rust/kernel/sync/locked_by.rs @@ -43,7 +43,7 @@ /// struct InnerDirectory { /// /// The sum of the bytes used by all files. /// bytes_used: u64, -/// _files: Vec<File>, +/// _files: KVec<File>, /// } /// /// struct Directory { diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index c426c36a4db7..22b1faac874c 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -135,7 +135,7 @@ unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {} /// # use kernel::types::ScopeGuard; /// fn example3(arg: bool) -> Result { /// let mut vec = -/// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len())); +/// ScopeGuard::new_with_data(KVec::new(), |v| pr_info!("vec had {} elements\n", v.len())); /// /// vec.push(10u8, GFP_KERNEL)?; /// if arg { diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index e9347cff99ab..bc011061de45 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -11,7 +11,6 @@ prelude::*, types::{AsBytes, FromBytes}, }; -use alloc::vec::Vec; use core::ffi::{c_ulong, c_void}; use core::mem::{size_of, MaybeUninit};
@@ -46,7 +45,6 @@ /// every byte in the region. /// /// ```no_run -/// use alloc::vec::Vec; /// use core::ffi::c_void; /// use kernel::error::Result; /// use kernel::uaccess::{UserPtr, UserSlice}; @@ -54,7 +52,7 @@ /// fn bytes_add_one(uptr: UserPtr, len: usize) -> Result<()> { /// let (read, mut write) = UserSlice::new(uptr, len).reader_writer(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// for b in &mut buf { @@ -69,7 +67,6 @@ /// Example illustrating a TOCTOU (time-of-check to time-of-use) bug. /// /// ```no_run -/// use alloc::vec::Vec; /// use core::ffi::c_void; /// use kernel::error::{code::EINVAL, Result}; /// use kernel::uaccess::{UserPtr, UserSlice}; @@ -78,21 +75,21 @@ /// fn is_valid(uptr: UserPtr, len: usize) -> Result<bool> { /// let read = UserSlice::new(uptr, len).reader(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// todo!() /// } /// /// /// Returns the bytes behind this user pointer if they are valid. -/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result<Vec<u8>> { +/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result<KVec<u8>> { /// if !is_valid(uptr, len)? { /// return Err(EINVAL); /// } /// /// let read = UserSlice::new(uptr, len).reader(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// // THIS IS A BUG! The bytes could have changed since we checked them. @@ -130,7 +127,7 @@ pub fn new(ptr: UserPtr, length: usize) -> Self { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(self, buf: &mut Vec<u8>, flags: Flags) -> Result { + pub fn read_all(self, buf: &mut KVec<u8>, flags: Flags) -> Result { self.reader().read_all(buf, flags) }
@@ -291,9 +288,9 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(mut self, buf: &mut Vec<u8>, flags: Flags) -> Result { + pub fn read_all(mut self, buf: &mut KVec<u8>, flags: Flags) -> Result { let len = self.length; - VecExt::<u8>::reserve(buf, len, flags)?; + buf.reserve(len, flags)?;
// The call to `try_reserve` was successful, so the spare capacity is at least `len` bytes // long. diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 1f1d3a28032c..939ae00b723a 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -242,7 +242,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// #[pin_data] /// struct DriverData { /// #[pin] -/// queue: Mutex<Vec<Command>>, +/// queue: Mutex<KVec<Command>>, /// buf: KBox<[u8; 1024 * 1024]>, /// } /// ``` @@ -251,7 +251,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// #[pin_data(PinnedDrop)] /// struct DriverData { /// #[pin] -/// queue: Mutex<Vec<Command>>, +/// queue: Mutex<KVec<Command>>, /// buf: KBox<[u8; 1024 * 1024]>, /// raw_info: *mut Info, /// } @@ -281,7 +281,7 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { /// #[pin_data(PinnedDrop)] /// struct DriverData { /// #[pin] -/// queue: Mutex<Vec<Command>>, +/// queue: Mutex<KVec<Command>>, /// buf: KBox<[u8; 1024 * 1024]>, /// raw_info: *mut Info, /// } diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index 2a9eaab62d1c..4aaf117bf8e3 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -13,7 +13,7 @@ }
struct RustMinimal { - numbers: Vec<i32>, + numbers: KVec<i32>, }
impl kernel::Module for RustMinimal { @@ -21,7 +21,7 @@ fn init(_module: &'static ThisModule) -> Result<Self> { pr_info!("Rust minimal sample (init)\n"); pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
- let mut numbers = Vec::new(); + let mut numbers = KVec::new(); numbers.push(72, GFP_KERNEL)?; numbers.push(108, GFP_KERNEL)?; numbers.push(200, GFP_KERNEL)?;
From: Danilo Krummrich dakr@kernel.org
commit 405966efc789888c3e1a53cd09d2c2b338064438 upstream.
Now that all existing `Vec` users were moved to the kernel `Vec` type, remove the `VecExt` extension.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-21-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 1 - rust/kernel/alloc/vec_ext.rs | 185 ----------------------------------- rust/kernel/prelude.rs | 5 +- 3 files changed, 1 insertion(+), 190 deletions(-) delete mode 100644 rust/kernel/alloc/vec_ext.rs
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 86d2077a8e64..7fc2e404e594 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -7,7 +7,6 @@ pub mod kbox; pub mod kvec; pub mod layout; -pub mod vec_ext;
#[cfg(any(test, testlib))] pub mod allocator_test; diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs deleted file mode 100644 index 1297a4be32e8..000000000000 --- a/rust/kernel/alloc/vec_ext.rs +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Extensions to [`Vec`] for fallible allocations. - -use super::{AllocError, Flags}; -use alloc::vec::Vec; - -/// Extensions to [`Vec`]. -pub trait VecExt<T>: Sized { - /// Creates a new [`Vec`] instance with at least the given capacity. - /// - /// # Examples - /// - /// ``` - /// let v = Vec::<u32>::with_capacity(20, GFP_KERNEL)?; - /// - /// assert!(v.capacity() >= 20); - /// # Ok::<(), Error>(()) - /// ``` - fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError>; - - /// Appends an element to the back of the [`Vec`] instance. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// assert_eq!(&v, &[1]); - /// - /// v.push(2, GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 2]); - /// # Ok::<(), Error>(()) - /// ``` - fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>; - - /// Pushes clones of the elements of slice into the [`Vec`] instance. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// - /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 20, 30, 40]); - /// - /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); - /// # Ok::<(), Error>(()) - /// ``` - fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> - where - T: Clone; - - /// Ensures that the capacity exceeds the length by at least `additional` elements. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// - /// v.reserve(10, GFP_KERNEL)?; - /// let cap = v.capacity(); - /// assert!(cap >= 10); - /// - /// v.reserve(10, GFP_KERNEL)?; - /// let new_cap = v.capacity(); - /// assert_eq!(new_cap, cap); - /// - /// # Ok::<(), Error>(()) - /// ``` - fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>; -} - -impl<T> VecExt<T> for Vec<T> { - fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> { - let mut v = Vec::new(); - <Self as VecExt<_>>::reserve(&mut v, capacity, flags)?; - Ok(v) - } - - fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { - <Self as VecExt<_>>::reserve(self, 1, flags)?; - let s = self.spare_capacity_mut(); - s[0].write(v); - - // SAFETY: We just initialised the first spare entry, so it is safe to increase the length - // by 1. We also know that the new length is <= capacity because of the previous call to - // `reserve` above. - unsafe { self.set_len(self.len() + 1) }; - Ok(()) - } - - fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> - where - T: Clone, - { - <Self as VecExt<_>>::reserve(self, other.len(), flags)?; - for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { - slot.write(item.clone()); - } - - // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase - // the length by the same amount. We also know that the new length is <= capacity because - // of the previous call to `reserve` above. - unsafe { self.set_len(self.len() + other.len()) }; - Ok(()) - } - - #[cfg(any(test, testlib))] - fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> { - Vec::reserve(self, additional); - Ok(()) - } - - #[cfg(not(any(test, testlib)))] - fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { - let len = self.len(); - let cap = self.capacity(); - - if cap - len >= additional { - return Ok(()); - } - - if core::mem::size_of::<T>() == 0 { - // The capacity is already `usize::MAX` for SZTs, we can't go higher. - return Err(AllocError); - } - - // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size - // is greater than `isize::MAX`. So the multiplication by two won't overflow. - let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); - let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?; - - let (old_ptr, len, cap) = destructure(self); - - // We need to make sure that `ptr` is either NULL or comes from a previous call to - // `krealloc_aligned`. A `Vec<T>`'s `ptr` value is not guaranteed to be NULL and might be - // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T>`'s capacity - // to be zero if no memory has been allocated yet. - let ptr = if cap == 0 { - core::ptr::null_mut() - } else { - old_ptr - }; - - // SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to - // `krealloc_aligned`. We also verified that the type is not a ZST. - let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) }; - if new_ptr.is_null() { - // SAFETY: We are just rebuilding the existing `Vec` with no changes. - unsafe { rebuild(self, old_ptr, len, cap) }; - Err(AllocError) - } else { - // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap - // is greater than `cap`, so it continues to be >= `len`. - unsafe { rebuild(self, new_ptr.cast::<T>(), len, new_cap) }; - Ok(()) - } - } -} - -#[cfg(not(any(test, testlib)))] -fn destructure<T>(v: &mut Vec<T>) -> (*mut T, usize, usize) { - let mut tmp = Vec::new(); - core::mem::swap(&mut tmp, v); - let mut tmp = core::mem::ManuallyDrop::new(tmp); - let len = tmp.len(); - let cap = tmp.capacity(); - (tmp.as_mut_ptr(), len, cap) -} - -/// Rebuilds a `Vec` from a pointer, length, and capacity. -/// -/// # Safety -/// -/// The same as [`Vec::from_raw_parts`]. -#[cfg(not(any(test, testlib)))] -unsafe fn rebuild<T>(v: &mut Vec<T>, ptr: *mut T, len: usize, cap: usize) { - // SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`. - let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) }; - core::mem::swap(&mut tmp, v); -} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 80223cdaa485..07daccf6ca8e 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,10 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{flags::*, vec_ext::VecExt, Box, KBox, KVBox, KVVec, KVec, VBox, VVec}; - -#[doc(no_inline)] -pub use alloc::vec::Vec; +pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec};
#[doc(no_inline)] pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
From: Danilo Krummrich dakr@kernel.org
commit 3145dc91c3c0ad945f06354385a6eb89d22becdb upstream.
Now that we removed `VecExt` and the corresponding includes in prelude.rs, add the new kernel `Vec` type instead.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-22-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/prelude.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 07daccf6ca8e..8bdab9aa0d16 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,7 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin;
-pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec}; +pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
#[doc(no_inline)] pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
From: Danilo Krummrich dakr@kernel.org
commit 29a48d25ff53c183482dc88a99133a0fb5aa541a upstream.
Use `core::alloc::LayoutError` instead of `alloc::alloc::LayoutError` in preparation to get rid of Rust's alloc crate.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-23-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index be6509d5f4a4..aced2fe68b86 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -6,7 +6,7 @@
use crate::{alloc::AllocError, str::CStr};
-use alloc::alloc::LayoutError; +use core::alloc::LayoutError;
use core::fmt; use core::num::NonZeroI32;
From: Danilo Krummrich dakr@kernel.org
commit 4a28ab469ff01855eb819dfd94754d1792f03f2a upstream.
Additional to `testlib` also check for `test` in `Error::name`. This is required by a subsequent patch that (indirectly) uses `Error` in test cases.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-24-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index aced2fe68b86..7cd3bbab52f2 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -161,7 +161,7 @@ pub fn to_ptr<T>(self) -> *mut T { }
/// Returns a string representing the error, if one exists. - #[cfg(not(testlib))] + #[cfg(not(any(test, testlib)))] pub fn name(&self) -> Option<&'static CStr> { // SAFETY: Just an FFI call, there are no extra safety requirements. let ptr = unsafe { bindings::errname(-self.0.get()) }; @@ -178,7 +178,7 @@ pub fn name(&self) -> Option<&'static CStr> { /// When `testlib` is configured, this always returns `None` to avoid the dependency on a /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still /// run in userspace. - #[cfg(testlib)] + #[cfg(any(test, testlib))] pub fn name(&self) -> Option<&'static CStr> { None }
From: Danilo Krummrich dakr@kernel.org
commit 909037ce0369bc3f4fd31743fd2d8d7096f06002 upstream.
Provide a simple helper function to check whether given flags do contain one or multiple other flags.
This is used by a subsequent patch implementing the Cmalloc `Allocator` to check for __GFP_ZERO.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-25-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 7fc2e404e594..049fca7a514d 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -35,7 +35,7 @@ /// They can be combined with the operators `|`, `&`, and `!`. /// /// Values can be used from the [`flags`] module. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub struct Flags(u32);
impl Flags { @@ -43,6 +43,11 @@ impl Flags { pub(crate) fn as_raw(self) -> u32 { self.0 } + + /// Check whether `flags` is contained in `self`. + pub fn contains(self, flags: Flags) -> bool { + (self & flags) == flags + } }
impl core::ops::BitOr for Flags {
From: Danilo Krummrich dakr@kernel.org
commit dd09538fb4093176a818fcecd45114430cc5840f upstream.
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.
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-26-dakr@kernel.org [ Removed the temporary `allow(dead_code)` as discussed in the list and fixed typo, added backticks. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 1 - rust/kernel/alloc/allocator_test.rs | 89 ++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 049fca7a514d..c6024afa3739 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -215,7 +215,6 @@ unsafe fn free(ptr: NonNull<u8>, layout: Layout) { } }
-#[allow(dead_code)] /// 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; diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index bd0cbcd93e52..54ca85964d4a 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -1,22 +1,95 @@ // 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::{AllocError, Allocator, Flags}; +use super::{flags::*, AllocError, Allocator, Flags}; use core::alloc::Layout; +use core::cmp; +use core::ptr; use core::ptr::NonNull;
-pub struct Kmalloc; +/// The userspace allocator based on libc. +pub struct Cmalloc; + +pub type Kmalloc = Cmalloc; pub type Vmalloc = Kmalloc; pub type KVmalloc = Kmalloc;
-unsafe impl Allocator for Kmalloc { +extern "C" { + #[link_name = "aligned_alloc"] + fn libc_aligned_alloc(align: usize, size: usize) -> *mut core::ffi::c_void; + + #[link_name = "free"] + fn libc_free(ptr: *mut core::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, + ptr: Option<NonNull<u8>>, + layout: Layout, + old_layout: Layout, + flags: Flags, ) -> Result<NonNull<[u8]>, AllocError> { - panic!(); + 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, + )); + } + + // 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()) } as *mut 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())) } }
From: Danilo Krummrich dakr@kernel.org
commit eb6f92cd3f755c179204ea1f933b07cf992892fd upstream.
The current implementation of tests in str.rs use `format!` to format strings for comparison, which, internally, creates a new `String`.
In order to prepare for getting rid of Rust's alloc crate, we have to cut this dependency. Instead, implement `format!` for `CString`.
Note that for userspace tests, `Kmalloc`, which is backing `CString`'s memory, is just a type alias to `Cmalloc`.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-27-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/str.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 6053bc7a98d1..aff6baa521d4 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -524,7 +524,28 @@ macro_rules! c_str { #[cfg(test)] mod tests { use super::*; - use alloc::format; + + struct String(CString); + + impl String { + fn from_fmt(args: fmt::Arguments<'_>) -> Self { + String(CString::try_from_fmt(args).unwrap()) + } + } + + impl Deref for String { + type Target = str; + + fn deref(&self) -> &str { + self.0.to_str().unwrap() + } + } + + macro_rules! format { + ($($f:tt)*) => ({ + &*String::from_fmt(kernel::fmt!($($f)*)) + }) + }
const ALL_ASCII_CHARS: &'static str = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
From: Danilo Krummrich dakr@kernel.org
commit 8ae740c3917ff92108df17236b3cf1b9a74bd359 upstream.
Before we remove Rust's alloc crate, rewrite the module comment in alloc.rs to avoid a rustdoc warning.
Besides that, the module comment in alloc.rs isn't correct anymore, we're no longer extending Rust's alloc crate.
Reviewed-by: Alice Ryhl aliceryhl@google.com 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-28-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index c6024afa3739..f2f7f3a53d29 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0
-//! Extensions to the [`alloc`] crate. +//! Implementation of the kernel's memory allocation infrastructure.
#[cfg(not(any(test, testlib)))] pub mod allocator;
From: Danilo Krummrich dakr@kernel.org
commit 392e34b6bc22077ef63abf62387ea3e9f39418c1 upstream.
Now that we have our own `Allocator`, `Box` and `Vec` types we can remove Rust's `alloc` crate and the `new_uninit` unstable feature.
Also remove `Kmalloc`'s `GlobalAlloc` implementation -- we can't remove this in a separate patch, since the `alloc` crate requires a `#[global_allocator]` to set, that implements `GlobalAlloc`.
Signed-off-by: Danilo Krummrich dakr@kernel.org Link: https://lore.kernel.org/r/20241004154149.93856-29-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/Makefile | 43 +++++--------------- rust/exports.c | 1 - rust/kernel/alloc/allocator.rs | 65 +------------------------------ scripts/Makefile.build | 4 +- scripts/generate_rust_analyzer.py | 11 +----- 5 files changed, 16 insertions(+), 108 deletions(-)
diff --git a/rust/Makefile b/rust/Makefile index b16456ac5d77..9358d3eb7555 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -15,8 +15,8 @@ always-$(CONFIG_RUST) += libmacros.so no-clean-files += libmacros.so
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs -obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o -always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \ +obj-$(CONFIG_RUST) += bindings.o kernel.o +always-$(CONFIG_RUST) += exports_helpers_generated.h \ exports_bindings_generated.h exports_kernel_generated.h
always-$(CONFIG_RUST) += uapi/uapi_generated.rs @@ -53,11 +53,6 @@ endif core-cfgs = \ --cfg no_fp_fmt_parse
-alloc-cfgs = \ - --cfg no_global_oom_handling \ - --cfg no_rc \ - --cfg no_sync - quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< cmd_rustdoc = \ OBJTREE=$(abspath $(objtree)) \ @@ -81,7 +76,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< # command-like flags to solve the issue. Meanwhile, we use the non-custom case # and then retouch the generated files. rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \ - rustdoc-alloc rustdoc-kernel + rustdoc-kernel $(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/ $(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/ $(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \ @@ -108,20 +103,11 @@ rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE +$(call if_changed,rustdoc)
-# We need to allow `rustdoc::broken_intra_doc_links` because some -# `no_global_oom_handling` functions refer to non-`no_global_oom_handling` -# functions. Ideally `rustdoc` would have a way to distinguish broken links -# due to things that are "configured out" vs. entirely non-existing ones. -rustdoc-alloc: private rustc_target_flags = $(alloc-cfgs) \ - -Arustdoc::broken_intra_doc_links -rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE - +$(call if_changed,rustdoc) - -rustdoc-kernel: private rustc_target_flags = --extern alloc \ +rustdoc-kernel: private rustc_target_flags = \ --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \ --extern bindings --extern uapi rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \ - rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \ + rustdoc-compiler_builtins $(obj)/libmacros.so \ $(obj)/bindings.o FORCE +$(call if_changed,rustdoc)
@@ -165,7 +151,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $< mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \ OBJTREE=$(abspath $(objtree)) \ $(RUSTDOC) --test $(rust_flags) \ - -L$(objtree)/$(obj) --extern alloc --extern kernel \ + -L$(objtree)/$(obj) --extern kernel \ --extern build_error --extern macros \ --extern bindings --extern uapi \ --no-run --crate-name kernel -Zunstable-options \ @@ -201,7 +187,7 @@ rusttest-macros: $(src)/macros/lib.rs FORCE +$(call if_changed,rustc_test) +$(call if_changed,rustdoc_test)
-rusttest-kernel: private rustc_target_flags = --extern alloc \ +rusttest-kernel: private rustc_target_flags = \ --extern build_error --extern macros --extern bindings --extern uapi rusttest-kernel: $(src)/kernel/lib.rs \ rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \ @@ -328,9 +314,6 @@ quiet_cmd_exports = EXPORTS $@ $(obj)/exports_core_generated.h: $(obj)/core.o FORCE $(call if_changed,exports)
-$(obj)/exports_alloc_generated.h: $(obj)/alloc.o FORCE - $(call if_changed,exports) - # Even though Rust kernel modules should never use the bindings directly, # symbols from the `bindings` crate and the C helpers need to be exported # because Rust generics and inlined functions may not get their code generated @@ -377,7 +360,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
rust-analyzer: $(Q)$(srctree)/scripts/generate_rust_analyzer.py \ - --cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \ + --cfgs='core=$(core-cfgs)' \ $(realpath $(srctree)) $(realpath $(objtree)) \ $(rustc_sysroot) $(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \ $(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json @@ -415,12 +398,6 @@ $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*' $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE +$(call if_changed_rule,rustc_library)
-$(obj)/alloc.o: private skip_clippy = 1 -$(obj)/alloc.o: private skip_flags = -Wunreachable_pub -$(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs) -$(obj)/alloc.o: $(RUST_LIB_SRC)/alloc/src/lib.rs $(obj)/compiler_builtins.o FORCE - +$(call if_changed_rule,rustc_library) - $(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE +$(call if_changed_rule,rustc_library)
@@ -435,9 +412,9 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \ $(obj)/uapi/uapi_generated.rs FORCE +$(call if_changed_rule,rustc_library)
-$(obj)/kernel.o: private rustc_target_flags = --extern alloc \ +$(obj)/kernel.o: private rustc_target_flags = \ --extern build_error --extern macros --extern bindings --extern uapi -$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \ +$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \ $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE +$(call if_changed_rule,rustc_library)
diff --git a/rust/exports.c b/rust/exports.c index e5695f3b45b7..82a037381798 100644 --- a/rust/exports.c +++ b/rust/exports.c @@ -16,7 +16,6 @@ #define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
#include "exports_core_generated.h" -#include "exports_alloc_generated.h" #include "exports_helpers_generated.h" #include "exports_bindings_generated.h" #include "exports_kernel_generated.h" diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index f8a1f0feb25d..a041bbfdabec 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -8,8 +8,8 @@ //! //! Reference: https://docs.kernel.org/core-api/memory-allocation.html
-use super::{flags::*, Flags}; -use core::alloc::{GlobalAlloc, Layout}; +use super::Flags; +use core::alloc::Layout; use core::ptr; use core::ptr::NonNull;
@@ -54,23 +54,6 @@ fn aligned_size(new_layout: Layout) -> usize { layout.size() }
-/// 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. -pub(crate) unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: Flags) -> *mut u8 { - let size = aligned_size(new_layout); - - // 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 from `layout.size()` (which cannot be zero according - // to the function safety requirement) - unsafe { bindings::krealloc(ptr as *const core::ffi::c_void, size, flags.0) as *mut u8 } -} - /// # Invariants /// /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`. @@ -156,43 +139,6 @@ unsafe fn realloc( } }
-// SAFETY: TODO. -unsafe impl GlobalAlloc for Kmalloc { - unsafe fn alloc(&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, GFP_KERNEL) } - } - - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - // SAFETY: TODO. - unsafe { - 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, 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, GFP_KERNEL | __GFP_ZERO) } - } -} - // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that // - memory remains valid until it is explicitly freed, // - passing a pointer to a valid memory allocation is OK, @@ -240,10 +186,3 @@ unsafe fn realloc( unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) } } } - -#[global_allocator] -static ALLOCATOR: Kmalloc = Kmalloc; - -// See https://github.com/rust-lang/rust/pull/86844. -#[no_mangle] -static __rust_no_alloc_shim_is_unstable: u8 = 0; diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 64518c2f3d9c..2bba59e790b8 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -248,7 +248,7 @@ $(obj)/%.lst: $(obj)/%.c FORCE # Compile Rust sources (.rs) # ---------------------------------------------------------------------------
-rust_allowed_features := arbitrary_self_types,lint_reasons,new_uninit +rust_allowed_features := arbitrary_self_types,lint_reasons
# `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree @@ -258,7 +258,7 @@ rust_common_cmd = \ -Zallow-features=$(rust_allowed_features) \ -Zcrate-attr=no_std \ -Zcrate-attr='feature($(rust_allowed_features))' \ - -Zunstable-options --extern force:alloc --extern kernel \ + -Zunstable-options --extern kernel \ --crate-type rlib -L $(objtree)/rust/ \ --crate-name $(basename $(notdir $@)) \ --sysroot=/dev/null \ diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index d2bc63cde8c6..09e1d166d8d2 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -64,13 +64,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): [], )
- append_crate( - "alloc", - sysroot_src / "alloc" / "src" / "lib.rs", - ["core", "compiler_builtins"], - cfg=crates_cfgs.get("alloc", []), - ) - append_crate( "macros", srctree / "rust" / "macros" / "lib.rs", @@ -96,7 +89,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): append_crate( "kernel", srctree / "rust" / "kernel" / "lib.rs", - ["core", "alloc", "macros", "build_error", "bindings"], + ["core", "macros", "build_error", "bindings"], cfg=cfg, ) crates[-1]["source"] = { @@ -133,7 +126,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): append_crate( name, path, - ["core", "alloc", "kernel"], + ["core", "kernel"], cfg=cfg, )
From: Danilo Krummrich dakr@kernel.org
commit 6ce162a002657910104c7a07fb50017681bc476c upstream.
Add maintainers entry for the Rust `alloc` module.
Currently, this includes the `Allocator` API itself, `Allocator` implementations, such as `Kmalloc` or `Vmalloc`, as well as the kernel's implementation of the primary memory allocation data structures, `Box` and `Vec`.
Signed-off-by: Danilo Krummrich dakr@kernel.org Link: https://lore.kernel.org/r/20241004154149.93856-30-dakr@kernel.org Signed-off-by: Miguel Ojeda ojeda@kernel.org --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS index f4e08a0851bd..de04c7ba8571 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20183,6 +20183,13 @@ F: scripts/*rust* F: tools/testing/selftests/rust/ K: \b(?i:rust)\b
+RUST [ALLOC] +M: Danilo Krummrich dakr@kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/alloc.rs +F: rust/kernel/alloc/ + RXRPC SOCKETS (AF_RXRPC) M: David Howells dhowells@redhat.com M: Marc Dionne marc.dionne@auristor.com
From: Thomas Böhler witcher@wiredspace.de
commit c408dd81678bb0a957eae96962c913c242e069f7 upstream.
Rust's standard library's `std::iter::Iterator` trait provides a function `find` that finds the first element that satisfies a predicate. The function `Version::from_segments` is doing the same thing but is implementing the same logic itself.
Clippy complains about this in the `manual_find` lint:
error: manual implementation of `Iterator::find` --> drivers/gpu/drm/drm_panic_qr.rs:212:9 | 212 | / for v in (1..=40).map(|k| Version(k)) { 213 | | if v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum() { 214 | | return Some(v); 215 | | } 216 | | } 217 | | None | |____________^ help: replace with an iterator: `(1..=40).map(|k| Version(k)).find(|&v| v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum())` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_find = note: `-D clippy::manual-find` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_find)]`
Use `Iterator::find` instead to make the intention clearer.
At the same time, clean up the redundant closure that Clippy warns about too:
error: redundant closure --> drivers/gpu/drm/drm_panic_qr.rs:212:31 | 212 | for v in (1..=40).map(|k| Version(k)) { | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `Version` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure = note: `-D clippy::redundant-closure` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-2-witcher@wiredspace.de [ Reworded to mention the redundant closure cleanup too. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index 447740d79d3d..25edc69f8e22 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -209,12 +209,9 @@ impl Version { /// Returns the smallest QR version than can hold these segments. fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> { - for v in (1..=40).map(|k| Version(k)) { - if v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum() { - return Some(v); - } - } - None + (1..=40) + .map(Version) + .find(|&v| v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum()) }
fn width(&self) -> u8 {
From: Thomas Böhler witcher@wiredspace.de
commit 7b6de57e0b2d1e62becfa3aac063c4c58d2c2c42 upstream.
The function `alignment_pattern` returns a static reference to a `u8` slice. The borrow of the returned element in `ALIGNMENT_PATTERNS` is already a reference as defined in the array definition above so this borrow is unnecessary and removed by the compiler. Clippy notes this in `needless_borrow`:
error: this expression creates a reference which is immediately dereferenced by the compiler --> drivers/gpu/drm/drm_panic_qr.rs:245:9 | 245 | &ALIGNMENT_PATTERNS[self.0 - 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change this to: `ALIGNMENT_PATTERNS[self.0 - 1]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `-D clippy::needless-borrow` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
Remove the unnecessary borrow.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-3-witcher@wiredspace.de Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index 25edc69f8e22..ce245d6b9b91 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -239,7 +239,7 @@ fn g1_blk_size(&self) -> usize { }
fn alignment_pattern(&self) -> &'static [u8] { - &ALIGNMENT_PATTERNS[self.0 - 1] + ALIGNMENT_PATTERNS[self.0 - 1] }
fn poly(&self) -> &'static [u8] {
From: Thomas Böhler witcher@wiredspace.de
commit ae75c40117b53ae3d91dfc9d0bf06984a079f044 upstream.
Eliding lifetimes when possible instead of specifying them directly is both shorter and easier to read. Clippy notes this in the `needless_lifetimes` lint:
error: the following explicit lifetimes could be elided: 'b --> drivers/gpu/drm/drm_panic_qr.rs:479:16 | 479 | fn new<'a, 'b>(segments: &[&Segment<'b>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { | ^^ ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes = note: `-D clippy::needless-lifetimes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_lifetimes)]` help: elide the lifetimes | 479 - fn new<'a, 'b>(segments: &[&Segment<'b>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { 479 + fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { |
Remove the explicit lifetime annotation in favour of an elided lifetime.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-4-witcher@wiredspace.de Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ce245d6b9b91..f7e224ad340d 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -476,7 +476,7 @@ struct EncodedMsg<'a> { /// Data to be put in the QR code, with correct segment encoding, padding, and /// Error Code Correction. impl EncodedMsg<'_> { - fn new<'a, 'b>(segments: &[&Segment<'b>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { + fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> { let version = Version::from_segments(segments)?; let ec_size = version.ec_size(); let g1_blocks = version.g1_blocks();
From: Thomas Böhler witcher@wiredspace.de
commit da13129a3f2a75d49469e1d6f7dcefac2d11d205 upstream.
Rust allows initializing fields of a struct without specifying the attribute that is assigned if the variable has the same name. In this instance this is done for all other attributes of the struct except for `data`. Clippy notes the redundant field name:
error: redundant field names in struct initialization --> drivers/gpu/drm/drm_panic_qr.rs:495:13 | 495 | data: data, | ^^^^^^^^^^ help: replace it with: `data` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_na... = note: `-D clippy::redundant-field-names` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_field_names)]`
Remove the redundant `data` in the assignment to be consistent.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-5-witcher@wiredspace.de [ Reworded to add Clippy warning like it is done in the rest of the series. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index f7e224ad340d..c0f9fd69d6cf 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -489,7 +489,7 @@ fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<' data.fill(0);
let mut em = EncodedMsg { - data: data, + data, ec_size, g1_blocks, g2_blocks,
From: Thomas Böhler witcher@wiredspace.de
commit 5bb698e6fc514ddd9e23b6649b29a0934d8d8586 upstream.
It is common practice in Rust to indent the next line the same amount of space as the previous one if both belong to the same list item. Clippy checks for this with the lint `doc_lazy_continuation`.
error: doc list item without indentation --> drivers/gpu/drm/drm_panic_qr.rs:979:5 | 979 | /// conversion to numeric segments. | ^ | = help: if this is supposed to be its own paragraph, add a blank line = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuat... = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` help: indent this line | 979 | /// conversion to numeric segments. | ++
Indent the offending line by 2 more spaces to remove this Clippy error.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-6-witcher@wiredspace.de [ Reworded to indent Clippy's message. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index c0f9fd69d6cf..ed87954176e3 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -975,7 +975,7 @@ fn draw_all(&mut self, data: impl Iterator<Item = u8>) { /// * `url_len`: Length of the URL. /// /// * If `url_len` > 0, remove the 2 segments header/length and also count the -/// conversion to numeric segments. +/// conversion to numeric segments. /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment. #[no_mangle] pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
From: Thomas Böhler witcher@wiredspace.de
commit 27aef8a52e4b7f120ce47cd638d9d83065b759d2 upstream.
Clippy complains about a non-minimal boolean expression with `nonminimal_bool`:
error: this boolean expression can be simplified --> drivers/gpu/drm/drm_panic_qr.rs:722:9 | 722 | (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool = note: `-D clippy::nonminimal-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` help: try | 722 | !(x >= 8 || y >= 8 && y < end) || (x >= end && y < 8) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 722 | (y >= end || y < 8) && x < 8 || (x >= end && y < 8) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While this can be useful in a lot of cases, it isn't here because the line expresses clearly what the intention is. Simplifying the expression means losing clarity, so opt-out of this lint for the offending line.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-7-witcher@wiredspace.de Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ed87954176e3..4671a4fb99da 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -719,7 +719,10 @@ fn draw_finders(&mut self) {
fn is_finder(&self, x: u8, y: u8) -> bool { let end = self.width - 8; - (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8) + #[expect(clippy::nonminimal_bool)] + { + (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8) + } }
// Alignment pattern: 5x5 squares in a grid.
From: Thomas Böhler witcher@wiredspace.de
commit 06b919e3fedf4798a1f0f60e0b67caa192f724a7 upstream.
Clippy warns about a reimplementation of `RangeInclusive::contains`:
error: manual `!RangeInclusive::contains` implementation --> drivers/gpu/drm/drm_panic_qr.rs:986:8 | 986 | if version < 1 || version > 40 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!(1..=40).contains(&version)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_conta... = note: `-D clippy::manual-range-contains` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_range_contains)]`
Ignore this and keep the current implementation as that makes it easier to read.
Fixes: cb5164ac43d0 ("drm/panic: Add a QR code panic screen") Reported-by: Miguel Ojeda ojeda@kernel.org Link: https://github.com/Rust-for-Linux/linux/issues/1123 Signed-off-by: Thomas Böhler witcher@wiredspace.de Reviewed-by: Jocelyn Falempe jfalempe@redhat.com Link: https://lore.kernel.org/r/20241019084048.22336-8-witcher@wiredspace.de Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index 4671a4fb99da..ef2d490965ba 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -982,6 +982,7 @@ fn draw_all(&mut self, data: impl Iterator<Item = u8>) { /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment. #[no_mangle] pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize { + #[expect(clippy::manual_range_contains)] if version < 1 || version > 40 { return 0; }
From: "Ethan D. Twardy" ethan.twardy@gmail.com
commit b2c261fa8629dff2bd1143fa790797a773ace102 upstream.
Previously, the rusttest target for the macros crate did not specify the dependencies necessary to run the rustdoc tests. These tests rely on the kernel crate, so add the dependencies.
Signed-off-by: Ethan D. Twardy ethan.twardy@gmail.com Link: https://github.com/Rust-for-Linux/linux/issues/1076 Link: https://lore.kernel.org/r/20240704145607.17732-2-ethan.twardy@gmail.com [ Rebased (`alloc` is gone nowadays, sysroot handling is simpler) and simplified (reused `rustdoc_test` rule instead of adding a new one, no need for `rustdoc-compiler_builtins`, removed unneeded `macros` explicit path). Made `vtable` example fail (avoiding to increase the complexity in the `rusttest` target). Removed unstable `-Zproc-macro-backtrace` option. Reworded accordingly. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/Makefile | 17 +++++++++++++---- rust/macros/lib.rs | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/rust/Makefile b/rust/Makefile index 9358d3eb7555..5e7612f69cea 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -129,6 +129,14 @@ rusttestlib-macros: private rustc_test_library_proc = yes rusttestlib-macros: $(src)/macros/lib.rs FORCE +$(call if_changed,rustc_test_library)
+rusttestlib-kernel: private rustc_target_flags = \ + --extern build_error --extern macros \ + --extern bindings --extern uapi +rusttestlib-kernel: $(src)/kernel/lib.rs \ + rusttestlib-bindings rusttestlib-uapi rusttestlib-build_error \ + $(obj)/libmacros.so $(obj)/bindings.o FORCE + +$(call if_changed,rustc_test_library) + rusttestlib-bindings: $(src)/bindings/lib.rs FORCE +$(call if_changed,rustc_test_library)
@@ -181,19 +189,20 @@ quiet_cmd_rustc_test = RUSTC T $<
rusttest: rusttest-macros rusttest-kernel
-rusttest-macros: private rustc_target_flags = --extern proc_macro +rusttest-macros: private rustc_target_flags = --extern proc_macro \ + --extern macros --extern kernel rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro -rusttest-macros: $(src)/macros/lib.rs FORCE +rusttest-macros: $(src)/macros/lib.rs \ + rusttestlib-macros rusttestlib-kernel FORCE +$(call if_changed,rustc_test) +$(call if_changed,rustdoc_test)
rusttest-kernel: private rustc_target_flags = \ --extern build_error --extern macros --extern bindings --extern uapi -rusttest-kernel: $(src)/kernel/lib.rs \ +rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-kernel \ rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \ rusttestlib-uapi FORCE +$(call if_changed,rustc_test) - +$(call if_changed,rustc_test_library)
ifdef CONFIG_CC_IS_CLANG bindgen_c_flags = $(c_flags) diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 939ae00b723a..b16402a16acd 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -132,7 +132,7 @@ pub fn module(ts: TokenStream) -> TokenStream { /// calls to this function at compile time: /// /// ```compile_fail -/// # use kernel::error::VTABLE_DEFAULT_ERROR; +/// # // Intentionally missing `use`s to simplify `rusttest`. /// kernel::build_error(VTABLE_DEFAULT_ERROR) /// ``` ///
From: Gary Guo gary@garyguo.net
commit 75c1fd41a671a0843b89d1526411a837a7163fa2 upstream.
Without `-fno-builtin`, for functions like memcpy/memmove (and many others), bindgen seems to be using the clang-provided prototype. This prototype is ABI-wise compatible, but the issue is that it does not have the same information as the source code w.r.t. typedefs.
For example, bindgen generates the following:
extern "C" { pub fn strlen(s: *const core::ffi::c_char) -> core::ffi::c_ulong; }
note that the return type is `c_ulong` (i.e. unsigned long), despite the size_t-is-usize behavior (this is default, and we have not opted out from it using --no-size_t-is-usize).
Similarly, memchr's size argument should be of type `__kernel_size_t`, but bindgen generates `c_ulong` directly.
We want to ensure any `size_t` is translated to Rust `usize` so that we can avoid having them be different type on 32-bit and 64-bit architectures, and hence would require a lot of excessive type casts when calling FFI functions.
I found that this bindgen behavior (which probably is caused by libclang) can be disabled by `-fno-builtin`. Using the flag for compiled code can result in less optimisation because compiler cannot assume about their properties anymore, but this should not affect bindgen.
[ Trevor asked: "I wonder how reliable this behavior is. Maybe bindgen could do a better job controlling this, is there an open issue?".
Gary replied: ..."apparently this is indeed the suggested approach in https://github.com/rust-lang/rust-bindgen/issues/1770". - Miguel ]
Signed-off-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240913213041.395655-2-gary@garyguo.net [ Formatted comment. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/rust/Makefile b/rust/Makefile index 5e7612f69cea..a6e80caa42c1 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -264,7 +264,11 @@ else bindgen_c_flags_lto = $(bindgen_c_flags) endif
-bindgen_c_flags_final = $(bindgen_c_flags_lto) -D__BINDGEN__ +# `-fno-builtin` is passed to avoid `bindgen` from using `clang` builtin +# prototypes for functions like `memcpy` -- if this flag is not passed, +# `bindgen`-generated prototypes use `c_ulong` or `c_uint` depending on +# architecture instead of generating `usize`. +bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
# Each `bindgen` release may upgrade the list of Rust target versions. By # default, the highest stable release in their list is used. Thus we need to set
From: Gary Guo gary@garyguo.net
commit 2fd6f55c048d0c863ffbc8590b1bd2edb5ff13e5 upstream.
Currently bindgen has special logic to recognise `size_t` and `ssize_t` and map them to Rust `usize` and `isize`. Similarly, `ptrdiff_t` is mapped to `isize`.
However this falls short for `__kernel_size_t`, `__kernel_ssize_t` and `__kernel_ptrdiff_t`. To ensure that they are mapped to usize/isize rather than 32/64 integers depending on platform, blocklist them in bindgen parameters and manually provide their definition.
Signed-off-by: Gary Guo gary@garyguo.net Reviewed-by: Alice Ryhl aliceryhl@google.com Reviewed-by: Trevor Gross tmgross@umich.edu Link: https://lore.kernel.org/r/20240913213041.395655-3-gary@garyguo.net [ Formatted comment. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/bindgen_parameters | 5 +++++ rust/bindings/lib.rs | 5 +++++ rust/uapi/lib.rs | 5 +++++ 3 files changed, 15 insertions(+)
diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters index b7c7483123b7..0f96af8b9a7f 100644 --- a/rust/bindgen_parameters +++ b/rust/bindgen_parameters @@ -1,5 +1,10 @@ # SPDX-License-Identifier: GPL-2.0
+# We want to map these types to `isize`/`usize` manually, instead of +# define them as `int`/`long` depending on platform bitwidth. +--blocklist-type __kernel_s?size_t +--blocklist-type __kernel_ptrdiff_t + --opaque-type xregs_state --opaque-type desc_struct --opaque-type arch_lbr_state diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs index d6da3011281a..014af0d1fc70 100644 --- a/rust/bindings/lib.rs +++ b/rust/bindings/lib.rs @@ -27,6 +27,11 @@ #[allow(dead_code)] #[allow(clippy::undocumented_unsafe_blocks)] mod bindings_raw { + // Manual definition for blocklisted types. + type __kernel_size_t = usize; + type __kernel_ssize_t = isize; + type __kernel_ptrdiff_t = isize; + // Use glob import here to expose all helpers. // Symbols defined within the module will take precedence to the glob import. pub use super::bindings_helper::*; diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs index fea2de330d19..13495910271f 100644 --- a/rust/uapi/lib.rs +++ b/rust/uapi/lib.rs @@ -25,4 +25,9 @@ unsafe_op_in_unsafe_fn )]
+// Manual definition of blocklisted types. +type __kernel_size_t = usize; +type __kernel_ssize_t = isize; +type __kernel_ptrdiff_t = isize; + include!(concat!(env!("OBJTREE"), "/rust/uapi/uapi_generated.rs"));
From: Gary Guo gary@garyguo.net
commit d072acda4862f095ec9056979b654cc06a22cc68 upstream.
Currently FFI integer types are defined in libcore. This commit creates the `ffi` crate and asks bindgen to use that crate for FFI integer types instead of `core::ffi`.
This commit is preparatory and no type changes are made in this commit yet.
Signed-off-by: Gary Guo gary@garyguo.net Link: https://lore.kernel.org/r/20240913213041.395655-4-gary@garyguo.net [ Added `rustdoc`, `rusttest` and KUnit tests support. Rebased on top of `rust-next` (e.g. migrated more `core::ffi` cases). Reworded crate docs slightly and formatted. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/Makefile | 39 +++++++++++++++++++---------- rust/ffi.rs | 13 ++++++++++ rust/kernel/alloc/allocator.rs | 2 +- rust/kernel/alloc/allocator_test.rs | 4 +-- rust/kernel/alloc/kbox.rs | 12 ++++----- rust/kernel/block/mq/operations.rs | 18 ++++++------- rust/kernel/block/mq/raw_writer.rs | 2 +- rust/kernel/block/mq/tag_set.rs | 2 +- rust/kernel/error.rs | 20 +++++++-------- rust/kernel/init.rs | 2 +- rust/kernel/lib.rs | 2 ++ rust/kernel/net/phy.rs | 16 ++++++------ rust/kernel/str.rs | 4 +-- rust/kernel/sync/arc.rs | 6 ++--- rust/kernel/sync/condvar.rs | 2 +- rust/kernel/sync/lock.rs | 2 +- rust/kernel/sync/lock/mutex.rs | 2 +- rust/kernel/sync/lock/spinlock.rs | 2 +- rust/kernel/task.rs | 8 ++---- rust/kernel/time.rs | 4 +-- rust/kernel/types.rs | 14 +++++------ rust/kernel/uaccess.rs | 6 ++--- rust/macros/module.rs | 8 +++--- 23 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 rust/ffi.rs
diff --git a/rust/Makefile b/rust/Makefile index a6e80caa42c1..09521fc449dc 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -3,7 +3,7 @@ # Where to place rustdoc generated documentation rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
-obj-$(CONFIG_RUST) += core.o compiler_builtins.o +obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o always-$(CONFIG_RUST) += exports_core_generated.h
# Missing prototypes are expected in the helpers since these are exported @@ -103,10 +103,13 @@ rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE +$(call if_changed,rustdoc)
-rustdoc-kernel: private rustc_target_flags = \ +rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE + +$(call if_changed,rustdoc) + +rustdoc-kernel: private rustc_target_flags = --extern ffi \ --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \ --extern bindings --extern uapi -rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \ +rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \ rustdoc-compiler_builtins $(obj)/libmacros.so \ $(obj)/bindings.o FORCE +$(call if_changed,rustdoc) @@ -124,12 +127,15 @@ quiet_cmd_rustc_test_library = RUSTC TL $< rusttestlib-build_error: $(src)/build_error.rs FORCE +$(call if_changed,rustc_test_library)
+rusttestlib-ffi: $(src)/ffi.rs FORCE + +$(call if_changed,rustc_test_library) + rusttestlib-macros: private rustc_target_flags = --extern proc_macro rusttestlib-macros: private rustc_test_library_proc = yes rusttestlib-macros: $(src)/macros/lib.rs FORCE +$(call if_changed,rustc_test_library)
-rusttestlib-kernel: private rustc_target_flags = \ +rusttestlib-kernel: private rustc_target_flags = --extern ffi \ --extern build_error --extern macros \ --extern bindings --extern uapi rusttestlib-kernel: $(src)/kernel/lib.rs \ @@ -137,10 +143,12 @@ rusttestlib-kernel: $(src)/kernel/lib.rs \ $(obj)/libmacros.so $(obj)/bindings.o FORCE +$(call if_changed,rustc_test_library)
-rusttestlib-bindings: $(src)/bindings/lib.rs FORCE +rusttestlib-bindings: private rustc_target_flags = --extern ffi +rusttestlib-bindings: $(src)/bindings/lib.rs rusttestlib-ffi FORCE +$(call if_changed,rustc_test_library)
-rusttestlib-uapi: $(src)/uapi/lib.rs FORCE +rusttestlib-uapi: private rustc_target_flags = --extern ffi +rusttestlib-uapi: $(src)/uapi/lib.rs rusttestlib-ffi FORCE +$(call if_changed,rustc_test_library)
quiet_cmd_rustdoc_test = RUSTDOC T $< @@ -159,7 +167,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $< mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \ OBJTREE=$(abspath $(objtree)) \ $(RUSTDOC) --test $(rust_flags) \ - -L$(objtree)/$(obj) --extern kernel \ + -L$(objtree)/$(obj) --extern ffi --extern kernel \ --extern build_error --extern macros \ --extern bindings --extern uapi \ --no-run --crate-name kernel -Zunstable-options \ @@ -197,9 +205,9 @@ rusttest-macros: $(src)/macros/lib.rs \ +$(call if_changed,rustc_test) +$(call if_changed,rustdoc_test)
-rusttest-kernel: private rustc_target_flags = \ +rusttest-kernel: private rustc_target_flags = --extern ffi \ --extern build_error --extern macros --extern bindings --extern uapi -rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-kernel \ +rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \ rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \ rusttestlib-uapi FORCE +$(call if_changed,rustc_test) @@ -286,7 +294,7 @@ bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__ quiet_cmd_bindgen = BINDGEN $@ cmd_bindgen = \ $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.68 \ - --use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \ + --use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \ --no-debug '.*' --enable-function-attribute-detection \ -o $@ -- $(bindgen_c_flags_final) -DMODULE \ $(bindgen_target_cflags) $(bindgen_target_extra) @@ -414,18 +422,23 @@ $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE $(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE +$(call if_changed_rule,rustc_library)
+$(obj)/ffi.o: $(src)/ffi.rs $(obj)/compiler_builtins.o FORCE + +$(call if_changed_rule,rustc_library) + +$(obj)/bindings.o: private rustc_target_flags = --extern ffi $(obj)/bindings.o: $(src)/bindings/lib.rs \ - $(obj)/compiler_builtins.o \ + $(obj)/ffi.o \ $(obj)/bindings/bindings_generated.rs \ $(obj)/bindings/bindings_helpers_generated.rs FORCE +$(call if_changed_rule,rustc_library)
+$(obj)/uapi.o: private rustc_target_flags = --extern ffi $(obj)/uapi.o: $(src)/uapi/lib.rs \ - $(obj)/compiler_builtins.o \ + $(obj)/ffi.o \ $(obj)/uapi/uapi_generated.rs FORCE +$(call if_changed_rule,rustc_library)
-$(obj)/kernel.o: private rustc_target_flags = \ +$(obj)/kernel.o: private rustc_target_flags = --extern ffi \ --extern build_error --extern macros --extern bindings --extern uapi $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \ $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE diff --git a/rust/ffi.rs b/rust/ffi.rs new file mode 100644 index 000000000000..be153c4d551b --- /dev/null +++ b/rust/ffi.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Foreign function interface (FFI) types. +//! +//! This crate provides mapping from C primitive types to Rust ones. +//! +//! The Rust [`core`] crate provides [`core::ffi`], which maps integer types to the platform default +//! C ABI. The kernel does not use [`core::ffi`], so it can customise the mapping that deviates from +//! the platform default. + +#![no_std] + +pub use core::ffi::*; diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index a041bbfdabec..439985e29fbc 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -58,7 +58,7 @@ fn aligned_size(new_layout: Layout) -> usize { /// /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`. struct ReallocFunc( - unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void, + unsafe extern "C" fn(*const crate::ffi::c_void, usize, u32) -> *mut crate::ffi::c_void, );
impl ReallocFunc { diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs index 54ca85964d4a..e3240d16040b 100644 --- a/rust/kernel/alloc/allocator_test.rs +++ b/rust/kernel/alloc/allocator_test.rs @@ -24,10 +24,10 @@
extern "C" { #[link_name = "aligned_alloc"] - fn libc_aligned_alloc(align: usize, size: usize) -> *mut core::ffi::c_void; + fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;
#[link_name = "free"] - fn libc_free(ptr: *mut core::ffi::c_void); + fn libc_free(ptr: *mut crate::ffi::c_void); }
// SAFETY: diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index d69c32496b86..9ce414361c2c 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -355,17 +355,17 @@ impl<T: 'static, A> ForeignOwnable for Box<T, A> { type Borrowed<'a> = &'a T;
- fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { Box::into_raw(self) as _ }
- unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. unsafe { Box::from_raw(ptr as _) } }
- unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T { // SAFETY: The safety requirements of this method ensure that the object remains alive and // immutable for the duration of 'a. unsafe { &*ptr.cast() } @@ -378,18 +378,18 @@ impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> { type Borrowed<'a> = Pin<&'a T>;
- fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { // SAFETY: We are still treating the box as pinned. Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ }
- unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } }
- unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index 9ba7fdfeb4b2..c8646d0d9866 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -131,7 +131,7 @@ impl<T: Operations> OperationsVTable<T> { unsafe extern "C" fn poll_callback( _hctx: *mut bindings::blk_mq_hw_ctx, _iob: *mut bindings::io_comp_batch, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { T::poll().into() }
@@ -145,9 +145,9 @@ impl<T: Operations> OperationsVTable<T> { /// for the same context. unsafe extern "C" fn init_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, - _tagset_data: *mut core::ffi::c_void, - _hctx_idx: core::ffi::c_uint, - ) -> core::ffi::c_int { + _tagset_data: *mut crate::ffi::c_void, + _hctx_idx: crate::ffi::c_uint, + ) -> crate::ffi::c_int { from_result(|| Ok(0)) }
@@ -159,7 +159,7 @@ impl<T: Operations> OperationsVTable<T> { /// This function may only be called by blk-mq C infrastructure. unsafe extern "C" fn exit_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, - _hctx_idx: core::ffi::c_uint, + _hctx_idx: crate::ffi::c_uint, ) { }
@@ -176,9 +176,9 @@ impl<T: Operations> OperationsVTable<T> { unsafe extern "C" fn init_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, - _hctx_idx: core::ffi::c_uint, - _numa_node: core::ffi::c_uint, - ) -> core::ffi::c_int { + _hctx_idx: crate::ffi::c_uint, + _numa_node: crate::ffi::c_uint, + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: By the safety requirements of this function, `rq` points // to a valid allocation. @@ -203,7 +203,7 @@ impl<T: Operations> OperationsVTable<T> { unsafe extern "C" fn exit_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, - _hctx_idx: core::ffi::c_uint, + _hctx_idx: crate::ffi::c_uint, ) { // SAFETY: The tagset invariants guarantee that all requests are allocated with extra memory // for the request data. diff --git a/rust/kernel/block/mq/raw_writer.rs b/rust/kernel/block/mq/raw_writer.rs index 9222465d670b..7e2159e4f6a6 100644 --- a/rust/kernel/block/mq/raw_writer.rs +++ b/rust/kernel/block/mq/raw_writer.rs @@ -25,7 +25,7 @@ fn new(buffer: &'a mut [u8]) -> Result<RawWriter<'a>> { }
pub(crate) fn from_array<const N: usize>( - a: &'a mut [core::ffi::c_char; N], + a: &'a mut [crate::ffi::c_char; N], ) -> Result<RawWriter<'a>> { Self::new( // SAFETY: the buffer of `a` is valid for read and write as `u8` for diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index f9a1ca655a35..d7f175a05d99 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -53,7 +53,7 @@ pub fn new( queue_depth: num_tags, cmd_size, flags: bindings::BLK_MQ_F_SHOULD_MERGE, - driver_data: core::ptr::null_mut::core::ffi::c_void(), + driver_data: core::ptr::null_mut::crate::ffi::c_void(), nr_maps: num_maps, ..tag_set } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 7cd3bbab52f2..52c502432447 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -100,7 +100,7 @@ impl Error { /// /// It is a bug to pass an out-of-range `errno`. `EINVAL` would /// be returned in such a case. - pub fn from_errno(errno: core::ffi::c_int) -> Error { + pub fn from_errno(errno: crate::ffi::c_int) -> Error { if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { // TODO: Make it a `WARN_ONCE` once available. crate::pr_warn!( @@ -119,7 +119,7 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error { /// Creates an [`Error`] from a kernel error code. /// /// Returns [`None`] if `errno` is out-of-range. - const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> { + const fn try_from_errno(errno: crate::ffi::c_int) -> Option<Error> { if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { return None; } @@ -133,7 +133,7 @@ const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> { /// # Safety /// /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`). - const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error { + const unsafe fn from_errno_unchecked(errno: crate::ffi::c_int) -> Error { // INVARIANT: The contract ensures the type invariant // will hold. // SAFETY: The caller guarantees `errno` is non-zero. @@ -141,7 +141,7 @@ const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> { }
/// Returns the kernel error code. - pub fn to_errno(self) -> core::ffi::c_int { + pub fn to_errno(self) -> crate::ffi::c_int { self.0.get() }
@@ -259,7 +259,7 @@ fn from(e: core::convert::Infallible) -> Error {
/// Converts an integer as returned by a C kernel function to an error if it's negative, and /// `Ok(())` otherwise. -pub fn to_result(err: core::ffi::c_int) -> Result { +pub fn to_result(err: crate::ffi::c_int) -> Result { if err < 0 { Err(Error::from_errno(err)) } else { @@ -282,15 +282,15 @@ pub fn to_result(err: core::ffi::c_int) -> Result { /// fn devm_platform_ioremap_resource( /// pdev: &mut PlatformDevice, /// index: u32, -/// ) -> Result<*mut core::ffi::c_void> { +/// ) -> Result<*mut kernel::ffi::c_void> { /// // SAFETY: `pdev` points to a valid platform device. There are no safety requirements /// // on `index`. /// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) }) /// } /// ``` pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { - // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid. - let const_ptr: *const core::ffi::c_void = ptr.cast(); + // CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid. + let const_ptr: *const crate::ffi::c_void = ptr.cast(); // SAFETY: The FFI function does not deref the pointer. if unsafe { bindings::IS_ERR(const_ptr) } { // SAFETY: The FFI function does not deref the pointer. @@ -306,7 +306,7 @@ pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { // // SAFETY: `IS_ERR()` ensures `err` is a // negative value greater-or-equal to `-bindings::MAX_ERRNO`. - return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) }); + return Err(unsafe { Error::from_errno_unchecked(err as crate::ffi::c_int) }); } Ok(ptr) } @@ -326,7 +326,7 @@ pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { /// # use kernel::bindings; /// unsafe extern "C" fn probe_callback( /// pdev: *mut bindings::platform_device, -/// ) -> core::ffi::c_int { +/// ) -> kernel::ffi::c_int { /// from_result(|| { /// let ptr = devm_alloc(pdev)?; /// bindings::platform_set_drvdata(pdev, ptr); diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 812ae1d06077..c962029f96e1 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -133,7 +133,7 @@ //! # } //! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround. //! # trait FromErrno { -//! # fn from_errno(errno: core::ffi::c_int) -> Error { +//! # fn from_errno(errno: kernel::ffi::c_int) -> Error { //! # // Dummy error that can be constructed outside the `kernel` crate. //! # Error::from(core::fmt::Error) //! # } diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 40c903515586..d764cb7ff5d7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -27,6 +27,8 @@ // Allow proc-macros to refer to `::kernel` inside the `kernel` crate (this crate). extern crate self as kernel;
+pub use ffi; + pub mod alloc; #[cfg(CONFIG_BLOCK)] pub mod block; diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 910ce867480a..beb62ec712c3 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -314,7 +314,7 @@ impl<T: Driver> Adapter<T> { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn soft_reset_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -328,7 +328,7 @@ impl<T: Driver> Adapter<T> { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we can exclusively access `phy_device` because @@ -345,7 +345,7 @@ impl<T: Driver> Adapter<T> { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn get_features_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -359,7 +359,7 @@ impl<T: Driver> Adapter<T> { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: The C core code ensures that the accessors on // `Device` are okay to call even though `phy_device->lock` @@ -373,7 +373,7 @@ impl<T: Driver> Adapter<T> { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: The C core code ensures that the accessors on // `Device` are okay to call even though `phy_device->lock` @@ -389,7 +389,7 @@ impl<T: Driver> Adapter<T> { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn config_aneg_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -405,7 +405,7 @@ impl<T: Driver> Adapter<T> { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn read_status_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -421,7 +421,7 @@ impl<T: Driver> Adapter<T> { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn match_phy_device_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on // `Device` are okay to call. diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index aff6baa521d4..d04c12a1426d 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -184,7 +184,7 @@ pub const fn is_empty(&self) -> bool { /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` /// must not be mutated. #[inline] - pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { + pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { // SAFETY: The safety precondition guarantees `ptr` is a valid pointer // to a `NUL`-terminated C string. let len = unsafe { bindings::strlen(ptr) } + 1; @@ -247,7 +247,7 @@ pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
/// Returns a C pointer to the string. #[inline] - pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { + pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { self.0.as_ptr() as _ }
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index db9da352d588..fa4509406ee9 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -332,11 +332,11 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> { impl<T: 'static> ForeignOwnable for Arc<T> { type Borrowed<'a> = ArcBorrow<'a, T>;
- fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { ManuallyDrop::new(self).ptr.as_ptr() as _ }
- unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { // By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`. let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap(); @@ -346,7 +346,7 @@ unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> { unsafe { ArcBorrow::new(inner) } }
- unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and // holds a reference count increment that is transferrable to us. diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index a1a29c0bdb3a..7df565038d7d 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -7,6 +7,7 @@
use super::{lock::Backend, lock::Guard, LockClassKey}; use crate::{ + ffi::{c_int, c_long}, init::PinInit, pin_init, str::CStr, @@ -14,7 +15,6 @@ time::Jiffies, types::Opaque, }; -use core::ffi::{c_int, c_long}; use core::marker::PhantomPinned; use core::ptr; use macros::pin_data; diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 07fcf2d8efc6..528eb6907231 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -46,7 +46,7 @@ pub unsafe trait Backend { /// remain valid for read indefinitely. unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, );
diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index f8f6d530db7d..59a872cbcac6 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -96,7 +96,7 @@ unsafe impl super::Backend for MutexBackend {
unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, ) { // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index a9096a4dc42a..b77eed1789ad 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -95,7 +95,7 @@ unsafe impl super::Backend for SpinLockBackend {
unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, ) { // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 55dff7e088bf..5bce090a3869 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,13 +4,9 @@ //! //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
+use crate::ffi::{c_int, c_long, c_uint}; use crate::types::Opaque; -use core::{ - ffi::{c_int, c_long, c_uint}, - marker::PhantomData, - ops::Deref, - ptr, -}; +use core::{marker::PhantomData, ops::Deref, ptr};
/// A sentinel value used for infinite timeouts. pub const MAX_SCHEDULE_TIMEOUT: c_long = c_long::MAX; diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index e3bb5e89f88d..379c0f5772e5 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -12,10 +12,10 @@ pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64;
/// The time unit of Linux kernel. One jiffy equals (1/HZ) second. -pub type Jiffies = core::ffi::c_ulong; +pub type Jiffies = crate::ffi::c_ulong;
/// The millisecond time unit. -pub type Msecs = core::ffi::c_uint; +pub type Msecs = crate::ffi::c_uint;
/// Converts milliseconds to jiffies. #[inline] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 22b1faac874c..7c8c531ef190 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -29,7 +29,7 @@ pub trait ForeignOwnable: Sized { /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in /// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. - fn into_foreign(self) -> *const core::ffi::c_void; + fn into_foreign(self) -> *const crate::ffi::c_void;
/// Borrows a foreign-owned object. /// @@ -37,7 +37,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Self::Borrowed<'a>;
/// Converts a foreign-owned object back to a Rust-owned one. /// @@ -47,7 +47,7 @@ pub trait ForeignOwnable: Sized { /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for /// this object must have been dropped. - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self;
/// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -58,7 +58,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must either be null or satisfy the safety requirements for /// [`ForeignOwnable::from_foreign`]. - unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> { + unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option<Self> { if ptr.is_null() { None } else { @@ -72,13 +72,13 @@ unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option<Self> { impl ForeignOwnable for () { type Borrowed<'a> = ();
- fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() }
- unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn borrow<'a>(_: *const crate::ffi::c_void) -> Self::Borrowed<'a> {}
- unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *const crate::ffi::c_void) -> Self {} }
/// Runs a cleanup function/closure when dropped. diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index bc011061de45..66cc76e68428 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -8,10 +8,10 @@ alloc::Flags, bindings, error::Result, + ffi::{c_ulong, c_void}, prelude::*, types::{AsBytes, FromBytes}, }; -use core::ffi::{c_ulong, c_void}; use core::mem::{size_of, MaybeUninit};
/// The type used for userspace addresses. @@ -45,7 +45,7 @@ /// every byte in the region. /// /// ```no_run -/// use core::ffi::c_void; +/// use kernel::ffi::c_void; /// use kernel::error::Result; /// use kernel::uaccess::{UserPtr, UserSlice}; /// @@ -67,7 +67,7 @@ /// Example illustrating a TOCTOU (time-of-check to time-of-use) bug. /// /// ```no_run -/// use core::ffi::c_void; +/// use kernel::ffi::c_void; /// use kernel::error::{code::EINVAL, Result}; /// use kernel::uaccess::{UserPtr, UserSlice}; /// diff --git a/rust/macros/module.rs b/rust/macros/module.rs index aef3b132f32b..e7a087b7e884 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -253,7 +253,7 @@ mod __module_init {{ #[doc(hidden)] #[no_mangle] #[link_section = ".init.text"] - pub unsafe extern "C" fn init_module() -> core::ffi::c_int {{ + pub unsafe extern "C" fn init_module() -> kernel::ffi::c_int {{ // SAFETY: This function is inaccessible to the outside due to the double // module wrapping it. It is called exactly once by the C side via its // unique name. @@ -292,7 +292,7 @@ mod __module_init {{ #[doc(hidden)] #[link_section = "{initcall_section}"] #[used] - pub static __{name}_initcall: extern "C" fn() -> core::ffi::c_int = __{name}_init; + pub static __{name}_initcall: extern "C" fn() -> kernel::ffi::c_int = __{name}_init;
#[cfg(not(MODULE))] #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] @@ -307,7 +307,7 @@ mod __module_init {{ #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] - pub extern "C" fn __{name}_init() -> core::ffi::c_int {{ + pub extern "C" fn __{name}_init() -> kernel::ffi::c_int {{ // SAFETY: This function is inaccessible to the outside due to the double // module wrapping it. It is called exactly once by the C side via its // placement above in the initcall section. @@ -330,7 +330,7 @@ mod __module_init {{ /// # Safety /// /// This function must only be called once. - unsafe fn __init() -> core::ffi::c_int {{ + unsafe fn __init() -> kernel::ffi::c_int {{ match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{ Ok(m) => {{ // SAFETY: No data race, since `__MOD` can only be accessed by this
From: Asahi Lina lina@asahilina.net
commit b7ed2b6f4e8d7f64649795e76ee9db67300de8eb upstream.
We were accidentally allocating a layout for the *square* of the object size due to a variable shadowing mishap.
Fixes memory bloat and page allocation failures in drm/asahi.
Reported-by: Janne Grunau j@jannau.net Fixes: 9e7bbfa18276 ("rust: alloc: introduce `ArrayLayout`") Signed-off-by: Asahi Lina lina@asahilina.net Acked-by: Danilo Krummrich dakr@kernel.org Reviewed-by: Neal Gompa neal@gompa.dev Link: https://lore.kernel.org/r/20241123-rust-fix-arraylayout-v1-1-197e64c95bd4@as... Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/kernel/alloc/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rust/kernel/alloc/layout.rs b/rust/kernel/alloc/layout.rs index 7e0c2f46157b..4b3cd7fdc816 100644 --- a/rust/kernel/alloc/layout.rs +++ b/rust/kernel/alloc/layout.rs @@ -45,7 +45,7 @@ pub const fn empty() -> Self { /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. pub const fn new(len: usize) -> Result<Self, LayoutError> { match len.checked_mul(core::mem::size_of::<T>()) { - Some(len) if len <= ISIZE_MAX => { + Some(size) if size <= ISIZE_MAX => { // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. Ok(Self { len,
On Fri, Mar 07, 2025 at 11:49:07PM +0100, Miguel Ojeda wrote:
Hi Greg, Sasha,
Please consider this series for 6.12.y. It should apply cleanly on top of v6.12.18.
These are the patches to backport the `alloc` series for Rust, which will be useful for Rust Android Binder and others. It also means that, with this applied, we will not rely on the standard library `alloc` (and the unstable `cfg` option we used) anymore in any stable kernel that supports several Rust versions, so e.g. upstream Rust could consider removing that `cfg` if they needed.
The entire series of cherry-picks apply almost cleanly (only 2 trivial conflicts) -- to achieve that, I included the `#[expect]` support, which will make future backports that use that feature easier anyway. That series also enabled some Clippy warnings. We could reduce the series, but the end result is warning-free and Clippy is opt-in anyway. Out-of-tree code could, of course, see some warnings if they use it.
I also included a bunch of Clippy warnings cleanups for the DRM QR Code to have this series clean up to Rust 1.85.0 (the latest stable), but I could send them separately if needed.
Finally, I included the "Custom FFI" series backport, which in turn solves the arm64 + Rust 1.85.0 + `CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y` issue. It will also make future patches easier to backport, since we will have the same `ffi::` types.
I tested that the entire series builds between every commit for x86_64 `LLVM=1` with the latest stable and minimum supported Rust compiler versions. I also ran my usual stable kernel tests on the end result; that is, boot-tested in QEMU for several architectures etc. In v6.12.18 for loongarch there is an unrelated error that was not there in v6.12.17 when I did a previous test run -- reported separately.
Things could still break, so extra tests on the next -rc from users in Cc here would be welcome -- thanks!
All queued up now, thanks!
greg k-h
Hi, I think this is missing one final change, specifically 27c7518e, or rather, the only line of it that applies:
pub unsafe extern "C" fn drm_panic_qr_generate( - url: *const i8, + url: *const kernel::ffi::c_char,
Without it, the build fails on Rust 1.85 / aarch64.
On 2025-03-08 01:49, Miguel Ojeda wrote:
Hi Greg, Sasha,
Please consider this series for 6.12.y. It should apply cleanly on top of v6.12.18.
These are the patches to backport the `alloc` series for Rust, which will be useful for Rust Android Binder and others. It also means that, with this applied, we will not rely on the standard library `alloc` (and the unstable `cfg` option we used) anymore in any stable kernel that supports several Rust versions, so e.g. upstream Rust could consider removing that `cfg` if they needed.
The entire series of cherry-picks apply almost cleanly (only 2 trivial conflicts) -- to achieve that, I included the `#[expect]` support, which will make future backports that use that feature easier anyway. That series also enabled some Clippy warnings. We could reduce the series, but the end result is warning-free and Clippy is opt-in anyway. Out-of-tree code could, of course, see some warnings if they use it.
I also included a bunch of Clippy warnings cleanups for the DRM QR Code to have this series clean up to Rust 1.85.0 (the latest stable), but I could send them separately if needed.
Finally, I included the "Custom FFI" series backport, which in turn solves the arm64 + Rust 1.85.0 + `CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y` issue. It will also make future patches easier to backport, since we will have the same `ffi::` types.
I tested that the entire series builds between every commit for x86_64 `LLVM=1` with the latest stable and minimum supported Rust compiler versions. I also ran my usual stable kernel tests on the end result; that is, boot-tested in QEMU for several architectures etc. In v6.12.18 for loongarch there is an unrelated error that was not there in v6.12.17 when I did a previous test run -- reported separately.
Things could still break, so extra tests on the next -rc from users in Cc here would be welcome -- thanks!
Cheers, Miguel
Asahi Lina (1): rust: alloc: Fix `ArrayLayout` allocations
Benno Lossin (1): rust: alloc: introduce `ArrayLayout`
Danilo Krummrich (28): rust: alloc: add `Allocator` trait rust: alloc: separate `aligned_size` from `krealloc_aligned` rust: alloc: rename `KernelAllocator` to `Kmalloc` rust: alloc: implement `ReallocFunc` rust: alloc: make `allocator` module public rust: alloc: implement `Allocator` for `Kmalloc` rust: alloc: add module `allocator_test` rust: alloc: implement `Vmalloc` allocator rust: alloc: implement `KVmalloc` allocator rust: alloc: add __GFP_NOWARN to `Flags` rust: alloc: implement kernel `Box` rust: treewide: switch to our kernel `Box` type rust: alloc: remove extension of std's `Box` rust: alloc: add `Box` to prelude rust: alloc: implement kernel `Vec` type rust: alloc: implement `IntoIterator` for `Vec` rust: alloc: implement `collect` for `IntoIter` rust: treewide: switch to the kernel `Vec` type rust: alloc: remove `VecExt` extension rust: alloc: add `Vec` to prelude rust: error: use `core::alloc::LayoutError` rust: error: check for config `test` in `Error::name` rust: alloc: implement `contains` for `Flags` rust: alloc: implement `Cmalloc` in module allocator_test rust: str: test: replace `alloc::format` rust: alloc: update module comment of alloc.rs kbuild: rust: remove the `alloc` crate and `GlobalAlloc` MAINTAINERS: add entry for the Rust `alloc` module
Ethan D. Twardy (1): rust: kbuild: expand rusttest target for macros
Filipe Xavier (2): rust: error: make conversion functions public rust: error: optimize error type to use nonzero
Gary Guo (3): rust: fix size_t in bindgen prototypes of C builtins rust: map `__kernel_size_t` and friends also to usize/isize rust: use custom FFI integer types
Miguel Ojeda (17): rust: workqueue: remove unneeded ``#[allow(clippy::new_ret_no_self)]` rust: sort global Rust flags rust: types: avoid repetition in `{As,From}Bytes` impls rust: enable `clippy::undocumented_unsafe_blocks` lint rust: enable `clippy::unnecessary_safety_comment` lint rust: enable `clippy::unnecessary_safety_doc` lint rust: enable `clippy::ignored_unit_patterns` lint rust: enable `rustdoc::unescaped_backticks` lint rust: init: remove unneeded `#[allow(clippy::disallowed_names)]` rust: sync: remove unneeded `#[allow(clippy::non_send_fields_in_send_ty)]` rust: introduce `.clippy.toml` rust: replace `clippy::dbg_macro` with `disallowed_macros` rust: provide proper code documentation titles rust: enable Clippy's `check-private-items` Documentation: rust: add coding guidelines on lints rust: start using the `#[expect(...)]` attribute Documentation: rust: discuss `#[expect(...)]` in the guidelines
Thomas Böhler (7): drm/panic: avoid reimplementing Iterator::find drm/panic: remove unnecessary borrow in alignment_pattern drm/panic: prefer eliding lifetimes drm/panic: remove redundant field when assigning value drm/panic: correctly indent continuation of line in list item drm/panic: allow verbose boolean for clarity drm/panic: allow verbose version check
.clippy.toml | 9 + .gitignore | 1 + Documentation/rust/coding-guidelines.rst | 148 ++++ MAINTAINERS | 8 + Makefile | 15 +- drivers/block/rnull.rs | 4 +- drivers/gpu/drm/drm_panic_qr.rs | 23 +- mm/kasan/kasan_test_rust.rs | 3 +- rust/Makefile | 92 +-- rust/bindgen_parameters | 5 + rust/bindings/bindings_helper.h | 1 + rust/bindings/lib.rs | 6 + rust/exports.c | 1 - rust/ffi.rs | 13 + rust/helpers/helpers.c | 1 + rust/helpers/slab.c | 6 + rust/helpers/vmalloc.c | 9 + rust/kernel/alloc.rs | 150 +++- rust/kernel/alloc/allocator.rs | 208 ++++-- rust/kernel/alloc/allocator_test.rs | 95 +++ rust/kernel/alloc/box_ext.rs | 89 --- rust/kernel/alloc/kbox.rs | 456 +++++++++++ rust/kernel/alloc/kvec.rs | 913 +++++++++++++++++++++++ rust/kernel/alloc/layout.rs | 91 +++ rust/kernel/alloc/vec_ext.rs | 185 ----- rust/kernel/block/mq/operations.rs | 18 +- rust/kernel/block/mq/raw_writer.rs | 2 +- rust/kernel/block/mq/tag_set.rs | 2 +- rust/kernel/error.rs | 79 +- rust/kernel/init.rs | 127 ++-- rust/kernel/init/__internal.rs | 13 +- rust/kernel/init/macros.rs | 18 +- rust/kernel/ioctl.rs | 2 +- rust/kernel/lib.rs | 5 +- rust/kernel/list.rs | 1 + rust/kernel/list/arc_field.rs | 2 +- rust/kernel/net/phy.rs | 16 +- rust/kernel/prelude.rs | 5 +- rust/kernel/print.rs | 5 +- rust/kernel/rbtree.rs | 49 +- rust/kernel/std_vendor.rs | 12 +- rust/kernel/str.rs | 46 +- rust/kernel/sync/arc.rs | 25 +- rust/kernel/sync/arc/std_vendor.rs | 2 + rust/kernel/sync/condvar.rs | 7 +- rust/kernel/sync/lock.rs | 8 +- rust/kernel/sync/lock/mutex.rs | 4 +- rust/kernel/sync/lock/spinlock.rs | 4 +- rust/kernel/sync/locked_by.rs | 2 +- rust/kernel/task.rs | 8 +- rust/kernel/time.rs | 4 +- rust/kernel/types.rs | 140 ++-- rust/kernel/uaccess.rs | 23 +- rust/kernel/workqueue.rs | 29 +- rust/macros/lib.rs | 14 +- rust/macros/module.rs | 8 +- rust/uapi/lib.rs | 6 + samples/rust/rust_minimal.rs | 4 +- samples/rust/rust_print.rs | 1 + scripts/Makefile.build | 4 +- scripts/generate_rust_analyzer.py | 11 +- 61 files changed, 2482 insertions(+), 756 deletions(-) create mode 100644 .clippy.toml create mode 100644 rust/ffi.rs create mode 100644 rust/helpers/vmalloc.c create mode 100644 rust/kernel/alloc/allocator_test.rs delete mode 100644 rust/kernel/alloc/box_ext.rs create mode 100644 rust/kernel/alloc/kbox.rs create mode 100644 rust/kernel/alloc/kvec.rs create mode 100644 rust/kernel/alloc/layout.rs delete mode 100644 rust/kernel/alloc/vec_ext.rs
-- 2.48.1
On Sun, Mar 9, 2025 at 1:42 PM Ilya K me@0upti.me wrote:
Hi, I think this is missing one final change, specifically 27c7518e, or rather, the only line of it that applies:
pub unsafe extern "C" fn drm_panic_qr_generate(
- url: *const i8,
- url: *const kernel::ffi::c_char,
Without it, the build fails on Rust 1.85 / aarch64.
Bah, sorry, my bad, that is embarrassing... It is not just that one -- the actual remap is not there. Let me re-send...
Greg: no changes except for the 2 extra on top you will see.
It still holds that the x86_64 build still builds commit-by-commit, and I double-checked that hash builds for x86_64, arm64 and riscv64 with the min and max compilers.
Let me also run a test for loongarch64 with the unrelated fix applied.
Cheers, Miguel
On Sun, Mar 09, 2025 at 03:20:56PM +0100, Miguel Ojeda wrote:
On Sun, Mar 9, 2025 at 1:42 PM Ilya K me@0upti.me wrote:
Hi, I think this is missing one final change, specifically 27c7518e, or rather, the only line of it that applies:
pub unsafe extern "C" fn drm_panic_qr_generate(
- url: *const i8,
- url: *const kernel::ffi::c_char,
Without it, the build fails on Rust 1.85 / aarch64.
Bah, sorry, my bad, that is embarrassing... It is not just that one -- the actual remap is not there. Let me re-send...
Greg: no changes except for the 2 extra on top you will see.
It still holds that the x86_64 build still builds commit-by-commit, and I double-checked that hash builds for x86_64, arm64 and riscv64 with the min and max compilers.
Let me also run a test for loongarch64 with the unrelated fix applied.
Please just send additional ones, not the whole series, otherwise I'm going to get confused :)
thanks,
greg k-h
Two missing ones on top of the other 60 -- sorry again! I tested the end result of applying the 62 on top of v6.12.18 with all combinations of:
- The minimum and maximum Rust compiler versions (i.e. 1.78.0 and 1.85.0).
- x86_64, arm64, riscv64 and loongarch64 (this last one with the other unrelated-to-Rust fix on top).
- A defconfig with Rust users enabled (rust_minimal, rust_print, rnull, drm_panic_qr, qt2025, ax88796b_rust) plus a similar with a couple debug options on top (Rust debug assertions and KUnit Rust doctests).
All pass my usual tests, are `WERROR=y` and Clippy-clean etc.
Plus x86_64 out-of-tree build, a x86_64 subdir build and a x86_64 Rust disabled build. On x86_64, it should still build commit-by-commit.
Cheers, Miguel
Gary Guo (1): rust: map `long` to `isize` and `char` to `u8`
Miguel Ojeda (1): rust: finish using custom FFI integer types
drivers/gpu/drm/drm_panic_qr.rs | 2 +- rust/ffi.rs | 37 ++++++++++++++++++++++++++++++++- rust/kernel/error.rs | 5 +---- rust/kernel/firmware.rs | 2 +- rust/kernel/uaccess.rs | 27 +++++++----------------- 5 files changed, 46 insertions(+), 27 deletions(-)
-- 2.48.1
commit 27c7518e7f1ccaaa43eb5f25dc362779d2dc2ccb upstream.
In the last kernel cycle we migrated most of the `core::ffi` cases in commit d072acda4862 ("rust: use custom FFI integer types"):
Currently FFI integer types are defined in libcore. This commit creates the `ffi` crate and asks bindgen to use that crate for FFI integer types instead of `core::ffi`.
This commit is preparatory and no type changes are made in this commit yet.
Finish now the few remaining/new cases so that we perform the actual remapping in the next commit as planned.
Acked-by: Jocelyn Falempe jfalempe@redhat.com # drm Link: https://lore.kernel.org/rust-for-linux/CANiq72m_rg42SvZK=bF2f0yEoBLVA33UBhiA... Link: https://lore.kernel.org/all/cc9253fa-9d5f-460b-9841-94948fb6580c@redhat.com/ Signed-off-by: Miguel Ojeda ojeda@kernel.org --- drivers/gpu/drm/drm_panic_qr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ef2d490965ba..bcf248f69252 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -931,7 +931,7 @@ fn draw_all(&mut self, data: impl Iterator<Item = u8>) { /// They must remain valid for the duration of the function call. #[no_mangle] pub unsafe extern "C" fn drm_panic_qr_generate( - url: *const i8, + url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize,
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 27c7518e7f1ccaaa43eb5f25dc362779d2dc2ccb
Status in newer kernel trees: 6.13.y | Present (different SHA1: 0545eb878267)
Note: The patch differs from the upstream commit: --- 1: 27c7518e7f1cc < -: ------------- rust: finish using custom FFI integer types -: ------------- > 1: e14eb7876bb06 rust: finish using custom FFI integer types ---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.12.y | Success | Success |
From: Gary Guo gary@garyguo.net
commit 1bae8729e50a900f41e9a1c17ae81113e4cf62b8 upstream.
The following FFI types are replaced compared to `core::ffi`:
1. `char` type is now always mapped to `u8`, since kernel uses `-funsigned-char` on the C code. `core::ffi` maps it to platform default ABI, which can be either signed or unsigned.
2. `long` is now always mapped to `isize`. It's very common in the kernel to use `long` to represent a pointer-sized integer, and in fact `intptr_t` is a typedef of `long` in the kernel. Enforce this mapping rather than mapping to `i32/i64` depending on platform can save us a lot of unnecessary casts.
Signed-off-by: Gary Guo gary@garyguo.net Reviewed-by: Alice Ryhl aliceryhl@google.com Link: https://lore.kernel.org/r/20240913213041.395655-5-gary@garyguo.net [ Moved `uaccess` changes from the next commit, since they were irrefutable patterns that Rust >= 1.82.0 warns about. Reworded slightly and reformatted a few documentation comments. Rebased on top of `rust-next`. Added the removal of two casts to avoid Clippy warnings. - Miguel ] Signed-off-by: Miguel Ojeda ojeda@kernel.org --- rust/ffi.rs | 37 ++++++++++++++++++++++++++++++++++++- rust/kernel/error.rs | 5 +---- rust/kernel/firmware.rs | 2 +- rust/kernel/uaccess.rs | 27 +++++++-------------------- 4 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/rust/ffi.rs b/rust/ffi.rs index be153c4d551b..584f75b49862 100644 --- a/rust/ffi.rs +++ b/rust/ffi.rs @@ -10,4 +10,39 @@
#![no_std]
-pub use core::ffi::*; +macro_rules! alias { + ($($name:ident = $ty:ty;)*) => {$( + #[allow(non_camel_case_types, missing_docs)] + pub type $name = $ty; + + // Check size compatibility with `core`. + const _: () = assert!( + core::mem::size_of::<$name>() == core::mem::size_of::core::ffi::$name() + ); + )*} +} + +alias! { + // `core::ffi::c_char` is either `i8` or `u8` depending on architecture. In the kernel, we use + // `-funsigned-char` so it's always mapped to `u8`. + c_char = u8; + + c_schar = i8; + c_uchar = u8; + + c_short = i16; + c_ushort = u16; + + c_int = i32; + c_uint = u32; + + // In the kernel, `intptr_t` is defined to be `long` in all platforms, so we can map the type to + // `isize`. + c_long = isize; + c_ulong = usize; + + c_longlong = i64; + c_ulonglong = u64; +} + +pub use core::ffi::c_void; diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 52c502432447..5fece574ec02 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -153,11 +153,8 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
/// Returns the error encoded as a pointer. pub fn to_ptr<T>(self) -> *mut T { - #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { - bindings::ERR_PTR(self.0.get().into()) as *mut _ - } + unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ } }
/// Returns a string representing the error, if one exists. diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index 13a374a5cdb7..c5162fdc95ff 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -12,7 +12,7 @@ /// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`, /// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`. struct FwFunc( - unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32, + unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32, );
impl FwFunc { diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index 66cc76e68428..5a3c2d4df65f 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -8,7 +8,7 @@ alloc::Flags, bindings, error::Result, - ffi::{c_ulong, c_void}, + ffi::c_void, prelude::*, types::{AsBytes, FromBytes}, }; @@ -224,13 +224,9 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit<u8>]) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write + // SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write // that many bytes to it. - let res = - unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) }; + let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) }; if res != 0 { return Err(EFAULT); } @@ -259,9 +255,6 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; let mut out: MaybeUninit<T> = MaybeUninit::uninit(); // SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes. // @@ -272,7 +265,7 @@ pub fn read<T: FromBytes>(&mut self) -> Result<T> { bindings::_copy_from_user( out.as_mut_ptr().cast::<c_void>(), self.ptr as *const c_void, - len_ulong, + len, ) }; if res != 0 { @@ -335,12 +328,9 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read + // SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read // that many bytes from it. - let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len_ulong) }; + let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) }; if res != 0 { return Err(EFAULT); } @@ -359,9 +349,6 @@ pub fn write<T: AsBytes>(&mut self, value: &T) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; // SAFETY: The reference points to a value of type `T`, so it is valid for reading // `size_of::<T>()` bytes. // @@ -372,7 +359,7 @@ pub fn write<T: AsBytes>(&mut self, value: &T) -> Result { bindings::_copy_to_user( self.ptr as *mut c_void, (value as *const T).cast::<c_void>(), - len_ulong, + len, ) }; if res != 0 {
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues: ℹ️ This is part 2/2 of a series ❌ Build failures detected
The upstream commit SHA1 provided is correct: 1bae8729e50a900f41e9a1c17ae81113e4cf62b8
WARNING: Author mismatch between patch and upstream commit: Backport author: Miguel Ojedaojeda@kernel.org Commit author: Gary Guogary@garyguo.net
Status in newer kernel trees: 6.13.y | Present (different SHA1: 7efbbb5407e7)
Note: The patch differs from the upstream commit: --- Failed to apply patch cleanly. ---
NOTE: These results are for this patch alone. Full series testing will be performed when all parts are received.
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.12.y | Failed | N/A |
Build Errors: Patch failed to apply on stable/linux-6.12.y. Reject:
diff a/rust/kernel/error.rs b/rust/kernel/error.rs (rejected hunks) @@ -153,11 +153,8 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
/// Returns the error encoded as a pointer. pub fn to_ptr<T>(self) -> *mut T { - #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { - bindings::ERR_PTR(self.0.get().into()) as *mut _ - } + unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ } }
/// Returns a string representing the error, if one exists. diff a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs (rejected hunks) @@ -8,7 +8,7 @@ alloc::Flags, bindings, error::Result, - ffi::{c_ulong, c_void}, + ffi::c_void, prelude::*, types::{AsBytes, FromBytes}, };
On Thu, Mar 13, 2025 at 10:01 AM Sasha Levin sashal@kernel.org wrote:
[ Sasha's backport helper bot ]
Summary of potential issues: ℹ️ This is part 2/2 of a series ❌ Build failures detected
Failed to apply patch cleanly.
Patch failed to apply on stable/linux-6.12.y. Reject:
Hmm... these patches are already applied in -rc.
I guess the bot picked up these 2 "independent" patches that were not really independent but rather were meant to be applied on top of the other 60 I sent.
All 62 were applied by Greg, the 2-series at commit 9cbe3832da9c ("rust: map `long` to `isize` and `char` to `u8`") and the 60-series at commit bfc1c86b1e13 ("rust: alloc: Fix `ArrayLayout` allocations").
I hope that helps!
Cheers, Miguel
On Sun, Mar 09, 2025 at 09:42:15PM +0100, Miguel Ojeda wrote:
Two missing ones on top of the other 60 -- sorry again! I tested the end result of applying the 62 on top of v6.12.18 with all combinations of:
The minimum and maximum Rust compiler versions (i.e. 1.78.0 and 1.85.0).
x86_64, arm64, riscv64 and loongarch64 (this last one with the other unrelated-to-Rust fix on top).
A defconfig with Rust users enabled (rust_minimal, rust_print, rnull, drm_panic_qr, qt2025, ax88796b_rust) plus a similar with a couple debug options on top (Rust debug assertions and KUnit Rust doctests).
All pass my usual tests, are `WERROR=y` and Clippy-clean etc.
Plus x86_64 out-of-tree build, a x86_64 subdir build and a x86_64 Rust disabled build. On x86_64, it should still build commit-by-commit.
Cheers, Miguel
Gary Guo (1): rust: map `long` to `isize` and `char` to `u8`
Miguel Ojeda (1): rust: finish using custom FFI integer types
drivers/gpu/drm/drm_panic_qr.rs | 2 +- rust/ffi.rs | 37 ++++++++++++++++++++++++++++++++- rust/kernel/error.rs | 5 +---- rust/kernel/firmware.rs | 2 +- rust/kernel/uaccess.rs | 27 +++++++----------------- 5 files changed, 46 insertions(+), 27 deletions(-)
-- 2.48.1
Now queued up, thanks.
greg k-h
linux-stable-mirror@lists.linaro.org