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]> Reviewed-by: Andreas Hindborg <[email protected]> --- rust/kernel/owned.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++++- rust/kernel/sync/aref.rs | 11 ++++- rust/kernel/types.rs | 2 +- 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index 466b7ecda6d9f4f54852ca0b59b36ac882ab3f47..ad38a4d378fa8fcf934f1c41cd902d79a2c8baa5 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -3,6 +3,7 @@ //! Unique reference types for objects with custom destructors. They should be used for C-allocated //! objects which by API-contract are owned by Rust, but need to be freed through the C API. +use crate::sync::aref::{ARef, RefCounted}; use core::{ marker::PhantomData, mem::ManuallyDrop, @@ -19,7 +20,8 @@ /// /// 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. /// /// # Safety /// @@ -193,3 +195,124 @@ fn drop(&mut self) { unsafe { T::release(self.ptr) }; } } + +/// 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::cell::Cell; +/// use core::ptr::NonNull; +/// use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// use kernel::sync::aref::{ARef, RefCounted}; +/// use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // Example internally refcounted struct. +/// // +/// // # Invariants +/// // +/// // - `refcount` is always non-zero for a valid object. +/// // - `refcount` is >1 if there are more then 1 Rust references to it. +/// // +/// struct Foo { +/// refcount: Cell<usize>, +/// } +/// +/// impl Foo { +/// fn new() -> Result<Owned<Self>, AllocError> { +/// // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is +/// // not actually a C-allocated object. +/// let result = KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result = NonNull::new(KBox::into_raw(result)) +/// .expect("Raw pointer to newly allocation KBox is null, this should never happen."); +/// // SAFETY: We just allocated the `Self`, thus it is valid and there cannot be any other +/// // Rust references. Calling `into_raw()` makes us responsible for ownership and +/// // we won't use the raw pointer anymore, thus we can transfer ownership to the `Owned`. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement 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.replace(self.refcount.get() + 1); +/// } +/// +/// 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 }; +/// let new_refcount = refcount.get() - 1; +/// if new_refcount == 0 { +/// // The `Foo` will be dropped when `KBox` goes out of scope. +/// // SAFETY: The [`KBox<Foo>`] is still alive as the old refcount is 1. We can pass +/// // ownership to the [`KBox`] as by requirement on calling this function, +/// // the `Self` will no longer be used by the caller. +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// } +/// +/// impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>> { +/// if this.refcount.get() == 1 { +/// // SAFETY: The `Foo` is still alive and has no other Rust references as the refcount +/// // is 1. +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// } +/// +/// // SAFETY: What out `release()` function does is safe of any valid `Self`. +/// unsafe 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().expect("Failed to allocate a Foo. This shouldn't happen"); +/// let mut foo = ARef::from(foo); +/// { +/// let bar = foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// ``` +pub trait OwnableRefCounted: RefCounted + Ownable + Sized { + /// Checks if the [`ARef`] is unique and convert it to an [`Owned`] it that is that 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> { + // SAFETY: Safe by the requirements on implementing the trait. + unsafe { ARef::from_raw(Owned::into_raw(this)) } + } +} + +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. + 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 97cfddd9ec2ad788a4a659f404a9b6790da08e29..605c56b3d634e048cdfe1524881ab1e2e76ae3a4 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -15,7 +15,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`](crate::types::OwnableRefCounted) allows to convert between unique and +/// shared references (i.e. [`Owned<Self>`](crate::types::Owned) and +/// [`ARef<Self>`](crate::types::Owned)). /// /// # Safety /// @@ -165,6 +168,12 @@ fn from(b: &T) -> Self { } } +impl<T: crate::types::OwnableRefCounted> From<crate::types::Owned<T>> for ARef<T> { + fn from(b: crate::types::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 8ef01393352bb2510524bf070ad4141147ed945f..a9b72709d0d3c7fc58444a19fae896aed7506128 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,7 +11,7 @@ }; use pin_init::{PinInit, Wrapper, Zeroable}; -pub use crate::owned::{Ownable, Owned}; +pub use crate::owned::{Ownable, OwnableRefCounted, Owned}; pub use crate::sync::aref::{ARef, AlwaysRefCounted, RefCounted}; -- 2.51.0
