[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251009204504.6b833fa1@nimda.home>
Date: Thu, 9 Oct 2025 20:45:04 +0300
From: Onur Özkan <work@...rozkan.dev>
To: Markus Probst <markus.probst@...teo.de>
Cc: Danilo Krummrich <dakr@...nel.org>, Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>, Lee Jones <lee@...nel.org>, Pavel
Machek <pavel@...nel.org>, Lorenzo Stoakes <lorenzo.stoakes@...cle.com>,
Vlastimil Babka <vbabka@...e.cz>, "Liam R. Howlett"
<Liam.Howlett@...cle.com>, Uladzislau Rezki <urezki@...il.com>, Boqun Feng
<boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
bjorn3_gh@...tonmail.com, Benno Lossin <lossin@...nel.org>, Andreas
Hindborg <a.hindborg@...nel.org>, Alice Ryhl <aliceryhl@...gle.com>, Trevor
Gross <tmgross@...ch.edu>, rust-for-linux@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-leds@...r.kernel.org
Subject: Re: [PATCH 1/2] rust: add basic Pin<Vec<T, A>> abstractions
On Thu, 09 Oct 2025 17:07:56 +0000
Markus Probst <markus.probst@...teo.de> wrote:
Hi Markus,
I noticed a few typos in the code comments and the commit descriptions.
> Implement core Pin<Vec<T, A>> abstractions, incluing
> * `Vec::pin` and `Vec::into_pin` for constructing a `Pin<Vec<T, A>>`.
> If T does not implement `Unpin`, it values will never be moved.
> * a extension for `Pin<Vec<T, A>>` allowing PinInit to be initialied
> on a Pin<Vec>, as well as truncating and poping values from the Vec
>
"incluing" -> "including"
"it values will..." -> "its values will..."
"a extension" -> "an extension"
"initialied" -> "initialized"
"poping values" -> "popping values"
Thanks,
Onur
> Signed-off-by: Markus Probst <markus.probst@...teo.de>
> ---
> rust/kernel/alloc.rs | 1 +
> rust/kernel/alloc/kvec.rs | 86
> +++++++++++++++++++++++++++++++++++++++ rust/kernel/prelude.rs |
> 2 +- 3 files changed, 88 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
> index a2c49e5494d3..9c129eaf0625 100644
> --- a/rust/kernel/alloc.rs
> +++ b/rust/kernel/alloc.rs
> @@ -24,6 +24,7 @@
> pub use self::kvec::KVec;
> pub use self::kvec::VVec;
> pub use self::kvec::Vec;
> +pub use self::kvec::PinnedVecExt;
>
> /// Indicates an allocation error.
> #[derive(Copy, Clone, PartialEq, Eq, Debug)]
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> index 3c72e0bdddb8..d5582a7f17e9 100644
> --- a/rust/kernel/alloc/kvec.rs
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -16,11 +16,13 @@
> ops::DerefMut,
> ops::Index,
> ops::IndexMut,
> + pin::Pin,
> ptr,
> ptr::NonNull,
> slice,
> slice::SliceIndex,
> };
> +use pin_init::PinInit;
>
> mod errors;
> pub use self::errors::{InsertError, PushError, RemoveError};
> @@ -109,6 +111,21 @@ pub struct Vec<T, A: Allocator> {
> _p: PhantomData<A>,
> }
>
> +/// Extension for Pin<Vec<T, A>>
> +pub trait PinnedVecExt<T> {
> + /// Pin-initializes P and appends it to the back of the [`Vec`]
> instance without reallocating.
> + fn push_pin_init<E: From<PushError<P>>, P: PinInit<T, E>>(&mut
> self, init: P) -> Result<(), E>; +
> + /// Shortens the vector, setting the length to `len` and drops
> the removed values.
> + /// If `len` is greater than or equal to the current length,
> this does nothing.
> + ///
> + /// This has no effect on the capacity and will not allocate.
> + fn truncate(&mut self, len: usize);
> +
> + /// Removes the last element from a vector and drops it
> returning true, or false if it is empty.
> + fn pop(&mut self) -> bool;
> +}
> +
> /// Type alias for [`Vec`] with a [`Kmalloc`] allocator.
> ///
> /// # Examples
> @@ -719,6 +736,18 @@ pub fn retain(&mut self, mut f: impl FnMut(&mut
> T) -> bool) { }
> self.truncate(num_kept);
> }
> +
> + /// Constructs a new `Pin<Vec<T, A>>`.
> + #[inline]
> + pub fn pin(capacity: usize, flags: Flags) -> Result<Pin<Self>,
> AllocError> {
> + Self::with_capacity(capacity, flags).map(Pin::<Self>::from)
> + }
> +
> + /// Convert a [`Vec<T,A>`] to a [`Pin<Vec<T,A>>`]. If `T` does
> not implement
> + /// [`Unpin`], then its values will be pinned in memory and
> can't be moved.
> + pub fn into_pin(this: Self) -> Pin<Self> {
> + this.into()
> + }
> }
>
> impl<T: Clone, A: Allocator> Vec<T, A> {
> @@ -1294,6 +1323,63 @@ fn drop(&mut self) {
> }
> }
>
> +impl<T, A: Allocator> PinnedVecExt<T> for Pin<Vec<T, A>> {
> + fn truncate(&mut self, len: usize) {
> + // SAFETY: truncate will not reallocate the Vec
> + // CAST: Pin<Ptr> is a transparent wrapper of Ptr
> + unsafe { &mut *core::ptr::from_mut(self).cast::<Vec<T, A>>()
> }.truncate(len);
> + }
> +
> + fn push_pin_init<E: From<PushError<P>>, P: PinInit<T, E>>(&mut
> self, init: P) -> Result<(), E> {
> + // SAFETY: capacity, spare_capacity_mut and inc_len will not
> + // reallocate the Vec.
> + // CAST: Pin<Ptr> is a transparent wrapper of Ptr
> + let this = unsafe { &mut
> *core::ptr::from_mut(self).cast::<Vec<T, A>>() }; +
> + if this.len() < this.capacity() {
> + let spare = this.spare_capacity_mut();
> + // SAFETY: the length is less than the capacity, so
> `spare` is non-empty.
> + unsafe {
> init.__pinned_init(spare.get_unchecked_mut(0).as_mut_ptr())? };
> + // 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.
> + unsafe { this.inc_len(1) };
> + Ok(())
> + } else {
> + Err(E::from(PushError(init)))
> + }
> + }
> +
> + fn pop(&mut self) -> bool {
> + if self.is_empty() {
> + return false;
> + }
> +
> + // SAFETY:
> + // - We just checked that the length is at least one.
> + // - dec_len will not reallocate the Vec
> + // CAST: Pin<Ptr> is a transparent wrapper of Ptr
> + let ptr: *mut [T] = unsafe {
> (*core::ptr::from_mut(self).cast::<Vec<T, A>>()).dec_len(1) }; +
> + // SAFETY: the contract of `dec_len` guarantees that the
> elements in `ptr` are
> + // valid elements whose ownership has been transferred to
> the caller.
> + unsafe { ptr::drop_in_place(ptr) };
> + true
> + }
> +}
> +
> +impl<T, A: Allocator> From<Vec<T, A>> for Pin<Vec<T, A>> {
> + /// Converts a `Vec<T, A>` into a `Pin<Vec<T, A>>`. If `T` does
> not implement [`Unpin`], then
> + /// every value in v will be pinned in memory and can't be moved.
> + ///
> + /// This moves `v` into `Pin` without moving any of the values
> of `v` or allocating and copying
> + /// any memory.
> + fn from(v: Vec<T, A>) -> Self {
> + // SAFETY: The values wrapped inside a `Pin<Vec<T, A>>`
> cannot be moved or replaced as long
> + // as `T` does not implement `Unpin`.
> + unsafe { Pin::new_unchecked(v) }
> + }
> +}
> +
> #[macros::kunit_tests(rust_kvec_kunit)]
> mod tests {
> use super::*;
> diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> index 25fe97aafd02..7179e2ca2a14 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -19,7 +19,7 @@
> c_ushort, c_void,
> };
>
> -pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec,
> VBox, VVec, Vec}; +pub use crate::alloc::{flags::*, Box, KBox, KVBox,
> KVVec, KVec, PinnedVecExt, VBox, VVec, Vec};
> #[doc(no_inline)]
> pub use macros::{export, kunit_tests, module, vtable};
Powered by blists - more mailing lists