From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 BE54E3C9ED5; Thu, 10 Sep 2026 09:02:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030955; cv=none; b=nWjVHlIYupapATZPcZaDu3r3XAycvBCvmyrT9WtkKb51nr5242wAjbh/Ta4wEWZC9O0QNukj+7wK4WHxo3VQEnc48R5QYp0xUPDn5730fchLzywBJ0LQd+IAWtrYQN6KW1fNbcOroVMYByzAlk2uijBC1XxECY5yaZWp7AnCSPg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030955; c=relaxed/simple; bh=WHW93VvrHeXgOCjNosfBMI4vPnTOHHkUoJXKjGlJMdY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hFlmSFtP82uGRHKtPxj/xTkKkKdPliRU+4zg6b9afpduo9ddj9rk6nc8EkrcdNqJhbpxBN8Vd2AyoO7dq7LDEJei4DkNv9ipr/mdOOzcP3C3Nq44F3NPcDcgujRpWw5sYBGE8hH8fsLV6MpHSH8PA0gbrGwR5TQs1Rr1+jDQE9I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=If5M6sRe; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="If5M6sRe" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA4011F00893; Thu, 10 Sep 2026 09:02:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030954; bh=bi6HQbpS7WbVT11MZapyDiTA6f2yGohKV5fr13xqRJc=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=If5M6sReucxfAa8nllZsBD5rzyKL9ELmN7J++KhzVHXMFwuo+ywIXweYK0qHvKt73 1DlZC6yieZdrctVpoPbK8xAnJ01MqKDgn8JNOrREKfLrtY3kuk1QD0WFmmwZvIkpKc cjwQhwi6gfGiK1mJpr70MGacbhPTAkvMJSrfODwcnkW7h00u9xgR6Tozex936pATmf Y/e3g5Q+e44jwwElZlmy2drakal4M8C3ZYhzWEtU1LZSzTfNXyLU3yRFX7wXmiz5xW ThtO/NXMID8mQwyR1hAETqMn3NvdBwCEMEnIpbQLdGFzMn0iPU5Qgbppp1CAYsoqRp rYXsEVBqyS45Q== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:05 +0200 Subject: [PATCH v21 1/9] rust: alloc: add `KBox::into_non_null` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-1-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1188; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=WHW93VvrHeXgOCjNosfBMI4vPnTOHHkUoJXKjGlJMdY=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGhYtutHmW3K5/iWt2PtNR0EOOEvKOh8GOE3 cAXhRn6VpqJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxoQAKCRD6UCkIqsW9 0PiAEAC1ZaUVBOkvlRXYa1uoG7fv8BkX7iuoYs3OUE6Xs7RBS7CbugsVYpLdGgml2yB5Xo/AfF1 lOrJHP03TKEIawI0QIjvbDUNXrYGXND3iwPfW4oW9EKyBDMM7aQlMGM2ptkYJDcGzux3kw7pAqx zYjptUpVSESYUlKv7c6+bSMK1AeydAw1bt04eyJrzPRMgus+QTTFKWMkFU2w4n/A2Vybuz6QDSb +gMpzM9B3XcB5EYFx92khT1NMRiQsSRHxCc54Ro6JbS9nA7SFf4X1SRG2ZwFwEYJQw4+P2eXu/B kn8z2qUOFN7+DY5TEDT7kwV+OE7FFgKaMjSOLZh48VmeDrw9fYdtqIKT7xIuy1KqplTIuTjsNpb Iy++9Nqzy8yEHUWDqdzclvjSepDS5DSFpG5VMDldAC4AENbijZpOJVJwq41LMojHASK+t1NsF2T t6P+wfaQTuumBObShygOAi7WRMKfgFIBmoMisdn0c5sE+W1UPIzdRH53GVM7b8aY6Q+rsRPEu32 rNoYVKX1ZCSGlH/Cai+CxLnb58kRzvOkj9jCMjG804rAMG2AgG+ExQoP1ymqRN4D8kik1NLlEy3 5yp5HL4qYcm91XRinv0cXg5icrFwfKuSpkpNl0UuMdJs9OSwTJV3P5cjHJpDbgZcd/sKdO+4yNt KzVWbdwXn+Hi8TQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add a method to consume a `Box` and return a `NonNull`. This is a convenience wrapper around `Self::into_raw` for callers that need a `NonNull` pointer rather than a raw pointer. Assisted-by: LLM Signed-off-by: Andreas Hindborg Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo --- rust/kernel/alloc/kbox.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index c63d6acdbb6f9..27c31120c3854 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -211,6 +211,15 @@ pub fn leak<'a>(b: Self) -> &'a mut T { // which points to an initialized instance of `T`. unsafe { &mut *Box::into_raw(b) } } + + /// Consumes the `Box` and returns a `NonNull`. + /// + /// Like [`Self::into_raw`], but returns a `NonNull`. + #[inline] + pub fn into_non_null(b: Self) -> NonNull { + // SAFETY: `Box::into_raw` returns a valid pointer. + unsafe { NonNull::new_unchecked(Self::into_raw(b)) } + } } =20 impl Box, A> --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 A14F03E0724; Thu, 10 Sep 2026 09:01:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030918; cv=none; b=AdnCUG70zoNb59dmSk+5NLPUnemyVu8b/gkKeaKpsIyWZeNhZrOu8UWirL2vp0dFQr8AAmplrrPILNgOnmTfartaqxf15o7MFXLXYwgOl9PKM5vOZ1mB3PeN6n/TnYBpqsgZHSQZaMATtOplVzts7BaoQ8WfdctLGo6meaNaR+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030918; c=relaxed/simple; bh=fY1ZeofKGZP0R0vybxeg1uDiO6Ilyw3mZ+JLjl5dn54=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hMkeQdKnKm7IoXV1/jvdJyCp/wUr0usc9moye+CnMWxRdWlMK2C6+OW4BNOzsKpYpVQowLi1EO4HknbGd7F4t/UgWCA46Odh3L9+YX+IuHfP0urOz7gktww2aYDSCTksAs8hb1EEYCkdtV37pzAVqo9QxiruziQPGPgzYrEY8/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QZWIIJTB; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QZWIIJTB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ECBD01F00898; Thu, 10 Sep 2026 09:01:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030907; bh=oG+KGaYcq/LrlTcZix6QO2VK530O5ka3Rs0mLGMUdtQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=QZWIIJTBzOkomxOJZk4c4zQ6MbJ0v3zPVJsPyIuRa5nV8nkbTJBgQpOwM6+eKWDwW NIWYg6lV2Rf5Pcf6Pwsk5vA7Bnybe4Z/p1arxTLXuDwSTp7ObNfBVWkf25B42ubZce JrYPgyGaiekosD4Cy4w3kQ+Ejq2uGfF+t5K5fY4jehr1pcWgw01Bo7i5DKJ89VCQBq 1U5UvB+GTawRXP7F4cSCrCWgzFN4cUfTBj1zVNVzwWOWYbhjvwp1D0bX4ipRzQg2fy Cb1rf4aYJxmh5rD4NiKaw1gkePmSaDBPnQ1+iuziDYde8t8lE4IiJk4cFdmmF0wDZW P7A4dDPt+2HAA== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:06 +0200 Subject: [PATCH v21 2/9] rust: types: Add Ownable/Owned types Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-2-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org, Asahi Lina , Oliver Mangold , Boqun Feng X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10889; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=qRWbwqK7TEegrbGW6xNA+C4LOYo7zhHcjmaxGwUnwrg=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGiPIkyRWHCPutOl1uLHFVvk9aNknONcu/+h iyukNOXlNSJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxogAKCRD6UCkIqsW9 0H2iD/94uZ+/2TTsjRDkp3mW4k6lM7pFW3XrwqmAvOnTUTZu/fd9IR+QhzSO8P2RZPMZqzu8cx4 D3OG/kExKrOKXYWb47NgduXUNtewyvIqQXlilx3UEhqXJ5+xwCqUlVVCsP7Od++epay7sGzPEgn RxcDpya/PX6yICJqUwI6DsvXvELp1E+2v8nknLgxh3Y0VZ1h/NE9FiEiV/2FggB4h61WOLJBeOY SKuAuBoyNmbBcGZaisPKZJUx0BW2OE22xQk4bcdv2oZA3VLB9g0/oIyGPtMCzTWzjZHTjQ9eYYs 3j+VB8hdgVG65zWngPJg2B5Ul7vEimDMz6T+FH517CAa79TxRWznfwe1F2L6wZMEYQEO7otFeOj 2O54Q2K6QyMj8fS/7KS/28tShfTswvS0a5PJnlcCm8vn3lHACVaRzDvutvcRAONo8XGwQXigoLv freczsK+iGeY3gRKwCvDOI2a6IfsQ/RsGxLxu92NY25A7R2V+iq/27kN1cSgdt9vtMlEf4dHhvH 0tQQmqrPVS5arR6l1vNiHgS7zxs6Jj3NMgks8mDrpeC9BWMASWH8ITGec0I1lVE8BohTBTKKTO2 CbXcw0QSI72C1tEGpi1JeTVLI45hI+Tp1POlcHXChhpsycUTtb0Vuy/zMUXfdjDDjpr33ehawQ7 h3SAu2vbn0U7HRg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 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. [ om: - Split code into separate file and `pub use` it from types.rs. - Make from_raw() and into_raw() public. - Remove OwnableMut, and make DerefMut dependent on Unpin instead. - Usage example/doctest for Ownable/Owned. - Fixes to documentation and commit message. ] Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asah= ilina.net/ Signed-off-by: Asahi Lina Co-developed-by: Oliver Mangold Signed-off-by: Oliver Mangold Reviewed-by: Boqun Feng Reviewed-by: Daniel Almeida Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl [ Andreas: Updated documentation, examples, and formatting. Change safety requirements, safety comments. ] Assisted-by: LLM Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/lib.rs | 1 + rust/kernel/owned.rs | 191 +++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/sync/aref.rs | 5 ++ rust/kernel/types.rs | 5 ++ 4 files changed, 202 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 4d5c96ddc49c..bcacd03c67a6 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -108,6 +108,7 @@ pub mod of; #[cfg(CONFIG_PM_OPP)] pub mod opp; +pub mod owned; pub mod page; #[cfg(CONFIG_PCI)] pub mod pci; diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs new file mode 100644 index 000000000000..b76edd7c4151 --- /dev/null +++ b/rust/kernel/owned.rs @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Unique owned pointer types for objects with custom drop logic. +//! +//! These pointer types are useful for C-allocated objects which by API-co= ntract +//! are owned by Rust, but need to be freed through the C API. + +use core::{ + mem::ManuallyDrop, + ops::{ + Deref, + DerefMut, // + }, + pin::Pin, + ptr::NonNull, // +}; + +/// Types that specify their own way of performing allocation and destruct= ion. Typically, this trait +/// is implemented on types from the C side. +/// +/// Implementing this trait allows types to be referenced via the [`Owned<= Self>`] 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 obje= ct is dropped. +/// +/// Note: The underlying object is not required to provide internal refere= nce counting, because it +/// represents a unique, owned reference. If reference counting (on the Ru= st side) is required, +/// [`AlwaysRefCounted`](crate::sync::aref::AlwaysRefCounted) should be im= plemented. +/// +/// # Examples +/// +/// A minimal example implementation of [`Ownable`] and its usage with [`O= wned`] looks like +/// this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// # use core::cell::Cell; +/// # use core::ptr::NonNull; +/// # use kernel::sync::global_lock; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::types::{Owned, Ownable}; +/// +/// // Let's count the allocations to see if freeing works. +/// kernel::sync::global_lock! { +/// // SAFETY: we call `init()` right below, before doing anything els= e. +/// unsafe(uninit) static FOO_ALLOC_COUNT: Mutex =3D 0; +/// } +/// // SAFETY: We call `init()` only once, here. +/// unsafe { FOO_ALLOC_COUNT.init() }; +/// +/// struct Foo; +/// +/// impl Foo { +/// fn new() -> Result> { +/// // We are just using a `KBox` here to handle the actual alloca= tion, as our `Foo` is +/// // not actually a C-allocated object. +/// let result =3D KBox::new( +/// Foo {}, +/// flags::GFP_KERNEL, +/// )?; +/// let result =3D KBox::into_non_null(result); +/// // Count new allocation +/// *FOO_ALLOC_COUNT.lock() +=3D 1; +/// // SAFETY: +/// // - We just allocated the `Self`, thus it is valid and we ow= n it. +/// // - We can transfer this ownership to the `from_raw` method. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// impl Ownable for Foo { +/// unsafe fn release(this: NonNull) { +/// // SAFETY: The [`KBox`] is still alive. We can pass owne= rship to the [`KBox`], as +/// // by requirement on calling this function. +/// drop(unsafe { KBox::from_raw(this.as_ptr()) }); +/// // Count released allocation +/// *FOO_ALLOC_COUNT.lock() -=3D 1; +/// } +/// } +/// +/// { +/// let foo =3D Foo::new()?; +/// assert!(*FOO_ALLOC_COUNT.lock() =3D=3D 1); +/// } +/// // `foo` is out of scope now, so we expect no live allocations. +/// assert!(*FOO_ALLOC_COUNT.lock() =3D=3D 0); +/// # Ok::<(), Error>(()) +/// ``` +pub trait Ownable { + /// Tear down this `Ownable`. + /// + /// Implementers of `Ownable` can use this function to clean up the us= e of `Self`. This can + /// include freeing the underlying object. + /// + /// # Safety + /// + /// Callers must ensure that they have exclusive ownership of the `Sel= f` pointed to by `this`, + /// and that this ownership is transferred to the `release` method. `t= his` must not be used + /// after calling this method, as the underlying object may have been = freed. + unsafe fn release(this: NonNull); +} + +/// A mutable reference to an owned `T`. +/// +/// The [`Ownable`] is automatically freed or released when an instance of= [`Owned`] is +/// dropped. +/// +/// # Invariants +/// +/// - Until `T::release` is called, this `Owned` exclusively owns the u= nderlying `T`. +/// - The `T` value is pinned. +pub struct Owned { + ptr: NonNull, +} + +impl Owned { + /// Creates a new instance of [`Owned`]. + /// + /// This function takes over ownership of the underlying object. + /// + /// # Safety + /// + /// Callers must ensure that: + /// - `ptr` points to a valid instance of `T`. + /// - Until `T::release` is called, the returned `Owned` exclusivel= y owns the underlying `T`. + /// - The `T` pointed to by `ptr` is treated as pinned from this call = on: unless `T: Unpin`, it + /// must not be moved for the rest of its lifetime, including after = the pointer is recovered + /// with [`Owned::into_raw`]. + #[inline] + pub unsafe fn from_raw(ptr: NonNull) -> Self { + // INVARIANT: By the function safety requirements, we have exclusi= ve ownership of the `T` + // and the `T` is treated as pinned, satisfying both invariants of= `Self`. + Self { ptr } + } + + /// Consumes the [`Owned`], returning a raw pointer. + /// + /// This function does not drop the underlying `T`. When this function= returns, ownership of the + /// underlying `T` is with the caller. + #[inline] + pub fn into_raw(me: Self) -> NonNull { + ManuallyDrop::new(me).ptr + } + + /// Get a pinned mutable reference to the data owned by this `Owned= `. + #[inline] + pub fn as_pin_mut(&mut self) -> Pin<&mut T> { + // SAFETY: The type invariants guarantee that the object is valid,= and that we can safely + // return a mutable reference to it. + let unpinned =3D unsafe { self.ptr.as_mut() }; + + // SAFETY: By type invariant `T` is pinned. + unsafe { Pin::new_unchecked(unpinned) } + } +} + +// SAFETY: It is safe to send an [`Owned`] to another thread when the u= nderlying `T` is [`Send`], +// because of the ownership invariant. Sending an [`Owned`] is equivale= nt to sending the `T`. +unsafe impl Send for Owned {} + +// SAFETY: It is safe to send [`&Owned`] to another thread when the und= erlying `T` is [`Sync`], +// because of the ownership invariant. Sending an [`&Owned`] is equival= ent to sending the `&T`. +unsafe impl Sync for Owned {} + +impl Deref for Owned { + type Target =3D T; + + #[inline] + fn deref(&self) -> &Self::Target { + // SAFETY: The type invariants guarantee that the object is valid. + unsafe { self.ptr.as_ref() } + } +} + +impl DerefMut for Owned { + #[inline] + 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 { + #[inline] + fn drop(&mut self) { + // SAFETY: By existence of `&mut self` we exclusively own `self` a= nd the underlying `T`. As + // we are dropping `self`, we can transfer ownership of the `T` to= the `release` method. + unsafe { T::release(self.ptr) }; + } +} diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index 9983ee085248..1876e40c76df 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -39,6 +39,11 @@ /// 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`](crate::types::Ownable) should be implemented which allows = types to be wrapped in an +/// [`Owned`](crate::types::Owned). +/// /// # Safety /// /// Implementers must ensure that increments to the reference count keep t= he object alive in memory diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 132dd428c1f6..b23e1d60cdd6 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,6 +18,11 @@ ForLt, // }; =20 +pub use crate::owned::{ + Ownable, + 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 --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 12F6F423E8B; Thu, 10 Sep 2026 09:02:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030933; cv=none; b=rLXLOinsFpXb33Kx1jIhRhkliKKvoNLF7jJGDA23cdB4G0yumUQv/YTRDE7fbLktjXLcqejXF6Q7RiDzNBGx3UKB5A6GFc+DX6QTLJsTXcfir8Iyog1cs8BjKCwX9Twj7JTsGK1f94mrEZGaaca+KTHDfKPWxUxnzpG8nMb6eOI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030933; c=relaxed/simple; bh=O2wzGYJMYAkc/T2itapqXFBmX/u7K5ttf1JgBR/HfM0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=J6bu7CD7NCMqy64DQMDu8xet3LBz0CFGVs857Ask7ZCmAVwgV/m1fcrTVg9t7h95W/md2lcK5dhqPuJ2p82cffqa8h7ZrjqzxO0JsJrKhXQv7wyh3TiZlovrBmF81oabzxPDydBcXaAY9633cCjigpLpBqljRpaOzZNki8Qw9Yc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jZe2GdwO; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jZe2GdwO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B707A1F00893; Thu, 10 Sep 2026 09:01:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030930; bh=nMuMfZ5oOT5xSQNE2UbnqHDsN16Vf+j3KeZtRcXbj5Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=jZe2GdwOlAtK2Y/DOgIkQVr++reMQhah0vlgv6xXz1IeuoFD6LxcNE0jRYaUZrkqr Nh4Kfb6H0sjZ/vWlR09a9d/t7FmyuRr5lwq8BQQpuWgwcbSBs3gYCszxCc6opuexwl rI12KdSLv4BUZH0JjgRbkTrNcz2peyBAc2gL6KF7JEyYm2WT32wELiGPU/hSO0w/Hi YQ0/qtRVZxZCkxXNXHXP/2x8/msUwDKOJH+kwguKlwEyCxrLfIdng7SiuzDxmJYWQE FHq/Vv64FeSeWdF1pQvfMfjuR90V4qVR8eWlUfgzF++JnUnK0avT4qUXVkZmXXpudm 5kRP7FdZovV8w== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:07 +0200 Subject: [PATCH v21 3/9] rust: implement `ForeignOwnable` for `Owned` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-3-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2790; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=O2wzGYJMYAkc/T2itapqXFBmX/u7K5ttf1JgBR/HfM0=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGjQYuzzLPzVcDFmo/+nPkuUnB8xRZWr6uP/ wqulSxov86JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxowAKCRD6UCkIqsW9 0AeWD/4xQAImVQJWGybdMjjzNA5J/mQ//XrWd8nl0WREOfKnkBJ5A44YG9C3TPFyt5i++gERKuU cfW3tb2jUIisOMF9GnvwnRpDoGb36Wfz0h2an+YSgiEzrFpsE3tK6u4RI4TF9GAx6YMnuqXjNiF 0Vfl8fQjrSZxR2Ym5O3DIZjCrwYtOVdDxpygxWu6TKL0pdI6vq+LKduP9hqXBhOUPlRgaVgNiBL 97Ggf0jMjmag0lqML/jN10MQFyLATAWhQnxJDAsRMLL5cctk0xrQQX4U1bV67D/NPS2gOtyb9ny RS6v6yaTlmmrF+xfuO5k4ZlKJ8/Q+XNI6HqEHYFCg8KUG0FPZoOfW5bbL40whtN9cqBHyu0uTvc GKWLJxaizTo0hqfGi196tFw0K76kzTRS5IVr/jrGkdsVO9Z7aFICi8t4DRqehZOiLqa8/Kgc1qS fz2gm5J/3wBIHTS5EtZSWUcuXYB6p9u1UcuiKVmt0hPcd2kVOonaHsn2oF2cgKeWG2LAtTlQE/j iOtBj660fPiupzl1yKm+ulg9UvkMrWGYJUwQJ0SdwOS/2wd4SgSrdOqyiDCCgu1VoVHxAPa4eBc gd/3hd5BB9l/mZO25TBpArMYuKfUECI2bGD/Rz1k6Cr/KkOdqTw2QInQHRguGnD2w6NXoeJTqQx Wg1ZeU9c+ANsrIw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Implement `ForeignOwnable` for `Owned`. This allows use of `Owned` in places such as the `XArray`. Note that `T` does not need to implement `ForeignOwnable` for `Owned` to implement `ForeignOwnable`. Assisted-by: LLM Signed-off-by: Andreas Hindborg Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl --- rust/kernel/owned.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++= ++ 1 file changed, 50 insertions(+) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index b76edd7c4151..e54a058d65cd 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -15,6 +15,8 @@ ptr::NonNull, // }; =20 +use kernel::types::ForeignOwnable; + /// Types that specify their own way of performing allocation and destruct= ion. Typically, this trait /// is implemented on types from the C side. /// @@ -189,3 +191,51 @@ fn drop(&mut self) { unsafe { T::release(self.ptr) }; } } + +// SAFETY: We derive the pointer to `T` from a valid `T`, so the returned +// pointer satisfy alignment requirements of `T`. +unsafe impl ForeignOwnable for Owned { + const FOREIGN_ALIGN: usize =3D core::mem::align_of::(); + + type Borrowed<'a> + =3D &'a T + where + Self: 'a; + type BorrowedMut<'a> + =3D Pin<&'a mut T> + where + Self: 'a; + + #[inline] + fn into_foreign(self) -> *mut kernel::ffi::c_void { + Owned::into_raw(self).as_ptr().cast() + } + + #[inline] + unsafe fn from_foreign(ptr: *mut kernel::ffi::c_void) -> Self { + // SAFETY: By function safety contract, `ptr` came from `into_fore= ign` and cannot be null. + let ptr =3D unsafe { NonNull::new_unchecked(ptr.cast()) }; + + // SAFETY: By the function safety contract, `ptr` was returned by = `into_foreign`, which gave + // up exclusive ownership of a valid, pinned `T`; we retake that o= wnership here. + unsafe { Owned::from_raw(ptr) } + } + + #[inline] + unsafe fn borrow<'a>(ptr: *mut kernel::ffi::c_void) -> Self::Borrowed<= 'a> { + // SAFETY: By function safety requirements, `ptr` is valid for use= as a + // reference for `'a`. + unsafe { &*ptr.cast() } + } + + #[inline] + unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::Borro= wedMut<'a> { + // SAFETY: By function safety requirements, `ptr` is valid for use= as a + // unique reference for `'a`. + let inner =3D unsafe { &mut *ptr.cast() }; + + // SAFETY: We never move out of inner, and we do not hand out muta= ble + // references when `T: !Unpin`. + unsafe { Pin::new_unchecked(inner) } + } +} --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 DF3B73DD536; Thu, 10 Sep 2026 09:01:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030900; cv=none; b=ePyorE9Lc7nNI4raqO/z8/fGsyfRRaQNf28grgw7zzLHsEftgwwRIkHw9D3h6QPZGvzH0zicw+BUxDXwiUpp1t2ga3S7v5zwr370w22WBOiJT+YW2TeOA7hihifl1SbPIw4zEP8HzC/ZtfeJzKoqqjnfsIlgbiix8xmUvmk6JeI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030900; c=relaxed/simple; bh=1tqqvpjhx2OAkbG5Ud8PXC1RlcxT7MiBvIOm0S/0LEc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mwxVhpIETJQBTMEDTxSXRQHhUVtLtI+n4Pev2+3ouhuNZyzlCrgKGVJRewdKB8dz4igqtn7uhyEe7lRO5qcLjBU5ppBNE0yRbmSqicPS/LBhNFrbLDCG1Qc9paR8mCEZfCVFa3zRakHTp2X+xo5bbBaCieITId/nt/d0R2qjKNA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GF1FkrFn; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GF1FkrFn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D13671F000FF; Thu, 10 Sep 2026 09:01:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030884; bh=N69w1tIguM4Hdt3qM0oLkhXCHVLtaEMP44Mm/RQY1Zg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=GF1FkrFnxAT7x6BK1dDA+qo5edpg5Nk47WyU/PKWiun+EClOPNwi1TKmUrDZf3glN aYDyx1KKcEpJivX9ZgElDG53kTLbBeLYiJxBZLvW9A5xk3mQe2ztGBElTSxpq89ypd F7SwZ9Nbkd0rSizMV3OaAoq4M4AsBD5saf8ljXnn1cMm9Q9dTByJgcXhYNizXo1fNe SwqSLVSo9KeUllZUT3GVAiLQ3En682WxMcGSFlbd600Ds5w6u0u1/gzduJtzaQTTSz /ToVT9l1iJz4EcjHlF/ETFeIMlH/Dz/p+VtsadspesWPskM0EVLWfQPr9tupkXRDch cdX/CkmqC+nUA== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:08 +0200 Subject: [PATCH v21 4/9] rust: rename `AlwaysRefCounted` to `RefCounted`. Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-4-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org, Oliver Mangold , Viresh Kumar , Igor Korotin X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=41983; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=tMZps0y09d+eieqOpxKg/yZV3IVQ5wWryLvjLCJUoVY=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGk8fQumjiA5S7esSKkgrQ0orD4jJmjhd6Xd 9bHZtUQRWWJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxpAAKCRD6UCkIqsW9 0PrpEACFGIgkRYkA9AfeeGmaGAdH5BswkSPC8MX2zpsyFGlbM9X0m7dE9isReY5LDd8sN/jbgs6 VcTAT3uw/Ax6yLreQ4WoMD+R2v3XsnmOu28/zBn7bB08fg261rSlK7mvvNNkvNhWvut2rP2I1ww W8Dz+Ay6/WMPcC+PkGini3oT2IDBf2OA0CTNfq5qFFvRx/RbMqSD8Jx1dVxY2NI1Cu7HvmJeBSr +wM1JclmuXQafDeaSLH/rDFyLBZd/ZcFkpusaJ/u9+zZNDC/r+0wFbUFXl3n0syt4u1GQgI3dcJ Fv/Ml6dibFvXoFET4JGp4K85yIrEbcdcQZ35qYxFzBPCXtP1M/NphvvWgUth8VNwB5QZh946wXD l7XKBjWba2BeLszuxxnZVNKPtHsLPfC+M+jrsAqM6fgBsy5n/lvJjHe94Pu/j/VAFG3BYOJZ8St WZ+qEUWaxdOeuKtm9O0Pr+a3e2lbn8wndkjLZ0q4BxOedivLLeNUNWeRMB+Kldqm2Oxd91WeTGj mjo+SqeEKGGV7Kjd9C2cA3I58fUzyWj8xijwP9FfBlHnpCReBFLGd9X9DBdgf9mTL7bm99kx2SV 793hOT0uFIf52A6xn60pMlsENB0RWMbxuN9FT5DnOVvRHyTbn3wMZH7SimYLYyR4zFMwVnTrObJ KcFGrCmVreJCzMw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Oliver Mangold There are types where it may both be reference counted in some cases and owned in others. In such cases, obtaining `ARef` from `&T` would be unsound as it allows creation of `ARef` copy from `&Owned`. Therefore, we split `AlwaysRefCounted` into `RefCounted` (which `ARef` would require) and a marker trait to indicate that the type is always reference counted (and not `Ownable`) so the `&T` -> `ARef` conversion is possible. - Rename `AlwaysRefCounted` to `RefCounted`. - Add a new unsafe trait `AlwaysRefCounted`. - Implement the new trait `AlwaysRefCounted` for the newly renamed `RefCounted` implementations. This leaves functionality of existing implementers of `AlwaysRefCounted` intact. Suggested-by: Alice Ryhl Reviewed-by: Daniel Almeida Signed-off-by: Oliver Mangold [ Andreas: Updated commit message and rebase on rust-next (7.2) ] Acked-by: Igor Korotin Acked-by: Danilo Krummrich Acked-by: Viresh Kumar Reviewed-by: Gary Guo Assisted-by: LLM Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/auxiliary.rs | 10 ++++++- rust/kernel/block/mq/request.rs | 19 ++++++++----- rust/kernel/cred.rs | 16 +++++++++-- rust/kernel/device.rs | 12 +++++++-- rust/kernel/device/property.rs | 11 ++++++-- rust/kernel/drm/device.rs | 9 +++++-- rust/kernel/drm/gem/mod.rs | 16 ++++++++--- rust/kernel/drm/gpuvm/mod.rs | 9 +++++-- rust/kernel/drm/gpuvm/vm_bo.rs | 6 ++++- rust/kernel/fs/file.rs | 23 +++++++++++++--- rust/kernel/i2c.rs | 13 ++++++--- rust/kernel/mm.rs | 22 ++++++++++++--- rust/kernel/mm/mmput_async.rs | 12 +++++++-- rust/kernel/opp.rs | 16 ++++++++--- rust/kernel/owned.rs | 2 +- rust/kernel/pci.rs | 10 ++++++- rust/kernel/pid_namespace.rs | 15 +++++++++-- rust/kernel/platform.rs | 10 ++++++- rust/kernel/pwm.rs | 12 +++++++-- rust/kernel/sync/aref.rs | 59 +++++++++++++++++++++++++------------= ---- rust/kernel/task.rs | 13 +++++++-- rust/kernel/types.rs | 12 ++++++--- rust/kernel/usb.rs | 17 +++++++++--- rust/kernel/workqueue.rs | 8 +++--- 24 files changed, 272 insertions(+), 80 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 60dfbec8f3302..52e86ccdb0caa 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -19,6 +19,10 @@ to_result, // }, prelude::*, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::{ CovariantForLt, ForLt, @@ -376,7 +380,7 @@ unsafe impl device::AsBusDe= vice for Device kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::sync::aref::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_ref().as_raw()) }; @@ -395,6 +399,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Device`. +unsafe impl 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/block/mq/request.rs b/rust/kernel/block/mq/request= .rs index ce3e30c81cb5e..8dad15ae4cfb0 100644 --- a/rust/kernel/block/mq/request.rs +++ b/rust/kernel/block/mq/request.rs @@ -9,7 +9,11 @@ block::mq::Operations, error::Result, sync::{ - aref::{ARef, AlwaysRefCounted}, + aref::{ + ARef, + AlwaysRefCounted, + RefCounted, // + }, atomic::Relaxed, Refcount, }, @@ -229,11 +233,10 @@ unsafe impl Send for Request {} // mutate `self` are internally synchronized` unsafe impl Sync for Request {} =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) { self.wrapper_ref().refcount().inc(); } @@ -255,3 +258,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { } } } + +// SAFETY: We currently do not implement `Ownable`, thus it is okay to obt= ain 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 ffa156b9df377..b17736a9adcd5 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -8,7 +8,15 @@ //! //! Reference: =20 -use crate::{bindings, sync::aref::AlwaysRefCounted, task::Kuid, types::Opa= que}; +use crate::{ + bindings, + sync::aref::RefCounted, + task::Kuid, + types::{ + AlwaysRefCounted, + Opaque, // + }, // +}; =20 /// Wraps the kernel's `struct cred`. /// @@ -76,7 +84,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. @@ -90,3 +98,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 obtain an `AR= ef` from a +// `&Credential`. +unsafe impl AlwaysRefCounted for Credential {} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 2291d85b6849e..afda4ac4a3045 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -8,8 +8,12 @@ bindings, fmt, prelude::*, - sync::aref::ARef, + sync::aref::{ + ARef, + RefCounted, // + }, types::{ + AlwaysRefCounted, ForeignOwnable, Opaque, // }, // @@ -435,7 +439,7 @@ pub fn name(&self) -> &CStr { kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::sync::aref::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()) }; @@ -447,6 +451,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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/device/property.rs b/rust/kernel/device/property.rs index 5aead835fbbc0..cee7e25013689 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -14,7 +14,10 @@ fmt, prelude::*, str::{CStr, CString}, - sync::aref::ARef, + sync::aref::{ + ARef, + AlwaysRefCounted, // + }, types::Opaque, }; =20 @@ -360,7 +363,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Resul= t { } =20 // SAFETY: Instances of `FwNode` are always reference-counted. -unsafe impl crate::sync::aref::AlwaysRefCounted for FwNode { +unsafe impl crate::sync::aref::RefCounted for FwNode { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the // refcount is non-zero. @@ -374,6 +377,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&FwNode`. +unsafe impl AlwaysRefCounted for FwNode {} + enum Node<'a> { Borrowed(&'a FwNode), Owned(ARef), diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index 6b88ade28e242..33b787aea3cb1 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -17,7 +17,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::{ NotThreadSafe, @@ -480,7 +481,7 @@ fn deref(&self) -> &Self::Target { =20 // SAFETY: DRM device objects are always reference counted and the get/put= functions // satisfy the requirements. -unsafe impl 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::drm_dev_get(self.as_raw()) }; @@ -495,6 +496,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Device`. +unsafe impl AlwaysRefCounted for Device {} + impl AsRef> for Device { fn as_ref(&self) -> &T::ParentDevice { // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM= device itself is valid, diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index e1ebad77ebe2a..2fa16d33e670e 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -21,7 +21,7 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + RefCounted, // }, types::Opaque, }; @@ -34,7 +34,7 @@ #[cfg(CONFIG_RUST_DRM_GEM_SHMEM_HELPER)] pub mod shmem; =20 -/// A macro for implementing [`AlwaysRefCounted`] for any GEM object type. +/// A macro for implementing [`RefCounted`] for any GEM object type. /// /// Since all GEM objects use the same refcounting scheme. #[macro_export] @@ -47,7 +47,7 @@ impl $( <$( $tparam_id:ident ),+> )? for $type:ty )? ) =3D> { // SAFETY: All GEM objects are refcounted. - unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRe= fCounted for $type + unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::RefCount= ed for $type where Self: IntoGEMObject, $( $( $bind_param : $bind_trait ),+ )? @@ -66,6 +66,14 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { unsafe { bindings::drm_gem_object_put(obj) }; } } + + // SAFETY: We do not implement `Ownable`, thus it is okay to obtai= n an `ARef<$type>` from a + // `&$type`. + unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRe= fCounted for $type + where + Self: IntoGEMObject, + $( $( $bind_param : $bind_trait ),+ )? + {} }; } #[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), allow(unused))] @@ -197,7 +205,7 @@ fn create_handle(&self, file: &drm::File) -> R= esult /// Looks up an object by its handle for a given `File`. fn lookup_handle(file: &drm::File, handle: u32) -> Result> where - Self: AllocImpl + AlwaysRefCounted, + Self: AllocImpl + RefCounted, D: drm::Driver, F: drm::file::DriverFile, { diff --git a/rust/kernel/drm/gpuvm/mod.rs b/rust/kernel/drm/gpuvm/mod.rs index d9d43d7197613..1612a88a455f2 100644 --- a/rust/kernel/drm/gpuvm/mod.rs +++ b/rust/kernel/drm/gpuvm/mod.rs @@ -22,7 +22,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::Opaque, // }; @@ -81,7 +82,7 @@ unsafe impl Send for GpuVm {} unsafe impl Sync for GpuVm {} =20 // SAFETY: By type invariants, the allocation is managed by the refcount i= n `self.vm`. -unsafe impl AlwaysRefCounted for GpuVm { +unsafe impl RefCounted for GpuVm { fn inc_ref(&self) { // SAFETY: By type invariants, the allocation is managed by the re= fcount in `self.vm`. unsafe { bindings::drm_gpuvm_get(self.vm.get()) }; @@ -93,6 +94,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef>` from a +// `&GpuVm`. +unsafe impl AlwaysRefCounted for GpuVm {} + impl PartialEq for GpuVm { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/rust/kernel/drm/gpuvm/vm_bo.rs b/rust/kernel/drm/gpuvm/vm_bo.rs index 5989972da829b..3692e832df419 100644 --- a/rust/kernel/drm/gpuvm/vm_bo.rs +++ b/rust/kernel/drm/gpuvm/vm_bo.rs @@ -29,7 +29,7 @@ unsafe impl Send for GpuVmBo {} unsafe impl Sync for GpuVmBo {} =20 // SAFETY: By type invariants, the allocation is managed by the refcount i= n `self.inner`. -unsafe impl AlwaysRefCounted for GpuVmBo { +unsafe impl RefCounted for GpuVmBo { fn inc_ref(&self) { // SAFETY: By type invariants, the allocation is managed by the re= fcount in `self.inner`. unsafe { bindings::drm_gpuvm_bo_get(self.inner.get()) }; @@ -44,6 +44,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef>` from a +// `&GpuVmBo`. +unsafe impl AlwaysRefCounted for GpuVmBo {} + impl PartialEq for GpuVmBo { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index 23ee689bd2400..720e57418358d 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -12,8 +12,15 @@ cred::Credential, error::{code::*, to_result, Error, Result}, fmt, - sync::aref::{ARef, AlwaysRefCounted}, - types::{NotThreadSafe, Opaque}, + sync::aref::{ + ARef, + RefCounted, // + }, + types::{ + AlwaysRefCounted, + NotThreadSafe, + Opaque, // + }, // }; use core::ptr; =20 @@ -197,7 +204,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. @@ -212,6 +219,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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. @@ -233,7 +244,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. @@ -249,6 +260,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&LocalFile`. +unsafe impl AlwaysRefCounted for LocalFile {} + impl LocalFile { /// Constructs a new `struct file` wrapper from a file descriptor. /// diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 0487bae811fba..0f3f62a81763f 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -18,7 +18,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::Opaque, // }; @@ -415,7 +416,7 @@ pub fn get(index: i32) -> Result> { kernel::impl_device_context_into_aref!(I2cAdapter); =20 // SAFETY: Instances of `I2cAdapter` are always reference-counted. -unsafe impl AlwaysRefCounted for I2cAdapter { +unsafe impl RefCounted for I2cAdapter { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. @@ -428,6 +429,9 @@ unsafe fn dec_ref(obj: NonNull) { unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) } } } +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from an +// `&I2cAdapter`. +unsafe impl AlwaysRefCounted for I2cAdapter {} =20 /// The i2c board info representation /// @@ -493,7 +497,7 @@ unsafe impl device::AsBusDe= vice for I2cClient) { unsafe { bindings::put_device(&raw mut (*obj.as_ref().as_raw()).de= v) } } } +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from an +// `&I2cClient`. +unsafe impl AlwaysRefCounted for I2cClient {} =20 impl AsRef> for I2cClient<= Ctx> { fn as_ref(&self) -> &device::Device { diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs index 4764d7b68f2a7..83ed94fca14ca 100644 --- a/rust/kernel/mm.rs +++ b/rust/kernel/mm.rs @@ -13,8 +13,15 @@ =20 use crate::{ bindings, - sync::aref::{ARef, AlwaysRefCounted}, - types::{NotThreadSafe, Opaque}, + sync::aref::{ + ARef, + RefCounted, // + }, + types::{ + AlwaysRefCounted, + NotThreadSafe, + Opaque, // + }, // }; use core::{ops::Deref, ptr::NonNull}; =20 @@ -55,7 +62,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. @@ -69,6 +76,9 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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 @@ -91,7 +101,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. @@ -105,6 +115,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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 b8d2f051225c7..8fbc396e46028 100644 --- a/rust/kernel/mm/mmput_async.rs +++ b/rust/kernel/mm/mmput_async.rs @@ -10,7 +10,11 @@ use crate::{ bindings, mm::MmWithUser, - sync::aref::{ARef, AlwaysRefCounted}, + sync::aref::{ + ARef, + RefCounted, // + }, + types::AlwaysRefCounted, }; use core::{ops::Deref, ptr::NonNull}; =20 @@ -34,7 +38,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 +52,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` +// 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 62e44676125d1..b8db6bdefd077 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,8 +16,14 @@ ffi::{c_char, c_ulong}, prelude::*, str::CString, - sync::aref::{ARef, AlwaysRefCounted}, - types::Opaque, + sync::aref::{ + ARef, + RefCounted, // + }, + types::{ + AlwaysRefCounted, + Opaque, // + }, // }; =20 #[cfg(CONFIG_CPU_FREQ)] @@ -1041,7 +1047,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 { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -1055,6 +1061,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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/owned.rs b/rust/kernel/owned.rs index e54a058d65cd6..3414e8df692b3 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -27,7 +27,7 @@ /// /// Note: The underlying object is not required to provide internal refere= nce counting, because it /// represents a unique, owned reference. If reference counting (on the Ru= st side) is required, -/// [`AlwaysRefCounted`](crate::sync::aref::AlwaysRefCounted) should be im= plemented. +/// [`RefCounted`](crate::types::RefCounted) should be implemented. /// /// # Examples /// diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 3ec897709e890..d9898be45f1f5 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -19,6 +19,10 @@ }, prelude::*, str::CStr, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, ThisModule, // }; @@ -488,7 +492,7 @@ unsafe impl device::AsBusDe= vice for Device impl<'a> crate::dma::Device<'a> for Device> {} =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::sync::aref::AlwaysRefCounted for Device { +unsafe impl RefCounted for Device { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. @@ -502,6 +506,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Device`. +unsafe impl 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 979a9718f153d..067f68b99e8c5 100644 --- a/rust/kernel/pid_namespace.rs +++ b/rust/kernel/pid_namespace.rs @@ -7,7 +7,14 @@ //! C header: [`include/linux/pid_namespace.h`](srctree/include/linux/pid_= namespace.h) and //! [`include/linux/pid.h`](srctree/include/linux/pid.h) =20 -use crate::{bindings, sync::aref::AlwaysRefCounted, types::Opaque}; +use crate::{ + bindings, + sync::aref::RefCounted, + types::{ + AlwaysRefCounted, + Opaque, // + }, // +}; use core::ptr; =20 /// Wraps the kernel's `struct pid_namespace`. Thread safe. @@ -41,7 +48,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. @@ -55,6 +62,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` 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 ac0a012ae1bb6..08b534dbd331a 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -24,6 +24,10 @@ }, of, prelude::*, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, ThisModule, // }; @@ -534,7 +538,7 @@ pub fn optional_irq_by_name(&self, name: &CStr) -> Resu= lt> { impl<'a> crate::dma::Device<'a> for Device> {} =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::sync::aref::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_ref().as_raw()) }; @@ -546,6 +550,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Device`. +unsafe impl 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/pwm.rs b/rust/kernel/pwm.rs index 8aa47304bec36..5ae172cbc112c 100644 --- a/rust/kernel/pwm.rs +++ b/rust/kernel/pwm.rs @@ -13,7 +13,11 @@ devres, error::{self, to_result}, prelude::*, - sync::aref::{ARef, AlwaysRefCounted}, + sync::aref::{ + ARef, + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, // }; use core::{ @@ -627,7 +631,7 @@ pub fn new<'a>( } =20 // SAFETY: Implements refcounting for `Chip` using the embedded `struct de= vice`. -unsafe impl AlwaysRefCounted for Chip { +unsafe impl RefCounted for Chip { #[inline] fn inc_ref(&self) { // SAFETY: `self.0.get()` points to a valid `pwm_chip` because `se= lf` exists. @@ -645,6 +649,10 @@ unsafe fn dec_ref(obj: NonNull>) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef>` from a +// `&Chip`. +unsafe impl AlwaysRefCounted for Chip {} + // SAFETY: `Chip` is a wrapper around `*mut bindings::pwm_chip`. The under= lying C // structure's state is managed and synchronized by the kernel's device mo= del // and PWM core locking mechanisms. Therefore, it is safe to move the `Chi= p` diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index 1876e40c76df4..215e7eb139fac 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -11,7 +11,7 @@ //! underlying object, but this refcount is internal to the object. It ess= entially is a Rust //! implementation of the `get_` and `put_` pattern used in C for referenc= e counting. //! -//! To make use of [`ARef`], `MyType` needs to implement [`AlwaysR= efCounted`]. It is a trait +//! To make use of [`ARef`], `MyType` needs to implement [`RefCoun= ted`]. It is a trait //! for accessing the internal reference count of an object of the `MyType= ` type. //! //! [`Arc`]: crate::sync::Arc @@ -29,11 +29,9 @@ types::ForeignOwnable, // }; =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 @@ -50,9 +48,8 @@ /// 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 @@ -65,11 +62,27 @@ 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 +/// Always reference-counted type. +/// +/// It allows deriving a counted reference [`ARef`] from a `&T`. +/// +/// This provides some convenience, but it allows "escaping" borrow checks= on `&T`. As it +/// complicates attempts to ensure that a reference to T is unique, it is = optional to provide for +/// [`RefCounted`] types. See *Safety* below. +/// +/// # Safety +/// +/// Implementers must ensure that no safety invariants are violated by upg= rading an `&T` to an +/// [`ARef`]. In particular that implies [`AlwaysRefCounted`] and [`cra= te::types::Ownable`] +/// cannot be implemented for the same type, as this would allow violating= the uniqueness guarantee +/// of [`crate::types::Owned`] by dereferencing it into an `&T` and obt= aining 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 @@ -80,7 +93,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, } @@ -89,19 +102,19 @@ 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 // Even if `T` is pinned, pointers to `T` can still move. -impl Unpin for ARef {} +impl Unpin 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. @@ -130,12 +143,12 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// ``` /// use core::ptr::NonNull; - /// use kernel::sync::aref::{ARef, AlwaysRefCounted}; + /// use kernel::sync::aref::{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) {} /// } @@ -153,7 +166,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. @@ -161,7 +174,7 @@ fn clone(&self) -> Self { } } =20 -impl Deref for ARef { +impl Deref for ARef { type Target =3D T; =20 fn deref(&self) -> &Self::Target { @@ -178,7 +191,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. @@ -188,15 +201,15 @@ fn drop(&mut self) { =20 impl PartialEq> for ARef where - T: AlwaysRefCounted + PartialEq, - U: AlwaysRefCounted, + T: RefCounted + PartialEq, + U: RefCounted, { #[inline] fn eq(&self, other: &ARef) -> bool { T::eq(&**self, &**other) } } -impl Eq for ARef {} +impl Eq for ARef {} =20 // SAFETY: `into_foreign` returns a pointer from `NonNull::as_ptr`, so it'= s non-null. The // `ARef` invariant guarantees that `ptr` points to a valid `T`, so it's a= ligned to `T`. @@ -245,7 +258,7 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T { =20 impl PartialEq<&'_ U> for ARef where - T: AlwaysRefCounted + PartialEq, + T: RefCounted + PartialEq, { #[inline] fn eq(&self, other: &&U) -> bool { diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 3336df493decc..da363e27664fa 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -10,7 +10,12 @@ pid_namespace::PidNamespace, prelude::*, sync::aref::ARef, - types::{NotThreadSafe, Opaque}, + types::{ + AlwaysRefCounted, + NotThreadSafe, + Opaque, + RefCounted, // + }, }; use core::{ ops::Deref, @@ -347,7 +352,7 @@ pub fn group_leader(&self) -> &Task { } =20 // SAFETY: The type invariants guarantee that `Task` is always refcounted. -unsafe impl crate::sync::aref::AlwaysRefCounted for Task { +unsafe impl RefCounted for Task { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -361,6 +366,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Task`. +unsafe impl AlwaysRefCounted for Task {} + impl PartialEq for Task { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index b23e1d60cdd65..f97b8ab6dad55 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,9 +18,15 @@ ForLt, // }; =20 -pub use crate::owned::{ - Ownable, - Owned, // +pub use crate::{ + owned::{ + Ownable, + Owned, // + }, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, // }; =20 /// Used to transfer ownership to and from foreign (non-Rust) languages. diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 993760ff332b8..88af466cedaba 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -18,7 +18,10 @@ to_result, // }, prelude::*, - sync::aref::AlwaysRefCounted, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, ThisModule, // }; @@ -373,7 +376,7 @@ fn as_ref(&self) -> &Device { } =20 // SAFETY: Instances of `Interface` are always reference-counted. -unsafe impl AlwaysRefCounted for Interface { +unsafe impl RefCounted for Interface { #[inline] fn inc_ref(&self) { // SAFETY: The invariants of `Interface` guarantee that `self.as_r= aw()` @@ -389,6 +392,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Interface`. +unsafe impl AlwaysRefCounted for Interface {} + // SAFETY: A `Interface` is always reference-counted and can be released f= rom any thread. unsafe impl Send for Interface {} =20 @@ -426,7 +433,7 @@ fn as_raw(&self) -> *mut bindings::usb_device { kernel::impl_device_context_into_aref!(Device); =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl AlwaysRefCounted for Device { +unsafe impl RefCounted for Device { #[inline] fn inc_ref(&self) { // SAFETY: The invariants of `Device` guarantee that `self.as_raw(= )` @@ -442,6 +449,10 @@ unsafe fn dec_ref(obj: NonNull) { } } =20 +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Device`. +unsafe impl 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/workqueue.rs b/rust/kernel/workqueue.rs index 7e253b6f299ce..77673b8ea45fb 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -192,7 +192,7 @@ sync::{ aref::{ ARef, - AlwaysRefCounted, // + RefCounted, // }, Arc, LockClassKey, // @@ -954,7 +954,7 @@ unsafe impl RawDelayedWorkItem fo= r Pin> // implementation of `WorkItemPointer` for `ARef`. unsafe impl WorkItemPointer for ARef where - T: AlwaysRefCounted, + T: RefCounted, T: WorkItem, T: HasWork, { @@ -987,7 +987,7 @@ unsafe impl WorkItemPointer for A= Ref // requirements of `WorkItemPointer`. unsafe impl RawWorkItem for ARef where - T: AlwaysRefCounted, + T: RefCounted, T: WorkItem, T: HasWork, { @@ -1020,7 +1020,7 @@ unsafe impl RawDelayedWorkItem = for ARef where T: WorkItem, T: HasDelayedWork, - T: AlwaysRefCounted, + T: RefCounted, { } =20 --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 048E6400DF9; Thu, 10 Sep 2026 09:01:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030922; cv=none; b=td8nxKd/iLwTvsxdhvURWYpq9TCP6yoiZ8wF3pWgxt82Hww0Tjzft9BAq4cnBINfV2YSV+/bnFuKGvuaybuQskJRM/odeORKbVRU7D4hgy6AvvvgjQ9Is46JP1oCJ5GhoWVeYHjZRpiAui1aCJwAKe3DSPJeMsgkz4G+brqr5A8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030922; c=relaxed/simple; bh=/zjO9zdfV440sS+2/8AsObuBj/yeJcE7efHr9UaL+8Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O5oZKMzOCFGAzLjG3Z0tZ8DXc2dqn8t1qGfzUT/w0KUg5TVB4uZjHbaCeVLyXUkEJznD6qzYy53MkyxHlTOhn/kAD2y6+ZfkLahzfA6GfNq6LinAX+xfn0i4adM6GShZjiAn8IyEsbuDNr9moQfVH/rtBdCSr7cnTOZHBylLQl0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OLZ5B3fu; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OLZ5B3fu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C0B21F000FF; Thu, 10 Sep 2026 09:01:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030919; bh=yt5UAGueNm32iTeFR6jcKBb+FhJxYmboaOihvjd/LlU=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=OLZ5B3fuSqJeJziVml2J7+SuEmvWItkOgOQyjncwSG2DimnGwv4KyDQJlXLXW5sxM nvCLV+4THEj2dC4voriGeaOEl5QiGheN3Z2q+ABMVBOmnvBJ8FuiomSDYgcAkjYXpC WmtKW9WFO9JI1P3g0nUTzXvMxX7Fg2E2spCP2GDThib+uN4W2ZmGUi3s7tMBahhhib nssJ+bxC5fSWQ5nIEawiqdv8AluaXKDpA29tlDrzi1jNgnhNaksN5SQ2CgBz20IqKC z8oV75B01Z2KKl9IwRK3SOYnF1oqFwMJIWTDbyu/FS6hpLcCRVklw5rhUr6Y6iWJ7g 7BtR/7T+ldmkw== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:09 +0200 Subject: [PATCH v21 5/9] rust: Add missing SAFETY documentation for `ARef` example Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-5-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1957; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=BNWtmHgpjNUhrCkbsOHEBA7MTI0LVX3SSpIhyT98+Ow=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGlMsJOOFdosQ0jUhYoghNsqo0y4sSrnWOtC 1TQjvbumFuJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxpQAKCRD6UCkIqsW9 0Cd+D/9nAUfqKWaGoqKv7nfm0hhF9sliL+paN7BmyiCqXpgYuTMfax03XP7wuBLX+p1hrdviAhE H1PrBfVWfd3V3zHdCH/GokxiWtF4Uwki/PnMnl8bXFvJby5yN9P2wz1Bzr+ZoeZXdPlcAVwaUYf lAZgSE0szcxSq5yZYh5NZ5e1derfpNSOMIS6F/k3KTRFoPA6OpW6thdkVIXZOTacMnm6Gc0ZZW3 cEKyHvTgntPVD4mYH2VewLR6LRt/3un9vJT2T5oj7/dHNQAaLmguQFggWup1xYA6a65I2dHc7Ol 9mPIKE0Rc+s8IJMPX7bLzDvoNu/uBR4+qJTEQbtS5fzpYL/VubrnZpOqDkG+WdgWDbHYS29hpv1 hOaNVXWUzxLlqPWyXJb0Kxq7nMnROnusibYCYRrnu6y588044SLI8D4h+WprDXV5ikecb+C3oVT uZbiWr2DcD406Wq9a1ctobdItGN7JO8tuPmepticFVhV3cd9xwr10q29wJ3DNgWY7Z00GxtadFk CxEV8zx8CkgTamGEaSpsZns8tdzXSdPz3lC5bnjzKC33CPk8iUrRGERISKT/xET9BJxqZjEAuHU tjAeZT75VZmxlGKiT22VwccqR12Y9eQ580MdcvGQVWbtb5BDrxCo6ka0p9YA+acEkL89XEl3Ljw 4AK7zgNZG4eUFqg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Oliver Mangold SAFETY comment in rustdoc example was just 'TODO'. Fixed. Link: https://github.com/Rust-for-Linux/linux/issues/351 Signed-off-by: Oliver Mangold Reviewed-by: Daniel Almeida Assisted-by: LLM Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg Reviewed-by: Alice Ryhl --- rust/kernel/sync/aref.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index 215e7eb139fa..ae76bd9b6c1c 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -147,7 +147,10 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// struct Empty {} /// - /// # // SAFETY: TODO. + /// // SAFETY: The `RefCounted` implementation for `Empty` does not co= unt references, and + /// // `dec_ref` never frees the underlying object, so a decrement can= not invalidate it. The + /// // object instead lives as long as the `Empty` value itself, so cr= eators of `ARef` + /// // must guarantee that the value outlives every `ARef` derived fro= m it (as done below). /// unsafe impl RefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} @@ -155,7 +158,9 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// let mut data =3D Empty {}; /// let ptr =3D NonNull::::new(&mut data).unwrap(); - /// # // SAFETY: TODO. + /// // SAFETY: As the refcount operations of `Empty` are no-ops, we ca= n treat `ptr` as owning + /// // an increment on the refcount. `data` outlives the created `ARef= `, upholding the + /// // liveness guarantee required by the `RefCounted` implementation = above. /// let data_ref: ARef =3D unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull =3D ARef::into_raw(data_ref); /// --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 2EC3138DC7A; Thu, 10 Sep 2026 09:00:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030865; cv=none; b=NcXGRIVVB9qUVHPDTzRpbTlL6hO0sloHqn2T3/YQ1rM64asGoEvTsq6Wzif/0jYp6nFfB4RIGFwvhzfmmnYWY+v8Oy/VAJH+HcM290vyaEliIXCu3DR9VTvCDgKvYN4moU/1Kii186w7CYgLhOM/AuO02+kI5jfCAJWzq5hCgCQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030865; c=relaxed/simple; bh=Hb2HNhVK5xYDFsjqho1bSkwk0fFnV2KftqOWKG6uYyM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qJVsUIrGZrX60OmcvJgcJrjtiRjHRkgcVWmV+rLDOmDHS5ih9GBJMTjDxx8ofV7xtZo9MRx2v0N+Rpi6/0+IpfFiPerZunz0X9d/G+cPj0wbSVFoZ7f2Lo/ZPyf2Qa9cqXn6Nc3zTCc3bA5F1StxuAw7BGv5mdMk9UJyYqkFKiw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bMe5u/k2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bMe5u/k2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 37E9D1F000FF; Thu, 10 Sep 2026 09:00:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030849; bh=uQml9IWDW5+htLmEYNNi48E8YJfucS2455Ey2j2BYFA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=bMe5u/k2HwLOKRURCP4zIpVVO7Vhj0W0uicOP2neknaxys8AM8ILpI2lfOCOID19q BvIRygBnGtMD8iHTPcoyyI7mrinkS3FTeclLoPxVenqn+emuNIvW2IlJDUOF4fU9kg BdjyV0RQB2SBUlwUv1K4PPKS4qlEyIFKMkpNnYxZFNDQ37/Al+v/T/jP1D+12WEMCO tYuXsQ4EjCus+vZDIGXGLKa7gw/94vq4Ap7oXnrZEsnv0rEvyu/hdUsXAV7bUM6MiL XEvOF7RUwpft5taUZ1JYtku9zItwzIxyCwFX340Uevkvy8Mlj4tVYsOGZu9ukySezW dYQoGKvssPCjg== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:10 +0200 Subject: [PATCH v21 6/9] rust: Add `OwnableRefCounted` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-6-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10710; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=LhNdeWjsAq8Iqh7hoE5lqbiBvBxHde9km6+3nWP/qJU=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGmXTFp4HVdd/kifr5tO6N87tVIDwru8njrQ k5wrayLpWeJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxpgAKCRD6UCkIqsW9 0ObFEACwkRjVnLx3u2xUyFPxylC/Jwz599HvQ+QYkPCiunJXkm1mjGrf2XGk1kcyie056aA01On GwMqBcMi5WhnW+7z4paWiyFy2LCOB0955PxWZh3TDqbdZTj0rrH+3P/SumzGfE3xx+wwRwImVAI CAqrvNoM3Vn683/l4le3xfZ8DhwiK5/LBTg9iSenUpk2+R70vmvukEo/L1ENzh4bQY2Px8CjM6p 0gtk5bp45Krn3Rl69DG6uJdnSoz9aO9qdLjTAKwLYqK3xYfQ8rAXBpEdqeSMULKuZf9sPnFsd8F oXhsun19gpVDvqHhBLxAE2S4GNiDWLiX6cWfUdZVwHn/07ljp5p9R94X8VFvgFVCnbVjfAjzGvh EM5yy0H9TZzO33EtEfZlRtaL8kIgnEH4+aaI9A28KEYA+hEAczluwSQjsOPzSju9dZfzjl6X80X pnNZk6dFK2vkHkpln25EGPI/lKEeNOKA9Rum+aSF0tFDT/15evwMJJnQw+1XCYT6xDfjNsFb2YE swp+qoQvcp1E4gc9TLssUCeAOA5LADHblFX/kGBZ7WQJBW1e/ss5Y0K2C/apoEJ534kXaMTvhVv L87paAlbYpA9VgNSxZvOGdv3PNsBMQqwnPUe6TrrL51/QC7lhmW/Bq2WJ9EDcosbHqsmAF36VFs XTxCa6/CD334bKg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 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. ] Assisted-by: LLM Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/owned.rs | 147 +++++++++++++++++++++++++++++++++++++++++++= ++-- rust/kernel/sync/aref.rs | 16 +++++- rust/kernel/types.rs | 1 + 3 files changed, 158 insertions(+), 6 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index 3414e8df692b..ff3fa31ce1d1 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, // +}; =20 use kernel::types::ForeignOwnable; =20 /// Types that specify their own way of performing allocation and destruct= ion. Typically, this trait /// is implemented on types from the C side. /// -/// Implementing this trait allows types to be referenced via the [`Owned<= Self>`] 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 obje= ct is dropped. +/// Implementing this trait allows types to be referenced via the [`Owned<= Self>`] pointer type. +/// - This is useful when it is desirable to tie the lifetime of an objec= t reference to an owned +/// object, rather than pass around a bare reference. +/// - [`Ownable`] types can define custom drop logic that is executed whe= n the owned reference +/// of type [`Owned<_>`] pointing to the object is dropped. /// /// Note: The underlying object is not required to provide internal refere= nce counting, because it /// represents a unique, owned reference. If reference counting (on the Ru= st 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 `Sel= f` pointed to by `this`, /// and that this ownership is transferred to the `release` method. `t= his` 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); } =20 @@ -139,6 +147,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 @@ -239,3 +249,130 @@ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_voi= d) -> 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::ptr::NonNull; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::sync::aref::{ARef, RefCounted}; +/// # use kernel::sync::atomic::Acquire; +/// # use kernel::sync::Refcount; +/// # use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // An internally refcounted struct for demonstration purposes. +/// // +/// // # Invariants +/// // +/// // - `refcount` counts the live references to the object, so the objec= t is valid while +/// // `refcount` is non-zero. +/// struct Foo { +/// refcount: Refcount, +/// } +/// +/// impl Foo { +/// fn new() -> Result> { +/// // We are just using a `KBox` here to handle the actual alloca= tion, as our `Foo` is +/// // not actually a C-allocated object. +/// // INVARIANT: We initialize `refcount` to 1, counting the refe= rence held by the +/// // returned `Owned`. +/// let result =3D KBox::new( +/// Foo { +/// refcount: Refcount::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// let result =3D KBox::into_non_null(result); +/// // SAFETY: +/// // - We just allocated the `Self`, thus it is valid and we ow= n it. +/// // - We can transfer this ownership to the `from_raw` method. +/// Ok(unsafe { Owned::from_raw(result) }) +/// } +/// } +/// +/// // SAFETY: We increment and decrement the refcount each time the respe= ctive function is +/// // called, and only free the `Foo` when the refcount reaches zero. +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.inc(); +/// } +/// +/// unsafe fn dec_ref(this: NonNull) { +/// // SAFETY: By requirement on calling this function, the refcou= nt is non-zero, +/// // implying the underlying object is valid. +/// let refcount =3D unsafe { &this.as_ref().refcount }; +/// if refcount.dec_and_test() { +/// // SAFETY: The refcount reached zero, so by requirement on= calling this function +/// // no reference to the object remains and it will no longe= r be used. We can +/// // reclaim the allocation by passing ownership back to the= [`KBox`], which frees +/// // the `Foo` when dropped. +/// drop(unsafe { KBox::from_raw(this.as_ptr()) }); +/// } +/// } +/// } +/// +/// impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef) -> Result, ARef> { +/// // `this` is a live reference, so the refcount cannot drop bel= ow 1, and it can only +/// // grow through an existing reference. Thus observing 1 means = that `this` is the only +/// // reference to the object. The `Acquire` ordering synchronize= s with the release +/// // decrements of references dropped on other threads. +/// if this.refcount.as_atomic().load(Acquire) =3D=3D 1 { +/// // SAFETY: The `Foo` is valid and `this` holds the only re= ference to it, so we +/// // can transfer this last reference to the returned `Owned= `. +/// 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 (refcoun= t 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 =3D Foo::new()?; +/// let foo =3D ARef::from(foo); +/// { +/// let bar =3D 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`] i= f that is the 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; +} + +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. + #[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 ae76bd9b6c1c..f12d091faafa 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, // +}; =20 use crate::{ prelude::*, @@ -40,7 +44,10 @@ /// Note: Implementing this trait allows types to be wrapped in an [`ARef<= Self>`]. It requires an /// internal reference count and provides only shared references. If uniqu= e 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 /// @@ -196,6 +203,13 @@ fn from(b: &T) -> Self { } } =20 +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 f97b8ab6dad5..65593c5c5fab 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -21,6 +21,7 @@ pub use crate::{ owned::{ Ownable, + OwnableRefCounted, Owned, // }, sync::aref::{ --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 2DD283B8D79; Thu, 10 Sep 2026 09:01:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030906; cv=none; b=ARal8Scv3dpgzMkxhTjnwVBy2DCSxryLV99Rf5PacWs15w01QGnAQP85iP3QefToWU8OQwlGp7e3fAQguVLc/ODpWSymtAruKX//mWpRC8uWvCT0Vr6nzDU2JkMwMVLBct1h68cQ7sJmL/JYsqT7M0Qo98OK98S9TzUSK/i/uAk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030906; c=relaxed/simple; bh=MzvogiSVtIi0JzAdUhuy0ypaJ0xsEpb23czzoBLd/44=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RpgEKpwhoRJfUwFSVWvLDtsWji1BdNiDGOrDOQr6CfsTryyQWlyao3z4dOoOJbi3YXE1NtJATwpZnxLHomvS/dC3y1ZDWqA3KeKsmMoFrQ5+rP7i007RluYqpJpAH6sdIbue8g45cSIJtCx3lQK18m41dlixIiPpHbrvIueTNvQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FfRrjUoI; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FfRrjUoI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BF21B1F00893; Thu, 10 Sep 2026 09:01:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030895; bh=w08aFcBZiHcoZ2r5Zzk3hvO4D194rjKTlY03OdL6b/o=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=FfRrjUoI2hpiRRSKPTHPsbEm+xn40k/OwGKhAma58ndbXeIeB6v9/CJqcDA3X15Yl gpavGcMwOLjRFXFoWNJ25+l5+t/LABe09ZFQC5GhHSZ4ANY3FdwcV/aAXRS1IKdwoE AT4ZJxcx2Jf1/A6B9R0JgBF8I6ZLWBjbd3JcuRmijxF6330obnkModGJZyc6kJjw6K STJAM8uKTOt5gPdl6F3oeg6oGMTaWL2Zivy62/wi0+QOPQ0q3zeZ9gaEGn7tkrSJ3i 3qJnSElae92pP5H7cLkeW3SIHWDp6MNVeVAaNkgKxDwYn0U9dpC1W9JRtZWusMWjTX izLtjNAl9CAYg== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:11 +0200 Subject: [PATCH v21 7/9] rust: page: convert to `AlwaysRefCounted` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-7-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=13638; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=MzvogiSVtIi0JzAdUhuy0ypaJ0xsEpb23czzoBLd/44=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGnRfwXpyx8BzJPC8ZRC+TfpL+BfWiRRFCaX Fb46cvs4waJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxpwAKCRD6UCkIqsW9 0KcqD/4+0srT0ERXRO6+ouXfDxwXH6yF/vbr4iCkHuscqs8CwfwnUTkiSgVXWv2dXaeJRrReD04 UZWExYv67OUTplV2uxHUaVfy3P/rdaaaPmxSvTnaIPM37c/I9tpef2WDMfTpPse9XmudhC6Y49J W+Bc6u8rgpiM+9Lqad7+0EFcim3rvIh9Whfsn76nIVxm/SZUD/EhRL5aW2wXymy2uCWKDstaPyi XaHpX07cbVWVNYKoEUquLfBzE23B/KjAbPssJAXGv3AQAcyUFLu6buPNGEcMen8x3n2YZVNcQFP 6WnX+R+gOarjBG960qcMm8h4DjeFJsQOBvYhwQU06RfqE1O91xERvJs43qas3IZfw3fB2sWks2L tYtjZjSFrgY1yv59VzdOOviIdipWV52+v/BaaXoZ3VDVclXjka7Hf+i6+i8OpS4gKcpXMoXwZ5H fHAP5myQTqLnOgRCDgKpLSM59QZg68nYK1MZZ5bUmXO8RFzef3FRxi+SSUEZBWT734iduuwOjAr BL1AhHg/1/duKXV3TgsazOrEIoWrpaytAPjdjbCv/onIDDphaH4HD+SbPWlYApHgBzcz9Tvg1Sk qP60+qzkDO+8fKi0+VExIe0n65NokRY8zXy8HchaD5m1j8PUtPmQ08RYqAmQb8QSugb3TNNu0dz FkFk1E97MntHDZQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 `struct page` is managed by a native reference count, and kernel C code routinely takes its own references to pages, for example when a page is inserted into a VMA with `vm_insert_page()`. Thus, implement `RefCounted` for `Page`, backed by `get_page()` and `put_page()`, mark it `AlwaysRefCounted`, and return `ARef` from `Page::alloc_page()`. The page is freed when the last reference to it is dropped; for the order-0 pages allocated here, this is equivalent to `__free_pages()`. This also allows `Page` references to be returned as borrowed references without owning the `struct page`. Remove `BorrowedPage` and update users to use `&Page` and `ARef`. Assisted-by: LLM Suggested-by: Alice Ryhl Signed-off-by: Andreas Hindborg Reviewed-by: Alice Ryhl --- drivers/android/binder/page_range.rs | 8 +- rust/helpers/page.c | 10 +++ rust/kernel/alloc/allocator.rs | 21 +++--- rust/kernel/alloc/allocator/iter.rs | 6 +- rust/kernel/page.rs | 139 ++++++++++++-------------------= ---- 5 files changed, 73 insertions(+), 111 deletions(-) diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/= page_range.rs index 52ffbf3504e7f..1117e1f6ece02 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -198,7 +198,7 @@ unsafe impl Send for Inner {} #[repr(C)] struct PageInfo { lru: bindings::list_head, - page: Option, + page: Option>, range: *const ShrinkablePageRange, } =20 @@ -206,7 +206,7 @@ impl PageInfo { /// # Safety /// /// The caller ensures that writing to `me.page` is ok, and that the p= age is not currently set. - unsafe fn set_page(me: *mut PageInfo, page: Page) { + unsafe fn set_page(me: *mut PageInfo, page: ARef) { // SAFETY: This pointer offset is in bounds. let ptr =3D unsafe { &raw mut (*me).page }; =20 @@ -229,13 +229,13 @@ unsafe fn get_page<'a>(me: *const PageInfo) -> Option= <&'a Page> { let ptr =3D unsafe { &raw const (*me).page }; =20 // SAFETY: The pointer is valid for reading. - unsafe { (*ptr).as_ref() } + unsafe { (*ptr).as_deref() } } =20 /// # Safety /// /// The caller ensures that writing to `me.page` is ok for the duratio= n of 'a. - unsafe fn take_page(me: *mut PageInfo) -> Option { + unsafe fn take_page(me: *mut PageInfo) -> Option> { // SAFETY: This pointer offset is in bounds. let ptr =3D unsafe { &raw mut (*me).page }; =20 diff --git a/rust/helpers/page.c b/rust/helpers/page.c index f8463fbed2a26..906eb4b18f029 100644 --- a/rust/helpers/page.c +++ b/rust/helpers/page.c @@ -10,6 +10,16 @@ __rust_helper struct page *rust_helper_alloc_pages(gfp_t= gfp_mask, return alloc_pages(gfp_mask, order); } =20 +__rust_helper void rust_helper_get_page(struct page *page) +{ + get_page(page); +} + +__rust_helper void rust_helper_put_page(struct page *page) +{ + put_page(page); +} + __rust_helper void *rust_helper_kmap_local_page(struct page *page) { return kmap_local_page(page); diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index cd4203f27aed0..27d957b7956e5 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -17,7 +17,7 @@ =20 use crate::{ bindings, - page, // + page::Page, // }; =20 use core::{ @@ -169,7 +169,7 @@ unsafe fn realloc( } =20 impl Vmalloc { - /// Convert a pointer to a [`Vmalloc`] allocation to a [`page::Borrowe= dPage`]. + /// Convert a pointer to a [`Vmalloc`] allocation to a [`Page`] refere= nce. /// /// # Examples /// @@ -202,20 +202,17 @@ impl Vmalloc { /// /// - `ptr` must be a valid pointer to a [`Vmalloc`] allocation. /// - `ptr` must remain valid for the entire duration of `'a`. - pub unsafe fn to_page<'a>(ptr: NonNull) -> page::BorrowedPage<'a> { + pub unsafe fn to_page<'a>(ptr: NonNull) -> &'a Page { // SAFETY: `ptr` is a valid pointer to `Vmalloc` memory. let page =3D unsafe { bindings::vmalloc_to_page(ptr.as_ptr().cast(= )) }; =20 - // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct = page` for a valid pointer - // to `Vmalloc` memory. - let page =3D unsafe { NonNull::new_unchecked(page) }; - // SAFETY: - // - `page` is a valid pointer to a `struct page`, given that by t= he safety requirements of - // this function `ptr` is a valid pointer to a `Vmalloc` allocat= ion. - // - By the safety requirements of this function `ptr` is valid fo= r the entire lifetime of - // `'a`. - unsafe { page::BorrowedPage::from_raw(page) } + // - `vmalloc_to_page` returns a valid, non-null pointer to a `str= uct page` for a valid + // pointer to `Vmalloc` memory, given that by the safety require= ments of this function + // `ptr` is a valid pointer to a `Vmalloc` allocation. + // - By the safety requirements of this function `ptr`, and hence = the `struct page`, is + // valid for the entire lifetime of `'a`. + unsafe { &*page.cast() } } } =20 diff --git a/rust/kernel/alloc/allocator/iter.rs b/rust/kernel/alloc/alloca= tor/iter.rs index 02fda3ea5cae6..8dcc16ed89893 100644 --- a/rust/kernel/alloc/allocator/iter.rs +++ b/rust/kernel/alloc/allocator/iter.rs @@ -9,7 +9,7 @@ ptr::NonNull, // }; =20 -/// An [`Iterator`] of [`page::BorrowedPage`] items owned by a [`Vmalloc`]= allocation. +/// An [`Iterator`] of [`Page`](page::Page) references owned by a [`Vmallo= c`] allocation. /// /// # Guarantees /// @@ -28,11 +28,11 @@ pub struct VmallocPageIter<'a> { size: usize, /// The current page index of the [`Iterator`]. index: usize, - _p: PhantomData>, + _p: PhantomData<&'a page::Page>, } =20 impl<'a> Iterator for VmallocPageIter<'a> { - type Item =3D page::BorrowedPage<'a>; + type Item =3D &'a page::Page; =20 fn next(&mut self) -> Option { let offset =3D self.index.checked_mul(page::PAGE_SIZE)?; diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index 1c0796ea229f0..a2610774c7499 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -12,16 +12,17 @@ code::*, Result, // }, + sync::aref::{ + ARef, + AlwaysRefCounted, + RefCounted, // + }, + types::Opaque, uaccess::UserSliceReader, // }; -use core::{ - marker::PhantomData, - mem::ManuallyDrop, - ops::Deref, - ptr::{ - self, - NonNull, // - }, // +use core::ptr::{ + self, + NonNull, // }; =20 /// A bitwise shift for the page size. @@ -65,93 +66,30 @@ pub const fn page_align(addr: usize) -> Option { Some(sum & PAGE_MASK) } =20 -/// Representation of a non-owning reference to a [`Page`]. -/// -/// This type provides a borrowed version of a [`Page`] that is owned by s= ome other entity, e.g. a -/// [`Vmalloc`] allocation such as [`VBox`]. -/// -/// # Example -/// -/// ``` -/// # use kernel::{bindings, prelude::*}; -/// use kernel::page::{BorrowedPage, Page, PAGE_SIZE}; -/// # use core::{mem::MaybeUninit, ptr, ptr::NonNull }; -/// -/// fn borrow_page<'a>(vbox: &'a mut VBox>) -= > BorrowedPage<'a> { -/// let ptr =3D ptr::from_ref(&**vbox); -/// -/// // SAFETY: `ptr` is a valid pointer to `Vmalloc` memory. -/// let page =3D unsafe { bindings::vmalloc_to_page(ptr.cast()) }; -/// -/// // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct = page` for a valid -/// // pointer to `Vmalloc` memory. -/// let page =3D unsafe { NonNull::new_unchecked(page) }; -/// -/// // SAFETY: -/// // - `self.0` is a valid pointer to a `struct page`. -/// // - `self.0` is valid for the entire lifetime of `self`. -/// unsafe { BorrowedPage::from_raw(page) } -/// } -/// -/// let mut vbox =3D VBox::<[u8; PAGE_SIZE]>::new_uninit(GFP_KERNEL)?; -/// let page =3D borrow_page(&mut vbox); -/// -/// // SAFETY: There is no concurrent read or write to this page. -/// unsafe { page.fill_zero_raw(0, PAGE_SIZE)? }; -/// # Ok::<(), Error>(()) -/// ``` -/// -/// # Invariants -/// -/// The borrowed underlying pointer to a `struct page` is valid for the en= tire lifetime `'a`. -/// -/// [`VBox`]: kernel::alloc::VBox -/// [`Vmalloc`]: kernel::alloc::allocator::Vmalloc -pub struct BorrowedPage<'a>(ManuallyDrop, PhantomData<&'a Page>); - -impl<'a> BorrowedPage<'a> { - /// Constructs a [`BorrowedPage`] from a raw pointer to a `struct page= `. - /// - /// # Safety - /// - /// - `ptr` must point to a valid `bindings::page`. - /// - `ptr` must remain valid for the entire lifetime `'a`. - pub unsafe fn from_raw(ptr: NonNull) -> Self { - let page =3D Page { page: ptr }; - - // INVARIANT: The safety requirements guarantee that `ptr` is vali= d for the entire lifetime - // `'a`. - Self(ManuallyDrop::new(page), PhantomData) - } -} - -impl<'a> Deref for BorrowedPage<'a> { - type Target =3D Page; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// Trait to be implemented by types which provide an [`Iterator`] impleme= ntation of -/// [`BorrowedPage`] items, such as [`VmallocPageIter`](kernel::alloc::all= ocator::VmallocPageIter). +/// Trait to be implemented by types which provide an [`Iterator`] of [`Pa= ge`] references, such as +/// [`VmallocPageIter`](kernel::alloc::allocator::VmallocPageIter). pub trait AsPageIter { /// The [`Iterator`] type, e.g. [`VmallocPageIter`](kernel::alloc::all= ocator::VmallocPageIter). - type Iter<'a>: Iterator> + type Iter<'a>: Iterator where Self: 'a; =20 - /// Returns an [`Iterator`] of [`BorrowedPage`] items over all pages o= wned by `self`. + /// Returns an [`Iterator`] of [`Page`] references over all pages owne= d by `self`. fn page_iter(&mut self) -> Self::Iter<'_>; } =20 -/// A pointer to a page that owns the page allocation. +/// A `struct page`. +/// +/// A `Page` is accessed through a shared reference or through an owning [= `ARef`]. The page +/// allocation is freed when the last reference to it is dropped. /// /// # Invariants /// -/// The pointer is valid, and has ownership over the page. +/// The `Page` is backed by a valid `struct page` whose allocation is mana= ged by the page +/// reference count. +#[repr(transparent)] pub struct Page { - page: NonNull, + page: Opaque, } =20 // SAFETY: Pages have no logic that relies on them staying on a given thre= ad, so moving them across @@ -185,19 +123,20 @@ impl Page { /// # Ok::<(), kernel::alloc::AllocError>(()) /// ``` #[inline] - pub fn alloc_page(flags: Flags) -> Result { + pub fn alloc_page(flags: Flags) -> Result, AllocError> { // SAFETY: Depending on the value of `gfp_flags`, this call may sl= eep. Other than that, it // is always safe to call this method. let page =3D unsafe { bindings::alloc_pages(flags.as_raw(), 0) }; let page =3D NonNull::new(page).ok_or(AllocError)?; - // INVARIANT: We just successfully allocated a page, so we now hav= e ownership of the newly - // allocated page. We transfer that ownership to the new `Page` ob= ject. - Ok(Self { page }) + // SAFETY: We just successfully allocated a page, so we own the re= ference count returned + // by `alloc_pages`, and we transfer that reference to the new `AR= ef`. Since `Page` + // is transparent, we can cast the pointer directly. + Ok(unsafe { ARef::from_raw(page.cast()) }) } =20 /// Returns a raw pointer to the page. pub fn as_ptr(&self) -> *mut bindings::page { - self.page.as_ptr() + self.page.get() } =20 /// Get the node id containing this page. @@ -373,10 +312,26 @@ pub unsafe fn copy_from_user_slice_raw( } } =20 -impl Drop for Page { +// SAFETY: `struct page` is managed by the page reference count. Increment= ing it via `get_page()` +// keeps the page alive at least until a matching `put_page()`, which free= s the page when the +// count reaches zero. By the type invariant, all `Page` instances are bac= ked by refcounted +// pages. +unsafe impl RefCounted for Page { #[inline] - fn drop(&mut self) { - // SAFETY: By the type invariants, we have ownership of the page a= nd can free it. - unsafe { bindings::__free_pages(self.page.as_ptr(), 0) }; + fn inc_ref(&self) { + // SAFETY: By the type invariant, `self.as_ptr()` points to a vali= d `struct page` with a + // non-zero reference count. + unsafe { bindings::get_page(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: By the function safety requirements, the caller relinqu= ishes a reference count + // on the page. Since `Page` is transparent, we can cast the point= er directly. + unsafe { bindings::put_page(obj.cast().as_ptr()) }; } } + +// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a +// `&Page`. +unsafe impl AlwaysRefCounted for Page {} --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 F350B379EC6; Thu, 10 Sep 2026 09:01:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030882; cv=none; b=cKb8B1MsZW1bXXBkoRejRiBR3HvV4DcFUA1hQucz3p+mFwVQ3jOupK8InnG/NPS4wfhY1BBWvhzTAqb/Gbo1kojY/lXath5R+0aNc59uLIvKKPsfBWWVdW+EZppqFf1tovym7hPH+dps/9GEj3PszVNep3Rvm4LLehre5GGVvjs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030882; c=relaxed/simple; bh=SXD5uNcrjbDkLGWlPX/KbflXX1vgmQ5tBA1rgWw6Oxo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U+egxhW+zjea3siP0mvtjZsoJvveloY54fMQdwWI9500OW3PicCqX8qBljw3B9Ipd86Zo8HH32vAN6MvRtJ76YXkFrnxsJ26sg0ehS5MYixIbjBNWkC6RkoNpLed/12QCyjTGTgN2dSzcDuGQFXwB8iknZ498GbZp8kGioaOFbI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IJ+XqesX; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IJ+XqesX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3AEF11F00898; Thu, 10 Sep 2026 09:01:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030872; bh=s7S7XXrE3nWzY3ONCdrsA6SEjg/y++hz7JJ/gIuPEcM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=IJ+XqesXeR3rwnE8YiSGAMy74CDSFRf2vn9CkYC94FFki3qkJju9gP347J8asQYy1 Ba4hgpuYSs1N56xySaWeWTdoWQLbFuJf3QU0GE2gD//1hacXnchFL+XZyvbRWckVud 43sG/uMibp+/HuD70PSFtTf+xbxQVPfiBghz7yXppW+a0mFJck0q0ErSG4AKF4+lvF 0vsVu83SO6vFPFQOsm+r2wtgEisrUEHNUgPza4UklC7aewEaRRYDHU/lX2LBcIS0EH tg9wd9zfGWKo6QLeDt2BSO+Vm3gjyr81Onnwto6R/eTQNwDvJtKQklRZ987kcoS4It w4akeFg8drFyw== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:12 +0200 Subject: [PATCH v21 8/9] rust: page: add `from_raw()` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-8-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1342; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=qsvOsH5eJ/6SOy/kG5D1q9n3SKwDVeax/chnlBoc3Xo=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGoab6vY8s20eqgiCSmL4uGzV7sGy2smNjbZ wuNFu6zRxGJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxqAAKCRD6UCkIqsW9 0P2ED/4y0eQDwdjf1HYThRZR1AGuMa3kPD5Z55q5tNW5zGzFQWEjGOPwoKokVlha/nFjzxaddX+ REzqMGWyTOcbuX/SXoeDCy0OhknY/kwnhAsS+xJxaARcFVrwakURX9JQs91mLwqDYGSNHC20cFy U+YgPREcQJVQzzJAGyOK/2PCUqC0bDxTjUWVdtTIV6RMUE7U89ulN79TUItTzt4bjrw4IpFCY6U sTBgSAf3wfNHkKD5JazKA3TyWPREJUNfqTAdSIz+f/hTa1qbLHcRQlL93CFB+9FmUxVCcCiaD4s q1z82eE61CdMs6UWpHhYDll19pW6abxVa5iNqq+WNxz2QYfYhOCzc4es7H+PiT+CbxrSaFTImWk x+XNqAwXFQ10L2uHjklUOUIcJ6KAmrBeXazqL/6UgXMRe8ISncWYSC9nAnITCrtOOr/puGiEF1E m5zLFhTnvBu7N0872U1cJqrESNiReM4HckNcw5GEOH9xOHRcoM2tI7B+gnogw7atqjMmWVEneMv 6v/v0CDDBmwj1/jjMupa8FRmoz9xr3zMIOZMZVYMz7AtueK6DiKX5Rbg8srWyL7FalAf4ifRHJG i1JpqOo/KpwQCCRSzIlJYJw/LSWKs6dcfoLoD09ol2jQkAsfpqkEERGE/JQO8mlhgHR6VNnOdL6 gKJ8ZCKmAm5v1mg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Andreas Hindborg Add a method to `Page` that allows construction of an instance from `struct page` pointer. Assisted-by: LLM Signed-off-by: Andreas Hindborg Reviewed-by: Onur =C3=96zkan --- rust/kernel/page.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index a2610774c749..cd394b0656c0 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -146,6 +146,20 @@ pub fn nid(&self) -> i32 { unsafe { bindings::page_to_nid(self.as_ptr()) } } =20 + /// Create a `&Page` from a raw `struct page` pointer. + /// + /// # Safety + /// + /// `ptr` must be convertible to a shared reference with a lifetime of= `'a`. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *const bindings::page) -> &'a Self { + // INVARIANT: By the function safety requirements, `ptr` refers to= a valid `struct page`, so + // the returned reference upholds the type invariant of `Page`. + // SAFETY: By function safety requirements, `ptr` is not null and = is convertible to a shared + // reference. + unsafe { &*ptr.cast() } + } + /// Runs a piece of code with this page mapped to an address. /// /// The page is unmapped when this call returns. --=20 2.51.2 From nobody Fri Sep 25 16:50:45 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.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 446863DCD83; Thu, 10 Sep 2026 09:01:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030876; cv=none; b=Ta26opAnPqwjjG4TRDrP7zY1Jx362nFIglhTL3QDR6N74DE1OfzWD3ACJDbNUBpfgt3qNjq+G9GihnMbwcbEzDG0FMQb/ueXgAKEwjFF7GnN0PjLQhfF3giV2tvJ36yRGpXNgKWvyo1FWDuYFRI7QAfAnuUrv2CYO6lkN3X4KiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789030876; c=relaxed/simple; bh=mGjHroTCuk5mK+JJ+qPXVN3JjYkyaG93c58j6hdhhAw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lq0XcNe1CI/PDtNOsZWchhof12IFZVeExGp/sSZGmrFl8kpWMz4MM45KKQ8ZztXY+2j1Hm+YtCNMv33n22/02LhNXKoTMvFCgpAtvFBfRyIAZkMRHwKFccm0B77htenn68u2gSHciCXfHiNVfadYkM/YOJYLqkHSRzZKoEq6eKs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=M3BerBbv; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="M3BerBbv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C4B481F00893; Thu, 10 Sep 2026 09:00:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789030860; bh=Wg/k9xgyZfA9ou1Djuuw6WTAhRSTMUQxS2X1MvSzmrw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=M3BerBbvMzXCbqj1EM09oZC1x/XqtdFtYXby2y7p5INcP1rT/onE38lD3s9fbAPt1 dTM3owMdOb51VKsqIS7ZY4Jwd+kmExADj4SdFBpqtRitNVsuPob0zCPz/YCbvq/NWg bKEUVq61CO36E7mG2RaRdMSHyjZ7cCks9P0bE1iIUh50r0w6bwX3IzKb2uL/bCD0J0 XCJ+26ItEf7z37CManyUaT30zxZl0HKA6kD+wNWZ99EgI8FR8q7xtGE26//BdQyFY5 r/Vf5yfq3gWNKI5fBzX4eKcDmkrgIXN0SXzDQwGZVe6/iwbjS5wVgAkLQVgjI7Wj+N 34OcU8MdNduOw== From: Andreas Hindborg Date: Thu, 10 Sep 2026 11:00:13 +0200 Subject: [PATCH v21 9/9] rust: page: add `ExclusivePage` for race-free page access Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-unique-ref-v21-9-e83257373062@kernel.org> References: <20260910-unique-ref-v21-0-e83257373062@kernel.org> In-Reply-To: <20260910-unique-ref-v21-0-e83257373062@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 , 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 , Ira Weiny , Matthew Brost , =?utf-8?q?Thomas_Hellstr=C3=B6m?= , Ira Weiny 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, linux-usb@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=4137; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=mGjHroTCuk5mK+JJ+qPXVN3JjYkyaG93c58j6hdhhAw=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqonGpjFpIGLMETXkqUNOBWFFizecM/26XuOncT XS44dh5H5CJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaqJxqQAKCRD6UCkIqsW9 0LrMEACOm8qftJlk0GIO4ABiC6zoPZAx2wOPesrHLpI3yWQgcGB9ibsYkXK02yOfxuQMd5U1XEy kbzCsSAVhUUTuRLhFIUTEOpjgX/MXvSnmXJxnZogRyVBym3A6Je6rXWsgU4Je3qDsRWaz7kFXUk R1drGj+gxmakDZaVaxEoWBkzuRr7ZvwKHWUIJxhzkDb5psCDVvZOY6A1xcTwC5rate+r3NPo516 +iVFq6MqVlAcHnwGGMGsCkBBUt9aWLt/Hiunh84LwSYOTzrIDtFEQoSr450gCDwK9FTjmcpoHXj 94+1SOEu5P9+U2V3aRAQYVVOJAL5tAaLDeLcLNvP9OY9Z9iZmx9BOHShqepoaOf/E+sG3s5hDgB dwqZVd5fHyf0EuSdKGM/fNhQiRwPJ4aAL7pONHTSNWJTYRIT4dmS5Zspd9WlBHs0KP64c5Jbee5 wmnyR4QPIDeyzzTkw9d7GDN+Dg4409ufq3emr5PX6XMRdxHiScv1MJ5x6fLF62b+xZZtP04ahI/ UJPJHdQKHsuZoK1JYSiGqLBv01CXdiSuV3oDAlLBqcSBCdj3jmNlD3RyWwimRU3WsP3JyBSMSla 2VTyzkCqWTXDpUa5HncvNKHmXLW4Hb/YlycVtlU1KkGP0vZIYslkDWvSezPQAc2SODRqlPkf8uz cvfoyXcSbtziopA== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 `ExclusivePage` wraps a regular page but adds an invariant that the page data area does not incur data races. This means `ExclusivePage` cannot be mapped to user space or shared with devices, and it becomes simpler to directly reference the contents of the page. Since `Page` implements `AlwaysRefCounted`, handing out a `&Page` from an `ExclusivePage` would allow safe code to obtain an `ARef` to the page and break the aliasing invariant of `ExclusivePage`. Thus, do not implement `Deref` for `ExclusivePage`. Assisted-by: LLM Signed-off-by: Andreas Hindborg --- This patch was previously submitted as part of a different series, see link below. It is included in this series to provide an example user of `Owned`. Link: https://lore.kernel.org/r/20260605-page-additions-v2-1-03f04c8fdbbf@k= ernel.org --- rust/kernel/page.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index cd394b0656c0..4e5b1c2f4346 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -17,7 +17,11 @@ AlwaysRefCounted, RefCounted, // }, - types::Opaque, + types::{ + Opaque, + Ownable, + Owned, // + }, uaccess::UserSliceReader, // }; use core::ptr::{ @@ -349,3 +353,52 @@ unsafe fn dec_ref(obj: NonNull) { // SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `AR= ef` from a // `&Page`. unsafe impl AlwaysRefCounted for Page {} + +/// A page whose data area follows standard Rust aliasing rules. +/// +/// [`ExclusivePage`] has the same usage constraints as other Rust types. = Thus, it cannot be mapped +/// to user space or shared with devices. This makes it safe to reference = the contents of the page +/// while the page is mapped in kernel space. +/// +/// Note: [`ExclusivePage`] does not provide access to the underlying [`Pa= ge`]. Handing out a +/// `&Page` would allow safe code to obtain an [`ARef`] to the page,= which would violate the +/// invariants of `ExclusivePage`. +/// +/// # Invariants +/// +/// The data of this page is accessed only through references to [`Exclusi= vePage`]. While a shared +/// reference to a [`ExclusivePage`] exists, there are no writes to its da= ta. While an exclusive +/// reference exists, there are no other reads or writes of its data. +#[repr(transparent)] +pub struct ExclusivePage(Page); + +impl ExclusivePage { + /// Allocates a new `ExclusivePage`. + pub fn alloc_page(flags: Flags) -> Result, AllocError> { + // SAFETY: Depending on the value of `gfp_flags`, this call may sl= eep. Other than that, it + // is always safe to call this method. + let page =3D unsafe { bindings::alloc_pages(flags.as_raw(), 0) }; + let page =3D NonNull::new(page).ok_or(AllocError)?; + + // INVARIANT: The page was just allocated, so its data is only acc= essible through the + // returned `Owned`. + // SAFETY: + // - We just successfully allocated a page, so we hold the only r= eference to it, and we can + // transfer that exclusive ownership to the new `Owned`. Since + // `ExclusivePage` + // is transparent over `Page`, we can cast the pointer directly. + // - The page is never moved out of its allocation, so we can tre= at it as pinned. + Ok(unsafe { Owned::from_raw(page.cast()) }) + } +} + +impl Ownable for ExclusivePage { + #[inline] + unsafe fn release(this: NonNull) { + // SAFETY: By the function safety requirements, we have exclusive = ownership of the page, and + // by the type invariant no other references to it exist, so we re= linquish the last + // reference count and the page is freed. Since `ExclusivePage` is= transparent over `Page`, + // we can cast the pointer directly. + unsafe { bindings::put_page(this.cast().as_ptr()) }; + } +} --=20 2.51.2