From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EA4DBCDE008 for ; Fri, 26 Jun 2026 11:56:06 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D72726B0134; Fri, 26 Jun 2026 07:56:05 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id D22CF6B0136; Fri, 26 Jun 2026 07:56:05 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BEC066B0137; Fri, 26 Jun 2026 07:56:05 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 87BDC6B0134 for ; Fri, 26 Jun 2026 07:56:05 -0400 (EDT) Received: from smtpin09.hostedemail.com (lb01a-stub [10.200.18.249]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 164F6A0426 for ; Fri, 26 Jun 2026 11:56:05 +0000 (UTC) X-FDA: 84921910290.09.4056D9A Received: from sea.source.kernel.org (sea.source.kernel.org [172.234.252.31]) by imf02.hostedemail.com (Postfix) with ESMTP id 47DD380003 for ; Fri, 26 Jun 2026 11:56:03 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20260515 header.b=FZbwL1UB; dmarc=pass (policy=quarantine) header.from=kernel.org; spf=pass (imf02.hostedemail.com: domain of a.hindborg@kernel.org designates 172.234.252.31 as permitted sender) smtp.mailfrom=a.hindborg@kernel.org ARC-Seal: i=1; a=rsa-sha256; d=hostedemail.com; s=arc-20220608; cv=none; t=1782474963; b=2b77D7d3YeNK1fTZV0hFZ/Rql5+G4bxnb3mxa/9TsX6IKDIj2050+E3Orzr3n5gtY2haOH NttF9sBaIO/XkpGOZdOH3yrP1SHYDaqevhEhcT+K9tyUYtOz/eLQu0rdM/6IhLC1vTT3f0 e/6K1UQkkKn5g42RVhvaTkbTtg5BPfw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1782474963; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=g2qCRhgwlWX9/P0bA+PS5udzVG7MD/qZuekO4L1dWDw=; b=YoXe0RlMxutjdI6HZoZ9mdRRFJbvyTLI2uq9ofcXjnigYFrjbJ06pm2gpOxRWUEeBcn0Mi gCbrqe0M+Whl6v7YR2uonP8RmgfQ7CAPnaIwXallxIoBeJ5c9KDNy/7+p+8AwKEKODmjHt Pp2a2d5MWFQmC6nobWzznzi7eCm7t4w= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20260515 header.b=FZbwL1UB; dmarc=pass (policy=quarantine) header.from=kernel.org; spf=pass (imf02.hostedemail.com: domain of a.hindborg@kernel.org designates 172.234.252.31 as permitted sender) smtp.mailfrom=a.hindborg@kernel.org Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by sea.source.kernel.org (Postfix) with ESMTP id 8706142A17; Fri, 26 Jun 2026 11:56:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id EF74D1F00A3A; Fri, 26 Jun 2026 11:55:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474962; bh=g2qCRhgwlWX9/P0bA+PS5udzVG7MD/qZuekO4L1dWDw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=FZbwL1UB9mQ6/EFj0VxpRurpZzje4Pb+HbDaMHQ5DdX8SuQpd33TJ8VDJdpJt+SKQ ExU7/khxjOViyyjzw1MrqhcEVx7APVfZDpy87TjSdICi3NT7abaM2qB45e/fo81vKs b3fbtXIP5ufeYhC8FVU8ZkWsIPvL5ZijqK+8Le5uMep4OYSQUnVg6pXIwD8fpOlYPy SuGLz0Uy/RZ3Q6T41Ceif97dX060gK/qKvYVZ2arMxVGxL6MO0zRLWa+VaaOWUUmLz b5u5im5gFBxeyzJQzwp2FEqVUUenSXJ0dGYakOGBxFMK/RySMg63y9t/tOjMVybIel 5Zn7wuyjBYb2Q== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:04 +0200 Subject: [PATCH v19 7/8] rust: Add `OwnableRefCounted` MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260626-unique-ref-v19-7-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=10339; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=lkUx1VbobxlmYWNdC/nDxmr1MRox1ssQduBu64GCO0o=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh6iRQlVRYs+/JmJorUWWxwrlu5daYDi25CA 7qZ7bMs1gKJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5oegAKCRD6UCkIqsW9 0EKJEACgd+t56MS0rxXiwvX3owU4yecPRO8VWtFmQlAx8uvYnHraUytyHUp4oS9jMa/IjyhltnN J9y+ZrUMGvegKDN6WM6iICxyan6JOiS/9CiUa7G5jHJLQw9v5LknXk9qwQHQi2+H/9f49cNBQT2 Is3xnpEiOthg2H2aFup17CG3ZrVEBXh9sFG6vCZ2I8XulkNWndNSJ/qGXUmIP9TGqIPTcmUZtTg Bn/QRQTInOmj4PXVAdQALnmMvXZo9ahXrG3OAgREvDbeLByUHUEeNrzO+0Oaj4fA7rG69RwslWx foJ4NSG8J4nxMV9a7uvFIsAEDSUp7EfJE2uPqew+vjnigu9PoEZxLE7jhAsA2n62Be/VDFpxQ7j +VJDjYbNA2NFTT8Auk3rlehY4SH6JhkUEIxaA3JOgyYdxYerP4lysYt5CCgTZfqNLqV9shrj2bK unF/4va6/rZFfpDAoZoiKptccJexDKekvlze3LZrQGPSTWPalmhV7GDywTFral7H12TNat/HIny NLNHuNRtgtqz5XSQsf7evqkKSqG28ZYPtvLxZrGGpYTTJu+WN3g30Q72Dr4YIwPic5xBQGz/dGA 234yW+ax1T8D/gsZeWlmCsprJfXYZZX58M+is7qjX3AxA9vu7cHVq8wL69IhGryf1NYmD48PuQh wVLS8IIK+gvotUw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 X-Rspamd-Server: rspam11 X-Rspamd-Queue-Id: 47DD380003 X-Rspam-User: X-Stat-Signature: f1yc1imqtbjuq4hbqpt4p6peibtyexfi X-HE-Tag: 1782474963-346929 X-HE-Meta: U2FsdGVkX1/IowCZyfvgrQjt2eWVihIBla1fxUnszvPJd9/UYet1IZRNReoF4YI3V+jJDtn/jRqd+7EQ0JOMlHyzMLT4j1pimjsJswwmALviel9uhcYzXl0L2SDxoOh/UOqqN6ybAVsCGnDkS8f9RwCtGfDnY85IbckgjguDA+E5xltOAa48PlwVmkI++BKrSrC2jlJ+PsLsNlGHOdWcR1Y44wDiwVueVhQyMYEcmcPXxGx2ZDBPp/x4bxRUo2lg45zuKcABwIyiRD3X7riJEVaZa8cFaq9tTg722U5+H1DqwlyzoIeUt4ohgzBpQn8DraJKzDmAFmjxy5NFztHUhxJNMfg7K0ryq4hFXRQ17pW1l0t4DXFtVdNytECbaNIHC4382A/wTYbp7rMLr6OGL8hd0/x+oXwOFVmOkd23nMeGnaB+1JFPpWrCUI895AdS5Vhq4IpE1W0zCnouTYQeRPriufwBrYHqTFoVRoTKMkg15JYCOueeEStepzYBKPRk+2hTJaMlnhBy84pqyfOUsRLbeBWMXsC6cYWPW5Xht858Qm5wbFmcSghIHIXDMxyntqzgRUn/IudwUWfO/6z0vE0UcB4Qncdeep4z4F6He+jRjo80s6T7y1EhTq7sR0mDlwFuQGwnzkWD5a11OH8kdYMTlDfEvKNNSy9AJcZuWxt0ltAdL836+ijbacbwUm18UM/jhgvrrlCKOGtgID4dSSOnw3u5g4uWUMO8ZWPU87ht8WrjprI0chf9vQPq7J2fMb0VGouZzKIgD2q0Jzl/LTjzGXHOzFA+5OA0+tn77VJjNc6HJVslpHGLaZd6ozqgLnOWuAy2zh1XSgqxcE7oI2zHATS0EToSi6VQI0gY2DmCWjExI36qSwqaF2ddKpJlAqQ6w3J+QAOXONu4EgaAJFlmPS7IlF9iq1BCRnxJVwsd9y/jeygpjt+OVlx+TOkxI2v5H92GvnysrwjAiMl 0hDcwzYX VfLc+swp/nSZ11ij5cdKvqPEFCVCtVWoBhINcjB8VAzJkyZQwVxFSArH7SaGL2fsz6PDtmj3O+xnDa4FlzRa4I+InzRjcEfArhTQp//jVa+CTQkNa8wZ1VIGFpK33QAiDwanrZ5y7z9+87KzT9u0rkd2Y/o+kunqBZPJJumusyuAXsjPxcLeG1L0XtOiDa4TIaLoz+CcV1Q4/CTLn23Is9F6OY7XrHJ3Cdt2aA4t1f5ETXTvlD0e683XIPg== Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Oliver Mangold 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 [ Andreas: Fix formatting, update documentation, fix error handling in examples. ] Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/owned.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++-- rust/kernel/sync/aref.rs | 16 +++++- rust/kernel/types.rs | 1 + 3 files changed, 156 insertions(+), 6 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index a156267bf8bb1..acb611f084ff3 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -14,20 +14,26 @@ pin::Pin, ptr::NonNull, // }; +use kernel::{ + sync::aref::ARef, + types::RefCounted, // +}; use kernel::types::ForeignOwnable; /// Types that specify their own way of performing allocation and destruction. Typically, this trait /// is implemented on types from the C side. /// -/// Implementing this trait allows types to be referenced via the [`Owned`] pointer type. This -/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather -/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is -/// executed when the owned reference [`Owned`] pointing to the object is dropped. +/// Implementing this trait allows types to be referenced via the [`Owned`] pointer type. +/// - This is useful when it is desirable to tie the lifetime of an object reference to an owned +/// object, rather than pass around a bare reference. +/// - [`Ownable`] types can define custom drop logic that is executed when the owned reference +/// of type [`Owned<_>`] pointing to the object is dropped. /// /// Note: The underlying object is not required to provide internal reference counting, because it /// represents a unique, owned reference. If reference counting (on the Rust side) is required, -/// [`RefCounted`](crate::types::RefCounted) should be implemented. +/// [`RefCounted`] should be implemented. [`OwnableRefCounted`] should be implemented if conversion +/// between unique and shared (reference counted) ownership is needed. /// /// # Examples /// @@ -99,6 +105,8 @@ pub trait Ownable { /// Callers must ensure that they have exclusive ownership of the `Self` pointed to by `this`, /// and that this ownership is transferred to the `release` method. `this` must not be used /// after calling this method, as the underlying object may have been freed. + /// + /// `this` is pinned and implementers of this method must observe this constraint. unsafe fn release(this: NonNull); } @@ -136,6 +144,8 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// This function does not drop the underlying `T`. When this function returns, ownership of the /// underlying `T` is with the caller. + /// + /// Note that the returned pointer is pinned. #[inline] pub fn into_raw(me: Self) -> NonNull { ManuallyDrop::new(me).ptr @@ -236,3 +246,128 @@ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a> unsafe { Pin::new_unchecked(inner) } } } + +/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and +/// [`ARef`]. +/// +/// # Examples +/// +/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with +/// [`ARef`] and [`Owned`] looks like this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// # use core::cell::Cell; +/// # use core::ptr::NonNull; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::sync::aref::{ARef, RefCounted}; +/// # use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // An internally refcounted struct for demonstration purposes. +/// // +/// // # Invariants +/// // +/// // - `refcount` is always non-zero for a valid object. +/// // - `refcount` is >1 if there is more than one Rust reference to it. +/// // +/// struct Foo { +/// refcount: Cell, +/// } +/// +/// impl Foo { +/// fn new() -> Result> { +/// // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is +/// // not actually a C-allocated object. +/// // INVARIANT: We initialize `refcount` to 1, satisfying the invariants. +/// let result = KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result = KBox::into_non_null(result); +/// // SAFETY: +/// // - We just allocated the `Self`, thus it is valid and we own it. +/// // - We can transfer this ownership to the `from_raw` method. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement each time the respective function is called and only free +/// // the `Foo` when the refcount reaches zero. +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.replace(self.refcount.get() + 1); +/// } +/// +/// unsafe fn dec_ref(this: NonNull) { +/// // SAFETY: By requirement on calling this function, the refcount is non-zero, +/// // implying the underlying object is valid. +/// let refcount = unsafe { &this.as_ref().refcount }; +/// let new_refcount = refcount.get() - 1; +/// if new_refcount == 0 { +/// // The `Foo` will be dropped when `KBox` goes out of scope. +/// // SAFETY: The [`KBox`] is still alive as the old refcount is 1. We can pass +/// // ownership to the [`KBox`] as by requirement on calling this function, +/// // the `Self` will no longer be used by the caller. +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// } +/// +/// impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef) -> Result, ARef> { +/// if this.refcount.get() == 1 { +/// // SAFETY: The `Foo` is still alive and has no other Rust references as the refcount +/// // is 1. +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// +/// fn into_shared(this: Owned) -> ARef { +/// // SAFETY: An `Owned` holds the unique reference (refcount 1), which we transfer to +/// // the new `ARef`. +/// unsafe { ARef::from_raw(Owned::into_raw(this)) } +/// } +/// } +/// +/// impl Ownable for Foo { +/// unsafe fn release(this: NonNull) { +/// // SAFETY: Using `dec_ref()` from [`RefCounted`] to release is okay, as the refcount is +/// // always 1 for an [`Owned`]. +/// unsafe { Foo::dec_ref(this) }; +/// } +/// } +/// +/// let foo = Foo::new()?; +/// let foo = ARef::from(foo); +/// { +/// let bar = foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// # Ok::<(), Error>(()) +/// ``` +pub trait OwnableRefCounted: RefCounted + Ownable + Sized { + /// Checks if the [`ARef`] is unique and converts it to an [`Owned`] if that is the case. + /// Otherwise it returns again an [`ARef`] to the same underlying object. + fn try_from_shared(this: ARef) -> Result, ARef>; + + /// Converts the [`Owned`] into an [`ARef`]. + fn into_shared(this: Owned) -> ARef; +} + +impl TryFrom> for Owned { + type Error = 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. + #[inline] + fn try_from(b: ARef) -> Result, Self::Error> { + T::try_from_shared(b) + } +} diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index f26ca39b84d0d..e6ffe7c650c39 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -23,6 +23,10 @@ ops::Deref, ptr::NonNull, // }; +use kernel::types::{ + OwnableRefCounted, + Owned, // +}; /// Types that are internally reference counted. /// @@ -35,7 +39,10 @@ /// Note: Implementing this trait allows types to be wrapped in an [`ARef`]. It requires an /// internal reference count and provides only shared references. If unique references are required /// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an -/// [`Owned`](crate::types::Owned). +/// [`Owned`](crate::types::Owned). Implementing the trait +/// [`OwnableRefCounted`] allows to convert between unique and +/// shared references (i.e. [`Owned`](crate::types::Owned) and +/// [`ARef`]). /// /// # Safety /// @@ -188,6 +195,13 @@ fn from(b: &T) -> Self { } } +impl From> for ARef { + #[inline] + 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.rs b/rust/kernel/types.rs index 5ef763717e59a..6aa760952cb63 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,6 +18,7 @@ pub use crate::{ owned::{ Ownable, + OwnableRefCounted, Owned, // }, sync::aref::{ -- 2.51.2