From nobody Thu Oct 9 09:03:17 2025 Received: from mail-24418.protonmail.ch (mail-24418.protonmail.ch [109.224.244.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51D872E3B12; Wed, 18 Jun 2025 12:27:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249676; cv=none; b=Jpoar0eiw/ZwJjQNxHShIOfuAwgctALuJK9ymbYrNxyK8RpT5Ok0L6UYhaMc358SiXbx4BJ5CJ4qbAEtZgWEVfSzv4SujFYhlfbnMbsCzgLdtpiWvm372daFgv+c9b5Rh/GE7KVKogfY3Et3puvBdC+5RJTm0qCwLsQXw9VqSqA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249676; c=relaxed/simple; bh=ARp0XvdRHptwJHdPyZbXBPQF+FSBwcUm72r29Of/fko=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JP0mOwo/4sa83ws86hqTgPZfjptyhNWCGijVKnheTrZoNRej9boKr6+hyR7KEfiQ9IzhklRbkmq9v/2sz7KuYy+oXYpzHOFYhuY27nNqPwlDfv7TRpWuvxIBOMV2EOyKiRDioNbdx0EHNkbSL7y/0nwQ7KqYEw3ByqmW5C8qzDY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=DtHrg2Ep; arc=none smtp.client-ip=109.224.244.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="DtHrg2Ep" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1750249666; x=1750508866; bh=4li1tGRJOI/fthB7Y4tx8/VU2ULNmgwbETEpIi0vvPA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=DtHrg2EpbFQ1zeNbeSDn+e85T1iKxv/HfXj98R+Ms0qcyj+Z0653idj6yHGMumoBp SQHlvJdyVBWgqmTONco+JE81bnLUjrpHEJTt3P47ISnRgW2h0qihq1hXit3lGqFBlG daHh52j9SU6UAa5m9GC1ugdAIvlTCmJ4ePjd16B6yPbBvFAShcOqx3pudD6lJIU2GA 1QCwpY9My+zc/jYqhWhy7ngDG+8LrzhjQ3SGfkabm+mzc+J+mqTQhBiTRTVeOBCN9z SR1GbTfLT+mg4L+fWBKC1NajTjaeMIixOkmh8uceuPgad39sTqKlI9Xm83Aavw5SIi 9bApR2cYCEi9g== Date: Wed, 18 Jun 2025 12:27:41 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Andreas Hindborg , Alice Ryhl , Trevor Gross , Benno Lossin , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v11 1/4] rust: types: Add Ownable/Owned types Message-ID: <20250618-unique-ref-v11-1-49eadcdc0aa6@pm.me> In-Reply-To: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> References: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 997fc21581854683f6f182f42e7856e03e6f537f Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Asahi Lina By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a (typically C FFI) type that *may* be owned by Rust, but need not be. Unlike `AlwaysRefCounted`, this mechanism expects the reference to be unique within Rust, and does not allow cloning. Conceptually, this is similar to a `KBox`, except that it delegates resource management to the `T` instead of using a generic allocator. Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asah= ilina.net/ Signed-off-by: Asahi Lina [ om: - split code into separate file and `pub use` it from types.rs - make from_raw() and into_raw() public - fixes to documentation and commit message ] Signed-off-by: Oliver Mangold Reviewed-by: Boqun Feng --- rust/kernel/types.rs | 7 +++ rust/kernel/types/ownable.rs | 134 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 141 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 22985b6f69820d6df8ff3aae0bf815fad36a9d92..c12ff4d2a3f2d79b760c34c0b84= a51b507d0cfb1 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,6 +11,9 @@ }; use pin_init::{PinInit, Zeroable}; =20 +pub mod ownable; +pub use ownable::{Ownable, OwnableMut, Owned}; + /// Used to transfer ownership to and from foreign (non-Rust) languages. /// /// Ownership is transferred from Rust to a foreign language by calling [`= Self::into_foreign`] and @@ -425,6 +428,10 @@ pub const fn raw_get(this: *const Self) -> *mut T { /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to c= reate reference-counted /// instances of a type. /// +/// 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 uniqu= e references are required +/// [`Ownable`] should be implemented which allows types to be wrapped in = an [`Owned`]. +/// /// # Safety /// /// Implementers must ensure that increments to the reference count keep t= he object alive in memory diff --git a/rust/kernel/types/ownable.rs b/rust/kernel/types/ownable.rs new file mode 100644 index 0000000000000000000000000000000000000000..f4065a0d627a62d3ecb15edabf3= 06e9b812556e1 --- /dev/null +++ b/rust/kernel/types/ownable.rs @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Owned reference types. + +use core::{ + marker::PhantomData, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr::NonNull, +}; + +/// Types that may be owned by Rust code or borrowed, but have a lifetime = managed by C code. +/// +/// It allows such types to define their own custom destructor function to= be called when a +/// Rust-owned reference is dropped. +/// +/// This is usually implemented by wrappers to existing structures on the = C side of the code. +/// +/// Note: Implementing this trait allows types to be wrapped in an [`Owned= `]. This does not +/// provide reference counting but represents a unique, owned reference. I= f reference counting is +/// required [`AlwaysRefCounted`](crate::types::AlwaysRefCounted) should b= e implemented which allows +/// types to be wrapped in an [`ARef`](crate::types::ARef). +/// +/// # Safety +/// +/// Implementers must ensure that: +/// - The [`release()`](Ownable::release) method leaves the underlying obj= ect in a state which the +/// kernel expects after ownership has been relinquished (i.e. no dangli= ng references in the +/// kernel is case it frees the object, etc.). +pub unsafe trait Ownable { + /// Releases the object (frees it or returns it to foreign ownership). + /// + /// # Safety + /// + /// Callers must ensure that: + /// - `this` points to a valid `Self`. + /// - The object is no longer referenced after this call. + unsafe fn release(this: NonNull); +} + +/// Type where [`Owned`] derefs to `&mut Self`. +/// +/// # Safety +/// +/// Implementers must ensure that access to a `&mut T` is safe, implying t= hat: +/// - It is safe to call [`core::mem::swap`] on the [`Ownable`]. This excl= udes pinned types +/// (i.e. most kernel types). +/// - The kernel will never access the underlying object (excluding intern= al mutability that follows +/// the usual rules) while Rust owns it. +pub unsafe trait OwnableMut: Ownable {} + +/// An owned reference to an ownable kernel object. +/// +/// The object is automatically freed or released when an instance of [`Ow= ned`] is +/// dropped. +/// +/// # Invariants +/// +/// The pointer stored in `ptr` can be considered owned by the [`Owned`] i= nstance. +pub struct Owned { + ptr: NonNull, + _p: PhantomData, +} + +// SAFETY: It is safe to send `Owned` to another thread when the underl= ying `T` is `Send` because +// it effectively means sending a `&mut T` (which is safe because `T` is `= Send`). +unsafe impl Send for Owned {} + +// SAFETY: It is safe to send `&Owned` to another thread when the under= lying `T` is `Sync` +// because it effectively means sharing `&T` (which is safe because `T` is= `Sync`). +unsafe impl Sync for Owned {} + +impl Owned { + /// Creates a new instance of [`Owned`]. + /// + /// It takes over ownership of the underlying object. + /// + /// # Safety + /// + /// Callers must ensure that: + /// - Ownership of the underlying object can be transferred to the `Ow= ned` (i.e. operations + /// which require ownership will be safe). + /// - No other Rust references to the underlying object exist. This im= plies that the underlying + /// object is not accessed through `ptr` anymore after the function = call (at least until the + /// the `Owned` is dropped). + /// - The C code follows the usual shared reference requirements. That= is, the kernel will never + /// mutate or free the underlying object (excluding interior mutabil= ity that follows the usual + /// rules) while Rust owns it. + /// - In case `T` implements [`OwnableMut`] the previous requirement i= s extended from shared to + /// mutable reference requirements. That is, the kernel will not mut= ate or free the underlying + /// object and is okay with it being modified by Rust code. + pub unsafe fn from_raw(ptr: NonNull) -> Self { + // INVARIANT: The safety requirements guarantee that the new insta= nce now owns the + // reference. + Self { + ptr, + _p: PhantomData, + } + } + + /// Consumes the [`Owned`], returning a raw pointer. + /// + /// This function does not actually relinquish ownership of the object= . After calling this + /// function, the caller is responsible for ownership previously manag= ed + /// by the [`Owned`]. + pub fn into_raw(me: Self) -> NonNull { + ManuallyDrop::new(me).ptr + } +} + +impl Deref for Owned { + type Target =3D T; + + fn deref(&self) -> &Self::Target { + // SAFETY: The type invariants guarantee that the object is valid. + unsafe { self.ptr.as_ref() } + } +} + +impl DerefMut for Owned { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: The type invariants guarantee that the object is valid,= and that we can safely + // return a mutable reference to it. + unsafe { self.ptr.as_mut() } + } +} + +impl Drop for Owned { + fn drop(&mut self) { + // SAFETY: The type invariants guarantee that the `Owned` owns the= object we're about to + // release. + unsafe { T::release(self.ptr) }; + } +} --=20 2.49.0 From nobody Thu Oct 9 09:03:17 2025 Received: from mail-24416.protonmail.ch (mail-24416.protonmail.ch [109.224.244.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA6BB2E9EB2 for ; Wed, 18 Jun 2025 12:28:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249688; cv=none; b=Z6Ku+InxVtNrGjsKmhSpOQhRV5B1CuAY5qoBXNDkggzTrF3AgX/9QMExsuFf2Ud5Nkw8ETZIn5+sRnyzgAPXpHECCTnrOeVJU/Yrvb0eK5kF1poA63rWUB10H2JtlmaGp2aaKklhk3ETFa9kAomvu4JL/NCXXhBk5+sFe+fSNMU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249688; c=relaxed/simple; bh=2sjwDLSUu7h2N+nQlYr1aK7WiYYZjJPKidJAeD19mbY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=L9horFDbinrnttgF5qWLlnfxeAOf1skFdqE9mN9cU54h8oGE/g31YI5BI8XM6BRLnOns5GF7/kOiqxEQRcYF6H2QPKF//CEbmtbNeVYwV6o05JFj9mFY1QurrTtbIZbvpxjaF9lPV6w2b9BJcyn/XWKObPTN8z6FMq8EzWSntBM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=lAhtYeMZ; arc=none smtp.client-ip=109.224.244.16 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="lAhtYeMZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1750249676; x=1750508876; bh=q8SXXCIyESUsGQ1fZD0Fag44Ey9ZIXSqgkr3XBssptE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=lAhtYeMZcGXAx2TTUsxJ+b8aPzbj6MEyYLq6/qAvLfMb1XyyZrmJREmlui/TvKKi8 G2zTTv/SZryabbARtavx13gPWuZS19XqL9tIRqz4hZu39gWa4xIFFbAsaCHOToMEVP YYdk+oy03pxHFhWXKrhxTYgu7o9UmjW4dXSDEsxgsHB9toZRLttg5ZwVVhd6JpXP56 7APWwRFRhRtmaq+GYNmj3E2Ae6/0Ghw3/ecG+ehiJGSu2C0w2CgAToPOuxR9vu7h5R x7pgUfPeSaOD+hQZ6/ROQ6fjOBNbx+Hdn1HyxdbFov3BrVKSNqbIpadfZZQAvrNeIL do0IXXedQnmXg== Date: Wed, 18 Jun 2025 12:27:49 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Andreas Hindborg , Alice Ryhl , Trevor Gross , Benno Lossin , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v11 2/4] rust: Split `AlwaysRefCounted` into two traits Message-ID: <20250618-unique-ref-v11-2-49eadcdc0aa6@pm.me> In-Reply-To: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> References: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 7866f2c0ed84be6cdd92bf381455f88025b7e7be Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" `AlwaysRefCounted` is renamed to `RefCounted`. `AlwaysRefCounted` will become a marker trait to indicate that it is allowed to obtain an `ARef` from a `&T`, which cannot be allowed for types which are also Ownable. Signed-off-by: Oliver Mangold Suggested-by: Alice Ryhl --- rust/kernel/block/mq/request.rs | 15 +++++++++------ rust/kernel/cred.rs | 8 ++++++-- rust/kernel/device.rs | 8 ++++++-- rust/kernel/fs/file.rs | 10 +++++++--- rust/kernel/mm.rs | 13 ++++++++++--- rust/kernel/mm/mmput_async.rs | 9 +++++++-- rust/kernel/opp.rs | 8 ++++++-- rust/kernel/pci.rs | 6 +++++- rust/kernel/pid_namespace.rs | 8 ++++++-- rust/kernel/platform.rs | 6 +++++- rust/kernel/task.rs | 6 +++++- rust/kernel/types.rs | 41 ++++++++++++++++++++++++-------------= ---- rust/kernel/types/ownable.rs | 4 ++-- 13 files changed, 98 insertions(+), 44 deletions(-) diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request= .rs index 4a5b7ec914efa598c65881b07c4ece59214fd7e7..ca02d07f13ade252bc3b4d2ca3e= 5e21a16a7288e 100644 --- a/rust/kernel/block/mq/request.rs +++ b/rust/kernel/block/mq/request.rs @@ -8,7 +8,7 @@ bindings, block::mq::Operations, error::Result, - types::{ARef, AlwaysRefCounted, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque, RefCounted}, }; use core::{ marker::PhantomData, @@ -226,11 +226,10 @@ fn atomic_relaxed_op_unless(target: &AtomicU64, op: i= mpl Fn(u64) -> u64, pred: u .is_ok() } =20 -// SAFETY: All instances of `Request` are reference counted. This -// implementation of `AlwaysRefCounted` ensure that increments to the ref = count -// keeps the object alive in memory at least until a matching reference co= unt -// decrement is executed. -unsafe impl AlwaysRefCounted for Request { +// SAFETY: All instances of `Request` are reference counted. This imple= mentation of `RefCounted` +// ensure that increments to the ref count keeps the object alive in memor= y at least until a +// matching reference count decrement is executed. +unsafe impl RefCounted for Request { fn inc_ref(&self) { let refcount =3D &self.wrapper_ref().refcount(); =20 @@ -260,3 +259,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { } } } + +// SAFETY: We currently do not implement `Ownable`, thus it is okay to can= obtain an `ARef` +// from a `&Request` (but this will change in the future). +unsafe impl AlwaysRefCounted for Request {} diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index 2599f01e8b285f2106aefd27c315ae2aff25293c..87fa2808050dd8a2838a0f5c21c= d7f567ba6b534 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -11,7 +11,7 @@ use crate::{ bindings, task::Kuid, - types::{AlwaysRefCounted, Opaque}, + types::{AlwaysRefCounted, Opaque, RefCounted}, }; =20 /// Wraps the kernel's `struct cred`. @@ -74,7 +74,7 @@ pub fn euid(&self) -> Kuid { } =20 // SAFETY: The type invariants guarantee that `Credential` is always ref-c= ounted. -unsafe impl AlwaysRefCounted for Credential { +unsafe impl RefCounted for Credential { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -88,3 +88,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { unsafe { bindings::put_cred(obj.cast().as_ptr()) }; } } + +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&Credential`. +unsafe impl AlwaysRefCounted for Credential {} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index dea06b79ecb536cee4d2b90c21b74658658417c7..afddb4d70d2f375c891facac7f8= 3501cd9918f54 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -7,7 +7,7 @@ use crate::{ bindings, str::CStr, - types::{ARef, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque, RefCounted}, }; use core::{fmt, marker::PhantomData, ptr}; =20 @@ -216,7 +216,7 @@ pub fn property_present(&self, name: &CStr) -> bool { kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl RefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::get_device(self.as_raw()) }; @@ -228,6 +228,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `Device` from a +// `&Device`. +unsafe impl AlwaysRefCounted for Device {} + // SAFETY: As by the type invariant `Device` can be sent to any thread. unsafe impl Send for Device {} =20 diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 72d84fb0e2664643619ad7fbcbbb55b3adc9f9b4..489f6d1f17508af7e064e3f5063= 49797fff497ae 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -11,7 +11,7 @@ bindings, cred::Credential, error::{code::*, Error, Result}, - types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, + types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque, RefCounted}, }; use core::ptr; =20 @@ -190,7 +190,7 @@ unsafe impl Sync for File {} =20 // SAFETY: The type invariants guarantee that `File` is always ref-counted= . This implementation // makes `ARef` own a normal refcount. -unsafe impl AlwaysRefCounted for File { +unsafe impl RefCounted for File { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -205,6 +205,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&File`. +unsafe impl AlwaysRefCounted for File {} + /// Wraps the kernel's `struct file`. Not thread safe. /// /// This type represents a file that is not known to be safe to transfer a= cross thread boundaries. @@ -226,7 +230,7 @@ pub struct LocalFile { =20 // SAFETY: The type invariants guarantee that `LocalFile` is always ref-co= unted. This implementation // makes `ARef` own a normal refcount. -unsafe impl AlwaysRefCounted for LocalFile { +unsafe impl RefCounted for LocalFile { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs index 43f525c0d16ce87340ba4f991c45d4e82a050eae..9bbb317896eaa06f0e654873993= ae9ff531d4c61 100644 --- a/rust/kernel/mm.rs +++ b/rust/kernel/mm.rs @@ -13,7 +13,7 @@ =20 use crate::{ bindings, - types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, + types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque, RefCounted}, }; use core::{ops::Deref, ptr::NonNull}; =20 @@ -54,7 +54,7 @@ unsafe impl Send for Mm {} unsafe impl Sync for Mm {} =20 // SAFETY: By the type invariants, this type is always refcounted. -unsafe impl AlwaysRefCounted for Mm { +unsafe impl RefCounted for Mm { #[inline] fn inc_ref(&self) { // SAFETY: The pointer is valid since self is a reference. @@ -68,6 +68,9 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a `&Mm`. +unsafe impl AlwaysRefCounted for Mm {} + /// A wrapper for the kernel's `struct mm_struct`. /// /// This type is like [`Mm`], but with non-zero `mm_users`. It can only be= used when `mm_users` can @@ -90,7 +93,7 @@ unsafe impl Send for MmWithUser {} unsafe impl Sync for MmWithUser {} =20 // SAFETY: By the type invariants, this type is always refcounted. -unsafe impl AlwaysRefCounted for MmWithUser { +unsafe impl RefCounted for MmWithUser { #[inline] fn inc_ref(&self) { // SAFETY: The pointer is valid since self is a reference. @@ -104,6 +107,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&MmWithUser`. +unsafe impl AlwaysRefCounted for MmWithUser {} + // Make all `Mm` methods available on `MmWithUser`. impl Deref for MmWithUser { type Target =3D Mm; diff --git a/rust/kernel/mm/mmput_async.rs b/rust/kernel/mm/mmput_async.rs index 9289e05f7a676b577e4edf45949c0fab6aacec14..1b8c5cc32123ed406079aa1505e= 623ea6af81011 100644 --- a/rust/kernel/mm/mmput_async.rs +++ b/rust/kernel/mm/mmput_async.rs @@ -10,7 +10,7 @@ use crate::{ bindings, mm::MmWithUser, - types::{ARef, AlwaysRefCounted}, + types::{ARef, AlwaysRefCounted, RefCounted}, }; use core::{ops::Deref, ptr::NonNull}; =20 @@ -34,7 +34,7 @@ unsafe impl Send for MmWithUserAsync {} unsafe impl Sync for MmWithUserAsync {} =20 // SAFETY: By the type invariants, this type is always refcounted. -unsafe impl AlwaysRefCounted for MmWithUserAsync { +unsafe impl RefCounted for MmWithUserAsync { #[inline] fn inc_ref(&self) { // SAFETY: The pointer is valid since self is a reference. @@ -48,6 +48,11 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 + +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` +// from a `&MmWithUserAsync`. +unsafe impl AlwaysRefCounted for MmWithUserAsync {} + // Make all `MmWithUser` methods available on `MmWithUserAsync`. impl Deref for MmWithUserAsync { type Target =3D MmWithUser; diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index a566fc3e7dcb87237c68eb7d174efa5658712ddb..b8a3dace7a616cd8944e3f64729= 3cc4ca79235bd 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,7 +16,7 @@ ffi::c_ulong, prelude::*, str::CString, - types::{ARef, AlwaysRefCounted, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque, RefCounted}, }; =20 #[cfg(CONFIG_CPU_FREQ)] @@ -1042,7 +1042,7 @@ unsafe impl Send for OPP {} unsafe impl Sync for OPP {} =20 /// SAFETY: The type invariants guarantee that [`OPP`] is always refcounte= d. -unsafe impl AlwaysRefCounted for OPP { +unsafe impl RefCounted for OPP { fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. unsafe { bindings::dev_pm_opp_get(self.0.get()) }; @@ -1054,6 +1054,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from an +// `&OPP`. +unsafe impl AlwaysRefCounted for OPP {} + impl OPP { /// Creates an owned reference to a [`OPP`] from a valid pointer. /// diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 8435f8132e38129ccc3495e7c4d3237fcaa97ad9..e56f48bfe1e60096208bc499630= 46fbdd070afee 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -435,7 +435,7 @@ pub fn set_master(&self) { kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::types::RefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::pci_dev_get(self.as_raw()) }; @@ -447,6 +447,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&Device`. +unsafe impl crate::types::AlwaysRefCounted for Device {} + impl AsRef> for Device { fn as_ref(&self) -> &device::Device { // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs index 0e93808e4639b37dd77add5d79f64058dac7cb87..b5e319fa050002179fa920dd40f= 02a08f8473b22 100644 --- a/rust/kernel/pid_namespace.rs +++ b/rust/kernel/pid_namespace.rs @@ -9,7 +9,7 @@ =20 use crate::{ bindings, - types::{AlwaysRefCounted, Opaque}, + types::{AlwaysRefCounted, Opaque, RefCounted}, }; use core::ptr; =20 @@ -44,7 +44,7 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::pid_name= space) -> &'a Self { } =20 // SAFETY: Instances of `PidNamespace` are always reference-counted. -unsafe impl AlwaysRefCounted for PidNamespace { +unsafe impl RefCounted for PidNamespace { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -58,6 +58,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from +// a `&PidNamespace`. +unsafe impl AlwaysRefCounted for PidNamespace {} + // SAFETY: // - `PidNamespace::dec_ref` can be called from any thread. // - It is okay to send ownership of `PidNamespace` across thread boundari= es. diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5b21fa517e55348582622ec10471918919502959..c37ba50e5dcc53891e08706343f= cd446d640cda1 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -196,7 +196,7 @@ fn as_raw(&self) -> *mut bindings::platform_device { kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::types::RefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::get_device(self.as_ref().as_raw()) }; @@ -208,6 +208,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&Device`. +unsafe impl crate::types::AlwaysRefCounted for Device {} + impl AsRef> for Device { fn as_ref(&self) -> &device::Device { // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 927413d854846477578cbaf06e27d1fc867d0682..6c16f03c50591d6aafe4b9176c5= c934e1a7b81ba 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -340,7 +340,7 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> { } =20 // SAFETY: The type invariants guarantee that `Task` is always refcounted. -unsafe impl crate::types::AlwaysRefCounted for Task { +unsafe impl crate::types::RefCounted for Task { fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. unsafe { bindings::get_task_struct(self.as_ptr()) }; @@ -352,6 +352,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to can obtain an= `ARef` from a +// `&Task`. +unsafe impl crate::types::AlwaysRefCounted for Task {} + impl Kuid { /// Get the current euid. #[inline] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index c12ff4d2a3f2d79b760c34c0b84a51b507d0cfb1..40c0138bd336057e7d3a835a9e8= 1391baa2fd2b1 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -418,11 +418,9 @@ pub const fn raw_get(this: *const Self) -> *mut T { } } =20 -/// Types that are _always_ reference counted. +/// Types that are internally reference counted. /// /// It allows such types to define their own custom ref increment and decr= ement functions. -/// Additionally, it allows users to convert from a shared reference `&T` = to an owned reference -/// [`ARef`]. /// /// This is usually implemented by wrappers to existing structures on the = C side of the code. For /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to c= reate reference-counted @@ -438,9 +436,8 @@ pub const fn raw_get(this: *const Self) -> *mut T { /// at least until matching decrements are performed. /// /// Implementers must also ensure that all instances are reference-counted= . (Otherwise they -/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_r= ef`] keep the object -/// alive.) -pub unsafe trait AlwaysRefCounted { +/// won't be able to honour the requirement that [`RefCounted::inc_ref`] k= eep the object alive.) +pub unsafe trait RefCounted { /// Increments the reference count on the object. fn inc_ref(&self); =20 @@ -453,11 +450,21 @@ pub unsafe trait AlwaysRefCounted { /// Callers must ensure that there was a previous matching increment t= o the reference count, /// and that the object is no longer used after its reference count is= decremented (as it may /// result in the object being freed), unless the caller owns another = increment on the refcount - /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls - /// [`AlwaysRefCounted::dec_ref`] once). + /// (e.g., it calls [`RefCounted::inc_ref`] twice, then calls [`RefCou= nted::dec_ref`] once). unsafe fn dec_ref(obj: NonNull); } =20 +/// An extension to RefCounted, which declares that it is allowed to conve= rt from a shared reference +/// `&T` to an owned reference [`ARef`]. +/// +/// # Safety +/// +/// Implementers must ensure that no safety invariants are violated by upg= rading an `&T` to an +/// [`ARef`]. In particular that implies [`AlwaysRefCounted`] and [`Own= able`] cannot be +/// implemented for the same type, as this would allow to violate the uniq= ueness guarantee of +/// [`Owned`] by derefencing it into an `&T` and obtaining an [`ARef`] = from that. +pub unsafe trait AlwaysRefCounted: RefCounted {} + /// An owned reference to an always-reference-counted object. /// /// The object's reference count is automatically decremented when an inst= ance of [`ARef`] is @@ -468,7 +475,7 @@ pub unsafe trait AlwaysRefCounted { /// /// The pointer stored in `ptr` is non-null and valid for the lifetime of = the [`ARef`] instance. In /// particular, the [`ARef`] instance owns an increment on the underlying = object's reference count. -pub struct ARef { +pub struct ARef { ptr: NonNull, _p: PhantomData, } @@ -477,16 +484,16 @@ pub struct ARef { // it effectively means sharing `&T` (which is safe because `T` is `Sync`)= ; additionally, it needs // `T` to be `Send` because any thread that has an `ARef` may ultimatel= y access `T` using a // mutable reference, for example, when the reference count reaches zero a= nd `T` is dropped. -unsafe impl Send for ARef {} +unsafe impl Send for ARef {} =20 // SAFETY: It is safe to send `&ARef` to another thread when the underl= ying `T` is `Sync` // because it effectively means sharing `&T` (which is safe because `T` is= `Sync`); additionally, // it needs `T` to be `Send` because any thread that has a `&ARef` may = clone it and get an // `ARef` on that thread, so the thread may ultimately access `T` using= a mutable reference, for // example, when the reference count reaches zero and `T` is dropped. -unsafe impl Sync for ARef {} +unsafe impl Sync for ARef {} =20 -impl ARef { +impl ARef { /// Creates a new instance of [`ARef`]. /// /// It takes over an increment of the reference count on the underlyin= g object. @@ -515,12 +522,12 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// ``` /// use core::ptr::NonNull; - /// use kernel::types::{ARef, AlwaysRefCounted}; + /// use kernel::types::{ARef, RefCounted}; /// /// struct Empty {} /// /// # // SAFETY: TODO. - /// unsafe impl AlwaysRefCounted for Empty { + /// unsafe impl RefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} /// } @@ -538,7 +545,7 @@ pub fn into_raw(me: Self) -> NonNull { } } =20 -impl Clone for ARef { +impl Clone for ARef { fn clone(&self) -> Self { self.inc_ref(); // SAFETY: We just incremented the refcount above. @@ -546,7 +553,7 @@ fn clone(&self) -> Self { } } =20 -impl Deref for ARef { +impl Deref for ARef { type Target =3D T; =20 fn deref(&self) -> &Self::Target { @@ -563,7 +570,7 @@ fn from(b: &T) -> Self { } } =20 -impl Drop for ARef { +impl Drop for ARef { fn drop(&mut self) { // SAFETY: The type invariants guarantee that the `ARef` owns the = reference we're about to // decrement. diff --git a/rust/kernel/types/ownable.rs b/rust/kernel/types/ownable.rs index f4065a0d627a62d3ecb15edabf306e9b812556e1..80cd990f6601767aa5a742a6c09= 97f4f67d06453 100644 --- a/rust/kernel/types/ownable.rs +++ b/rust/kernel/types/ownable.rs @@ -18,8 +18,8 @@ /// /// Note: Implementing this trait allows types to be wrapped in an [`Owned= `]. This does not /// provide reference counting but represents a unique, owned reference. I= f reference counting is -/// required [`AlwaysRefCounted`](crate::types::AlwaysRefCounted) should b= e implemented which allows -/// types to be wrapped in an [`ARef`](crate::types::ARef). +/// required [`RefCounted`](crate::types::RefCounted) should be implemente= d which allows types to be +/// wrapped in an [`ARef`](crate::types::ARef). /// /// # Safety /// --=20 2.49.0 From nobody Thu Oct 9 09:03:17 2025 Received: from mail-24417.protonmail.ch (mail-24417.protonmail.ch [109.224.244.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B03F2EA495 for ; Wed, 18 Jun 2025 12:28:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249691; cv=none; b=cZWwG97CCTUtDadzxC0Cr5HCXv8mdIg6vw+DmJMwl7p4m3lj6x8wNEwunPgfsiNLVTm2YIALtz2Nyicpubq/B+VXwJs2l4PG3NsOCh75ds862lsaLwfKXeNW1VuyCtEJSf2kMv9a7nLSPvQgyfu/V6av2q6Sh56AZEtYW64L0KY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249691; c=relaxed/simple; bh=PoENILfftPuKovdbTf1s6VqO1XZgvziz6Eq/RLvuL6k=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=R6RU8Y/zM39nL8+CSD7JR1FjTkmDR0X71uSmTgHGMeGaeiOftOPVUYF7O9Kmc0bFUjNAukxVo4l+jqTpvPREHnudyJl4S70zUutvmetkazG7PQzST2zgLP4JiJBD+iahN7joidvf+4wW8OcpgDmUY5ivBo1vuibVKpmIytAqWsQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=fhZ82mRS; arc=none smtp.client-ip=109.224.244.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="fhZ82mRS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1750249681; x=1750508881; bh=EUK7UbppZKvXdNuoTpuczW050PGsMvbPwEvZ2b3BRjk=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=fhZ82mRSd0oyCtUsVTOgSZhMvQeq+nIMXSzcveD49s4eJMvA808h3cWDcxL0Y93GY TwIxqJEHRGy0t/XFKFnKHuYH4gN3UudgNz+esiVppzqkAC/em04TCCreEPIt/BnN17 IHr5YViO29ZAkT41vrJ1r8Xpqq5ldYgwA4xg0FxaGzC8d/zqCAJtAtDpBwGu429SOq FigUMNpbeYVu1taByq9dagT3R+jjq0kFHbzape2Z0vujRytKBYG+Vkh2lWGHq8V3w/ xCzVdAjnDvLjUoi8Z6d4ZtPKi7f8TtnmqNTBqRUwvslMFxq3lr1FqsY14rtuwA6Rn5 KkBYFtkzddG0g== Date: Wed, 18 Jun 2025 12:27:55 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Andreas Hindborg , Alice Ryhl , Trevor Gross , Benno Lossin , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v11 3/4] rust: Add missing SAFETY documentation for `ARef` example Message-ID: <20250618-unique-ref-v11-3-49eadcdc0aa6@pm.me> In-Reply-To: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> References: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 76c778666a390c4fcd86d43530e3c2afc02800ae Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" SAFETY comment in rustdoc example was just 'TODO'. Fixed. Signed-off-by: Oliver Mangold --- rust/kernel/types.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 40c0138bd336057e7d3a835a9e81391baa2fd2b1..a22d5d39d89edfe357fdfe903ef= 42e5d5404237f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -526,7 +526,9 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// struct Empty {} /// - /// # // SAFETY: TODO. + /// // SAFETY: The `RefCounted` implementation for `Empty` does not co= unt references and + /// // never frees the underlying object. Thus we can act as having a = refcount on the object + /// // that we pass to the newly created `ARef`. /// unsafe impl RefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} @@ -534,7 +536,7 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// let mut data =3D Empty {}; /// let ptr =3D NonNull::::new(&mut data).unwrap(); - /// # // SAFETY: TODO. + /// // SAFETY: We keep `data` around longer than the `ARef`. /// let data_ref: ARef =3D unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull =3D ARef::into_raw(data_ref); /// --=20 2.49.0 From nobody Thu Oct 9 09:03:17 2025 Received: from mail-24417.protonmail.ch (mail-24417.protonmail.ch [109.224.244.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3E362EA160 for ; Wed, 18 Jun 2025 12:28:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249690; cv=none; b=mOwQ24u35G1ppKTR1vxTBQFArx0yyacokLEeOv28w14L8dnaars1L+VROUXoaFIC8+7OEooZOIlDChuqumtmQTgNwBrkFhfXlku9Z3vbTvayIG44dem2+bvDgS72wLTwbGO9gWDdF1toY++aOlWEZ7yQV6mpzvKPp5HX+XAskPA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750249690; c=relaxed/simple; bh=9u/lhjMuZxt5gdzNXkvyQGTpF7x7HkbR30b0gP7pFTQ=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pCmuDNkCEObOgZbpc/vRNzeBsEFGmZ9axQ8X+UB26snML5hXfS4ty06hhTEEjfc83F05+3s9CMxa/BmmN09pXT5HeTglTqzYspQTjeC+zGof3/pOEa+dBOqHJqUjxc6Ylxr4YDOCF3DGHx/I5VCvm40OLgWN2os7daCLQxTgtC0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=FzBotmvK; arc=none smtp.client-ip=109.224.244.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="FzBotmvK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1750249683; x=1750508883; bh=7QKZ3i7hDc5KAkLRl23tMe4ErKiHt7foEwQ0JMk9U1Y=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=FzBotmvK9PAiuMwDfGBa6o2B4C8mwMNhDBLuNyo3WYqwzarJaAbPEt73tBw7/vbKQ USPorzbIHZOtoqZzFxmTPtEaN9Vnv5g0fUGz47hNZBu2xtNvtHCazvlB27tf5kG9Sh 5GGhHnHmJFYe1Pj3+B+U/BknaIiFUO//LpFO3WY8cMDTNjeqxbNlRQgqwQFsnsgfPd dtkkIR1R4t9DjEQccSWqxhcAu9k4ZSQSlarl91KtoBQH4wvS0JksXLb3Wdt3LV6HJb 8ol1HNhOFAkmvak/OfJ3ZLZma/bpHGD1Ao+Jkl32xEHKDYlt1GwFv4UTouC14iKS1k zZ5uVgArRyi8g== Date: Wed, 18 Jun 2025 12:27:59 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Andreas Hindborg , Alice Ryhl , Trevor Gross , Benno Lossin , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v11 4/4] rust: Add `OwnableRefCounted` Message-ID: <20250618-unique-ref-v11-4-49eadcdc0aa6@pm.me> In-Reply-To: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> References: <20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: d2c8d1c6b9c72fcd37fa43299ef51e953e572141 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Types implementing one of these traits can safely convert between an `ARef` and an `Owned`. 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 Reviewed-by: Andreas Hindborg --- rust/kernel/types.rs | 10 +++- rust/kernel/types/ownable.rs | 127 +++++++++++++++++++++++++++++++++++++++= +++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index a22d5d39d89edfe357fdfe903ef42e5d5404237f..af0bda4ea50f54aed3c51327db0= e43f960868501 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -12,7 +12,7 @@ use pin_init::{PinInit, Zeroable}; =20 pub mod ownable; -pub use ownable::{Ownable, OwnableMut, Owned}; +pub use ownable::{Ownable, OwnableMut, OwnableRefCounted, Owned}; =20 /// Used to transfer ownership to and from foreign (non-Rust) languages. /// @@ -429,6 +429,8 @@ pub const fn raw_get(this: *const Self) -> *mut T { /// 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 uniqu= e references are required /// [`Ownable`] should be implemented which allows types to be wrapped in = an [`Owned`]. +/// Implementing the trait [`OwnableRefCounted`] allows to convert between= unique and shared +/// references (i.e. [`Owned`] and [`ARef`]). /// /// # Safety /// @@ -572,6 +574,12 @@ fn from(b: &T) -> Self { } } =20 +impl From> for ARef { + fn from(b: Owned) -> Self { + T::into_shared(b) + } +} + impl Drop for ARef { 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/ownable.rs b/rust/kernel/types/ownable.rs index 80cd990f6601767aa5a742a6c0997f4f67d06453..b5626dead6bb25ea76a0ae577db= 1b130308d98b1 100644 --- a/rust/kernel/types/ownable.rs +++ b/rust/kernel/types/ownable.rs @@ -2,6 +2,7 @@ =20 //! Owned reference types. =20 +use crate::types::{ARef, RefCounted}; use core::{ marker::PhantomData, mem::ManuallyDrop, @@ -18,8 +19,9 @@ /// /// Note: Implementing this trait allows types to be wrapped in an [`Owned= `]. This does not /// provide reference counting but represents a unique, owned reference. I= f reference counting is -/// required [`RefCounted`](crate::types::RefCounted) should be implemente= d which allows types to be -/// wrapped in an [`ARef`](crate::types::ARef). +/// required [`RefCounted`] should be implemented which allows types to be= wrapped in an +/// [`ARef`]. Implementing the trait [`OwnableRefCounted`] allows to= convert between unique +/// and shared references (i.e. [`Owned`] and [`ARef`]). /// /// # Safety /// @@ -132,3 +134,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`]. +/// +/// # Safety +/// +/// Implementers must ensure that: +/// +/// - [`try_from_shared()`](OwnableRefCounted::into_shared) only returns a= n [`Owned`] if +/// exactly one [`ARef`] exists. +/// - [`into_shared()`](OwnableRefCounted::into_shared) set the reference = count to the value which +/// the returned [`ARef`] expects for an object with a single refe= rence in existence. This +/// implies that if [`into_shared()`](OwnableRefCounted::into_shared) is= left on the default +/// implementation, which just rewraps the underlying object, the refere= nce count needs not to be +/// modified when converting an [`Owned`] to an [`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::types::{ +/// ARef, RefCounted, Owned, Ownable, OwnableRefCounted, +/// }; +/// +/// struct Foo { +/// refcount: Cell, +/// } +/// +/// impl Foo { +/// fn new() -> Result, AllocError> { +/// // Use a `KBox` to handle the actual allocation. +/// let result =3D KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result =3D NonNull::new(KBox::into_raw(result)) +/// .expect("Raw pointer to newly allocation KBox is null, thi= s should never happen."); +/// // SAFETY: We just allocated the `Foo`, thus it is valid. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement each time the respective functio= n 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) { +/// // SAFETY: The underlying object is always valid when the func= tion is called. +/// let refcount =3D unsafe { &this.as_ref().refcount }; +/// let new_refcount =3D refcount.get() - 1; +/// if new_refcount =3D=3D 0 { +/// // The `Foo` will be dropped when `KBox` goes out of scope. +/// // SAFETY: The `Box` is still alive as the old refcou= nt is 1. +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// } +/// +/// // SAFETY: We only convert into an `Owned` when the refcount is 1. +/// unsafe impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef) -> Result, ARef> { +/// if this.refcount.get() =3D=3D 1 { +/// // SAFETY: The `Foo` is still alive as the refcount is 1. +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// } +/// +/// // SAFETY: We are not `AlwaysRefCounted`. +/// unsafe impl Ownable for Foo { +/// unsafe fn release(this: NonNull) { +/// // SAFETY: Using `dec_ref()` from `RefCounted` to release is o= kay, as the refcount is +/// // always 1 for an `Owned`. +/// unsafe{ Foo::dec_ref(this) }; +/// } +/// } +/// +/// let foo =3D Foo::new().unwrap(); +/// let mut foo =3D ARef::from(foo); +/// { +/// let bar =3D foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// ``` +pub unsafe 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 obje= ct. + fn try_from_shared(this: ARef) -> Result, ARef= >; + + /// Converts the [`Owned`] into an [`ARef`]. + fn into_shared(this: Owned) -> ARef { + // SAFETY: Safe by the requirements on implementing the trait. + unsafe { ARef::from_raw(Owned::into_raw(this)) } + } +} + +impl TryFrom> for Owned { + type Error =3D ARef; + /// 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) -> Result, Self::Error> { + T::try_from_shared(b) + } +} --=20 2.49.0