FROMGIT: rust: alloc: add Vec::insert_within_capacity

This adds a variant of Vec::insert that does not allocate memory. This
makes it safe to use this function while holding a spinlock. Rust Binder
uses it for the range allocator fast path.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://lore.kernel.org/r/20250502-vec-methods-v5-7-06d20ad9366f@google.com
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

Bug: 414994413
(cherry picked from commit 771c5a7d9843643b035938624050e7769133b9cc
 https://github.com/Rust-for-Linux/linux.git alloc-next)
Change-Id: I5661d5ee9ff239a92c4a640e334ad6d60196ad25
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2025-05-02 13:19:35 +00:00
committed by Matthew Maurer
parent c28afde01d
commit 8313296331
2 changed files with 73 additions and 1 deletions

View File

@@ -22,7 +22,7 @@ use core::{
};
mod errors;
pub use self::errors::{PushError, RemoveError};
pub use self::errors::{InsertError, PushError, RemoveError};
/// Create a [`KVec`] containing the arguments.
///
@@ -358,6 +358,55 @@ where
unsafe { self.inc_len(1) };
}
/// Inserts an element at the given index in the [`Vec`] instance.
///
/// Fails if the vector does not have capacity for the new element. Panics if the index is out
/// of bounds.
///
/// # Examples
///
/// ```
/// use kernel::alloc::kvec::InsertError;
///
/// let mut v = KVec::with_capacity(5, GFP_KERNEL)?;
/// for i in 0..5 {
/// v.insert_within_capacity(0, i)?;
/// }
///
/// assert!(matches!(v.insert_within_capacity(0, 5), Err(InsertError::OutOfCapacity(_))));
/// assert!(matches!(v.insert_within_capacity(1000, 5), Err(InsertError::IndexOutOfBounds(_))));
/// assert_eq!(v, [4, 3, 2, 1, 0]);
/// # Ok::<(), Error>(())
/// ```
pub fn insert_within_capacity(
&mut self,
index: usize,
element: T,
) -> Result<(), InsertError<T>> {
let len = self.len();
if index > len {
return Err(InsertError::IndexOutOfBounds(element));
}
if len >= self.capacity() {
return Err(InsertError::OutOfCapacity(element));
}
// SAFETY: This is in bounds since `index <= len < capacity`.
let p = unsafe { self.as_mut_ptr().add(index) };
// INVARIANT: This breaks the Vec invariants by making `index` contain an invalid element,
// but we restore the invariants below.
// SAFETY: Both the src and dst ranges end no later than one element after the length.
// Since the length is less than the capacity, both ranges are in bounds of the allocation.
unsafe { ptr::copy(p, p.add(1), len - index) };
// INVARIANT: This restores the Vec invariants.
// SAFETY: The pointer is in-bounds of the allocation.
unsafe { ptr::write(p, element) };
// SAFETY: Index `len` contains a valid element due to the above copy and write.
unsafe { self.inc_len(1) };
Ok(())
}
/// Removes the last element from a vector and returns it, or `None` if it is empty.
///
/// # Examples

View File

@@ -36,3 +36,26 @@ impl From<RemoveError> for Error {
EINVAL
}
}
/// Error type for [`Vec::insert_within_capacity`].
pub enum InsertError<T> {
/// The value could not be inserted because the index is out of bounds.
IndexOutOfBounds(T),
/// The value could not be inserted because the vector is out of capacity.
OutOfCapacity(T),
}
impl<T> Debug for InsertError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
InsertError::IndexOutOfBounds(_) => write!(f, "Index out of bounds"),
InsertError::OutOfCapacity(_) => write!(f, "Not enough capacity"),
}
}
}
impl<T> From<InsertError<T>> for Error {
fn from(_: InsertError<T>) -> Error {
EINVAL
}
}