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 C9DDFC5516E for ; Fri, 20 Feb 2026 09:52:25 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 386586B0092; Fri, 20 Feb 2026 04:52:25 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 354526B0093; Fri, 20 Feb 2026 04:52:25 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 256FE6B0095; Fri, 20 Feb 2026 04:52:25 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 145596B0092 for ; Fri, 20 Feb 2026 04:52:25 -0500 (EST) Received: from smtpin16.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id D0A6C140B73 for ; Fri, 20 Feb 2026 09:52:24 +0000 (UTC) X-FDA: 84464369808.16.4ABE6C9 Received: from tor.source.kernel.org (tor.source.kernel.org [172.105.4.254]) by imf08.hostedemail.com (Postfix) with ESMTP id 1A7CB160007 for ; Fri, 20 Feb 2026 09:52:22 +0000 (UTC) Authentication-Results: imf08.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=RKSy6Ndf; spf=pass (imf08.hostedemail.com: domain of a.hindborg@kernel.org designates 172.105.4.254 as permitted sender) smtp.mailfrom=a.hindborg@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1771581143; a=rsa-sha256; cv=none; b=q4MKOQigXVyXjz+705K1oHrCFjfe37gT44gEr4/NQsuI6jl5sW0rUe3pz0mDKAkckBMhTq ZBwI2SVSGZfe96dfYUwPHvP13RBg4kCPE5BM7xroE30stfEk1DbZJhtEh2qUGHGQXXiyCu Od37DJXSJWnVwJq7rlBP03l1bdwtmaM= ARC-Authentication-Results: i=1; imf08.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=RKSy6Ndf; spf=pass (imf08.hostedemail.com: domain of a.hindborg@kernel.org designates 172.105.4.254 as permitted sender) smtp.mailfrom=a.hindborg@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1771581143; 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=c+GEowJDORYgDSGSLmZm3pqcbGViJEq48ny6/LxvDNI=; b=5/WRnMDuOJIIZDHwgMFTJfFGzmm/ZvjttKFBptt8ymecYByYnH+y6ozFWnthd0bMLWEFEC 0wuZJKVoF1bVAzxNF+SMPlfJ+jfKHQM+TccgYMY4tD195KbX7cYllO/ASXVI6TcjXYZXWl SZymZFNj93fJcec74E4W30PW2uAtwlo= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by tor.source.kernel.org (Postfix) with ESMTP id 848746184C; Fri, 20 Feb 2026 09:52:22 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id EC8BAC116C6; Fri, 20 Feb 2026 09:52:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1771581142; bh=h7Qzs2dunn+wg3aAaY3py9l1nvsdaskPimJWqJqhgnc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=RKSy6Ndf5g/d3iF10cr7qU9GA3dAzvE6yRcPhOX1hpStIChQIrjw7nQgKcZmt5+3P TibSAEtSJiXiQM1YSNytMSHxCIHwqhUR/w6jbDy+B+rTv6UetXQXZQiIpHS/6FzOjx inOgVbKYfxT1bwxlETsRyvf1Aiv34dlMJfeU389ZmcZUNNRnbAz8FNmGTMwynraHmU Tysy/+klBw1qaZlRGkvxm6n9B6E2eqaATPUOaQk40vYGEAuUBCcF3QZyKVUqFtzYoK g/esHuF2KDBNNs7WL2Py0+MBmv4SluexGcDi2gUC5mj+RPzuP35Po5MYP4LObjKAKc a7oGglzGFwdvg== From: Andreas Hindborg Date: Fri, 20 Feb 2026 10:51:14 +0100 Subject: [PATCH v15 5/9] rust: Add `OwnableRefCounted` MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260220-unique-ref-v15-5-893ed86b06cc@kernel.org> References: <20260220-unique-ref-v15-0-893ed86b06cc@kernel.org> In-Reply-To: <20260220-unique-ref-v15-0-893ed86b06cc@kernel.org> To: Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , "Rafael J. Wysocki" , David Airlie , Simona Vetter , Alexander Viro , Christian Brauner , Jan Kara , Igor Korotin , Daniel Almeida , Lorenzo Stoakes , "Liam R. Howlett" , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Boqun Feng , Boqun Feng Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, Andreas Hindborg , Oliver Mangold X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=10327; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=zcotFrEtdFYtqkneNkBZwYCdrxeK2+RRB4qJPSlD1DY=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpmC6irxNsgUEJMElTY4A222N7Or6D8uhpD50Ox weTgJRgPWyJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaZguogAKCRDhuBo+eShj d7vAD/0UpQQklci23qrfs3aXYOj+5817LSmZiQsn+zWunjLvs0tiOAF5R7rPMlRCPDz1ND3nnSP KeUVIf6+ULRMskvQCYVtXmxEtvOxhcxPYr8/3kQiKTVrXVv0mfjGMeo1FIcmoJ0GYqY1t5pM6HR KYyJuggbKa4Y8VLVJG63moXevMBV0B6FXFXIuSbc6nZMGTYhqaeOSAp/tmfO3z1u5qeY+YjwGRB J5Lu/LOkUR6uRakyHFiYRXTxPkA342V2L1ZSquJrl8uiBTSohjED99IHOK+yNQS5SqcqKei8Or6 ulKmeK3iKoY0XosxP0r4PdQGNAtyIbXEskYS0CDlWROoXZ56LEuGgqD/+A1fb3pO5Epr6VHgCLJ k33vlLk/h8K0xbpOw1HfM7pK5g5RS/lKuGgth9VN3IZbwqQZse+VMJoiamADB+LRFU/GXnmclOF TN/toq2c/7EVrje2XItX9jY5O9UGs0JRqRqLjMahG/ao9HNU+QxM/ZXpojIjJq2u4wRJ3FbCJXr tzGcnfSHlAau7CdGJcVXkVySkBkhE8Ag9+Hb4HL8Cd6zrJg0FoPXuqrHPurXqJDTQUlMgn1lve9 GjpSJNUrl33zzhRcwDh8E+5i9tGM9HitJY7w43VP0ASSV5qiwb2HXfBYmVW0aJsmH3Np6VgQotb 6gDfp1VkSFYzgOQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 X-Rspamd-Queue-Id: 1A7CB160007 X-Stat-Signature: jgkht3ftgwhme5attc375g8kihshbggq X-Rspam-User: X-Rspamd-Server: rspam04 X-HE-Tag: 1771581142-252326 X-HE-Meta: U2FsdGVkX1/CLP4CTgSFiR/uy2lBswSyNNGbFRsZy5HzcxB6gRuhXjSn0/ZSfZDFFpO/pskacY+AtBH9KO3nitU4j29YH3TM8ZaFBxv1L76VRlrKIvy6xqcnJJhsYfKRlBchqsTIGBUooDA5HhpUoT+pLpSTSo1W/L8qtt+5yH5Rtu8TTbE6qg/EF4Tpcs03w5qSgTWht08hgK4h3ha5+8j8EFj8Dwigjl6ezVAQ12VXRKtyiv6DS1Q+mnAH0icmlrHAh82zyCBxCmKgTeUGqg/GbRmMDAM7Ndb6vnbFs3n6f3kzBcBwB0phx5NacLmFpOHJUAoYbakV+gzzFskKcrbC4ufOrYLu8BF8v5a7TU8u4pYGO0F2/mOa6qxqNC3qcQsY8jp2kM8pu9/Y1If2CY+QutyYU9VsQgLYYx4Mnxo/koLddIiCkF9KORYaSfwaKSR2YhPTGDtpJ75md5UifsbB507gKTtkYNr789K5Ur179P9O0uJy5qxXOGoGQWS3/Re+dQ0w9mxWi3oBs374eiRqXhw/AqTaUk4EZ2wxmmDLN6vDYknlpAlEsotGPZM9svkZHZUmdEfV8g9r03HozDiSHNXwCQNjJAKQbTiHkByAG7iC6bVS1UYa34qrR/dxxkbaDIvlBO/caddpztp4mzAc9p2Uc3wtmL2VedTUXfyPt8nGuEcuFxJrjv9ZlkrpZt5KtUBN3eaXurP+1idTaZFtebmUrdCRlmjc+53joBtqVuNoryas3IkSKggIJKqupqXJ8o/jiHXPc0XfOmVplfbKxi1eDwQj9BzGGGQkO3n8hHTyZoavGNHaWTAeAWab3Mu/LTULvqBvNtJZfaP3OPGOu27EQar9D2ZKTKzTBMAR8ZAfI9nGUaduT9iTcwN+VvKlMLsy9x7malYi9M+xZI5D72LqoW9KOV9DNrPfa196cJ5BO0hVvWY6jPS10BdIUW2vvUykeMp3oOPJRXI zwNHzGw8 NPK3m3kUk7k+iQy8V5ogbddhW5nJCe5NAzxQKtGW1+0DMo6D+SWFuMsbx84hnnwTfrxeEiV++oTdnG1SySwVCnWor45WkB+kc04YB5MJR4FK2O0IJCpIEgiUD1vT3SsuXsPHitDqtIkODle5b8MdtUx9asWcDIUkmWfYUEjEsViF3V+t8c+MuDrln4QHeuyD7CBW3FDC9uptZt3UJFDoG16PRfEUMqomRHCtMM/m5M2Lckp4Uo4tCNcghdSagCvrv1lfeMVda0Zpt+AK/ChkhkSlY+VwdrhaCPIGbVBoPZLM7er4JXKPXPn/cXlEhdABiVK/d X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 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 | 143 ++++++++++++++++++++++++++++++++++++++++++++--- rust/kernel/sync/aref.rs | 15 ++++- rust/kernel/types.rs | 1 + 3 files changed, 150 insertions(+), 9 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index b8d3b9c725cf6..a9bc871e07ce1 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -14,18 +14,24 @@ pin::Pin, ptr::NonNull, // }; +use kernel::{ + sync::aref::ARef, + types::RefCounted, // +}; /// 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. /// /// # Safety /// @@ -63,8 +69,7 @@ /// Foo {}, /// flags::GFP_KERNEL, /// )?; -/// let result = NonNull::new(KBox::into_raw(result)) -/// .expect("Raw pointer to newly allocation KBox is null, this should never happen."); +/// let result = NonNull::new(KBox::into_raw(result)).ok_or(ENOMEM)?; /// // Count new allocation /// *FOO_ALLOC_COUNT.lock() += 1; /// // SAFETY: We just allocated the `Self`, thus it is valid and there cannot be any other @@ -88,11 +93,12 @@ /// } /// /// { -/// let foo = Foo::new().expect("Failed to allocate a Foo. This shouldn't happen"); +/// let foo = Foo::new()?; /// assert!(*FOO_ALLOC_COUNT.lock() == 1); /// } /// // `foo` is out of scope now, so we expect no live allocations. /// assert!(*FOO_ALLOC_COUNT.lock() == 0); +/// # Ok::<(), Error>(()) /// ``` pub unsafe trait Ownable { /// Releases the object. @@ -194,3 +200,124 @@ fn drop(&mut self) { unsafe { T::release(self.ptr) }; } } + +/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and +/// [`ARef`]. +/// +/// # Examples +/// +/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with +/// [`ARef`] and [`Owned`] looks like this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// # use core::cell::Cell; +/// # use core::ptr::NonNull; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::sync::aref::{ARef, RefCounted}; +/// # use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // 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. +/// let result = KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result = NonNull::new(KBox::into_raw(result)).ok_or(ENOMEM)?; +/// // SAFETY: We just allocated the `Self`, thus it is valid and there cannot be any other +/// // Rust references. Calling `into_raw()` makes us responsible for ownership and +/// // we won't use the raw pointer anymore, thus we can transfer ownership to the `Owned`. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement each time the respective function is called and only free +/// // the `Foo` when the refcount reaches zero. +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.replace(self.refcount.get() + 1); +/// } +/// +/// unsafe fn dec_ref(this: NonNull) { +/// // 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) +/// } +/// } +/// } +/// +/// // SAFETY: This implementation of `release()` is safe for any valid `Self`. +/// unsafe 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 mut 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 { + // SAFETY: Safe by the requirements on implementing the trait. + unsafe { ARef::from_raw(Owned::into_raw(this)) } + } +} + +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. + 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 3c63c9a5fb9be..77f6c8dc411eb 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`](crate::types::Owned)). /// /// # Safety /// @@ -185,6 +192,12 @@ fn from(b: &T) -> Self { } } +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.rs b/rust/kernel/types.rs index 9b96aa2ebdb7e..f43c091eeb8b7 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -14,6 +14,7 @@ pub use crate::{ owned::{ Ownable, + OwnableRefCounted, Owned, // }, sync::aref::{ -- 2.51.2