Messages in this thread Patch in this message | | | Date | Mon, 13 Mar 2023 01:24:27 +0000 | From | y86-dev <> | Subject | [PATCH v1 3/3] rust: sync: reduce stack usage of `UniqueArc::try_new_uninit` |
| |
`UniqueArc::try_new_uninit` calls `Arc::try_new(MaybeUninit::uninit())`. This results in the uninitialized memory being placed on the stack, which may be arbitrarily large due to the generic `T` and thus could cause a stack overflow for large types.
Change the implementation to use the pin-init API which enables in-place initialization. In particular it avoids having to first construct and then move the uninitialized memory from the stack into the final location.
Signed-off-by: Benno Lossin <y86-dev@protonmail.com> --- rust/kernel/lib.rs | 1 - rust/kernel/sync/arc.rs | 12 +++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3e2777d26ff5..d9df77132fa2 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -27,7 +27,6 @@ #[cfg(not(CONFIG_RUST))] compile_error!("Missing kernel configuration for conditional compilation"); -#[allow(unused_extern_crates)] // Allow proc-macros to refer to `::kernel` inside the `kernel` crate (this crate). extern crate self as kernel; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 5b4f64dd3ac8..6782d66039e1 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -18,6 +18,7 @@ use crate::{ bindings, error::{Error, Result}, + init, init::{InPlaceInit, Init, PinInit}, types::{ForeignOwnable, Opaque}, }; @@ -29,6 +30,7 @@ use core::{ pin::Pin, ptr::NonNull, }; +use macros::pin_data; /// A reference-counted pointer to an instance of `T`. /// @@ -121,6 +123,7 @@ pub struct Arc<T: ?Sized> { _p: PhantomData<ArcInner<T>>, } +#[pin_data] #[repr(C)] struct ArcInner<T: ?Sized> { refcount: Opaque<bindings::refcount_t>, @@ -501,9 +504,16 @@ impl<T> UniqueArc<T> { /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. pub fn try_new_uninit() -> Result<UniqueArc<MaybeUninit<T>>> { + // INVARIANT: The refcount is initialised to a non-zero value. + let inner = Box::init(init!(ArcInner<MaybeUninit<T>> { + // SAFETY: There are no safety requirements for this FFI call. + refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), + data <- init::uninit(), + }))?; Ok(UniqueArc::<MaybeUninit<T>> { // INVARIANT: The newly-created object has a ref-count of 1. - inner: Arc::try_new(MaybeUninit::uninit())?, + // SAFETY: The pointer from the `Box` is valid. + inner: unsafe { Arc::from_inner(Box::leak(inner).into()) }, }) } } -- 2.39.2
| |