summaryrefslogtreecommitdiff
path: root/rust/kernel/sync/arc.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-05-14 01:13:54 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2024-05-14 01:13:54 +0300
commit8f5b5f78113e881cb8570c961b0dc42b218a1b9e (patch)
tree23b6c6271d8299e0d30f5b032ef9257d4ead903c /rust/kernel/sync/arc.rs
parent84c7d76b5ab6a52e1b3d8101b9f910c128dca396 (diff)
parent97ab3e8eec0ce79d9e265e6c9e4c480492180409 (diff)
downloadlinux-8f5b5f78113e881cb8570c961b0dc42b218a1b9e.tar.xz
Merge tag 'rust-6.10' of https://github.com/Rust-for-Linux/linux
Pull Rust updates from Miguel Ojeda: "The most notable change is the drop of the 'alloc' in-tree fork. This is nicely reflected in the diffstat as a ~10k lines drop. In turn, this makes the version upgrades way simpler and smaller in the future, e.g. the latest one in commit 56f64b370612 ("rust: upgrade to Rust 1.78.0"). More importantly, this increases the chances that a newer compiler version just works, which in turn means supporting several compiler versions is easier now. Thus we will look into finally setting a minimum version in the near future. Toolchain and infrastructure: - Upgrade to Rust 1.78.0 This time around, due to how the kernel and Rust schedules have aligned, there are two upgrades in fact. These allow us to remove one more unstable feature ('offset_of') from the list, among other improvements - Drop 'alloc' in-tree fork of the standard library crate, which means all the unstable features used by 'alloc' (~30 language ones, ~60 library ones) are not a concern anymore - Support DWARFv5 via the '-Zdwarf-version' flag - Support zlib and zstd debuginfo compression via the '-Zdebuginfo-compression' flag 'kernel' crate: - Support allocation flags ('GFP_*'), particularly in 'Box' (via 'BoxExt'), 'Vec' (via 'VecExt'), 'Arc' and 'UniqueArc', as well as in the 'init' module APIs - Remove usage of the 'allocator_api' unstable feature - Remove 'try_' prefix in allocation APIs' names - Add 'VecExt' (an extension trait) to be able to drop the 'alloc' fork - Add the '{make,to}_{upper,lower}case()' methods to 'CStr'/'CString' - Add the 'as_ptr' method to 'ThisModule' - Add the 'from_raw' method to 'ArcBorrow' - Add the 'into_unique_or_drop' method to 'Arc' - Display column number in the 'dbg!' macro output by applying the equivalent change done to the standard library one - Migrate 'Work' to '#[pin_data]' thanks to the changes in the 'macros' crate, which allows to remove an unsafe call in its 'new' associated function - Prevent namespacing issues when using the '[try_][pin_]init!' macros by changing the generated name of guard variables - Make the 'get' method in 'Opaque' const - Implement the 'Default' trait for 'LockClassKey' - Remove unneeded 'kernel::prelude' imports from doctests - Remove redundant imports 'macros' crate: - Add 'decl_generics' to 'parse_generics()' to support default values, and use that to allow them in '#[pin_data]' Helpers: - Trivial English grammar fix Documentation: - Add section on Rust Kselftests to the 'Testing' document - Expand the 'Abstractions vs. bindings' section of the 'General Information' document" * tag 'rust-6.10' of https://github.com/Rust-for-Linux/linux: (31 commits) rust: alloc: fix dangling pointer in VecExt<T>::reserve() rust: upgrade to Rust 1.78.0 rust: kernel: remove redundant imports rust: sync: implement `Default` for `LockClassKey` docs: rust: extend abstraction and binding documentation docs: rust: Add instructions for the Rust kselftest rust: remove unneeded `kernel::prelude` imports from doctests rust: update `dbg!()` to format column number rust: helpers: Fix grammar in comment rust: init: change the generated name of guard variables rust: sync: add `Arc::into_unique_or_drop` rust: sync: add `ArcBorrow::from_raw` rust: types: Make Opaque::get const rust: kernel: remove usage of `allocator_api` unstable feature rust: init: update `init` module to take allocation flags rust: sync: update `Arc` and `UniqueArc` to take allocation flags rust: alloc: update `VecExt` to take allocation flags rust: alloc: introduce the `BoxExt` trait rust: alloc: introduce allocation flags rust: alloc: remove our fork of the `alloc` crate ...
Diffstat (limited to 'rust/kernel/sync/arc.rs')
-rw-r--r--rust/kernel/sync/arc.rs189
1 files changed, 147 insertions, 42 deletions
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 7d4c4bf58388..3673496c2363 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -16,7 +16,7 @@
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
use crate::{
- bindings,
+ alloc::{box_ext::BoxExt, AllocError, Flags},
error::{self, Error},
init::{self, InPlaceInit, Init, PinInit},
try_init,
@@ -24,7 +24,7 @@ use crate::{
};
use alloc::boxed::Box;
use core::{
- alloc::{AllocError, Layout},
+ alloc::Layout,
fmt,
marker::{PhantomData, Unsize},
mem::{ManuallyDrop, MaybeUninit},
@@ -57,7 +57,7 @@ mod std_vendor;
/// }
///
/// // Create a refcounted instance of `Example`.
-/// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
+/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;
///
/// // Get a new pointer to `obj` and increment the refcount.
/// let cloned = obj.clone();
@@ -96,7 +96,7 @@ mod std_vendor;
/// }
/// }
///
-/// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
+/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;
/// obj.use_reference();
/// obj.take_over();
/// # Ok::<(), Error>(())
@@ -119,7 +119,7 @@ mod std_vendor;
/// impl MyTrait for Example {}
///
/// // `obj` has type `Arc<Example>`.
-/// let obj: Arc<Example> = Arc::try_new(Example)?;
+/// let obj: Arc<Example> = Arc::new(Example, GFP_KERNEL)?;
///
/// // `coerced` has type `Arc<dyn MyTrait>`.
/// let coerced: Arc<dyn MyTrait> = obj;
@@ -137,6 +137,39 @@ struct ArcInner<T: ?Sized> {
data: T,
}
+impl<T: ?Sized> ArcInner<T> {
+ /// Converts a pointer to the contents of an [`Arc`] into a pointer to the [`ArcInner`].
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must have been returned by a previous call to [`Arc::into_raw`], and the `Arc` must
+ /// not yet have been destroyed.
+ unsafe fn container_of(ptr: *const T) -> NonNull<ArcInner<T>> {
+ let refcount_layout = Layout::new::<bindings::refcount_t>();
+ // SAFETY: The caller guarantees that the pointer is valid.
+ let val_layout = Layout::for_value(unsafe { &*ptr });
+ // SAFETY: We're computing the layout of a real struct that existed when compiling this
+ // binary, so its layout is not so large that it can trigger arithmetic overflow.
+ let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
+
+ // Pointer casts leave the metadata unchanged. This is okay because the metadata of `T` and
+ // `ArcInner<T>` is the same since `ArcInner` is a struct with `T` as its last field.
+ //
+ // This is documented at:
+ // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
+ let ptr = ptr as *const ArcInner<T>;
+
+ // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
+ // pointer, since it originates from a previous call to `Arc::into_raw` on an `Arc` that is
+ // still valid.
+ let ptr = unsafe { ptr.byte_sub(val_offset) };
+
+ // SAFETY: The pointer can't be null since you can't have an `ArcInner<T>` value at the null
+ // address.
+ unsafe { NonNull::new_unchecked(ptr.cast_mut()) }
+ }
+}
+
// This is to allow [`Arc`] (and variants) to be used as the type of `self`.
impl<T: ?Sized> core::ops::Receiver for Arc<T> {}
@@ -162,7 +195,7 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
impl<T> Arc<T> {
/// Constructs a new reference counted instance of `T`.
- pub fn try_new(contents: T) -> Result<Self, AllocError> {
+ pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
// INVARIANT: The refcount is initialised to a non-zero value.
let value = ArcInner {
// SAFETY: There are no safety requirements for this FFI call.
@@ -170,7 +203,7 @@ impl<T> Arc<T> {
data: contents,
};
- let inner = Box::try_new(value)?;
+ let inner = <Box<_> as BoxExt<_>>::new(value, flags)?;
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
// `Arc` object.
@@ -181,22 +214,22 @@ impl<T> Arc<T> {
///
/// If `T: !Unpin` it will not be able to move afterwards.
#[inline]
- pub fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Self>
+ pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self>
where
Error: From<E>,
{
- UniqueArc::pin_init(init).map(|u| u.into())
+ UniqueArc::pin_init(init, flags).map(|u| u.into())
}
/// Use the given initializer to in-place initialize a `T`.
///
/// This is equivalent to [`Arc<T>::pin_init`], since an [`Arc`] is always pinned.
#[inline]
- pub fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
+ pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
where
Error: From<E>,
{
- UniqueArc::init(init).map(|u| u.into())
+ UniqueArc::init(init, flags).map(|u| u.into())
}
}
@@ -232,27 +265,13 @@ impl<T: ?Sized> Arc<T> {
/// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
/// must not be called more than once for each previous call to [`Arc::into_raw`].
pub unsafe fn from_raw(ptr: *const T) -> Self {
- let refcount_layout = Layout::new::<bindings::refcount_t>();
- // SAFETY: The caller guarantees that the pointer is valid.
- let val_layout = Layout::for_value(unsafe { &*ptr });
- // SAFETY: We're computing the layout of a real struct that existed when compiling this
- // binary, so its layout is not so large that it can trigger arithmetic overflow.
- let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
-
- // Pointer casts leave the metadata unchanged. This is okay because the metadata of `T` and
- // `ArcInner<T>` is the same since `ArcInner` is a struct with `T` as its last field.
- //
- // This is documented at:
- // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
- let ptr = ptr as *const ArcInner<T>;
-
- // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
- // pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
- let ptr = unsafe { ptr.byte_sub(val_offset) };
+ // SAFETY: The caller promises that this pointer originates from a call to `into_raw` on an
+ // `Arc` that is still valid.
+ let ptr = unsafe { ArcInner::container_of(ptr) };
// SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
// reference count held then will be owned by the new `Arc` object.
- unsafe { Self::from_inner(NonNull::new_unchecked(ptr.cast_mut())) }
+ unsafe { Self::from_inner(ptr) }
}
/// Returns an [`ArcBorrow`] from the given [`Arc`].
@@ -271,6 +290,68 @@ impl<T: ?Sized> Arc<T> {
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
core::ptr::eq(this.ptr.as_ptr(), other.ptr.as_ptr())
}
+
+ /// Converts this [`Arc`] into a [`UniqueArc`], or destroys it if it is not unique.
+ ///
+ /// When this destroys the `Arc`, it does so while properly avoiding races. This means that
+ /// this method will never call the destructor of the value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::sync::{Arc, UniqueArc};
+ ///
+ /// let arc = Arc::new(42, GFP_KERNEL)?;
+ /// let unique_arc = arc.into_unique_or_drop();
+ ///
+ /// // The above conversion should succeed since refcount of `arc` is 1.
+ /// assert!(unique_arc.is_some());
+ ///
+ /// assert_eq!(*(unique_arc.unwrap()), 42);
+ ///
+ /// # Ok::<(), Error>(())
+ /// ```
+ ///
+ /// ```
+ /// use kernel::sync::{Arc, UniqueArc};
+ ///
+ /// let arc = Arc::new(42, GFP_KERNEL)?;
+ /// let another = arc.clone();
+ ///
+ /// let unique_arc = arc.into_unique_or_drop();
+ ///
+ /// // The above conversion should fail since refcount of `arc` is >1.
+ /// assert!(unique_arc.is_none());
+ ///
+ /// # Ok::<(), Error>(())
+ /// ```
+ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
+ // We will manually manage the refcount in this method, so we disable the destructor.
+ let me = ManuallyDrop::new(self);
+ // SAFETY: We own a refcount, so the pointer is still valid.
+ let refcount = unsafe { me.ptr.as_ref() }.refcount.get();
+
+ // If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
+ // return without further touching the `Arc`. If the refcount reaches zero, then there are
+ // no other arcs, and we can create a `UniqueArc`.
+ //
+ // SAFETY: We own a refcount, so the pointer is not dangling.
+ let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
+ if is_zero {
+ // SAFETY: We have exclusive access to the arc, so we can perform unsynchronized
+ // accesses to the refcount.
+ unsafe { core::ptr::write(refcount, bindings::REFCOUNT_INIT(1)) };
+
+ // INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We
+ // must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
+ // their values.
+ Some(Pin::from(UniqueArc {
+ inner: ManuallyDrop::into_inner(me),
+ }))
+ } else {
+ None
+ }
+ }
}
impl<T: 'static> ForeignOwnable for Arc<T> {
@@ -387,7 +468,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// e.into()
/// }
///
-/// let obj = Arc::try_new(Example)?;
+/// let obj = Arc::new(Example, GFP_KERNEL)?;
/// let cloned = do_something(obj.as_arc_borrow());
///
/// // Assert that both `obj` and `cloned` point to the same underlying object.
@@ -411,7 +492,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// }
/// }
///
-/// let obj = Arc::try_new(Example { a: 10, b: 20 })?;
+/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;
/// obj.as_arc_borrow().use_reference();
/// # Ok::<(), Error>(())
/// ```
@@ -453,6 +534,27 @@ impl<T: ?Sized> ArcBorrow<'_, T> {
_p: PhantomData,
}
}
+
+ /// Creates an [`ArcBorrow`] to an [`Arc`] that has previously been deconstructed with
+ /// [`Arc::into_raw`].
+ ///
+ /// # Safety
+ ///
+ /// * The provided pointer must originate from a call to [`Arc::into_raw`].
+ /// * For the duration of the lifetime annotated on this `ArcBorrow`, the reference count must
+ /// not hit zero.
+ /// * For the duration of the lifetime annotated on this `ArcBorrow`, there must not be a
+ /// [`UniqueArc`] reference to this value.
+ pub unsafe fn from_raw(ptr: *const T) -> Self {
+ // SAFETY: The caller promises that this pointer originates from a call to `into_raw` on an
+ // `Arc` that is still valid.
+ let ptr = unsafe { ArcInner::container_of(ptr) };
+
+ // SAFETY: The caller promises that the value remains valid since the reference count must
+ // not hit zero, and no mutable reference will be created since that would involve a
+ // `UniqueArc`.
+ unsafe { Self::new(ptr) }
+ }
}
impl<T: ?Sized> From<ArcBorrow<'_, T>> for Arc<T> {
@@ -499,7 +601,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {
/// }
///
/// fn test() -> Result<Arc<Example>> {
-/// let mut x = UniqueArc::try_new(Example { a: 10, b: 20 })?;
+/// let mut x = UniqueArc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;
/// x.a += 1;
/// x.b += 1;
/// Ok(x.into())
@@ -522,7 +624,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {
/// }
///
/// fn test() -> Result<Arc<Example>> {
-/// let x = UniqueArc::try_new_uninit()?;
+/// let x = UniqueArc::new_uninit(GFP_KERNEL)?;
/// Ok(x.write(Example { a: 10, b: 20 }).into())
/// }
///
@@ -542,7 +644,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {
/// }
///
/// fn test() -> Result<Arc<Example>> {
-/// let mut pinned = Pin::from(UniqueArc::try_new(Example { a: 10, b: 20 })?);
+/// let mut pinned = Pin::from(UniqueArc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?);
/// // We can modify `pinned` because it is `Unpin`.
/// pinned.as_mut().a += 1;
/// Ok(pinned.into())
@@ -556,21 +658,24 @@ pub struct UniqueArc<T: ?Sized> {
impl<T> UniqueArc<T> {
/// Tries to allocate a new [`UniqueArc`] instance.
- pub fn try_new(value: T) -> Result<Self, AllocError> {
+ pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {
Ok(Self {
// INVARIANT: The newly-created object has a refcount of 1.
- inner: Arc::try_new(value)?,
+ inner: Arc::new(value, flags)?,
})
}
/// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
- pub fn try_new_uninit() -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {
+ pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {
// INVARIANT: The refcount is initialised to a non-zero value.
- let inner = Box::try_init::<AllocError>(try_init!(ArcInner {
- // SAFETY: There are no safety requirements for this FFI call.
- refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
- data <- init::uninit::<T, AllocError>(),
- }? AllocError))?;
+ let inner = Box::try_init::<AllocError>(
+ try_init!(ArcInner {
+ // SAFETY: There are no safety requirements for this FFI call.
+ refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
+ data <- init::uninit::<T, AllocError>(),
+ }? AllocError),
+ flags,
+ )?;
Ok(UniqueArc {
// INVARIANT: The newly-created object has a refcount of 1.
// SAFETY: The pointer from the `Box` is valid.