[PATCH v9 1/6] rust: kernel: add `drop_contents` to `BoxExt`

From: Matt Gilbride
Date: Fri Aug 16 2024 - 16:48:17 EST


From: Benno Lossin <benno.lossin@xxxxxxxxx>

Sometimes (see [1]) it is necessary to drop the value inside of a
`Box<T>`, but retain the allocation. For example to reuse the allocation
in the future.
Introduce a new function `drop_contents` that turns a `Box<T>` into
`Box<MaybeUninit<T>>` by dropping the value.

Signed-off-by: Benno Lossin <benno.lossin@xxxxxxxxx>
Link: https://lore.kernel.org/rust-for-linux/20240418-b4-rbtree-v3-5-323e134390ce@xxxxxxxxxx/ [1]
Reviewed-by: Boqun Feng <boqun.feng@xxxxxxxxx>
Reviewed-by: Alice Ryhl <aliceryhl@xxxxxxxxxx>
---
rust/kernel/alloc/box_ext.rs | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/rust/kernel/alloc/box_ext.rs b/rust/kernel/alloc/box_ext.rs
index 829cb1c1cf9e..6cf79f96d6c7 100644
--- a/rust/kernel/alloc/box_ext.rs
+++ b/rust/kernel/alloc/box_ext.rs
@@ -5,6 +5,8 @@
use super::{AllocError, Flags};
use alloc::boxed::Box;
use core::mem::MaybeUninit;
+use core::ptr;
+use core::result::Result;

/// Extensions to [`Box`].
pub trait BoxExt<T>: Sized {
@@ -17,6 +19,18 @@ pub trait BoxExt<T>: Sized {
///
/// The allocation may fail, in which case an error is returned.
fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>;
+
+ /// Drops the contents, but keeps the allocation.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let value = Box::new([0; 32], flags::GFP_KERNEL)
+ /// let value = value.drop_contents();
+ /// // Now we can re-use `value`:
+ /// Box::write(value, [1; 32]);
+ /// ```
+ fn drop_contents(self) -> Box<MaybeUninit<T>>;
}

impl<T> BoxExt<T> for Box<T> {
@@ -53,4 +67,12 @@ fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
// zero-sized types, we use `NonNull::dangling`.
Ok(unsafe { Box::from_raw(ptr) })
}
+
+ fn drop_contents(self) -> Box<MaybeUninit<T>> {
+ let ptr = Box::into_raw(self);
+ // SAFETY: `ptr` is valid, because it came from `Box::into_raw`.
+ unsafe { ptr::drop_in_place(ptr) };
+ // SAFETY: `ptr` is valid, because it came from `Box::into_raw`.
+ unsafe { Box::from_raw(ptr.cast()) }
+ }
}

--
2.46.0.184.g6999bdac58-goog