Skip to content

Commit 294a7ec

Browse files
DarksonnDanilo Krummrich
authored andcommitted
rust: alloc: add Vec::remove
This is needed by Rust Binder in the range allocator, and by upcoming GPU drivers during firmware initialization. Panics in the kernel are best avoided when possible, so an error is returned if the index is out of bounds. An error type is used rather than just returning Option<T> to let callers handle errors with ?. 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-6-06d20ad9366f@google.com [ Remove `# Panics` section; `Vec::remove() handles the error properly.` - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent 9f14089 commit 294a7ec

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

rust/kernel/alloc/kvec.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use core::{
2222
};
2323

2424
mod errors;
25-
pub use self::errors::PushError;
25+
pub use self::errors::{PushError, RemoveError};
2626

2727
/// Create a [`KVec`] containing the arguments.
2828
///
@@ -389,6 +389,42 @@ where
389389
Some(unsafe { removed.read() })
390390
}
391391

392+
/// Removes the element at the given index.
393+
///
394+
/// # Examples
395+
///
396+
/// ```
397+
/// let mut v = kernel::kvec![1, 2, 3]?;
398+
/// assert_eq!(v.remove(1)?, 2);
399+
/// assert_eq!(v, [1, 3]);
400+
/// # Ok::<(), Error>(())
401+
/// ```
402+
pub fn remove(&mut self, i: usize) -> Result<T, RemoveError> {
403+
let value = {
404+
let value_ref = self.get(i).ok_or(RemoveError)?;
405+
// INVARIANT: This breaks the invariants by invalidating the value at index `i`, but we
406+
// restore the invariants below.
407+
// SAFETY: The value at index `i` is valid, because otherwise we would have already
408+
// failed with `RemoveError`.
409+
unsafe { ptr::read(value_ref) }
410+
};
411+
412+
// SAFETY: We checked that `i` is in-bounds.
413+
let p = unsafe { self.as_mut_ptr().add(i) };
414+
415+
// INVARIANT: After this call, the invalid value is at the last slot, so the Vec invariants
416+
// are restored after the below call to `dec_len(1)`.
417+
// SAFETY: `p.add(1).add(self.len - i - 1)` is `i+1+len-i-1 == len` elements after the
418+
// beginning of the vector, so this is in-bounds of the vector's allocation.
419+
unsafe { ptr::copy(p.add(1), p, self.len - i - 1) };
420+
421+
// SAFETY: Since the check at the beginning of this call did not fail with `RemoveError`,
422+
// the length is at least one.
423+
unsafe { self.dec_len(1) };
424+
425+
Ok(value)
426+
}
427+
392428
/// Creates a new [`Vec`] instance with at least the given capacity.
393429
///
394430
/// # Examples

rust/kernel/alloc/kvec/errors.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,18 @@ impl<T> From<PushError<T>> for Error {
2121
EINVAL
2222
}
2323
}
24+
25+
/// Error type for [`Vec::remove`].
26+
pub struct RemoveError;
27+
28+
impl Debug for RemoveError {
29+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
30+
write!(f, "Index out of bounds")
31+
}
32+
}
33+
34+
impl From<RemoveError> for Error {
35+
fn from(_: RemoveError) -> Error {
36+
EINVAL
37+
}
38+
}

0 commit comments

Comments
 (0)