From 03989773a94490383b062912feb0c4d175f20845 Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Wed, 27 Mar 2024 22:35:55 -0300 Subject: rust: alloc: introduce the `VecExt` trait Make `try_with_capacity`, `try_push`, and `try_extend_from_slice` methods available in `Vec` even though it doesn't implement them. It is implemented with `try_reserve` and `push_within_capacity`. This is in preparation for switching to the upstream `alloc` crate. Reviewed-by: Benno Lossin Suggested-by: Gary Guo Signed-off-by: Wedson Almeida Filho Link: https://lore.kernel.org/r/20240328013603.206764-3-wedsonaf@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/vec_ext.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 rust/kernel/alloc/vec_ext.rs (limited to 'rust/kernel/alloc/vec_ext.rs') diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs new file mode 100644 index 000000000000..311e62cc5784 --- /dev/null +++ b/rust/kernel/alloc/vec_ext.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Extensions to [`Vec`] for fallible allocations. + +use alloc::{collections::TryReserveError, vec::Vec}; +use core::result::Result; + +/// Extensions to [`Vec`]. +pub trait VecExt: Sized { + /// Creates a new [`Vec`] instance with at least the given capacity. + fn try_with_capacity(capacity: usize) -> Result; + + /// Appends an element to the back of the [`Vec`] instance. + fn try_push(&mut self, v: T) -> Result<(), TryReserveError>; + + /// Pushes clones of the elements of slice into the [`Vec`] instance. + fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> + where + T: Clone; +} + +impl VecExt for Vec { + fn try_with_capacity(capacity: usize) -> Result { + let mut v = Vec::new(); + v.try_reserve(capacity)?; + Ok(v) + } + + fn try_push(&mut self, v: T) -> Result<(), TryReserveError> { + if let Err(retry) = self.push_within_capacity(v) { + self.try_reserve(1)?; + let _ = self.push_within_capacity(retry); + } + Ok(()) + } + + fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> + where + T: Clone, + { + self.try_reserve(other.len())?; + for item in other { + self.try_push(item.clone())?; + } + + Ok(()) + } +} -- cgit v1.2.3 From 5ab560ce12ed0df3450968cfe4211e398ff2a8d7 Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Wed, 27 Mar 2024 22:36:00 -0300 Subject: rust: alloc: update `VecExt` to take allocation flags We also rename the methods by removing the `try_` prefix since the names are available due to our usage of the `no_global_oom_handling` config when building the `alloc` crate. Reviewed-by: Boqun Feng Signed-off-by: Wedson Almeida Filho Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20240328013603.206764-8-wedsonaf@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/vec_ext.rs | 158 +++++++++++++++++++++++++++++++++++++++---- rust/kernel/error.rs | 11 +-- rust/kernel/lib.rs | 1 - rust/kernel/str.rs | 6 +- rust/kernel/types.rs | 4 +- samples/rust/rust_minimal.rs | 6 +- 6 files changed, 152 insertions(+), 34 deletions(-) (limited to 'rust/kernel/alloc/vec_ext.rs') diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs index 311e62cc5784..e24d7c7675ca 100644 --- a/rust/kernel/alloc/vec_ext.rs +++ b/rust/kernel/alloc/vec_ext.rs @@ -2,47 +2,175 @@ //! Extensions to [`Vec`] for fallible allocations. -use alloc::{collections::TryReserveError, vec::Vec}; +use super::Flags; +use alloc::{alloc::AllocError, vec::Vec}; use core::result::Result; /// Extensions to [`Vec`]. pub trait VecExt: Sized { /// Creates a new [`Vec`] instance with at least the given capacity. - fn try_with_capacity(capacity: usize) -> Result; + /// + /// # Examples + /// + /// ``` + /// let v = Vec::::with_capacity(20, GFP_KERNEL)?; + /// + /// assert!(v.capacity() >= 20); + /// # Ok::<(), Error>(()) + /// ``` + fn with_capacity(capacity: usize, flags: Flags) -> Result; /// Appends an element to the back of the [`Vec`] instance. - fn try_push(&mut self, v: T) -> Result<(), TryReserveError>; + /// + /// # 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. - fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> + /// + /// # 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 VecExt for Vec { - fn try_with_capacity(capacity: usize) -> Result { + fn with_capacity(capacity: usize, flags: Flags) -> Result { let mut v = Vec::new(); - v.try_reserve(capacity)?; + >::reserve(&mut v, capacity, flags)?; Ok(v) } - fn try_push(&mut self, v: T) -> Result<(), TryReserveError> { - if let Err(retry) = self.push_within_capacity(v) { - self.try_reserve(1)?; - let _ = self.push_within_capacity(retry); - } + fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { + >::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 try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> + fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> where T: Clone, { - self.try_reserve(other.len())?; - for item in other { - self.try_push(item.clone())?; + >::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::() == 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::(new_cap).map_err(|_| AllocError)?; + + let (ptr, len, cap) = destructure(self); + + // 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, 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::(), len, new_cap) }; + Ok(()) + } + } +} + +#[cfg(not(any(test, testlib)))] +fn destructure(v: &mut Vec) -> (*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(v: &mut Vec, 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/error.rs b/rust/kernel/error.rs index 4786d3ee1e92..e53466937796 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -6,10 +6,7 @@ use crate::str::CStr; -use alloc::{ - alloc::{AllocError, LayoutError}, - collections::TryReserveError, -}; +use alloc::alloc::{AllocError, LayoutError}; use core::convert::From; use core::fmt; @@ -192,12 +189,6 @@ impl From for Error { } } -impl From for Error { - fn from(_: TryReserveError) -> Error { - code::ENOMEM - } -} - impl From for Error { fn from(_: LayoutError) -> Error { code::ENOMEM diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d3d345aed218..1e910fe7c2c7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -18,7 +18,6 @@ #![feature(new_uninit)] #![feature(receiver_trait)] #![feature(unsize)] -#![feature(vec_push_within_capacity)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 14ef4344cf6e..f454252c6215 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,7 +2,7 @@ //! String representations. -use crate::alloc::vec_ext::VecExt; +use crate::alloc::{flags::*, vec_ext::VecExt}; use alloc::alloc::AllocError; use alloc::vec::Vec; use core::fmt::{self, Write}; @@ -807,7 +807,7 @@ impl CString { let size = f.bytes_written(); // Allocate a vector with the required number of bytes, and write to it. - let mut buf = Vec::try_with_capacity(size)?; + let mut buf = as VecExt<_>>::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)?; @@ -856,7 +856,7 @@ impl<'a> TryFrom<&'a CStr> for CString { fn try_from(cstr: &'a CStr) -> Result { let mut buf = Vec::new(); - buf.try_extend_from_slice(cstr.as_bytes_with_nul()) + as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL) .map_err(|_| AllocError)?; // INVARIANT: The `CStr` and `CString` types have the same invariants for diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index aa77bad9bce4..8fad61268465 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -157,11 +157,11 @@ impl ForeignOwnable for () { /// let mut vec = /// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len())); /// -/// vec.try_push(10u8)?; +/// vec.push(10u8, GFP_KERNEL)?; /// if arg { /// return Ok(()); /// } -/// vec.try_push(20u8)?; +/// vec.push(20u8, GFP_KERNEL)?; /// Ok(()) /// } /// diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index dc05f4bbe27e..2a9eaab62d1c 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -22,9 +22,9 @@ impl kernel::Module for RustMinimal { pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); let mut numbers = Vec::new(); - numbers.try_push(72)?; - numbers.try_push(108)?; - numbers.try_push(200)?; + numbers.push(72, GFP_KERNEL)?; + numbers.push(108, GFP_KERNEL)?; + numbers.push(200, GFP_KERNEL)?; Ok(RustMinimal { numbers }) } -- cgit v1.2.3 From 2c1092853f163762ef0aabc551a630ef233e1be3 Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Wed, 27 Mar 2024 22:36:03 -0300 Subject: rust: kernel: remove usage of `allocator_api` unstable feature With the adoption of `BoxExt` and `VecExt`, we don't need the functions provided by this feature (namely the methods prefixed with `try_` and different allocator per collection instance). We do need `AllocError`, but we define our own as it is a trivial empty struct. Reviewed-by: Benno Lossin Signed-off-by: Wedson Almeida Filho Link: https://lore.kernel.org/r/20240328013603.206764-11-wedsonaf@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/alloc.rs | 4 ++++ rust/kernel/alloc/box_ext.rs | 3 +-- rust/kernel/alloc/vec_ext.rs | 4 ++-- rust/kernel/error.rs | 4 ++-- rust/kernel/init.rs | 3 +-- rust/kernel/lib.rs | 1 - rust/kernel/str.rs | 3 +-- rust/kernel/sync/arc.rs | 4 ++-- rust/kernel/workqueue.rs | 3 +-- 9 files changed, 14 insertions(+), 15 deletions(-) (limited to 'rust/kernel/alloc/vec_ext.rs') diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index 9bc1b48b5641..f1c2c4aa22d2 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -8,6 +8,10 @@ mod allocator; pub mod box_ext; pub mod vec_ext; +/// Indicates an allocation error. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct AllocError; + /// Flags to be used when allocating memory. /// /// They can be combined with the operators `|`, `&`, and `!`. diff --git a/rust/kernel/alloc/box_ext.rs b/rust/kernel/alloc/box_ext.rs index 76653d6f4257..cdbb5ad166d9 100644 --- a/rust/kernel/alloc/box_ext.rs +++ b/rust/kernel/alloc/box_ext.rs @@ -2,9 +2,8 @@ //! Extensions to [`Box`] for fallible allocations. -use super::Flags; +use super::{AllocError, Flags}; use alloc::boxed::Box; -use core::alloc::AllocError; use core::mem::MaybeUninit; use core::result::Result; diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs index e24d7c7675ca..6a916fcf8bf1 100644 --- a/rust/kernel/alloc/vec_ext.rs +++ b/rust/kernel/alloc/vec_ext.rs @@ -2,8 +2,8 @@ //! Extensions to [`Vec`] for fallible allocations. -use super::Flags; -use alloc::{alloc::AllocError, vec::Vec}; +use super::{AllocError, Flags}; +use alloc::vec::Vec; use core::result::Result; /// Extensions to [`Vec`]. diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index e53466937796..fc986bc24c6d 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -4,9 +4,9 @@ //! //! C header: [`include/uapi/asm-generic/errno-base.h`](srctree/include/uapi/asm-generic/errno-base.h) -use crate::str::CStr; +use crate::{alloc::AllocError, str::CStr}; -use alloc::alloc::{AllocError, LayoutError}; +use alloc::alloc::LayoutError; use core::convert::From; use core::fmt; diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index fec47b274ec3..9608f2bd2211 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -211,14 +211,13 @@ //! [`pin_init!`]: crate::pin_init! use crate::{ - alloc::{box_ext::BoxExt, Flags}, + alloc::{box_ext::BoxExt, AllocError, Flags}, error::{self, Error}, sync::UniqueArc, types::{Opaque, ScopeGuard}, }; use alloc::boxed::Box; use core::{ - alloc::AllocError, cell::UnsafeCell, convert::Infallible, marker::PhantomData, diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 1e910fe7c2c7..9a943d99c71a 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -12,7 +12,6 @@ //! do so first instead of bypassing this crate. #![no_std] -#![feature(allocator_api)] #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] #![feature(new_uninit)] diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index f454252c6215..27641c3e4df8 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,8 +2,7 @@ //! String representations. -use crate::alloc::{flags::*, vec_ext::VecExt}; -use alloc::alloc::AllocError; +use crate::alloc::{flags::*, vec_ext::VecExt, AllocError}; use alloc::vec::Vec; use core::fmt::{self, Write}; use core::ops::{self, Deref, DerefMut, Index}; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 0866378f1360..c2a3a2c7cbc5 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -16,7 +16,7 @@ //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html use crate::{ - alloc::{box_ext::BoxExt, Flags}, + alloc::{box_ext::BoxExt, AllocError, Flags}, bindings, error::{self, Error}, init::{self, InPlaceInit, Init, PinInit}, @@ -25,7 +25,7 @@ use crate::{ }; use alloc::boxed::Box; use core::{ - alloc::{AllocError, Layout}, + alloc::Layout, fmt, marker::{PhantomData, Unsize}, mem::{ManuallyDrop, MaybeUninit}, diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index ba5fb05130c5..9f47bad0b003 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -132,9 +132,8 @@ //! //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h) -use crate::alloc::Flags; +use crate::alloc::{AllocError, Flags}; use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque}; -use alloc::alloc::AllocError; use alloc::boxed::Box; use core::marker::PhantomData; use core::pin::Pin; -- cgit v1.2.3 From 00280272a0e5d98055e4d47db38a9b4b5517520e Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Mon, 1 Apr 2024 23:23:02 +0200 Subject: rust: kernel: remove redundant imports Rust's `unused_imports` lint covers both unused and redundant imports. In the upcoming 1.78.0, the lint detects more cases of redundant imports [1], e.g.: error: the item `bindings` is imported redundantly --> rust/kernel/print.rs:38:9 | 38 | use crate::bindings; | ^^^^^^^^^^^^^^^ the item `bindings` is already defined by prelude Most cases are `use crate::bindings`, plus a few other items like `Box`. Thus clean them up. Note that, in the `bindings` case, the message "defined by prelude" above means the extern prelude, i.e. the `--extern` flags we pass. Link: https://github.com/rust-lang/rust/pull/117772 [1] Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20240401212303.537355-3-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/alloc.rs | 1 - rust/kernel/alloc/allocator.rs | 2 -- rust/kernel/alloc/box_ext.rs | 1 - rust/kernel/alloc/vec_ext.rs | 1 - rust/kernel/error.rs | 1 - rust/kernel/net/phy.rs | 2 +- rust/kernel/print.rs | 5 ----- rust/kernel/str.rs | 5 +---- rust/kernel/sync/arc.rs | 1 - rust/kernel/sync/condvar.rs | 1 - rust/kernel/sync/lock.rs | 2 +- rust/kernel/sync/lock/mutex.rs | 2 -- rust/kernel/sync/lock/spinlock.rs | 2 -- rust/kernel/task.rs | 2 +- rust/kernel/workqueue.rs | 4 +--- 15 files changed, 5 insertions(+), 27 deletions(-) (limited to 'rust/kernel/alloc/vec_ext.rs') diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index f1c2c4aa22d2..531b5e471cb1 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -46,7 +46,6 @@ impl core::ops::Not for Flags { /// These are meant to be used in functions that can allocate memory. pub mod flags { use super::Flags; - use crate::bindings; /// Zeroes out the allocated memory. /// diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index ff88bce04fd4..229642960cd1 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -6,8 +6,6 @@ use super::{flags::*, Flags}; use core::alloc::{GlobalAlloc, Layout}; use core::ptr; -use crate::bindings; - struct KernelAllocator; /// Calls `krealloc` with a proper size to alloc a new object aligned to `new_layout`'s alignment. diff --git a/rust/kernel/alloc/box_ext.rs b/rust/kernel/alloc/box_ext.rs index cdbb5ad166d9..829cb1c1cf9e 100644 --- a/rust/kernel/alloc/box_ext.rs +++ b/rust/kernel/alloc/box_ext.rs @@ -5,7 +5,6 @@ use super::{AllocError, Flags}; use alloc::boxed::Box; use core::mem::MaybeUninit; -use core::result::Result; /// Extensions to [`Box`]. pub trait BoxExt: Sized { diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs index 6a916fcf8bf1..25025a36e250 100644 --- a/rust/kernel/alloc/vec_ext.rs +++ b/rust/kernel/alloc/vec_ext.rs @@ -4,7 +4,6 @@ use super::{AllocError, Flags}; use alloc::vec::Vec; -use core::result::Result; /// Extensions to [`Vec`]. pub trait VecExt: Sized { diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index fc986bc24c6d..55280ae9fe40 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -8,7 +8,6 @@ use crate::{alloc::AllocError, str::CStr}; use alloc::alloc::LayoutError; -use core::convert::From; use core::fmt; use core::num::TryFromIntError; use core::str::Utf8Error; diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 96e09c6e8530..fba19165aa64 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -6,7 +6,7 @@ //! //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h). -use crate::{bindings, error::*, prelude::*, str::CStr, types::Opaque}; +use crate::{error::*, prelude::*, types::Opaque}; use core::marker::PhantomData; diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 9b13aca832c2..a78aa3514a0a 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -13,9 +13,6 @@ use core::{ use crate::str::RawFormatter; -#[cfg(CONFIG_PRINTK)] -use crate::bindings; - // Called from `vsprintf` with format specifier `%pA`. #[no_mangle] unsafe extern "C" fn rust_fmt_argument( @@ -35,8 +32,6 @@ unsafe extern "C" fn rust_fmt_argument( /// Public but hidden since it should only be used from public macros. #[doc(hidden)] pub mod format_strings { - use crate::bindings; - /// The length we copy from the `KERN_*` kernel prefixes. const LENGTH_PREFIX: usize = 2; diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 27641c3e4df8..bb8d4f41475b 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -7,10 +7,7 @@ use alloc::vec::Vec; use core::fmt::{self, Write}; use core::ops::{self, Deref, DerefMut, Index}; -use crate::{ - bindings, - error::{code::*, Error}, -}; +use crate::error::{code::*, Error}; /// Byte string without UTF-8 validity guarantee. #[repr(transparent)] diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index a65716ec24a6..3673496c2363 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -17,7 +17,6 @@ use crate::{ alloc::{box_ext::BoxExt, AllocError, Flags}, - bindings, error::{self, Error}, init::{self, InPlaceInit, Init, PinInit}, try_init, diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ef6ffef0aa88..2b306afbe56d 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -7,7 +7,6 @@ use super::{lock::Backend, lock::Guard, LockClassKey}; use crate::{ - bindings, init::PinInit, pin_init, str::CStr, diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 5b5c8efe427a..f6c34ca4d819 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -6,7 +6,7 @@ //! spinlocks, raw spinlocks) to be provided with minimal effort. use super::LockClassKey; -use crate::{bindings, init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard}; +use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard}; use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned}; use macros::pin_data; diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 93e1c982facf..30632070ee67 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -4,8 +4,6 @@ //! //! This module allows Rust code to use the kernel's `struct mutex`. -use crate::bindings; - /// Creates a [`Mutex`] initialiser with the given name and a newly-created lock class. /// /// It uses the name if one is given, otherwise it generates one based on the file name and line diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 6e900807d3b7..ea5c5bc1ce12 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -4,8 +4,6 @@ //! //! This module allows Rust code to use the kernel's `spinlock_t`. -use crate::bindings; - /// Creates a [`SpinLock`] initialiser with the given name and a newly-created lock class. /// /// It uses the name if one is given, otherwise it generates one based on the file name and line diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index ca6e7e31d71c..55dff7e088bf 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,7 +4,7 @@ //! //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h). -use crate::{bindings, types::Opaque}; +use crate::types::Opaque; use core::{ ffi::{c_int, c_long, c_uint}, marker::PhantomData, diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 22813b76861d..1cec63a2aea8 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -131,10 +131,8 @@ //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h) use crate::alloc::{AllocError, Flags}; -use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque}; -use alloc::boxed::Box; +use crate::{prelude::*, sync::Arc, sync::LockClassKey, types::Opaque}; use core::marker::PhantomData; -use core::pin::Pin; /// Creates a [`Work`] initialiser with the given name and a newly-created lock class. #[macro_export] -- cgit v1.2.3 From 97ab3e8eec0ce79d9e265e6c9e4c480492180409 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 1 May 2024 15:47:43 +0200 Subject: rust: alloc: fix dangling pointer in VecExt::reserve() Currently, a Vec's ptr value, after calling Vec::new(), is initialized to Unique::dangling(). Hence, in VecExt::reserve(), we're passing a dangling pointer (instead of NULL) to krealloc() whenever a new Vec's backing storage is allocated through VecExt extension functions. This only works as long as align_of::(), used by Unique::dangling() to derive the dangling pointer, resolves to a value between 0x0 and ZERO_SIZE_PTR (0x10) and krealloc() hence treats it the same as a NULL pointer however. This isn't a case we should rely on, since there may be types whose alignment may exceed the range still covered by krealloc(), plus other kernel allocators are not as tolerant either. Instead, pass a real NULL pointer to krealloc_aligned() if Vec's capacity is zero. Fixes: 5ab560ce12ed ("rust: alloc: update `VecExt` to take allocation flags") Reviewed-by: Alice Ryhl Reviewed-by: Boqun Feng Reviewed-by: Benno Lossin Signed-off-by: Danilo Krummrich Reviewed-by: Wedson Almeida Filho Link: https://lore.kernel.org/r/20240501134834.22323-1-dakr@redhat.com [ Solved `use` conflict and applied the `if`-instead-of-`match` change discussed in the list. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/vec_ext.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'rust/kernel/alloc/vec_ext.rs') diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs index 25025a36e250..e9a81052728a 100644 --- a/rust/kernel/alloc/vec_ext.rs +++ b/rust/kernel/alloc/vec_ext.rs @@ -4,6 +4,7 @@ use super::{AllocError, Flags}; use alloc::vec::Vec; +use core::ptr; /// Extensions to [`Vec`]. pub trait VecExt: Sized { @@ -134,14 +135,20 @@ impl VecExt for Vec { let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); let layout = core::alloc::Layout::array::(new_cap).map_err(|_| AllocError)?; - let (ptr, len, cap) = destructure(self); + 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`'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`'s capacity + // to be zero if no memory has been allocated yet. + let ptr = if cap == 0 { 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, ptr, len, cap) }; + unsafe { rebuild(self, old_ptr, len, cap) }; Err(AllocError) } else { // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap -- cgit v1.2.3