Andrew Ballance
2025-Mar-15 02:43 UTC
[PATCH 0/3] rust: alloc: add Vec::resize and Vec::truncate
This patch series implements the Vec::truncate and Vec::resize methods that were needed by the nova driver and removes the corresponding item from their task list Andrew Ballance (3): rust: alloc: add Vec::truncate method rust: alloc: add Vec::resize method gpu: nova-core: remove completed Vec extentions from task list Documentation/gpu/nova/core/todo.rst | 10 ----- rust/kernel/alloc/kvec.rs | 61 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) -- 2.48.1
implements the equivalent to the std's Vec::truncate
on the kernel's Vec type.
Signed-off-by: Andrew Ballance <andrewjballance at gmail.com>
---
rust/kernel/alloc/kvec.rs | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index ae9d072741ce..75e9feebb81f 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -452,6 +452,42 @@ pub fn reserve(&mut self, additional: usize, flags:
Flags) -> Result<(), AllocEr
Ok(())
}
+
+ /// 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.
+ /// # Examples
+ /// ```
+ /// let mut v = kernel::kvec![1, 2, 3]?;
+ /// v.truncate(1);
+ /// assert_eq!(v.len(), 1);
+ /// assert_eq!(&v, &[1]);
+ ///
+ /// # Ok::<(), Error>(())
+ /// ```
+ pub fn truncate(&mut self, len: usize) {
+ if len >= self.len() {
+ return;
+ }
+
+ // [new_len, len) is guaranteed to be valid because [0, len) is
guaranteed to be valid
+ let drop_range = len..self.len();
+
+ // SAFETY:
+ // we can safely ignore the bounds check because we already did our own
check
+ let ptr: *mut [T] = unsafe { self.get_unchecked_mut(drop_range) };
+
+ // SAFETY:
+ // it is safe to shrink the length because the new length is
+ // guaranteed to be less than the old length
+ unsafe { self.set_len(len) };
+
+ // SAFETY:
+ // - the dropped values are valid `T`s
+ // - we are allowed to invalidate [new_len, old_len) because we just
changed the len
+ unsafe { ptr::drop_in_place(ptr) };
+ }
}
impl<T: Clone, A: Allocator> Vec<T, A> {
--
2.48.1
implemnts the equivalent of the rust std's Vec::resize
on the kernel's Vec type.
Signed-off-by: Andrew Ballance <andrewjballance at gmail.com>
---
rust/kernel/alloc/kvec.rs | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index 75e9feebb81f..cbfef2e56f9c 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -554,6 +554,31 @@ pub fn from_elem(value: T, n: usize, flags: Flags) ->
Result<Self, AllocError> {
Ok(v)
}
+
+ /// Resizes the [`Vec`] so that `len` is equal to `new_len`.
+ ///
+ /// If `new_len` is smaller than `len`, the `Vec` is [`Vec::truncate`]d.
+ /// If `new_len` is larger, each new slot is filled with clones of `value`.
+ ///
+ /// # Example
+ /// ```
+ /// let mut v = kernel::kvec![1, 2, 3]?;
+ /// v.resize(1, 42, GFP_KERNEL)?;
+ /// assert_eq!(&v, &[1]);
+ ///
+ /// v.resize(3, 42, GFP_KERNEL)?;
+ /// assert_eq!(&v, &[1, 42, 42]);
+ ///
+ /// # Ok::<(), Error>(())
+ /// ```
+ pub fn resize(&mut self, new_len: usize, value: T, flags: Flags) ->
Result<(), AllocError> {
+ if new_len > self.len() {
+ self.extend_with(new_len - self.len(), value, flags)
+ } else {
+ self.truncate(new_len);
+ Ok(())
+ }
+ }
}
impl<T, A> Drop for Vec<T, A>
--
2.48.1
Andrew Ballance
2025-Mar-15 02:43 UTC
[PATCH 3/3] gpu: nova-core: remove completed Vec extentions from task list
The requested Vec methods have been implemented thus, removes the completed item from the nova task list Signed-off-by: Andrew Ballance <andrewjballance at gmail.com> --- Documentation/gpu/nova/core/todo.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/core/todo.rst index ca08377d3b73..234d753d3eac 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -190,16 +190,6 @@ Rust abstraction for debugfs APIs. | Reference: Export GSP log buffers | Complexity: Intermediate -Vec extensions --------------- - -Implement ``Vec::truncate`` and ``Vec::resize``. - -Currently this is used for some experimental code to parse the vBIOS. - -| Reference vBIOS support -| Complexity: Beginner - GPU (general) ============ -- 2.48.1
On Sat Mar 15, 2025 at 3:42 AM CET, Andrew Ballance wrote:> implements the equivalent to the std's Vec::truncate > on the kernel's Vec type. > > Signed-off-by: Andrew Ballance <andrewjballance at gmail.com> > --- > rust/kernel/alloc/kvec.rs | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs > index ae9d072741ce..75e9feebb81f 100644 > --- a/rust/kernel/alloc/kvec.rs > +++ b/rust/kernel/alloc/kvec.rs > @@ -452,6 +452,42 @@ pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocEr > > Ok(()) > } > + > + /// 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. > + /// # Examples > + /// ``` > + /// let mut v = kernel::kvec![1, 2, 3]?; > + /// v.truncate(1); > + /// assert_eq!(v.len(), 1); > + /// assert_eq!(&v, &[1]); > + /// > + /// # Ok::<(), Error>(()) > + /// ``` > + pub fn truncate(&mut self, len: usize) { > + if len >= self.len() { > + return; > + } > + > + // [new_len, len) is guaranteed to be valid because [0, len) is guaranteed to be valid > + let drop_range = len..self.len(); > + > + // SAFETY: > + // we can safely ignore the bounds check because we already did our own check > + let ptr: *mut [T] = unsafe { self.get_unchecked_mut(drop_range) };What's this `get_unchecked_mut` method, I don't see it in `rust-next` or `alloc-next`.> + > + // SAFETY: > + // it is safe to shrink the length because the new length is > + // guaranteed to be less than the old lengthPlease take a look at the documentation of `set_len`, in the safety section you'll find what you need to justify here.> + unsafe { self.set_len(len) }; > + > + // SAFETY:A couple points missing: - why is the pointer valid?> + // - the dropped values are valid `T`s > + // - we are allowed to invalidate [new_len, old_len) because we just changed the lenThis should justify why the value will never be accessed again. --- Cheers, Benno> + unsafe { ptr::drop_in_place(ptr) }; > + } > } > > impl<T: Clone, A: Allocator> Vec<T, A> {
On Sat Mar 15, 2025 at 3:42 AM CET, Andrew Ballance wrote:> implemnts the equivalent of the rust std's Vec::resize > on the kernel's Vec type. > > Signed-off-by: Andrew Ballance <andrewjballance at gmail.com>Reviewed-by: Benno Lossin <benno.lossin at proton.me> --- Cheers, Benno> --- > rust/kernel/alloc/kvec.rs | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+)
Danilo Krummrich
2025-Mar-15 14:50 UTC
[PATCH 0/3] rust: alloc: add Vec::resize and Vec::truncate
Hi Andrew, On Fri, Mar 14, 2025 at 09:42:32PM -0500, Andrew Ballance wrote:> This patch series implements the Vec::truncate and Vec::resize methods > that were needed by the nova driver and removes the corresponding item > from their task list > > Andrew Ballance (3): > rust: alloc: add Vec::truncate method > rust: alloc: add Vec::resize method > gpu: nova-core: remove completed Vec extentions from task listThanks for picking this up! Once ready, I will pick up the first two patches for alloc-next and take the third one through the nova tree. But you can keep them in the same series for subsequent submissions. - Danilo
On Fri, Mar 14, 2025 at 09:42:34PM -0500, Andrew Ballance wrote:> implemnts the equivalent of the rust std's Vec::resize > on the kernel's Vec type.Nit: It is preferred to use the imperative form, i.e. "Implement the equivalent [...]".> > Signed-off-by: Andrew Ballance <andrewjballance at gmail.com> > --- > rust/kernel/alloc/kvec.rs | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+) > > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs > index 75e9feebb81f..cbfef2e56f9c 100644 > --- a/rust/kernel/alloc/kvec.rs > +++ b/rust/kernel/alloc/kvec.rs > @@ -554,6 +554,31 @@ pub fn from_elem(value: T, n: usize, flags: Flags) -> Result<Self, AllocError> { > > Ok(v) > } > + > + /// Resizes the [`Vec`] so that `len` is equal to `new_len`. > + /// > + /// If `new_len` is smaller than `len`, the `Vec` is [`Vec::truncate`]d. > + /// If `new_len` is larger, each new slot is filled with clones of `value`. > + /// > + /// # ExampleNit: Please add an empty line after the heading.> + /// ``` > + /// let mut v = kernel::kvec![1, 2, 3]?; > + /// v.resize(1, 42, GFP_KERNEL)?; > + /// assert_eq!(&v, &[1]); > + /// > + /// v.resize(3, 42, GFP_KERNEL)?; > + /// assert_eq!(&v, &[1, 42, 42]); > + /// > + /// # Ok::<(), Error>(()) > + /// ``` > + pub fn resize(&mut self, new_len: usize, value: T, flags: Flags) -> Result<(), AllocError> { > + if new_len > self.len() { > + self.extend_with(new_len - self.len(), value, flags) > + } else { > + self.truncate(new_len); > + Ok(()) > + } > + } > } > > impl<T, A> Drop for Vec<T, A> > -- > 2.48.1 >
On Fri, Mar 14, 2025 at 09:42:33PM -0500, Andrew Ballance wrote:> implements the equivalent to the std's Vec::truncate > on the kernel's Vec type. > > Signed-off-by: Andrew Ballance <andrewjballance at gmail.com> > --- > rust/kernel/alloc/kvec.rs | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs > index ae9d072741ce..75e9feebb81f 100644 > --- a/rust/kernel/alloc/kvec.rs > +++ b/rust/kernel/alloc/kvec.rs > @@ -452,6 +452,42 @@ pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocEr > > Ok(()) > } > + > + /// 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.Nit: Please also add an empty line here.> + /// # Examples > + /// ``` > + /// let mut v = kernel::kvec![1, 2, 3]?; > + /// v.truncate(1); > + /// assert_eq!(v.len(), 1); > + /// assert_eq!(&v, &[1]); > + /// > + /// # Ok::<(), Error>(()) > + /// ``` > + pub fn truncate(&mut self, len: usize) { > + if len >= self.len() { > + return; > + } > + > + // [new_len, len) is guaranteed to be valid because [0, len) is guaranteed to be validWe typically use markdown for comments.> + let drop_range = len..self.len(); > + > + // SAFETY: > + // we can safely ignore the bounds check because we already did our own check > + let ptr: *mut [T] = unsafe { self.get_unchecked_mut(drop_range) }; > + > + // SAFETY: > + // it is safe to shrink the length because the new length is > + // guaranteed to be less than the old length > + unsafe { self.set_len(len) };I just sent out a fix [1] for the safety requirements of set_len() in [1], which I think would be good to consider. [1] https://lore.kernel.org/rust-for-linux/20250315154436.65065-1-dakr at kernel.org/