From nobody Mon Jun 29 21:44:41 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 1CA1D3F4DC2; Fri, 26 Jun 2026 11:56:24 +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=1782474987; cv=none; b=a5vfyZT0se/LlXjagT6jqDE7g0OqYw6aej7LbeoDHTaxY04xSJL9rKjrpfh0mkTQA2FKqy9c8HeaZMfANaX+UXsQd2Yv/OD3NAg7zfU0ZnPnH5nAt9/WvZhQqzBUckWJ//xxZhutHogziR1YthTuxrxyrGVCNbtkOOpGPv2y2qc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474987; c=relaxed/simple; bh=L57zDm7ALp0lZWMW+Cln/Gg2DuJozYQVYKA2SZ2s83c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rb2rK14iGiEfHVb6aQHhaUfB+5f0kxtYwWLZVFIVIt4Heauqqw9let9rB0pITjPcL1CFTxQTA/l+EGE1Av8+MVTcnOybrAxvzaenx9SFB7LR4S3MEx9lT0uFaDqEacS2VuP6bsY6CVmc5Scfb9JNF2Wl0SXdAjCbnyYoW0tqGvM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HkuZ7XBk; 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="HkuZ7XBk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 32BDD1F000E9; Fri, 26 Jun 2026 11:56:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474984; bh=9MHwt/piGbHaBX1U0Ciw0A9tLdy3GnbZtG5V2/pNbH0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=HkuZ7XBkNBbPpmNh0jHv41Wuw70A+GdUFYjWET1qmXcQIKjTVrIaymEhyhQxZiJDQ OYQaC+YTngeDtEXGcTZg2nrhdNP6R8cyrSArn0Vcg4mmq7Hto8gxALTcWSWfRU8kgb i1NX1hBZ94yWCUrkJOY2045ItoVFnZTRZkQr1dHUJS9nY+rKTbTq6HIwWBAr/01JNd oDiP18WI45XFmDdzBNkxdUAOofCB8I9OwzTdx5AOBXno0NZp0mktQRseoVeUXD9ds/ Ea6yM6KoBk2H/UJkJmv+1gH1PriKePYHNbY2wWHbjbguzGKMCCtNXrSSLLiaCwHwV6 ioGjyljtNEVjg== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:53:58 +0200 Subject: [PATCH v19 1/8] 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: <20260626-unique-ref-v19-1-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1170; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=L57zDm7ALp0lZWMW+Cln/Gg2DuJozYQVYKA2SZ2s83c=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh0T9NXm2ekfnSlVS5q2a5Nkx3elel1Z+sUE lVzxvaywm6JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5odAAKCRD6UCkIqsW9 0GQwD/kBPhAfqhuRT/wPQuyxM0apWmNdKJ15rz0l+MH0DxUqynfkKds77p9Ba1hBaXZEiIgHmCH pDIBbcmrQR3ZzjLNEC27ic8X6+BdCVjQKsQBQWJ7NKui+imMc++MYWVIYyM0r0enlZe2kmN8hO5 neGpUe0IvwQ3Lj6UWc6ACsUoOIJ/VSSl4SFZNnkH2SbWvbImu4RPT5mmyv3heMJ9g65NMAedvle tw99mHlW+RMWghmbVY1G0CFXcrMFX/ICi7lpll6iz01cgmdWZ00Zk2kIk1MDSePNSLkiHcviPYo eujIyeR9+opejbUdjMsWAJIqUz1K+CusSsy+pMB9t+0TM36BK03TehWUHzki1rXsWQby8KUOQx5 JtTsLGUeCdq8jj5LJh7ikHfha1V5+4WAgb1NU6rWbu0HAaCDeoUfacnX5DMEVlA2YDZYl6lGSYy LTe2rZntwugKRllSVNPfbq+vpbu4eh/00OZ+rZuo6jg4qjxcaF8bpEujK1QOVaT6mqH0SIO6fL7 dafroHQszbX998/omhRnZ/sCkPDELv4EwBaAlkTH7N3G0DsXiUEUx3nko9wa630BA3dS1kWBvKn cRx4J3Tc31/zybazPxJ7yei5pHjMTfOHDnSsGrWwiXODWfvRUZiqgEWUO3S3KJWIZpG2VabKArA vHegIagDX5flLQQ== 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. 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 35d1e015848dd..d534e8adcf7b3 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: `KBox::into_raw` returns a valid pointer. + unsafe { NonNull::new_unchecked(Self::into_raw(b)) } + } } =20 impl Box, A> --=20 2.51.2 From nobody Mon Jun 29 21:44:41 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 CAFB33F4107; Fri, 26 Jun 2026 11:55:08 +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=1782474914; cv=none; b=rUqyiLRdpArCUhsk0wck2rkAeW6v/SzRF+ypOIlRd4X303LqnSJ4UYNqh0ErS8ohWBvBYB6JJeX2xVZFZbByY7krbyVilZ7IAWde7nGBsnLmcUFvLHKGODu/y+XMsS+SUguG8lIQ3eIBHJGsRjOfvmH4y8JG0AZpgzXjZesSKt4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474914; c=relaxed/simple; bh=TzIAIwSsIR9R0rqS8Uk6Of8uwDIlBqJKvjolimTvkP8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nRyp5l2TfSQK2JJmnNv/6uSPypEBvt+pyRH+E5gvmprSJknZGknwYRhMDBTcrardLepA6DCQmsUx7qplsAu+GKX+H2m+71KKl8LGSq/QhRZfz0OQyZEXRt2LQO6u+AhbSQ88biVCZBN/84MZRzqHBq8opZddqZ7FpfSgXyGBFtY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=G68sawEu; 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="G68sawEu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A82911F00A3A; Fri, 26 Jun 2026 11:54:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474907; bh=nW0Gvd41fIKfum8lv47xbr88JVN0R0Y3bAVxdgTJ0C0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=G68sawEuw+gEvqSfSgurM7H8cAkWAHHc6igip6wdMvPx6CefxPsB/T2xUn2kCSied ZmSRemfer+uGIJh/z4JgqMrkcwvu0XpteGfHapJw0qfiRwoWvby8q03TQliyFOjjm0 ZHancFmG7ACiJdcmiBLfge7bmJnJwUmMQO4yjgS1hea4gA/9HrrCOVeqWhKltu0Gm1 TI7xYOuH1sMW55p8gfHH8LO4FKT5m3FO0z9jASrwCtYWJ6nbg6DgnKXRBQHbLhHZIq PLiJSME3FXBcswt7d7RGbWQ331j6AukmnKqhpTLmgq6UY9QpT3kMqTrMRtv3lWM8AD ptkP5B81t14XA== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:53:59 +0200 Subject: [PATCH v19 2/8] 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: <20260626-unique-ref-v19-2-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Asahi Lina , Oliver Mangold , Boqun Feng X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=10621; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=GO++Qeu4a7kF68yEw+Vn2C+P9gU67mXjb8+4Ea2xpsk=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh1e991thBmNS1larSf58N6lP82euFt+uGl4 /Nen0uyLP2JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5odQAKCRD6UCkIqsW9 0LtiEACjpG+/YAYTyEyB97MqMW3AK9a/VdW3xvgboml23uZ0sLTW7YL0ZrVRGBTcyEpowCalfk5 VPA10IRd0mO1LTk7pH7nmC08j8BpjFJAUd+YP0V4G5m4+DIpk2tM8uCGMckFA6zd3EdTL5KG2N1 VnB++2B7UAYyvoh3d9/7rTsdxgdue/c6KrVy5UmYZQ712dYCnMi101z1Bg5g48EKVDkS9Z3fcQb z9+oLWFrFbtfrgNDoACvW+2EbDDdic3ZFC7hfe3F0nbVskO89kqoNP1AE2cnCvF/T0Lx/K4FM9Y I/buCan9NnPiN9XpDp2hGfRxcmwkwSxCKh3pKqMd86ijJe+E9RZBvIoiCVasLNAZcOD96+fjv4D 1+oGBLvncLjDS9u7OcqDmVV+F+Fz6qqiY2ipMFVXtkAz4k1GlqEMxpj1WMZOiWH5xMuzhn22dWd bU4zHkW5N2ILFifY6Sxip97LBzXIiTJ9aMtm6pcFlXW9UhjPUIaDPlOpfKaG7s2F921bcuVXXT3 K0V+F5CDojDbbMAu+f/L9T0Cq+M68EcV/OowMGgQgrdgs9HBKTnPJi6eakLH2TcKtcQSBQQVWQk HQHFxG/S+rjupRoK27Li0WMX1JULcawxDUNY5t62O3Z3Vd7EeoD8ZNccEyMV+OQc4sXCn1CW1OA YYLmizDpaAmO/SQ== 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. ] Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/lib.rs | 1 + rust/kernel/owned.rs | 188 +++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/sync/aref.rs | 5 ++ rust/kernel/types.rs | 5 ++ 4 files changed, 199 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 9512af7156df2..eb5256204a174 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -101,6 +101,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 0000000000000..7fe9ec3e55126 --- /dev/null +++ b/rust/kernel/owned.rs @@ -0,0 +1,188 @@ +// 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`. + #[inline] + pub unsafe fn from_raw(ptr: NonNull) -> Self { + // INVARIANT: By function safety requirement we satisfy the first = invariant of `Self`. + // We treat `T` as pinned from now on. + 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 b721b2e00b986..3bd5eb8a1a526 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -34,6 +34,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 ac316fd7b538f..c41eab0ec983c 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -15,6 +15,11 @@ pub mod for_lt; pub use for_lt::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 Mon Jun 29 21:44:41 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 38BF63F4100; Fri, 26 Jun 2026 11:55:29 +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=1782474935; cv=none; b=fetyyDOeTMe11SbeiTDIiEJZdpFhMCwjpmW5UKJ3TjYOk6Qvz22af4fUSZcs93X/KNphlZkxj0EHlzpR4PGYuTxC61mmQJnNG41nxlCax0PdkJTLvMUT+EWJKl5U0/BJITdC4yKpaHkxxYkxyjJpe5cy4uPc/CuUkllyz5jfp6A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474935; c=relaxed/simple; bh=rxFg/OxNn7Iq2MJWs1wke7ArbvlV7NG8RuAFMsQ/1ok=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tXqrf63HNDhvgbv18ZmxN+vw2h5pKB/K/eL4mBVL8+lsIUzXAbFmxw+O4L2Jhkh4a/pBrdjiPnh4I2TkF3WngziHAXHM1q+67HRVV8kXhhCPAXbfGHJ/0PEU8OYWvWEU1quMCOdunjMZMc9I3QfmIvg1CHaPSJOXpXDB0LareMY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mKqjad42; 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="mKqjad42" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EDE671F00A3A; Fri, 26 Jun 2026 11:55:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474929; bh=HqYVmoPun9uThSi6e4i4mienBqI4nWoqt5vN59RnpsA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=mKqjad42xYAZRLbtP8kQKjVT+kMZDvm4fSe5dDNcFTDtHA+DeVzUwint2IRD+Q5Mg bTyykVvfOMCyyi0fFgjAwDaQLjgJE+6HqZgjidFgpU+gClN253nuwYH7gg98QEYUcI SMASWXZe/TDARjw5RxOar6hvszN+EYdFT3adc/bZo6KF0fVuYV2wvwrx0SEb87SnQY O8/A0bgzp2tdZOvxAu6BpaPIRMCc6w18v+7RK+/AjIDavqzGu+oywzABLKtczpJane 6wlUHbr+HK+oVBoxw8a+CDhScUZmo/wqVWDn4dhDkvi6+VHgW4oFv3I/4ETXAtRYUr 1AG76K043EKcw== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:00 +0200 Subject: [PATCH v19 3/8] 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: <20260626-unique-ref-v19-3-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2726; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=rxFg/OxNn7Iq2MJWs1wke7ArbvlV7NG8RuAFMsQ/1ok=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh2mexRRMoFN1jy1lxkXcXvUPvmvPHbqJnCj QAUGGC7f7qJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5odgAKCRD6UCkIqsW9 0LrCD/93GVgfFyjgmqz4PMTBC6DC/QsQMpzEyq47kxne8s0C3CmAbCGQvd4mAcI8HSxqbwOjcFL OBDHo542xnGwDB/Bfgk8ZJ36Yp3PK+stZX0/+AFnICkNrNSqcJmhhHjdo9Tu7mV5bwpTyv3nC+C uj74AWk015g/E8FCrteSPOFOBGMSpal/pjGzSMsfpToOrxzxqQ8ThXzd6U7NE01vCWjJ5Nq/PD+ QP/IpqC+sXlkzjL2Dh3xl5vES+tBXeVFF97zq/7jfWtVddoEEJPYcwbsTFDhB+hFwVHQ5ti1+EQ 5PpYGdSk0GoVfIdBz251SFJuvtwmKa1xBMr/TU6UlazoxdbwHohI3mhrlz78g5SyUqyjgiahy90 +jB6ontwnaZZmTwallmY+6mowMat/7VB0RpL+RTMQqpvRWoNFF65ILwaLa7w7QYHY3fzDJvYuJn kWADzpzeZAO9GkNC5RRmCCobtIQBcbekBQj8O7eO8RBKHSuFvmBeUmoiG3SUSeNj3eYg7pKmvEa rwHJf8DWKqz4lWTKGDNqFeWEWHnRxPHqZBMITllCI6hpe2UxiuVRBUrao7AzseLD6qXGFth8/pE cDQm/5nPJMMkgAPTn7hMpZ0wfDTE2Rsq0bT03XgHYN8T/equKYrQVk8vTBgLp14kaEmAAS1kebW SBN8VIqJ/Bt9/gg== 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`. Signed-off-by: Andreas Hindborg Reviewed-by: Gary Guo --- rust/kernel/owned.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++= ++ 1 file changed, 50 insertions(+) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index 7fe9ec3e55126..93a5dfcc1e6f5 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. /// @@ -186,3 +188,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 Mon Jun 29 21:44:41 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 286B23F5BE3; Fri, 26 Jun 2026 11:56:13 +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=1782474977; cv=none; b=WmMNUdYmjBqn1M+Fepvlm1y3/HdreAqP4lilIUdv1tFwSdNXMyzGgSVtYGd4BPhWUaOXcm8edobGj/cxVIgCIhfErbeR2ytxJBFCPVDTZu2rv+WkMn4u7oxEw1skUhqcAyRPtlDsj4vHG6dhbjZl81Csrg1snNwViBqtrO/AW+8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474977; c=relaxed/simple; bh=eOVBkmdaix9R57OIZcNGlkDki841Kd/mNbMrRno0GwM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OBL350N+xnNuFOSytKiglQmO7y8fJ49T42MciHHvkivaNvYhRWKzcM/JeQN0nM21lLOvjHAVX7YFooc07hS1do4rCb/CFGVe6JdBoPdu0DQhF51/BU4Fn1cTSkTCmJ9OHrLyVS6zVOhTCCh7nYKn86NDKd2dfOXQoV5eHlZdq5Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e2HjqLdX; 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="e2HjqLdX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18FAA1F00A3D; Fri, 26 Jun 2026 11:56:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474973; bh=Bin9OshcS/0Q4LoasQxw3FlG5Jjc6G5Z3KsYRu0B2FU=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=e2HjqLdX8rb3hYbzK48OJyIhzraVLRWfX+FWMqFMCzo9gXVCLAJmVGfYTaQyp02MM 1beqryTAdyWlhi7c8QFSEtZ1CILF3aUHQzOWRlwXByODwaL9Bnq8chl9R+3hbRNzuk LtyKqJECTTnFiJNX/Zg06ZgWVSxdipj7gHPH7WB5O+BYypWSe5Y8ix9aG8b/tJVXXk CIPSlsoIN7RExURrPhXYmZq4TmtaiDl7xRxZeHvMIwAzMJcrjpIEgFd9fAJjE5dwC8 kF+Vj3jW3YfynSAzI4cWJenkzrsCZkwf1UYJr7zTsBxi9RwwBDY72q1eQbEDZckG3G MW/uszgOTFUjQ== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:01 +0200 Subject: [PATCH v19 4/8] rust: page: convert to `Ownable` 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: <20260626-unique-ref-v19-4-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Asahi Lina X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=11905; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=0tBaWt6qkrDUI2N6nu7SQxnFyUvs8y7lmCxwWfJLPDo=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh3GBh8sy4cjSOhi49SZKrsH/nNhyGHYuGzL 9PAeUuQrI2JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5odwAKCRD6UCkIqsW9 0CbOEACZXh9pBrAlP+99ZXl1KTzM4RDTQOAoAVSi+Bw95O0rsT2J+fuosnuDQ5YrJmItVU/Dz7y U61x8Ywaf4j9fvhXN1r1EX4pFWKlnP+DicNMYaH8HEAdBujyiy0meUMBbTy80I6mIvrMIhyUxPO vkTlHDUvVFeJTlcDOrj5ckCFf91f7aZxsx+xywEowRddbIQnntWXuCNtoRBV1maJYnKkWzLxWdi uAN8dUez524S3zZTvT5f/NlHuASDkrt0LV1I1hsR+SCD+4NaLspTp8x5FXtWhjVYjeopV9ISkt5 bWOez7NXzMKyrQv0lA2UV+vU0mC46FtIRBSXxNBzEqLjOiWZX3GaRSMG3KKWcPN/Ta42/KJU6UX DVF/MQNXw/GoRZvKcYl9RZBwJFPx6U2pprPKk1RuSAVTIDaLCLB8pThJJTnR9p4hgI/1NTQ4TSq 6/27mPZYD5tstAabYui/go4RXDZs31P0Rmxc2Cmr6H9BXrmTqalswXn5PdKl/+ih5bphPV4igdy AoKYXvqrp9aniFd47MZ6EaLEmo2TrATijJ/L1TSRrdr19HZi38Wb0YUOZi0i4zQ3NIZgbErWhCX gXfRj0Ks1/xoBreZHj5BauqvyoO83FCCQqthnuOvAI/CgtRMVAqQKHfwKl7pmha31aqzyp95k6Z UW7bIu8+7cUEDWg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Asahi Lina This allows Page references to be returned as borrowed references, without necessarily owning the struct page. Remove `BorrowedPage` and update users to use `Owned`. Signed-off-by: Asahi Lina [ Andreas: Fix formatting and add a safety comment, update users. ] Signed-off-by: Andreas Hindborg Reviewed-by: Gary Guo --- drivers/android/binder/page_range.rs | 10 +-- rust/kernel/alloc/allocator.rs | 19 +++--- rust/kernel/alloc/allocator/iter.rs | 6 +- rust/kernel/page.rs | 122 +++++++++----------------------= ---- 4 files changed, 46 insertions(+), 111 deletions(-) diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/= page_range.rs index e54a90e62402a..7941eb85b4ef4 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -33,7 +33,7 @@ sync::{aref::ARef, Mutex, SpinLock}, task::Pid, transmute::FromBytes, - types::Opaque, + types::{Opaque, Owned}, uaccess::UserSliceReader, }; =20 @@ -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: Owned) { // 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/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs index cd4203f27aed0..c7b9b069cf75d 100644 --- a/rust/kernel/alloc/allocator.rs +++ b/rust/kernel/alloc/allocator.rs @@ -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`](page::= Page) reference. /// /// # 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::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 8affd8262891b..6dc1c2395acaf 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -12,16 +12,16 @@ code::*, Result, // }, + types::{ + Opaque, + Ownable, + Owned, // + }, 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 +65,29 @@ 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 [= `Owned`]; the latter +/// frees the page allocation when it is dropped. /// /// # Invariants /// -/// The pointer is valid, and has ownership over the page. +/// The `Page` is backed by a valid `struct page`. +#[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 +121,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 now have o= wnership of the newly + // allocated page. We transfer that ownership to the new `Owned` object. + // Since `Page` is transparent, we can cast the pointer directly. + Ok(unsafe { Owned::from_raw(page.cast()) }) } =20 /// Returns a raw pointer to the page. pub fn as_ptr(&self) -> *mut bindings::page { - self.page.as_ptr() + Opaque::cast_into(&self.page) } =20 /// Get the node id containing this page. @@ -372,10 +309,11 @@ pub unsafe fn copy_from_user_slice_raw( } } =20 -impl Drop for Page { +impl Ownable 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) }; + unsafe fn release(this: NonNull) { + // SAFETY: By the function safety requirements, we have ownership = of the page and can free + // it. Since Page is transparent, we can cast the raw pointer dire= ctly. + unsafe { bindings::__free_pages(this.as_ptr().cast(), 0) }; } } --=20 2.51.2 From nobody Mon Jun 29 21:44:41 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 4ABBC373BFE; Fri, 26 Jun 2026 11:55:40 +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=1782474950; cv=none; b=WN0dS5jnJuC0NNc37RA6JlEyIMsJCAeZOTChrLTpFldPHQIgS2UF3BKnIQON/o1NlPeuBQfC9pqeBluoNl/sTykDZABVXhJCWfkkox7ZdqclO6iCzbpWw5Xny/VK/13hk3Jpef8DSXSNOCM9orU7VtMdJWxHG9LjhUWHBmUIt6Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474950; c=relaxed/simple; bh=gZ/T5q5RCluLWjyXgEizSiB5SPTYOFJe/V1V5ABMneg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nsbYGDz8WFD55A/P1U7TN+UPYFpJ/qCH8TkP8ZRDRId8zOz4vdr42KhPtV62zzVnsblyBYuhjk/S25CEsvopl9gz5dP+li6tqyOGkPcqxfA8wNS/rBLCHhG4mB+/n4i6K/wMZN/Lod3LuIoERSC7yPmfFVK/6RSL3PCfuOOryPQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=E1IRl0ei; 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="E1IRl0ei" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 35F5A1F00A3D; Fri, 26 Jun 2026 11:55:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474940; bh=IGEKVKFVZNVk1+RmVgzF30xF6YgxgNVpGsqZC2WxOns=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=E1IRl0eivr6Z99U8il9idrdCDm0NsLRp0CosMU3L7fk3LgRwZ3JzVuVqidxBu4yV4 OAaEqkhCrqEvmCnXjArRo+ctF4v3gKk+JfTbAaolbyRv+QAXFOkFS6VPjPs6Ujq8jH lGhrYnaXk7W0l4pBmRczdzNHToh1xy+7obn/6flX2mRTnWlt79ISg09nXsh+whlYKS V6sEVpS0OzIt5Tc5Jx0f7/j4AGYEGmrX5JW5sRqX+vTc7FBLe+1ULn/Drlu+UU/ED3 9jKCzFQ25Lot97b9MtcQcy48Told+kZJndiTAvVL282Pe8RI/HbbZClpgsVaQH548D m6qgGce03uGWA== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:02 +0200 Subject: [PATCH v19 5/8] 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: <20260626-unique-ref-v19-5-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Oliver Mangold , Viresh Kumar , Igor Korotin X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=39475; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=KeTm4SeXrKKGxF05HEt1R59iI3+B+CLRZiH9cKzash4=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh4tlg1JZ/NaxmbKr0YhqCLET1RMWX/rbcef w2uN1rItfGJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5oeAAKCRD6UCkIqsW9 0DyID/4oIMtbgYqNNdFVciS+MCcEOfwjv5zLemv8+ZKEzqhihybWEeO7gaX6n0krWj4GYYqjuK8 mOZQ7TFG3ToQ87Sp78uar4YZLdpJUlYQxBlHulSk4g6P5+dUOlMPA0tiBuiNCKwCL20E+jpiPtF PO3fs5vwquAyy3dsCzRlVyiNWSrfphnnkFNFrkVLcCYzx9mDraXEPEll2pPaKynUFGdrvBKennm 5mbCi2KBd9zNWwPFhizCBhcEtTHU7PYYwHOUMwyvJvh64cQpImch/+7IbPWHwqZzr0Mmc8XvnPF qpn6pppo2IvK3A1Y7DAeJMsP0CJR73YDZqUsbR7oSv9AclNlfgMhFTEdmG60QM6Nnk5GErG7Zrc guRNgn+3d6axximlOfTlD8Gylh99ewBVAg6iAWvnInxztQTUfQhC+pmCP/Qtih0Offdomrc//YI LAPS+z4lt3yzdDI8XBv7LsYmSypBcMQ7HVW04UQqusMW8k26dcGIj8/70Y23jXb7YLbs0klT53p /qUPV4YgOCc3QZQ8dzMmDZ8uzLbTYGV0Gf9ZA+9pO5xlvZpotgOe3F23KyIcG86F/ugrKgRxcSB qBzO11MiiKekmVJ3Tc1N/ujT7QWW3DI6vyWhTIujuxlCgIzsgc7Dpn0en4upvR5/8E3f7TknjzC ZelVd1yUESptyHA== 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 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/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 +++--- 22 files changed, 260 insertions(+), 77 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index c42928d5a2393..854525289c8b4 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -19,6 +19,10 @@ to_result, // }, prelude::*, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::{ ForLt, ForeignOwnable, @@ -344,7 +348,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()) }; @@ -363,6 +367,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 645afc49a27d6..2e90f6a06fd05 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, // }, // @@ -448,7 +452,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()) }; @@ -460,6 +464,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 403fc35353c74..368742a258376 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -15,7 +15,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::Opaque, workqueue::{ @@ -227,7 +228,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()) }; @@ -242,6 +243,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: `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 01b5bd47a3332..30d3718578fe8 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -17,7 +17,7 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + RefCounted, // }, types::Opaque, }; @@ -29,7 +29,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] @@ -42,7 +42,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 ),+ )? @@ -61,6 +61,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))] @@ -98,7 +106,7 @@ fn close(_obj: &::Object, _= file: &DriverFile) } =20 /// Trait that represents a GEM object subtype -pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted= { +pub trait IntoGEMObject: Sized + super::private::Sealed + RefCounted { /// Returns a reference to the raw `drm_gem_object` structure, which m= ust be valid as long as /// this owning object is valid. fn as_raw(&self) -> *mut bindings::drm_gem_object; 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 624b971ca8b0b..02b2c9220eb11 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -18,7 +18,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::Opaque, // }; @@ -424,7 +425,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 { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::i2c_get_adapter(self.index()) }; @@ -435,6 +436,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 /// @@ -500,7 +504,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 93a5dfcc1e6f5..a156267bf8bb1 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 5071cae6543fd..ea9ef99cecb07 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, // }; @@ -481,7 +485,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 { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::pci_dev_get(self.as_raw()) }; @@ -493,6 +497,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 9b362e0495d32..0ba676445b06d 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -27,6 +27,10 @@ }, of, prelude::*, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, ThisModule, // }; @@ -518,7 +522,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()) }; @@ -530,6 +534,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 6c9d667009ef7..2d1cd74dd98e1 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::{ @@ -629,7 +633,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. @@ -647,6 +651,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 3bd5eb8a1a526..ea5a16b8163a6 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 @@ -24,11 +24,9 @@ ptr::NonNull, // }; =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 @@ -45,9 +43,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 @@ -60,11 +57,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 @@ -75,7 +88,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, } @@ -84,19 +97,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. @@ -125,12 +138,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) {} /// } @@ -148,7 +161,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. @@ -156,7 +169,7 @@ fn clone(&self) -> Self { } } =20 -impl Deref for ARef { +impl Deref for ARef { type Target =3D T; =20 fn deref(&self) -> &Self::Target { @@ -173,7 +186,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. @@ -183,19 +196,19 @@ 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 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 38273f4eedb51..6259430b0ca31 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 c41eab0ec983c..5ef763717e59a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -15,9 +15,15 @@ pub mod for_lt; pub use for_lt::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 7aff0c82d0afc..59350c6b0df2a 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, // }; @@ -392,7 +395,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 { fn inc_ref(&self) { // SAFETY: The invariants of `Interface` guarantee that `self.as_r= aw()` // returns a valid `struct usb_interface` pointer, for which we wi= ll @@ -406,6 +409,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 @@ -443,7 +450,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 { fn inc_ref(&self) { // SAFETY: The invariants of `Device` guarantee that `self.as_raw(= )` // returns a valid `struct usb_device` pointer, for which we will @@ -457,6 +464,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 Mon Jun 29 21:44:41 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 DE8FF3F4105; Fri, 26 Jun 2026 11:55:51 +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=1782474955; cv=none; b=BnFkC9yV7JOintWcGVPyaQjZuumVr1iHclyhRdYyWFQCutcbQub6HY5xTyEbCfskjnlWo4J6FXWTGf9dEcfK7zvGyIoogRi2WdZfWev72E7K7lLj8OYAloxUzYJEwBWmoOvnqTP6gS1yW8uLh5I1yxVu5vAP5ZK6pJLi/9K9pzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474955; c=relaxed/simple; bh=IbxkR2S/sT5Qax06n21WRzHYxlna6pgSwprDnFizzhw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tyHP0Xes7rcBLqebFqPGTLd1XMmfc/MORcM1+1cp3QasGW/357ESksQ4sSxke7e/7CKoW508aR1nGk4KJO+Mniol6QoMWlyhbkMHbuXOJX6i1/bWXVmB+AUB4CXJQPMssTlmvdIeMlVlrKbIfiHPgFSSv3Tvf9urNR5XexQqIic= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FiipJjEX; 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="FiipJjEX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2ACD81F00A3E; Fri, 26 Jun 2026 11:55:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474951; bh=vL9knM2sUgbCQ85ffU5z6/s6VECuwJ6C1a0TUUfpb00=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=FiipJjEXIfzROm8Rj72S4kZbA2N2xxNfWgPz8qlLyZkwrxZDSeqHQJZ1nsFenldGj tWAeDPq4ViIib6znioJ1YDV40N4/fDRIR4XEVYUr7PCcBk/cmpHIKfk9oyXHcuZXKl a//DiKyx/pD6SgHukdZRldMDbxAwwSNLmE2L5/uieAxdHx+QL+0nEP9fEXpxPuFpSy AiicdSl595hg4y5Jee6UmXtWWodjgj40XIz2EoZj7oyfrNIRheyZoj0LiqGFa7fgIZ HwED5pjCaHPJaeuwX4RKtqfR/Mite71yOPDpiSBLYd+n/d5RS6FETeyBfte78Ut12A 7WpsQU7clOk3A== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:03 +0200 Subject: [PATCH v19 6/8] 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: <20260626-unique-ref-v19-6-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1545; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=Ze2x5FAumXdrYYXBmcLdm4zoQ8i0F4uXb1KFrUnACjQ=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh5c0RI24LrPZqVYg0Qx/n7FDb+Aok1GaRha 0/ilzrOjxuJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5oeQAKCRD6UCkIqsW9 0PXyEAC23Ea6LyXAN/vBRnS7DE97krNCqsfydxgaFROXpDBNURjHZXj31Sg9Y9erG7mlTtA97Gw iZD6mAFVeXU9IMvhvCOIKXmdpVoRgFwfKI9/DUonOzTp8xJhDY5gOv9HtK87T576QMcztAszcV7 /wMDeks1wYkasVZVNZN9s/O2Jj5f53J0aMqbuFUBR/NXPlCgZhvkGmAyVYQAfxggorCSwswCMa3 jTpCwRwxUyixOPghBItB+SJeP5g1jkfQSoKtrXYmDE3Ospvl3F/QKrlca5nOD2WZVBXOykd+eWN W+Yo6O/7GY8aUFLlqvkKJOR70V5tpF9WbYgZIJJBfV4X4C8tL973ay+P+s9ALXSivgXAYo4Hpxh LtUDPxjvcumLWA3ZVZ+7g9DoI+g470yRQIWZuICvGHW3kNmyC4x3Dzp9STvG//SeyCbzRqv0Hjd RZMLYvoHZbQHptlGTRvwvAF/ptDrYzdebxRBuTfU1QdsWLJvx6cYT80VRCvLe+EZl1VOsvwPwuQ AlyisIhRWiJciTyCkYIQoaG63qxA4PS5bQ3kJ8juifTWSp+5bPU9eeNv4LxJqHe0GsnMAb0CuX3 wdjTRgcuXTXNZZxEYRLnQQC+QOck8YxtWPw2OIB3ZPUfxIjpvhXNzn+wyH4lyqE38I2KJrba09V 8ov5/+T4CdIxqTQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Oliver Mangold SAFETY comment in rustdoc example was just 'TODO'. Fixed. Signed-off-by: Oliver Mangold Reviewed-by: Daniel Almeida Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/sync/aref.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs index ea5a16b8163a6..f26ca39b84d0d 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -142,7 +142,9 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// struct Empty {} /// - /// # // SAFETY: TODO. + /// // SAFETY: The `RefCounted` implementation for `Empty` does not co= unt references and never + /// // frees the underlying object. Thus we can act as owning an incre= ment on the refcount for + /// // the object that we pass to the newly created `ARef`. /// unsafe impl RefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} @@ -150,7 +152,7 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// let mut data =3D Empty {}; /// let ptr =3D NonNull::::new(&mut data).unwrap(); - /// # // SAFETY: TODO. + /// // SAFETY: We keep `data` around longer than the `ARef`. /// let data_ref: ARef =3D unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull =3D ARef::into_raw(data_ref); /// --=20 2.51.2 From nobody Mon Jun 29 21:44:41 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 340223F4125; Fri, 26 Jun 2026 11:56: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=1782474966; cv=none; b=DJY+jNj116h9isfx9ATmUY+er9A4f/M5AzLXwzasU0+n3dVFu8xuyNrN5UIfh67IbEzqdop3M3q4nbzZpJClcIfVsn7iiip+0KcAYUwbUv8RvtLuxiDfxI4K3NosGNhb5/7cyvDXLOAWGEJ2lnnQppYY5an7fDRGOt4k4xEgy+A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474966; c=relaxed/simple; bh=Xdb0rz3sLouqH/2i0NuitrHLOplnkdYXMmtb3yEucJY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Y9+pKYVhd+pZDJaxecWEi525/0SHDxHgBG8H4FUCE2rtSbRDqAzAgtPMNNUX01+c0ErC/TCYg+gU6NztW8181NgDrWGCtT5mPy54BBxfdXHEHCREzyiKv68Y39eZ4dhhyw1ulNXHyy2ot2/qlkmsBn2Y+Y3ISgxdFgP54dalTW4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FZbwL1UB; 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="FZbwL1UB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EF74D1F00A3A; Fri, 26 Jun 2026 11:55:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474962; bh=g2qCRhgwlWX9/P0bA+PS5udzVG7MD/qZuekO4L1dWDw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=FZbwL1UB9mQ6/EFj0VxpRurpZzje4Pb+HbDaMHQ5DdX8SuQpd33TJ8VDJdpJt+SKQ ExU7/khxjOViyyjzw1MrqhcEVx7APVfZDpy87TjSdICi3NT7abaM2qB45e/fo81vKs b3fbtXIP5ufeYhC8FVU8ZkWsIPvL5ZijqK+8Le5uMep4OYSQUnVg6pXIwD8fpOlYPy SuGLz0Uy/RZ3Q6T41Ceif97dX060gK/qKvYVZ2arMxVGxL6MO0zRLWa+VaaOWUUmLz b5u5im5gFBxeyzJQzwp2FEqVUUenSXJ0dGYakOGBxFMK/RySMg63y9t/tOjMVybIel 5Zn7wuyjBYb2Q== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:04 +0200 Subject: [PATCH v19 7/8] rust: Add `OwnableRefCounted` 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: <20260626-unique-ref-v19-7-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=10339; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=lkUx1VbobxlmYWNdC/nDxmr1MRox1ssQduBu64GCO0o=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh6iRQlVRYs+/JmJorUWWxwrlu5daYDi25CA 7qZ7bMs1gKJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5oegAKCRD6UCkIqsW9 0EKJEACgd+t56MS0rxXiwvX3owU4yecPRO8VWtFmQlAx8uvYnHraUytyHUp4oS9jMa/IjyhltnN J9y+ZrUMGvegKDN6WM6iICxyan6JOiS/9CiUa7G5jHJLQw9v5LknXk9qwQHQi2+H/9f49cNBQT2 Is3xnpEiOthg2H2aFup17CG3ZrVEBXh9sFG6vCZ2I8XulkNWndNSJ/qGXUmIP9TGqIPTcmUZtTg Bn/QRQTInOmj4PXVAdQALnmMvXZo9ahXrG3OAgREvDbeLByUHUEeNrzO+0Oaj4fA7rG69RwslWx foJ4NSG8J4nxMV9a7uvFIsAEDSUp7EfJE2uPqew+vjnigu9PoEZxLE7jhAsA2n62Be/VDFpxQ7j +VJDjYbNA2NFTT8Auk3rlehY4SH6JhkUEIxaA3JOgyYdxYerP4lysYt5CCgTZfqNLqV9shrj2bK unF/4va6/rZFfpDAoZoiKptccJexDKekvlze3LZrQGPSTWPalmhV7GDywTFral7H12TNat/HIny NLNHuNRtgtqz5XSQsf7evqkKSqG28ZYPtvLxZrGGpYTTJu+WN3g30Q72Dr4YIwPic5xBQGz/dGA 234yW+ax1T8D/gsZeWlmCsprJfXYZZX58M+is7qjX3AxA9vu7cHVq8wL69IhGryf1NYmD48PuQh wVLS8IIK+gvotUw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 From: Oliver Mangold Types implementing one of these traits can safely convert between an `ARef` and an `Owned`. This is useful for types which generally are accessed through an `ARef` but have methods which can only safely be called when the reference is unique, like e.g. `block::mq::Request::end_ok()`. Signed-off-by: Oliver Mangold [ Andreas: Fix formatting, update documentation, fix error handling in examples. ] Co-developed-by: Andreas Hindborg Signed-off-by: Andreas Hindborg --- rust/kernel/owned.rs | 145 +++++++++++++++++++++++++++++++++++++++++++= ++-- rust/kernel/sync/aref.rs | 16 +++++- rust/kernel/types.rs | 1 + 3 files changed, 156 insertions(+), 6 deletions(-) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index a156267bf8bb1..acb611f084ff3 100644 --- a/rust/kernel/owned.rs +++ b/rust/kernel/owned.rs @@ -14,20 +14,26 @@ pin::Pin, ptr::NonNull, // }; +use kernel::{ + sync::aref::ARef, + types::RefCounted, // +}; =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 @@ -136,6 +144,8 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// This function does not drop the underlying `T`. When this function= returns, ownership of the /// underlying `T` is with the caller. + /// + /// Note that the returned pointer is pinned. #[inline] pub fn into_raw(me: Self) -> NonNull { ManuallyDrop::new(me).ptr @@ -236,3 +246,128 @@ unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_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::cell::Cell; +/// # use core::ptr::NonNull; +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// # use kernel::sync::aref::{ARef, RefCounted}; +/// # use kernel::types::{Owned, Ownable, OwnableRefCounted}; +/// +/// // An internally refcounted struct for demonstration purposes. +/// // +/// // # Invariants +/// // +/// // - `refcount` is always non-zero for a valid object. +/// // - `refcount` is >1 if there is more than one Rust reference to it. +/// // +/// struct Foo { +/// refcount: Cell, +/// } +/// +/// impl Foo { +/// fn new() -> Result> { +/// // We are just using a `KBox` here to handle the actual alloca= tion, as our `Foo` is +/// // not actually a C-allocated object. +/// // INVARIANT: We initialize `refcount` to 1, satisfying the in= variants. +/// let result =3D KBox::new( +/// Foo { +/// refcount: Cell::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 each time the respective functio= n is called and only free +/// // the `Foo` when the refcount reaches zero. +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.replace(self.refcount.get() + 1); +/// } +/// +/// unsafe fn dec_ref(this: NonNull) { +/// // SAFETY: 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 }; +/// let new_refcount =3D refcount.get() - 1; +/// if new_refcount =3D=3D 0 { +/// // The `Foo` will be dropped when `KBox` goes out of scope. +/// // SAFETY: The [`KBox`] is still alive as the old ref= count is 1. We can pass +/// // ownership to the [`KBox`] as by requirement on calling = this function, +/// // the `Self` will no longer be used by the caller. +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// } +/// +/// impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef) -> Result, ARef> { +/// if this.refcount.get() =3D=3D 1 { +/// // SAFETY: The `Foo` is still alive and has no other Rust = references as the refcount +/// // is 1. +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// +/// fn into_shared(this: Owned) -> ARef { +/// // SAFETY: An `Owned` holds the unique reference (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 f26ca39b84d0d..e6ffe7c650c39 100644 --- a/rust/kernel/sync/aref.rs +++ b/rust/kernel/sync/aref.rs @@ -23,6 +23,10 @@ ops::Deref, ptr::NonNull, // }; +use kernel::types::{ + OwnableRefCounted, + Owned, // +}; =20 /// Types that are internally reference counted. /// @@ -35,7 +39,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 /// @@ -188,6 +195,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 5ef763717e59a..6aa760952cb63 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,6 +18,7 @@ pub use crate::{ owned::{ Ownable, + OwnableRefCounted, Owned, // }, sync::aref::{ --=20 2.51.2 From nobody Mon Jun 29 21:44:41 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 BA6573E274B; Fri, 26 Jun 2026 11:54:57 +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=1782474902; cv=none; b=fs06KRHzfmkBy+N8ElJLUl+0ZJuzHb93DlmUJtMVZZC8dZjm8McrBRvysFh0LcoEnw5EkrLK9AVzbICHYpuitg2QwzloL2A1IZ/N49rRRuSdDPB/m+yD2qSdpjOz80xGp3xNhtn2jzrZJ8kYjQKDEsAN2GN9mraBvJxpIVCWtiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782474902; c=relaxed/simple; bh=ognTfAxCvoFUWWNRr5OSlBl7wqX/Y/FRoHPVFZpyGvU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LNrisiGUxw/3H2j1AIIOCcbtc3ELzyNRD+H9wXGUNsTHO26wEDZ8ZPPj8mWMtdi777wIm0aQWlYmISSrqgQLThRE1aCygjGe6APHixug3S+HZYwKUTezYPKNw7yod9mgrlb4Ja0PDpetsMZfq4gNgIHk5t/UAzWiE+pohmvCjdI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BDYJfRsw; 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="BDYJfRsw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 14A8F1F000E9; Fri, 26 Jun 2026 11:54:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782474897; bh=tI6M6Y2nl4r0WViOFml8Atpt2yMNTJUDccu+Knxm3HI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=BDYJfRswmlllKsddWLlMEwcM95dTkCYCF64HPZ57pBzELZbt6jGAmmwVc66TTM2I8 3Tec5A5eq134VO8x4lpVU2IdVNs67nrqyt8fyg8fE5Bn9XtbdXao0gO113H0vAgkVI L5lyzQwN4csTXnXlgSWtUH1yP2A6+R08NaiVbghIFZkSxtH8b7Qt7s2GOEcx/R9+ZM DT76tQavBwrHC9hWkzwi3PM3tRxSffeOFhWE6iibzw3/BDvAO8l6XCA7dNfCbWY66R vFIHUjkysHLcCL0KtnND/khDEFldMef/K3qxDplJpjerBcOFvJ44cvKG9CvaoPT0xV Xrc6ROG/EnUew== From: Andreas Hindborg Date: Fri, 26 Jun 2026 13:54:05 +0200 Subject: [PATCH v19 8/8] 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: <20260626-unique-ref-v19-8-2607ca88dfdf@kernel.org> References: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> In-Reply-To: <20260626-unique-ref-v19-0-2607ca88dfdf@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Ira Weiny , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1326; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=IpZr4FT6FvBjQrQQDya19Z/r3yR23B/8jNNyN7AG0Ho=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqPmh7a/zRVuwRfdQ6Jwphd9HrB/PVCZ50OLsaK H9dvOcadCOJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaj5oewAKCRD6UCkIqsW9 0E/AD/9fh1ImpLa0wfs7Sz9/7ZOnEQUUeJqCH7og8Qo4iv0qdA+RBY/oO8FSq5vpQbQ13fY3Ayh DEgavk1z3cPYnuandw1SuuDrLQCxLOeLESl0BDoVxBj/yDzbm7szUpir2LpwCaENUs5GEThvdNZ umvXCC4H0gSO0/hFgyQdrAsF1zYGzD56WcIML0JIjVf99ajYtIrUKOdTbO08ex60k3hewtHYJYe vCz3gIAJNTxGsuumDy/14ym5oK3lmMcSYExXMxewTFyKYmSJRrJ7w8LxyJkvAGMO9gV16Y1BYKC 9A+tHkKCtyz4UPm6VlqNYdQk5VGahhJD2eZM+w9I1FzO58egJeNurQxW5HxgUiMvUoP7CFxyfvm JdZ7qlWp6XAYCVvhOcxzgflQAUlliy3D12W0TdgAT5OXESzE1IcQ/BHtUdXHJtgEIofBOzh2mgo eoDwgwfOXFNDpuiT5TMPQiBC8s9daFRsyQccAlBRfrjfWHBcK9D0fQm2yaZiHL8P7PmcKEY3f/y nL77s9uXC1QKlyBIB323xezmeOacU/pGxOFWljZ1QREEtu0r4u7rznmrDD1WibWb773+RjFKs+m aFKQw3HafY3hrMdsDHOrXjFu150vSQ+BQV9BTq+xWQPW7XYMXFNBqH+Hu/rPL8EXMIg6Du3CrHG wz+vQ055rIQkcfA== 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. 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 6dc1c2395acaf..c88fda09ead5a 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -143,6 +143,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