108d3f549SWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 208d3f549SWedson Almeida Filho 308d3f549SWedson Almeida Filho //! Extensions to [`Box`] for fallible allocations. 408d3f549SWedson Almeida Filho 52c109285SWedson Almeida Filho use super::{AllocError, Flags}; 608d3f549SWedson Almeida Filho use alloc::boxed::Box; 701db99b2SBenno Lossin use core::{mem::MaybeUninit, ptr, result::Result}; 808d3f549SWedson Almeida Filho 908d3f549SWedson Almeida Filho /// Extensions to [`Box`]. 1008d3f549SWedson Almeida Filho pub trait BoxExt<T>: Sized { 1108d3f549SWedson Almeida Filho /// Allocates a new box. 1208d3f549SWedson Almeida Filho /// 1308d3f549SWedson Almeida Filho /// The allocation may fail, in which case an error is returned. new(x: T, flags: Flags) -> Result<Self, AllocError>1408d3f549SWedson Almeida Filho fn new(x: T, flags: Flags) -> Result<Self, AllocError>; 1508d3f549SWedson Almeida Filho 1608d3f549SWedson Almeida Filho /// Allocates a new uninitialised box. 1708d3f549SWedson Almeida Filho /// 1808d3f549SWedson Almeida Filho /// The allocation may fail, in which case an error is returned. new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>1908d3f549SWedson Almeida Filho fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>; 2001db99b2SBenno Lossin 2101db99b2SBenno Lossin /// Drops the contents, but keeps the allocation. 2201db99b2SBenno Lossin /// 2301db99b2SBenno Lossin /// # Examples 2401db99b2SBenno Lossin /// 2501db99b2SBenno Lossin /// ``` 2601db99b2SBenno Lossin /// use kernel::alloc::{flags, box_ext::BoxExt}; 2701db99b2SBenno Lossin /// let value = Box::new([0; 32], flags::GFP_KERNEL)?; 2801db99b2SBenno Lossin /// assert_eq!(*value, [0; 32]); 29*ab309b6eSMiguel Ojeda /// let mut value = Box::drop_contents(value); 3001db99b2SBenno Lossin /// // Now we can re-use `value`: 31*ab309b6eSMiguel Ojeda /// value.write([1; 32]); 32*ab309b6eSMiguel Ojeda /// // SAFETY: We just wrote to it. 33*ab309b6eSMiguel Ojeda /// let value = unsafe { value.assume_init() }; 3401db99b2SBenno Lossin /// assert_eq!(*value, [1; 32]); 3501db99b2SBenno Lossin /// # Ok::<(), Error>(()) 3601db99b2SBenno Lossin /// ``` drop_contents(this: Self) -> Box<MaybeUninit<T>>3701db99b2SBenno Lossin fn drop_contents(this: Self) -> Box<MaybeUninit<T>>; 3808d3f549SWedson Almeida Filho } 3908d3f549SWedson Almeida Filho 4008d3f549SWedson Almeida Filho impl<T> BoxExt<T> for Box<T> { new(x: T, flags: Flags) -> Result<Self, AllocError>4108d3f549SWedson Almeida Filho fn new(x: T, flags: Flags) -> Result<Self, AllocError> { 420903b9e2SJubilee Young let mut b = <Self as BoxExt<_>>::new_uninit(flags)?; 430903b9e2SJubilee Young b.write(x); 440903b9e2SJubilee Young // SAFETY: We just wrote to it. 450903b9e2SJubilee Young Ok(unsafe { b.assume_init() }) 4608d3f549SWedson Almeida Filho } 4708d3f549SWedson Almeida Filho 4808d3f549SWedson Almeida Filho #[cfg(any(test, testlib))] new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>4908d3f549SWedson Almeida Filho fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { 5008d3f549SWedson Almeida Filho Ok(Box::new_uninit()) 5108d3f549SWedson Almeida Filho } 5208d3f549SWedson Almeida Filho 5308d3f549SWedson Almeida Filho #[cfg(not(any(test, testlib)))] new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>5408d3f549SWedson Almeida Filho fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { 5508d3f549SWedson Almeida Filho let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 { 5608d3f549SWedson Almeida Filho core::ptr::NonNull::<_>::dangling().as_ptr() 5708d3f549SWedson Almeida Filho } else { 5808d3f549SWedson Almeida Filho let layout = core::alloc::Layout::new::<MaybeUninit<T>>(); 5908d3f549SWedson Almeida Filho 6008d3f549SWedson Almeida Filho // SAFETY: Memory is being allocated (first arg is null). The only other source of 6108d3f549SWedson Almeida Filho // safety issues is sleeping on atomic context, which is addressed by klint. Lastly, 6208d3f549SWedson Almeida Filho // the type is not a SZT (checked above). 6308d3f549SWedson Almeida Filho let ptr = 6408d3f549SWedson Almeida Filho unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) }; 6508d3f549SWedson Almeida Filho if ptr.is_null() { 6608d3f549SWedson Almeida Filho return Err(AllocError); 6708d3f549SWedson Almeida Filho } 6808d3f549SWedson Almeida Filho 6908d3f549SWedson Almeida Filho ptr.cast::<MaybeUninit<T>>() 7008d3f549SWedson Almeida Filho }; 7108d3f549SWedson Almeida Filho 7208d3f549SWedson Almeida Filho // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For 7308d3f549SWedson Almeida Filho // zero-sized types, we use `NonNull::dangling`. 7408d3f549SWedson Almeida Filho Ok(unsafe { Box::from_raw(ptr) }) 7508d3f549SWedson Almeida Filho } 7601db99b2SBenno Lossin drop_contents(this: Self) -> Box<MaybeUninit<T>>7701db99b2SBenno Lossin fn drop_contents(this: Self) -> Box<MaybeUninit<T>> { 7801db99b2SBenno Lossin let ptr = Box::into_raw(this); 7901db99b2SBenno Lossin // SAFETY: `ptr` is valid, because it came from `Box::into_raw`. 8001db99b2SBenno Lossin unsafe { ptr::drop_in_place(ptr) }; 8101db99b2SBenno Lossin 8201db99b2SBenno Lossin // CAST: `MaybeUninit<T>` is a transparent wrapper of `T`. 8301db99b2SBenno Lossin let ptr = ptr.cast::<MaybeUninit<T>>(); 8401db99b2SBenno Lossin 8501db99b2SBenno Lossin // SAFETY: `ptr` is valid for writes, because it came from `Box::into_raw` and it is valid for 8601db99b2SBenno Lossin // reads, since the pointer came from `Box::into_raw` and the type is `MaybeUninit<T>`. 8701db99b2SBenno Lossin unsafe { Box::from_raw(ptr) } 8801db99b2SBenno Lossin } 8908d3f549SWedson Almeida Filho } 90