From nobody Sun Feb 8 04:57:37 2026 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 E4A99238141 for ; Fri, 2 May 2025 09:02:36 +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=1746176559; cv=none; b=LYelbEOht+1GqbQpwiGx+ErJSz6fTZL8lVlHAAr6sMPwO+IF0jjkE++i5L3DzQm2TKJa2MmAwLrHizILqY2Q/w0QZjFQLpHxlmdwzfXHq7uv+QmYyBJE7cR0Gcr643VpAyICv1DUtiDzPf8RLAgIS5uXSjBawGQE7o6LRzNGMIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176559; c=relaxed/simple; bh=ozAupGYHVSRKUknmmChuAkml7ixrXIgiyS8gR3oiaYg=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Dp0FL9hNO2I33FzN5aAZl0koFanaQJxLlwWdqY+q8/0kzMkvKdG4YMvMsSkiaeg2zMFOmxmCG9y3xWtegbUQwycyo7o11YE66XcC10czaDbSYzBj4YC2bFZoucQqRmkU64HgAhmoGXzy9D8f1TCmNC5ypSQBU6acSPp/VLNCs/8= 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=EHIPZinl; 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="EHIPZinl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1746176554; x=1746435754; bh=tH6qiUlK/jdZcb5djM2SKrcrDvCZTR4InRqz2V4jPnA=; 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=EHIPZinlcd2tfdxK6e8OoRWhWphZBKh6maCAn0YY/TP2mQBD+33UqR73CP/Bch4uj k+/PUmZ5+8y61tUhnfq6hi8CzAefuyZmHJprZ91OT1mwHGQAFTBLLNN9vAKWSLmJuD ypq7epRks6OiaZ2vGxAFm2LuRVjCsjWP+BHvNRmR6psDCqVxrKuAtA6yTyG2Rqtjjn vwQ2vGgJA11pKfcMucM3rl+cnsePpVej2Swi7H2BPu0ysCtIWy1Wtk2WIla7jsC7dS vItiX72EVdr8wxDngG2tikVyb+920Dyb58pajaXMaKggKuRJjttiBcCFyoDzo7mNoP dk+6pQHGtj5/w== Date: Fri, 02 May 2025 09:02:29 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v10 1/5] rust: types: Add Ownable/Owned types Message-ID: <20250502-unique-ref-v10-1-25de64c0307f@pm.me> In-Reply-To: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> References: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 4acd5acd5dc38b7f6147f3f413fa5d334514127a 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 ] Signed-off-by: Oliver Mangold Reviewed-by: Boqun Feng --- rust/kernel/types.rs | 3 ++ rust/kernel/types/ownable.rs | 117 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 120 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9d0471afc9648f2973235488b441eb109069adb1..5d8a99dcba4bf733107635bf3f0= c15840ec33e4c 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 diff --git a/rust/kernel/types/ownable.rs b/rust/kernel/types/ownable.rs new file mode 100644 index 0000000000000000000000000000000000000000..52e7a69019f1e2bbbe3cf715651= b67a5a5c7c13d --- /dev/null +++ b/rust/kernel/types/ownable.rs @@ -0,0 +1,117 @@ +// 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. +/// +/// # Safety +/// +/// Implementers must ensure that: +/// - Any objects owned by Rust as [`Owned`] stay alive while that owne= d reference exists (i.e. +/// until the [`release()`](Ownable::release) trait method is called). +/// - That the C code follows the usual mutable reference requirements. Th= at is, the kernel will +/// never mutate the [`Ownable`] (excluding internal mutability that fol= lows the usual rules) +/// while Rust owns it. +pub unsafe trait Ownable { + /// Releases the object (frees it or returns it to foreign ownership). + /// + /// # Safety + /// + /// Callers must ensure that the object is no longer referenced after = this call. + unsafe fn release(this: NonNull); +} + +/// A subtrait of Ownable that asserts that an [`Owned`] or `&mut Owned= ` Rust reference +/// may be dereferenced into a `&mut T`. +/// +/// # Safety +/// +/// Implementers must ensure that access to a `&mut T` is safe, implying t= hat it is okay to call +/// [`core::mem::swap`] on the `Ownable`. This excludes pinned types (mean= ing: most kernel types). +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` is valid for the lifetime of the [`Owned`]= instance. +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 the underlying object is acquired and can= be considered owned by + /// Rust. + 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 ownersh= ip previously managed + /// 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 Sun Feb 8 04:57:37 2026 Received: from mail-10630.protonmail.ch (mail-10630.protonmail.ch [79.135.106.30]) (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 774D823C50F for ; Fri, 2 May 2025 09:02:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176572; cv=none; b=ohi/B3oyr2Ns6oWwlSYtvueW/hi7qCszF/QbPTWKD3EXS+u2hr3gUI5RZzu/8fORavkHr8jpawpjZeQlnXVMFkvohjiXYRwXNpeJXQ2GllPQXYj6nmESyuFBxbOa+iYJnlFkvSqXN1Y2GEvn46zAa0zgoJZqPPHs5bqYJUjQAZk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176572; c=relaxed/simple; bh=KK7Urj6cy1NjgNkW9fTkz6gHuuLB2DlovX8CVk5bq5Y=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iAKRtdms80UB7150rW7RQtCi5/IilgnCG2Wfg9znO6o1hU3aT5M4s/6J6fXeT8zn/7CyFLLKlyGhL3aCMoq9Xl98w9IOHHPzY53FNr658DZrcjH/VXYdy5d6sc2oVlTADzhg9r0SCkVTITC2Gjx0Auv8E0c6lrSn55cSIrSgEsw= 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=Emiy8qxt; arc=none smtp.client-ip=79.135.106.30 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="Emiy8qxt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1746176562; x=1746435762; bh=2HGsionqViK0+ek7zHJadu8rQSHQgRW1JEGT6WiiphE=; 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=Emiy8qxtj1+iFfeJPVLEq1vUILeleXhAOD4S2SADk12tHNE4+uPuYT+IK5LnNysWL x5/9CsPsk0IxjMUDdv6N8cATJZQTnLnieE5+QYMjyUkHVBBrBxdAx6s7ZUs33VUF/u 7YGRs9pHsw+ljVvcptgmhNVhJ9EeJvimOAPx1FzOoRqS2J/or2bM0jGVn5595gBJSu wyxkpyPMt/2VI6g0Neg6OWLmm3bUg9rnrva6y3585qHv4LUHJZMQiCdVXW/vpI0cFV /JMtDohIciT1j/hw3DmsNFzidpkILX2h23rZ4RVNZTDNJb0bUP47ki9EWQTZN9WiaQ +6spxId2BwY1w== Date: Fri, 02 May 2025 09:02:37 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v10 2/5] rust: Rename AlwaysRefCounted to RefCounted Message-ID: <20250502-unique-ref-v10-2-25de64c0307f@pm.me> In-Reply-To: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> References: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 2fcf8bd602db40efae31109f0aca9298390f576e 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 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 Reviewed-by: Andreas Hindborg --- rust/kernel/block/mq/request.rs | 10 +++++++--- rust/kernel/cred.rs | 8 ++++++-- rust/kernel/device.rs | 8 ++++++-- rust/kernel/fs/file.rs | 10 +++++++--- 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 ++++++++++++++++++++++++-------------= ---- 9 files changed, 71 insertions(+), 32 deletions(-) diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request= .rs index 4a5b7ec914efa598c65881b07c4ece59214fd7e7..5ec5dbc052df964f10403d65f9b= f3dd847a41cf4 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, @@ -227,10 +227,10 @@ fn atomic_relaxed_op_unless(target: &AtomicU64, op: i= mpl Fn(u64) -> u64, pred: u } =20 // SAFETY: All instances of `Request` are reference counted. This -// implementation of `AlwaysRefCounted` ensure that increments to the ref = count +// implementation of `RefCounted` 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 { +unsafe impl RefCounted for Request { fn inc_ref(&self) { let refcount =3D &self.wrapper_ref().refcount(); =20 @@ -260,3 +260,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 21b343a1dc4d2b4ba75c3886ba954be53ada88c2..0b77faa4cc972aeff5809939a5d= bc430a396018b 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, ptr}; =20 @@ -190,7 +190,7 @@ pub fn property_present(&self, name: &CStr) -> bool { } =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()) }; @@ -202,6 +202,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 13a0e44cd1aa812eb404d452c076f90a37275b5b..76032e6abb3f0f0ab1f6536ecff= 06e2c24255d00 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. @@ -225,7 +229,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/pci.rs b/rust/kernel/pci.rs index c97d6d470b282219de255450d0c1980aefcf12c0..4c1fc28a1b5526376377098139e= a8c405b83ee25 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -443,7 +443,7 @@ fn from(dev: &Device) -> Self { } =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()) }; @@ -455,6 +455,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..3d8391113c1be150c5eb2ce3547= 37bb1e4d63a80 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 4917cb34e2fe8027d3d861e90de51de85f006735..49add3ae88a6841f02a1e8a8f00= 43672f15cb088 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -211,7 +211,7 @@ fn from(dev: &Device) -> Self { } =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()) }; @@ -223,6 +223,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 9e6f6854948d9ef9bb203a3548c9b082df8280e2..58086491ac85a219f795ecb473e= 9f6dd21bda773 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -329,7 +329,7 @@ pub fn wake_up(&self) { } =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()) }; @@ -341,6 +341,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 5d8a99dcba4bf733107635bf3f0c15840ec33e4c..d7fa8934c545f46a646ca900ab8= 957a04b0ad34d 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -394,11 +394,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 @@ -410,9 +408,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 @@ -425,11 +422,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= [`Ownable`] +/// cannot be implemented for the same type, as this would allow to violat= e the uniqueness +/// 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 @@ -440,7 +447,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, } @@ -449,16 +456,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. @@ -487,12 +494,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) {} /// } @@ -510,7 +517,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. @@ -518,7 +525,7 @@ fn clone(&self) -> Self { } } =20 -impl Deref for ARef { +impl Deref for ARef { type Target =3D T; =20 fn deref(&self) -> &Self::Target { @@ -535,7 +542,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. --=20 2.49.0 From nobody Sun Feb 8 04:57:37 2026 Received: from mail-10630.protonmail.ch (mail-10630.protonmail.ch [79.135.106.30]) (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 180E823C517; Fri, 2 May 2025 09:02:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176578; cv=none; b=fTN7FJbp11isN8zIqZS82UjEoQESOiFYqahS0J4QIINeSPhib1JoR1MKGCAXZEsZTkHXNQp6UNiwtUbi1OeDeG0VRUEFWx5xHK8lV90j+eHxUBHF7AMuCwxuvjSRIVND8QeMpX9Sl4oRwANUO4L8c0C9U/FRsNurcD1vwVoSl04= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176578; c=relaxed/simple; bh=Ar4lKIWcTiho0vArUzBhEcodfh10O5kWSMX5HswMJ1E=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=igFUtdQJKFTK6O8umXoI/5fzju+/ztyjCLBYtZtKvEhBiwQcKlnvF6r91v1p4UuuM0xYIswocJD6f9bKgDYlMGUHtNeAetyRcQD6tBQVb2+3bs/wUEumrUUhOYyICzWipKHb54iPvUqMW0B5XUvoFrltp3BGc+ZEN/Kvyf5SINI= 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=NSYmm22R; arc=none smtp.client-ip=79.135.106.30 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="NSYmm22R" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1746176574; x=1746435774; bh=HrwkYic3s8vLfkP4y8Kt+4FOjgbkN5SBXJN+ruGJsJY=; 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=NSYmm22Ry5eAQ4V6jbcV/Eg3z+cOGNfDQ95aNXap9TELJg89/NR8WSxJ1APq6AdUr QHO2MPiU7R2IIF8FKuWv2hNIb4wpB39MObc9B/zwdgS8Le5HUYa9aeqbfcb8TQ0cIb iULBnqaGYfzGTNHKJa9Rz+deGvzhvoR7nF5UI9U7qJlESkvGur3joqlSbOXRYFVLRZ 8PNY5mSARqrXWbcDxRWut6GMEVp6JRzrGk8IU0JhZICDVzAqRkCwVpFrRKWz5q68lr PrWf3fGHLi2bfAmixdP/GZV5/2xScYdCd3hemTQlyUkqdhIPqpd8Jcpwm0DRE0tDu3 jX14+FfD70Tig== Date: Fri, 02 May 2025 09:02:46 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v10 3/5] rust: Add missing SAFETY documentation for ARef example Message-ID: <20250502-unique-ref-v10-3-25de64c0307f@pm.me> In-Reply-To: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> References: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 25864bd009001c377ac62f6823ff8eb924649b19 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 d7fa8934c545f46a646ca900ab8957a04b0ad34d..33d2b4e4a87b991c6d934f4e8d2= c6c71a15b1bcb 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -498,7 +498,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 havin= g 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) {} @@ -506,7 +508,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 Sun Feb 8 04:57:37 2026 Received: from mail-10629.protonmail.ch (mail-10629.protonmail.ch [79.135.106.29]) (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 4090E23E342 for ; Fri, 2 May 2025 09:03:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.29 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176586; cv=none; b=ENTo4fkxR1a8NN38goaB6rM2EjRdITBCR5BclNSs/cD6QoR+HNiuHDyl2rCUaxkH87Hl+dZ4cQ2oRz/RRNWTfnttZlgATtwZmGQUpsKfAdO1xSWIE8jAGtT9LMfAv1NeAC0f2MkL2BDBo1n4g08MWYLl0rIrpV4tImeIYW+btsE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176586; c=relaxed/simple; bh=HVf+21hPVJuLZGJqbjtv80+9kY063qAQpNuSCz5YkVs=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JTfj6586KnN0UKaI+hfE3I2xVVtTA5x4Yl6zLDhmI6bbjCLfobivYIebzkuyy5g9ll+EH4noyWzYJ/0y93VA5q4RpAzw68L0aqXfIJpLAKYtR2Ni6yMKsY5rOeQm4q3V3HDgONrqv6I1KGdN0G7I4u/nl2X2cjZ5t20bRjM5u+s= 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=EAbEXjwS; arc=none smtp.client-ip=79.135.106.29 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="EAbEXjwS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1746176583; x=1746435783; bh=LC4muJgF9aO4kWCf6YNzTnzURDKFFJSrIvZ3fBgfPW0=; 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=EAbEXjwSKUfaHBGUxZvZrV2CnRHC1Z350HXzHbyQpVVYg6pxdoLwsbrjumniCaUXn LWwcjV61rioxbBvOu9xIGNLiPKT3g+ANvfmv1PvpjVtUD4ARe6ogNMbfKMUlQikGF0 UUqIf5HWKKqL1wdl4IUGr0Mp7paPBj+SLtmasSYOVxmFjAXykDQCDsVLZQgQpDPQch iGRGNnvt6riX+KCB15r2wNdN1pT+Y7j4DiNQcPajkJnx9KS8zJHsL/CDLLna0KyJ+7 AgC4DKIigoMo2uR9bWlggb9KLhp5VMSowQ6HJ+I1gMlPzOUURsRcbJFi8luGiTbwnV rogm1QI+6KTPg== Date: Fri, 02 May 2025 09:02:55 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v10 4/5] rust: kbuild: provide `RUSTC_HAS_DO_NOT_RECOMMEND` symbol Message-ID: <20250502-unique-ref-v10-4-25de64c0307f@pm.me> In-Reply-To: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> References: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 29275a13ff99657841e7389e7d241def33c76c99 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: Miguel Ojeda Rust 1.85.0 (current stable version) stabilized [1] `#[diagnostic::do_not_recommend]` [2]. In order to use it across all supported Rust versions, introduce a new Kconfig symbol for it. This allows to perform conditional compilation based on it, e.g. on the use site to enable the attribute: #[cfg_attr(RUSTC_HAS_DO_NOT_RECOMMEND, diagnostic::do_not_recommend)] impl A for i32 {} An alternative would have been to `allow` the following warning: #![allow(unknown_or_malformed_diagnostic_attributes)] However, that would lose the checking for typos across all versions, which we do not want to lose. One can also use the Kconfig symbol to allow the warning in older compilers instead, to avoid repeating the `cfg_attr` line above in all use sites: #![cfg_attr( not(RUSTC_HAS_DO_NOT_RECOMMEND), expect(unknown_or_malformed_diagnostic_attributes) )] That still loses the checking for typos in older versions, but we still keep it in newer ones, thus we should still catch mistakes eventually. In this case we can promote it to `expect` as shown above, so that we do not forget to remove these lines if we stop using the attribute somewhere. Link: https://github.com/rust-lang/rust/pull/132056 [1] Link: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-d= iagnosticdo_not_recommend-attribute [2] Link: https://lore.kernel.org/rust-for-linux/CANiq72mYfhuRWkjomb1vOMMPOaxvd= S6qjfVLAwxUw6ecdqyh2A@mail.gmail.com/ Signed-off-by: Miguel Ojeda Signed-off-by: Oliver Mangold Reviewed-by: Andreas Hindborg --- init/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/init/Kconfig b/init/Kconfig index dd2ea3b9a799205daa4c1f0c694a9027e344c690..556e274bba6c015cf482e22472e= 9c24d5a2a7ca5 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -140,6 +140,9 @@ config LD_CAN_USE_KEEP_IN_OVERLAY config RUSTC_HAS_COERCE_POINTEE def_bool RUSTC_VERSION >=3D 108400 =20 +config RUSTC_HAS_DO_NOT_RECOMMEND + def_bool RUSTC_VERSION >=3D 108500 + config PAHOLE_VERSION int default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE)) --=20 2.49.0 From nobody Sun Feb 8 04:57:37 2026 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) (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 502D6241CB0; Fri, 2 May 2025 09:03:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.22 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176593; cv=none; b=uT7QktLT2FzBU/j63DeN26jk/vHfOo9wuSTFxw7qVw2hyZxwHf60YDdZAMQJj47saTQztcb8vAgLnf7Y3gho1B9KcOXNFYfpkf0CwfEaSh024DxL1B+MXtyeYSEnbS4iBBuy2SPiog+xGliQ/pqWc9OXxvcXeheBDWwpc8+Y05Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746176593; c=relaxed/simple; bh=2DoRPY90HPb0vreL+1wdH6ifr2K0c+o6aU/jTWhXrT8=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N6GblCxAfQKesSXcTpvNnyaI5SzQaICC0D4OTpzlqaqbPl+RZnM3aJihBxEO1cpcIuQJzc/Q/Wyn9UtzqajEe269G85HjxM8sishWpTll48VgytY8rHz904ivEREoX8QvTs3dhSlFHlW92T8EOGVi4PfI8ONP8F7WcmYfbuDfIA= 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=fVboQKcO; arc=none smtp.client-ip=185.70.43.22 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="fVboQKcO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1746176589; x=1746435789; bh=FBltpZVjhwV8MQLDJxwMyi9+Fo4qdGjW9Xkiy47VWYM=; 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=fVboQKcOlH/bRO/jj7J2ZV2Czt6Xrl3RxiaEG+LduJDjYs/j0XYmfGSYLDQDZPItZ hZR0DC4KQ5TvgCy5WUQVdbJ9rcc8YXFj6HrIEc7T3Z0gFqdpXQIlfcc+3BSKhgr4Ih bXTmcFQdsZQlFHR9A5BpKyvklgWtOFuRGR8hRirqQ4BogPLV5b8xM+D/pPbbILQzYi 8bYd26/y48HFscFE1RcKyrdUixXaR1umPwW6pNiYbL+obfRw67+Eb12D2G25jZarlo z5x1iAGKpfZfH5kAiY3FW5C47PINedSeY5cUho1XeD/RIySefNckEKHaeJud37rWNq IMZ9F2/6b0m6Q== Date: Fri, 02 May 2025 09:03:04 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v10 5/5] rust: Add OwnableRefCounted and SimpleOwnableRefCounted Message-ID: <20250502-unique-ref-v10-5-25de64c0307f@pm.me> In-Reply-To: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> References: <20250502-unique-ref-v10-0-25de64c0307f@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: cd62f5405a586d7b2198e4e2882e4ab22b8e2e3b 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 | 8 +- rust/kernel/types/ownable.rs | 244 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 251 insertions(+), 1 deletion(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 33d2b4e4a87b991c6d934f4e8d2c6c71a15b1bcb..3a58905599eb9acb0e701c97bd9= 2d3b93b9515cf 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, SimpleOwn= ableRefCounted}; =20 /// Used to transfer ownership to and from foreign (non-Rust) languages. /// @@ -544,6 +544,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 52e7a69019f1e2bbbe3cf715651b67a5a5c7c13d..b79459d07870ea4fa4f5df0c756= 5ac72d65e2c53 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, @@ -115,3 +116,246 @@ 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: +/// +/// - Both the safety requirements for [`Ownable`] and [`RefCounted`] are = fulfilled. +/// - [`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 reference +/// in existence. This implies that if [`into_shared()`](OwnableRefCount= ed::into_shared) is left +/// on the default implementation, which just rewraps the underlying obj= ect, the reference count +/// needs not to be modified when converting a [`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)) } + } +} + +/// This trait allows to implement [`Ownable`] and [`OwnableRefCounted`] t= ogether in a simplified +/// way, only requiring to implement [`RefCounted`] and providing the meth= od +/// [`is_unique()`](SimpleOwnableRefCounted::is_unique). +/// +/// For non-standard cases where conversion between [`Ownable`] and [`RefC= ounted`] does not allow +/// [`Ownable::release()`] and [`RefCounted::dec_ref()`] to be the same me= thod, [`Ownable`] +/// and [`OwnableRefCounted`] should be implemented separately. +/// +/// # Safety +/// +/// Implementers must ensure that: +/// +/// - The safety requirements for [`Ownable`] are fulfilled and [`RefCount= ed::dec_ref()`] can +/// be used for [`Ownable::release()`]. +/// - [`is_unique`](SimpleOwnableRefCounted::is_unique) must only return `= true` in case only one +/// [`ARef`] exists and it is impossible for one to be obtained other th= an by cloning an existing +/// [`ARef`] or converting an [`Owned`] to an [`ARef`]. +/// - It is safe to convert an unique [`ARef`] into an [`Owned`] simply by= re-wrapping the +/// underlying object without modifying the refcount. +/// +/// # Examples +/// +/// A minimal example implementation of [`RefCounted`] and [`SimpleOwnable= RefCounted`] +/// 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, Owned, RefCounted, SimpleOwnableRefCounted, +/// }; +/// +/// 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 ensure that: +/// // - The `Foo` is only dropped when the refcount is zero. +/// // - `is_unique()` only returns `true` when the refcount is 1. +/// 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 ensure that: +/// // - `is_unique()` only returns `true` when the refcount is 1. +/// unsafe impl SimpleOwnableRefCounted for Foo { +/// fn is_unique(&self) -> bool { +/// self.refcount.get() =3D=3D 1 +/// } +/// } +/// +/// 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 SimpleOwnableRefCounted: RefCounted { + /// Checks if exactly one [`ARef`] to the object exists. In case the o= bject is [`Sync`], the + /// check needs to be race-free. + fn is_unique(&self) -> bool; +} + +#[cfg_attr(RUSTC_HAS_DO_NOT_RECOMMEND, diagnostic::do_not_recommend)] +// SAFETY: Safe by the requirements on implementation of [`SimpleOwnableRe= fCounted`]. +unsafe impl OwnableRefCounted for T { + fn try_from_shared(this: ARef) -> Result, ARef= > { + if T::is_unique(&*this) { + // SAFETY: Safe by the requirements on implementation of [`Sim= pleOwnable`]. + Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) + } else { + Err(this) + } + } +} + +#[cfg_attr(RUSTC_HAS_DO_NOT_RECOMMEND, diagnostic::do_not_recommend)] +// SAFETY: Safe by the requirements on implementation of [`SimpleOwnableRe= fCounted`]. +unsafe impl Ownable for T { + unsafe fn release(this: NonNull) { + // SAFETY: Safe by the requirements on implementation of + // [`SimpleOwnableRefCounted::dec_ref()`]. + unsafe { RefCounted::dec_ref(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