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

From: Benno Lossin
Date: Thu Apr 25 2024 - 17:34:59 EST


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]
---
rust/kernel/alloc/box_ext.rs | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

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

/// Extensions to [`Box`].
@@ -18,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> {
@@ -54,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) }
+ }
}
--
2.44.0