From: Oliver Mangold <[email protected]> Types implementing one of these traits can safely convert between an `ARef<T>` and an `Owned<T>`.
This is useful for types which generally are accessed through an `ARef` but have methods which can only safely be called when the reference is unique, like e.g. `block::mq::Request::end_ok()`. Signed-off-by: Oliver Mangold <[email protected]> [ Andreas: Fix formatting, update documentation, fix error handling in examples. ] Assisted-by: LLM Co-developed-by: Andreas Hindborg <[email protected]> Signed-off-by: Andreas Hindborg <[email protected]> --- rust/kernel/owned.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++-- rust/kernel/sync/aref.rs | 16 +++++- rust/kernel/types.rs | 1 + 3 files changed, 158 insertions(+), 6 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index 3414e8df692b..ff3fa31ce1d1 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -14,20 +14,26 @@ pin::Pin, ptr::NonNull, // }; +use kernel::{ + sync::aref::ARef, + types::RefCounted, // +}; use kernel::types::ForeignOwnable; /// Types that specify their own way of performing allocation and destruction. Typically, this trait /// is implemented on types from the C side. /// -/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. This -/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather -/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is -/// executed when the owned reference [`Owned<Self>`] pointing to the object is dropped. +/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. +/// - This is useful when it is desirable to tie the lifetime of an object reference to an owned +/// object, rather than pass around a bare reference. +/// - [`Ownable`] types can define custom drop logic that is executed when the owned reference +/// of type [`Owned<_>`] pointing to the object is dropped. /// /// Note: The underlying object is not required to provide internal reference counting, because it /// represents a unique, owned reference. If reference counting (on the Rust side) is required, -/// [`RefCounted`](crate::types::RefCounted) should be implemented. +/// [`RefCounted`] should be implemented. [`OwnableRefCounted`] should be implemented if conversion +/// between unique and shared (reference counted) ownership is needed. /// /// # Examples /// @@ -99,6 +105,8 @@ pub trait Ownable { /// Callers must ensure that they have exclusive ownership of the `Self` pointed to by `this`, /// and that this ownership is transferred to the `release` method. `this` must not be used /// after calling this method, as the underlying object may have been freed. + /// + /// `this` is pinned and implementers of this method must observe this constraint. unsafe fn release(this: NonNull<Self>); } @@ -139,6 +147,8 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { /// /// This function does not drop the underlying `T`. When this function returns, ownership of the /// underlying `T` is with the caller. + /// + /// Note that the returned pointer is pinned. #[inline] pub fn into_raw(me: Self) -> NonNull<T> { ManuallyDrop::new(me).ptr @@ -239,3 +249,130 @@ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a> unsafe { Pin::new_unchecked(inner) } } } + +/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and +/// [`ARef`]. +/// +/// # Examples +/// +/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with +/// [`ARef`] and [`Owned`] looks like this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// # use core::ptr::NonNull; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::sync::aref::{ARef, RefCounted}; +/// # use kernel::sync::atomic::Acquire; +/// # use kernel::sync::Refcount; +/// # use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // An internally refcounted struct for demonstration purposes. +/// // +/// // # Invariants +/// // +/// // - `refcount` counts the live references to the object, so the object is valid while +/// // `refcount` is non-zero. +/// struct Foo { +/// refcount: Refcount, +/// } +/// +/// impl Foo { +/// fn new() -> Result<Owned<Self>> { +/// // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is +/// // not actually a C-allocated object. +/// // INVARIANT: We initialize `refcount` to 1, counting the reference held by the +/// // returned `Owned<Foo>`. +/// let result = KBox::new( +/// Foo { +/// refcount: Refcount::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result = KBox::into_non_null(result); +/// // SAFETY: +/// // - We just allocated the `Self`, thus it is valid and we own it. +/// // - We can transfer this ownership to the `from_raw` method. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement the refcount each time the respective function is +/// // called, and only free the `Foo` when the refcount reaches zero. +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.inc(); +/// } +/// +/// unsafe fn dec_ref(this: NonNull<Self>) { +/// // SAFETY: By requirement on calling this function, the refcount is non-zero, +/// // implying the underlying object is valid. +/// let refcount = unsafe { &this.as_ref().refcount }; +/// if refcount.dec_and_test() { +/// // SAFETY: The refcount reached zero, so by requirement on calling this function +/// // no reference to the object remains and it will no longer be used. We can +/// // reclaim the allocation by passing ownership back to the [`KBox`], which frees +/// // the `Foo` when dropped. +/// drop(unsafe { KBox::from_raw(this.as_ptr()) }); +/// } +/// } +/// } +/// +/// impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>> { +/// // `this` is a live reference, so the refcount cannot drop below 1, and it can only +/// // grow through an existing reference. Thus observing 1 means that `this` is the only +/// // reference to the object. The `Acquire` ordering synchronizes with the release +/// // decrements of references dropped on other threads. +/// if this.refcount.as_atomic().load(Acquire) == 1 { +/// // SAFETY: The `Foo` is valid and `this` holds the only reference to it, so we +/// // can transfer this last reference to the returned `Owned<Foo>`. +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// +/// fn into_shared(this: Owned<Self>) -> ARef<Self> { +/// // SAFETY: An `Owned<Foo>` holds the unique reference (refcount 1), which we transfer to +/// // the new `ARef`. +/// unsafe { ARef::from_raw(Owned::into_raw(this)) } +/// } +/// } +/// +/// impl Ownable for Foo { +/// unsafe fn release(this: NonNull<Self>) { +/// // SAFETY: Using `dec_ref()` from [`RefCounted`] to release is okay, as the refcount is +/// // always 1 for an [`Owned<Foo>`]. +/// unsafe { Foo::dec_ref(this) }; +/// } +/// } +/// +/// let foo = Foo::new()?; +/// let foo = ARef::from(foo); +/// { +/// let bar = foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// # Ok::<(), Error>(()) +/// ``` +pub trait OwnableRefCounted: RefCounted + Ownable + Sized { + /// Checks if the [`ARef`] is unique and converts it to an [`Owned`] if that is the case. + /// Otherwise it returns again an [`ARef`] to the same underlying object. + fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>>; + + /// Converts the [`Owned`] into an [`ARef`]. + fn into_shared(this: Owned<Self>) -> ARef<Self>; +} + +impl<T: OwnableRefCounted> TryFrom<ARef<T>> for Owned<T> { + type Error = ARef<T>; + /// Tries to convert the [`ARef`] to an [`Owned`] by calling + /// [`try_from_shared()`](OwnableRefCounted::try_from_shared). In case the [`ARef`] is not + /// unique, it returns again an [`ARef`] to the same underlying object. + #[inline] + fn try_from(b: ARef<T>) -> Result<Owned<T>, Self::Error> { + T::try_from_shared(b) + } +} diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index ae76bd9b6c1c..f12d091faafa 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -23,6 +23,10 @@ ops::Deref, ptr::NonNull, // }; +use kernel::types::{ + OwnableRefCounted, + Owned, // +}; use crate::{ prelude::*, @@ -40,7 +44,10 @@ /// Note: Implementing this trait allows types to be wrapped in an [`ARef<Self>`]. It requires an /// internal reference count and provides only shared references. If unique references are required /// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an -/// [`Owned<Self>`](crate::types::Owned). +/// [`Owned<Self>`](crate::types::Owned). Implementing the trait +/// [`OwnableRefCounted`] allows to convert between unique and +/// shared references (i.e. [`Owned<Self>`](crate::types::Owned) and +/// [`ARef<Self>`]). /// /// # Safety /// @@ -196,6 +203,13 @@ fn from(b: &T) -> Self { } } +impl<T: OwnableRefCounted> From<Owned<T>> for ARef<T> { + #[inline] + fn from(b: Owned<T>) -> Self { + T::into_shared(b) + } +} + impl<T: RefCounted> Drop for ARef<T> { fn drop(&mut self) { // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index f97b8ab6dad5..65593c5c5fab 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -21,6 +21,7 @@ pub use crate::{ owned::{ Ownable, + OwnableRefCounted, Owned, // }, sync::aref::{ -- 2.51.2
