From nobody Mon Sep 28 08:45:51 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 6DBDA259498; Mon, 24 Aug 2026 11:19:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570368; cv=none; b=vEfvuLLwPIaVWxHympWmxD8fgm8of3/X3dtIjx3W/ON4jJkWv0CSDitEqY9d1JuWSJOOOvjFck9awjkhNgMohptTu5h6tYzhYC/EJownkfpa4Z7kp5TMXMhUJ+iSPuXPsZ8HvSI+PiYuBHdw9A//rxPZw8SRhoXDpb/GPmqHkcI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570368; c=relaxed/simple; bh=Bz9Y+wuriC6USNq9dghH0Oc0RgRceIN5mLKgknmkXjY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EYYHKPsSwSU2Du+fUli7vSi2BW+WvBt0xX+VpOl/r5BsIXPoVGLd3yMUqVZt7pXMHwd0uqXibvubfRry+VujvF5ugM5QHy5vkLrPxDrBCSF3uwsNLEqDxBiEKXOWUCIvxaK5Pw48ZOx2BIaJX1/lmm6XQbFU7RkyEmeTQ7zPu9k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Pt9mYJzd; 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="Pt9mYJzd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B2A601F00A3D; Mon, 24 Aug 2026 11:19:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570367; bh=9JfWIbwT4//CafJUB37oPZ4gAJDTQRPaodJm/XlS444=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Pt9mYJzdHdzl4fQzAVrswSnLK1ugEdizF+iDaboQyRXVOzra9ZiPlB/Z3pAX+gRQ7 FlvuxDHz487tjiESkDMKQq+qrWU6tUF5KyEJ5N5EoOqXeSYHfees5b2NvdTeY4JzGg 2ASC/szsGCPUbmXMcnP1YJhN9Voj39B3hlLhHUJuupoWLcKTtNJUxQo7g4As96pJBw cU5Waqa/ZJ9kBvahCcv4atl/fAiNgenV8MSkoIvfJkZNk75BrLcCFbWc0jAzm+P9bx VoTqsK9exzJ0Pevfe9KOF4zMp5ZeZG/LPDRC+HadCNWknQmgUdkQPzSBjTKZCbzQD8 BIsVt7vDKq/Pw== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:53 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-1-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1170; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=Bz9Y+wuriC6USNq9dghH0Oc0RgRceIN5mLKgknmkXjY=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiANjOTA/QLk0NbdgT+Aipy/VQqpA4/e4r1P uWaXDqaFq+JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowogAAKCRD6UCkIqsW9 0LcUD/9JlybCkRh5vp32gkmPMvQSq6QcOhJid/ktAibn3taPc2bE2UpUDNFbJn/mQH7ZVtCu1ZM Tuys8Ev6iAI3y5ohAEMU7v9qE67FroO23PPZqT3Fo/KhIAFQYpdvy5BC5GdaHEnW0RLQr/WpR5C lrzj4oZaLV/RfEkuTqzwgr/RcT/tNk6g95wN+JCT/GX28fo0bksGHfkal2ewedoOfK4REnj/6W6 897sw2bg+rKaHODMYi3mNwWJ/nk6crdtLhMpFjaV1m5I+m7PAKhrFK/J859fg6GceYm6Qk2qIuv h2xNuhsDtW6kBHqkN2FjJQSDvsjUozwkUmr3GbpsjE99tnoN0+LzFcKD8TafAZyBQESTkAD83t/ Dpo3yEG6fZUHtdq29nvUu1TDnotfGPxdUDGLtKAlpvVnxGvfaC3OnEkGrsNgugffVt7ObVl+d3E UZtUeA30SEzENwbdDvDLd3/SDxlBkY+vOTcv+Cxo5ZRLKr1gTMiLc+NWBFRyZWbLjboFrSDWOJf GEkBbnGOC23EJMljiV9hbphKVdr8Vh1b5XdRjMkVjl9g0HiMYMlzPRxgYyFn6SIwNxvKiFnlwoA JyBfok+kTwA5TiP6zAWy+d8Xo7+N/0qPbS+AwCN2XkIrv8K/hLcpPQrIUYclplEKXVyQwS9CoHV AblCyvWtJHkb08Q== 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 Acked-by: Danilo Krummrich --- 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..e6c637bbe2009 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -211,6 +211,15 @@ pub fn leak<'a>(b: Self) -> &'a mut T { // which points to an initialized instance of `T`. unsafe { &mut *Box::into_raw(b) } } + + /// Consumes the `Box` and returns a `NonNull`. + /// + /// Like [`Self::into_raw`], but returns a `NonNull`. + #[inline] + pub fn into_non_null(b: Self) -> NonNull { + // SAFETY: `Box::into_raw` returns a valid pointer. + unsafe { NonNull::new_unchecked(Self::into_raw(b)) } + } } =20 impl Box, A> --=20 2.51.2 From nobody Mon Sep 28 08:45:51 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 B7ADC40F75D; Mon, 24 Aug 2026 11:20:01 +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=1787570403; cv=none; b=h5CAKBXNoA0BB1vKkNUSCIR9I5VC0nj27PfkltCAev6/J+hqRZVW9ktoa4a+C2ZbUQlw4pk+9a2Duaz+Lym/Y1Tcvf6zt0jN7vDn6biViebw2x0L5W7tHM+1th8gjeCLLwxqioECbumUZ3RQGO2AGblg+xQQou4smS2u7sBEUyw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570403; c=relaxed/simple; bh=TzIAIwSsIR9R0rqS8Uk6Of8uwDIlBqJKvjolimTvkP8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UJPch/Kf89Cb36c2/+JO3rfpIcnEtmbVnHTsHkdULGCCywReo3SH0h6/omNwfMwfBGBzqD025cWjnAM448ERGNyr+V74f9eaipEYjEN2chvUZTULHLzPlYEHC58oD049GcWvScO5cT0m+eGD+JCVYXZZp7Zpg1j3QbADDoAN478= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k9Ss1Imm; 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="k9Ss1Imm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46F4E1F000E9; Mon, 24 Aug 2026 11:19:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570401; bh=nW0Gvd41fIKfum8lv47xbr88JVN0R0Y3bAVxdgTJ0C0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=k9Ss1ImmnTp+BNiJNQZZ1ogLaSj2TK3mGrEp+cfMzZa4dLWPVFQQuxdLWtQufl3t/ c97tCZshgvAk+N3/c7q4EFEW3QVe9BZAnEDz6SdSCW46ca8AnlglvoKt0wapYtiY5n FDAqcwST7FZOUw3rYYksuz1dvdeaBy7fIQMZ4chh3vfK/XQyURqRS1nPnR3w+zpG+a URubS/a5Qt3Uz2vcweFTiRSnrPW1Z0Ns/f3sbZtrNRHxUvfV1VrzB3fbu4Zgcsu695 2lwjWs/5Fd1nBPLSqmLNLCPyQv6QvXFtBIrGZVh3KK7LBZhDLM0uVOwmx+Puz1/9D/ +Zvpf4i+pVn7g== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:54 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-2-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Asahi Lina , Oliver Mangold , Boqun Feng X-Mailer: b4 0.16-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/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiBdMlT+SR0TYzYvvg6VCUOxiI5R9GJUJyUK HV55E54nEGJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowogQAKCRD6UCkIqsW9 0O0+D/9qBRK1TCio6k/0Tta5g889WaW728AnR/eO41sejRdpQpqDaI3a0o+Y1GFvN+pRg0WKTrZ R54Yp2LuDujUdHqQ8Syzo2oqWCXFq/eahqpkuZOYzuXrOdkgaw9K2vtVdKHV1YB38ry8X0gwfGy PovKTCmGojSGX/T9zv7y9JNH1aqGNB/VDObHwWbFAGNTiwZvuCOMq9sw3UsZC/JAyw9xW1bfUT7 Yhrls48eNxQ7lXUvT3ScVCQp6rADcg1fpR2QMdR72J36osQv4/yVTlqOH2ncZ03bp7Vj6RQPMdE t0ZcqPpTno5JultwD0VnueS3mR4bzbc9ZKfd3ParNPokfnmb7UONiTTYHukeB926IY1yl/WJeA+ 9v0V37erUsVUJQSWpaXZmDSkRxiyR6qBGG22LGljugJd+kIMOzRFmMWf1g8VzkYy4StbMU2bnJi s6axtmCIBrIl4rxAHwtZ1YG+Kij//5I2r4h4wMFNvON7YQRH0N89d0ccf8K3x948UMp1bfJTlvW FBNp5JqhH24rzGY1i6e1kIBDKSd7ea2mQmbXqMwgX3mP7z586EWo6GqtuA3Z0wmLCgyWsZUR3iv w6/GfvX5jwnyDCttAHEaXPvtuvW27YHe0WLGHE4NEh8BNuvw/uAB8PXRsDV0MkZdzApTt0QO0Ra y+xRkgSiP1RBm0A== 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 Sep 28 08:45:51 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 5986E25C804; Mon, 24 Aug 2026 11:19:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570379; cv=none; b=PpUWCL3BJyRp5ufGGeIPhK6qYsYHhY/UKWybf4gDpjjOsDLKcQqBB8fvcgUGriUKVUj12DvbBiBiXVBQMThMIvVssuPE56B+8k868IC7E5dDj7CG9ZXTpmrnVwc6J4/oyLaGjOTLIvBdx5HCLUCcMq6IMg5phD4MMAemqLor8Ew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570379; c=relaxed/simple; bh=2rKgaZ9YnwK1gJkiYXVWR75zXX3xU5rSz64pVhI43qg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=L9WHWOI8PNkVQby9DNhOleJ+ZK3O9j347yOATm3YYOIlDJJvHjbGP5jZ611GYvBoOEF2lL5pGJ9HMtqtmpQ2SkzCf6/rUHAXAiWX2eHhQNvxb9WgFY4+2bX5Wuoe0MVWVogb3WWoT9rBJ7lpULzhFxW8F9NR/qIrdjJnO5mrCQ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k4gAMO5B; 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="k4gAMO5B" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CACAD1F000E9; Mon, 24 Aug 2026 11:19:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570378; bh=FUl4cpxwoEAMk39ePpTbKQbCsCUQnhH3/2ILTsycWVk=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=k4gAMO5BvwRCt6he2XnMfQcxhipMLBwDNolB13eUen1E2wn7fAu3MBJqkfNdJr30p KtBtxAdupxFiZDW1l3khlIZo5i166WHgK9Pn+A7sa/vSe0+LeDbm8p0/efMQ/maOqb hFezxfgre2Rzvka0kHj7n6QCtLOkxvS1Bhg8inibr4T+JjjYrvDkZMTqYAfmi3k8j6 4oZ3KfuTIluGjYRLDL3kpp5vQXxd0TrKsfEdrDg/46DEbmuJqIMh5WqnKUbNs6hYOp zCXrqyY2xBjvOlklJqNgAt31S5TnrB+Usy8srISghFadNqdqLbUUZaoejrbb6VneEk HBGz5hSJfgoxA== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:55 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-3-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2774; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=2rKgaZ9YnwK1gJkiYXVWR75zXX3xU5rSz64pVhI43qg=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiCraxhcJ+w4vvZV1SY4iZnHh7vyhYoBDHKn QKMW9sWhP+JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowoggAKCRD6UCkIqsW9 0B6WD/96ff4wxEK2+JhzJICtEMa7fDp5dNRnYJUPIXjrv2eWMvj/7PONFiDRsfxAKSkZRZMmnB9 O8A0AaNhAuNv8rwfY1LPeVRWoOiCTsp1FtojPmOmZ8dURwpe5dEv+/YqdstPb2rvHEig/phd/z5 NCWuo+l2Xrvz1UlV0ptcV1qvzkuHDDb9C4gdkt8O/or/0CzdFXUOvC7/ur8ccqxXbWjF2IbURHF oMHferZlysAgx2DAbuQvX83sEfBBqNF5bRU5mfV6ggL3IrKaybaJfh68KWrqtqIZilPrQvRgBap OWErwdXMZDQeb577fnBxvQw4QdwJmJ5yw/Wpv1USJjvFeaUoYn8NTL4nDhOIyv2k2J1f5a23npA PFFqRK9rTt1ZeDkkXVMwlw31/NUmu10MiiyLigWpyvfNrLfhNrDQ3QPxLtst2VmNQPIwlQgJTDi 4lgouA4IUoJ1/4cU8GMhSBGKiZYBLOZpa7FRvBOSz7fsmYljgCaD7lv30wlzIsMNnyBs7iXj5qU HUf5FqukUr9Mb/8kinmk7pIsCIaUEtRk9+rP7VO7tiZAbTp5Sn7fHOELtHTTWMLaNvbvqC0tYjT RMDYuRxK7Mjj/sV7REuFDiPZVGd5wZseUkzphLtK8XVVo0kHdyhHjWzqqaR0WCiSV7grNLz1RdX m9njpTvrY5w7MyA== 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 Reviewed-by: Alice Ryhl --- rust/kernel/owned.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++= ++ 1 file changed, 50 insertions(+) diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs index 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 Sep 28 08:45:51 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 188853EF0A6; Mon, 24 Aug 2026 11:20:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570414; cv=none; b=gRH0ifllCdBNDsB4wfaOoVpjPBYyfM8q7oDpbQBUwAUUw7KLoLMfn9VCtR2di7JunVzTJdf67F+IPpXCh+xc8HNrcIkwhQ8S804MMVCZTgCAtetElMg4rGL8KU9NRdJqe9SlB0AM4uvgRLIRdsL811lQm2GuogJMHWfGbBM5sH4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570414; c=relaxed/simple; bh=z9ZkrvyT1lhrxAPCUNI7Dw58LGAJB6UCyITJGQ5O0gg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KJUNgx5UU2Grfu9FEikIxy46bxUSsJvc8rI6EPDH+Weoff8t6wUprYiB0oI4p103hW26c0g+IsrvX1S1hXNrcI4Tu+08SSe8YZ8Vtv8D8IRMsODLMlRIJ6nYMOkjd8qFDRABY/qqkIsfYeJFbi3vvmP3xh0BgrhYDDAcRnwBcRw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KRVia9o3; 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="KRVia9o3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ED4271F00A3A; Mon, 24 Aug 2026 11:20:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570412; bh=kDuMCVJhBqI1nqWxe278yrezudc3hlS3mEBUqJMOwj4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=KRVia9o3+c+QTPWV+szez05sgvDgo0NMs0Gu1+23Z+Iu5uaprBAw5EsE2ixNGlkut T3J+0+oVEeDwYn1p5XQnAkSkNGuN0n39I3PyPJAc0QUBVM7PGlHtFz/IErcpLcEpQW OxIpqqvhKAv5rFbb3MjLXPTVZcD+CZqokEM2s+5J5kukEgg5JKUiBj4fq8Ekp5llsR l47KpTVlrYGNsxAIiqOs8zWZYiq+SidBHSmnwfwrvGjVXpwaUp2gdCWBP4wZv8i14q oY3l0eZbGfi/xDKq7ZCRZLJQF5FZwCuh2Wz0n7WiSeVTRf+9R58D3jzvLgv2OaSkzC Av8TXMK+84YaA== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:56 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-4-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Asahi Lina X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=11939; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=G6w43uJEPXw5lopecxdvPOiB5xddhi2+71XcxmRyAs8=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiD9v9KKGbLCUpwJf5uJb70ntKm8NGC/+1D/ 8jS3Iq06K6JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowogwAKCRD6UCkIqsW9 0DoLD/9LpWae0rOQtPcUYnTs1LIXKraN0qmPeUbDXPA0KkfOzZCBp1v9Ny5YLNBvJEkpu7zXpDN yofW32pkcUVdGLs+LvGvNSV788U7QKCO45TjZEo1FwSifNrnvwK4SpgwtS7Wd3G1E3XeNJaPqxK KRySTsFoC12QUffhye1s62ft/d4duGjZXtpCM/sz/7Owt5Cfkuce3g+eeXuMHk1aSuoAIzNRTxW vGLMmDgWGo+zSFQqKDu6sBmrZX89sntkV5MxJoweExHZWvaTqPxRKLfXIgo/Np1m/V3MdhHk90h s+IT4c/xI6dHWISd69EzdB8XK7f954y+5W3n7Rox9fYIk5hMddl/C6z+wFeFyTH0KRQSjlNvtGJ 7AzTmD3D8j6z3HUyhYocd4OmuFytudsfN97fY/beJUDVD012XJUuyddj6VDZoH7lcypLvAq8CXd 8QNhprSja/FXct3vQqidL/0Lu2sIcNjkdp8o8RXaBMHsIWSJtVbiUNbIbbKk4Q6Cbw/Nzd3hnM1 y3Qz/jImYdAQot079+hRq/7QQXW62nw9o0pwdnSl1nLlgNS2mIhQHQhQyTNuIs05uy6k1L25UDS 1yCLPL1ZgiyzWM5NnHCuNVe36Z/4q4yOXMQjnXeN+q2Nv1JoiYKq/kX29a32i03XL1+b6Yfuubb T0MeqET9MMGvYQw== 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 Reviewed-by: Alice Ryhl Acked-by: Danilo Krummrich --- 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 e82a5523804f4..c55ba29abea71 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 1c0796ea229f0..e807ffe3cfefb 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() + self.page.get() } =20 /// Get the node id containing this page. @@ -373,10 +310,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 Sep 28 08:45:51 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 32F3625C804; Mon, 24 Aug 2026 11:19:04 +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=1787570347; cv=none; b=EIMlQ6s4+Dzfhs91/tvURsYtiDXyR2Z+1l0PTSGb4jOdPBR1YF2wJK8CyQW24Y9WqbVpDJDPCs8KlVUizHO5ih7xMTVTWnuiroJXm8IHc4aZJpgNPDHFPqwom6ybk002jwxejpqQS6nSF1cAe5/bUejZ/UdqoU2ufECOKw1LcvI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570347; c=relaxed/simple; bh=3sWCn/UFWA5BRIn0Fg0DzlXZahfqU3PEAXLu7vRwuUg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VD0qcTBMR6eHtmaMo6IHuVYk/2M/RBwnij0pct1FuKz/xWbUBhFDIV3IyCowtyXIV3yTZniaIYZbfr0CIdYlD1oY47fUldyaomvzp0etCvHUDIelh+duHA6WcRsVPEuSprHdmbpxPjFKRYdd2seHwv7Ck+mQ9Eq92hoCRRzBuLo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HOXHUKQP; 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="HOXHUKQP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 846D31F00A3A; Mon, 24 Aug 2026 11:18:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570344; bh=dk+NXuRVEaQqbKCJVWTLaDFWPRg95/xE5teR6CT/A+g=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=HOXHUKQPADhhafzHQsgm3JdxbEcIWdXYR3vrQ3wtgADl0S8/JCYAdB9pMPqm2gsbH fjNg1pDo6YIgGbUHtkeTPr/oidVPErUxugAZs2t4NKSqt8PBaQxYf2fv9dd3CGqVmb 9Zx8dEoLCw9C2YG7TEEDGJkyCIrGl/Rq4oeAz0smqxVrojgaqp0pVkHCiFA1v9/d3v /DCQa2vHXdARU4Vq5hlOtCZHRq/V7pRg0jEj+Us6t5BDoWSYVubATMg14cps13orRD IGjL2b8YMfrhdyJgyKOWJAXgqBMw1QHEjtSM3zjRGMrR2GfEFOSBoFMgRxWPokOqor ceKStLP0k9cOA== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:57 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-5-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Oliver Mangold , Viresh Kumar , Igor Korotin X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=39554; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=8QrIGIz4K+wYtPPxBgGBR/dzk4dCrUI7yUY8ldbML/Q=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiE1ZpgZtuKQL1bEMNeRm6q4e+O4BeeQIVlM 8WjmfTdOmGJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowohAAKCRD6UCkIqsW9 0Hk6EACHzL5Vdy1zdqMLe5G0RwBP5zWA7crgdx9IhjP2E1QFuG1KWZfQv28x1SAdh3BbkCV73vo bqop4DzkJwNsnPk6gnhwYXZ/qXH37vxIfw2Zp0Ma/OSOYwEi3+H9/Cp91VB59x7giN6wiwBsOp6 ED1hq3JNR9LFptFWriPPqTsDxPv47aC4va4joDofbnCLQ6ysCg6muAkQsJpyqa7WhboqUOoZao5 NtdDjYmlBNgwVPus3VPZ+voTgvQlRC+896hJALMduSiJOoPE55yAc3hRQhBoLRE9JnPEnXLLGyQ oxcfcDJCj0cbtGDOEKQ31wOkX3Y9s/Vgkly5Bds5NJmd4zZwdhuJmmeHVZBGUJEGjusfIs8isS5 Uv684LXavhRVRMQ71VfIXxqQuao4zWbrn1R+MQ7bJQPX1aCnFaxu2Pr77FMuf9JjsuTaCbD9n+K ZXmgPaoQXwx89xbwvpwfmaByt1/Ncxcs67h4kbuHEYesWAUfLDfNVlvcPriMc+7nmiW3+3Sja7y smVxKotDoyUa9WopzEO8SSr+MgD/hVQMoxfxUxlardByFbydICL18ofAoDKpHv+ieZyyB3x3ku6 MUJXMFAKz9M+ghm8eHbcDr3OqJS5UZmRRkXC/gdK2okbZ9+RgS7sFtu0ufyYUlzg7q23Fq3xCWV bb9p7LY5KYMwJEg== 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 Acked-by: Uwe Kleine-K=C3=B6nig # for pwm.rs --- 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 1a38b3bbdfb7d..9afecd3fa3237 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 477cf771fb10e..6fc02d504334e 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -17,7 +17,8 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + AlwaysRefCounted, + RefCounted, // }, types::{ NotThreadSafe, @@ -362,7 +363,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<= T, C> { +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()) }; @@ -377,6 +378,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<= T, C> {} + 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 c8b66d8168719..80affe6335acf 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -21,7 +21,7 @@ prelude::*, sync::aref::{ ARef, - AlwaysRefCounted, // + RefCounted, // }, types::Opaque, }; @@ -34,7 +34,7 @@ #[cfg(CONFIG_RUST_DRM_GEM_SHMEM_HELPER)] pub mod shmem; =20 -/// A macro for implementing [`AlwaysRefCounted`] for any GEM object type. +/// A macro for implementing [`RefCounted`] for any GEM object type. /// /// Since all GEM objects use the same refcounting scheme. #[macro_export] @@ -47,7 +47,7 @@ impl $( <$( $tparam_id:ident ),+> )? for $type:ty )? ) =3D> { // SAFETY: All GEM objects are refcounted. - unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRe= fCounted for $type + unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::RefCount= ed for $type where Self: IntoGEMObject, $( $( $bind_param : $bind_trait ),+ )? @@ -66,6 +66,14 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { unsafe { bindings::drm_gem_object_put(obj) }; } } + + // SAFETY: We do not implement `Ownable`, thus it is okay to obtai= n an `ARef<$type>` from a + // `&$type`. + unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRe= fCounted for $type + where + Self: IntoGEMObject, + $( $( $bind_param : $bind_trait ),+ )? + {} }; } #[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), allow(unused))] @@ -109,7 +117,7 @@ fn close(_obj: &DriverAllocImpl, _file: &DriverFi= le) {} } =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..f9aacb894f505 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 d41555a4b31d2..a4ddaa1cc3a40 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -24,6 +24,10 @@ }, of, prelude::*, + sync::aref::{ + AlwaysRefCounted, + RefCounted, // + }, types::Opaque, ThisModule, // }; @@ -519,7 +523,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()) }; @@ -531,6 +535,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 Sep 28 08:45:51 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 E796A3F58E5; Mon, 24 Aug 2026 11:19:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570391; cv=none; b=DsaMFlfin5rB2o1yWgwjOVA5FkWSsfn17nLjoRnWK5K9z6/6fAchZDf/gasIotYKvVKT082RxsBXmO8zi7dqpfdOY3C4EpzIi6V/ihqSHa579zq/us6DGB4Jp0oU5Vg5IfVhlhOb8HM2IDFVDKnlrg53Ka2VgiEUnt5USMzQWdA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570391; c=relaxed/simple; bh=IbxkR2S/sT5Qax06n21WRzHYxlna6pgSwprDnFizzhw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hma10a0iNfQe52Mkz2L6xaYM5FURVRJxeLsVxn+0C/yaSzC1bYjxD9Ezc4nrn2L+4ZjhTGIS/6it0dqg2s6HOOeVP2MxcdA8C1B6MKz0vy+hdRHK3hZk7OLw2YQd+perBIASYhQUmlIyqGpSu22d6SztiExnfEX5MBRlwD79xDs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cvBIFLRA; 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="cvBIFLRA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D12E71F00A3D; Mon, 24 Aug 2026 11:19:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570389; bh=vL9knM2sUgbCQ85ffU5z6/s6VECuwJ6C1a0TUUfpb00=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=cvBIFLRAcda2SZw/JlrD6tOLwNfKcnVd5E0WZoutY+y8hwmHZ/O/6Ev8gSNNOk796 R9vzEKuzdU0JQlwzbt/QCuq/vSRRoGFOgPbM7S8qMbmJ31pomA9Bx0DwWWtdXzPlcJ bjqOkSYxUEiNaBuOeH/wCMIyUw00fVSUWBMUKNuSXr6xs7IYK90q3cYemRq+iSN3Lp 5axDKiwZnhzf+2oCzUZiWtQn6Kack0hljwkugFf8B+PubZOZIRefgqHcsw1k1iK5TA pDNaW/raJJsv5Pm3utpa3a0gclsIoz8iz81EkexgcN3hfv/tI6cRuS9m/tkdjkhWCO XETF1EOKtNWPw== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:58 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-6-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16-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/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiF6dh93QL76FsS3p7E0fXhPzyq7P6N7DBZg tiDSEuYy0eJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowohQAKCRD6UCkIqsW9 0EkxD/0XM2c5th1h+pGWV6+q9sYgp81vNSAgToV6NWXab5X9Q41O3etvl4v1UKRuRknTeiCNln7 bdnWb7sf1ddcFR8ctDx7tKS1lyYDHeUT/VJzXWcKqQXtyaCjA+VBSZB++jWxz4eN3rfSR7GGLa/ PYUcrMQb3iNL7Fevrhvf4Tyj3IpFO95jaD1CNRpzQhqi5LFH+Dytg5TPMQLqIumEu4c8+b4t4UN eaR+Mvh/nBqPnjt/+0gfZGf9l1GN2VaOKj0BS0ubxibuJizarHIvv+PrZp3iwViSVF+h/SDC7rD 1ENtCS0a3zosJOc6hENkAzE5dI5c0eOBNs/pTaL+DicoOuNfO+FfTdMUCcuU/hKQ4XUEYrtPAcQ 2favBhHsZtH/gFr3Yjp19Vim0e/AiN3wVfmUHOHyinDd6vKgAoQEoZSvoDS20gDM58r1hMtN7Nc nbYGLRNRRz35IroNM4ReUJZ1u9Jg0MbwAhOQufvDKBPYsqUOoEwdLJyCZnnIZ29b2UQnr/Vzh8Z 7YPxMftrFJ5plKtEN0l9k4/KUzmhXfm+Le1zc1Lu74+OJHSl69zrN8kJFSPgCIqgPm5T5BL3/8n hsRCDyVeRiNXPfeq/4NxDWzlzJzTQbtE7XvlK3N9hl98xNr/tfa9Qfk8IyEcKJwFzzffLjXpFIR X6nSbfz4HsnxrIA== 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 Sep 28 08:45:51 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 82102259498; Mon, 24 Aug 2026 11:19:16 +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=1787570358; cv=none; b=HwhI9LJeGhFag+gnNuOzVup0nvGDpK4SDPZBgPPMPwGe/a9AjtAWxJsv2Mi+kqsn4BtCeEx4hrEBx1fW3ziFeMtHnD/cADFTyqDyYj/Flq1ZJNF2mlGER4vBRTK0juQVcCs6xinBYMjdeHBaTK3ZfNUWxMJNELeF3DFseQ9Z644= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570358; c=relaxed/simple; bh=Xdb0rz3sLouqH/2i0NuitrHLOplnkdYXMmtb3yEucJY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ftuekI09uxGkZ2lC195I/PrrkE4uSzf7oXFsxk9N3/eQmC/yCu9L94vxgwUHa81kBIkMvY5UoIgXq9JinkQpTB5H+WUDK5WZVHqa/1sYQ8Nzzm6y/DkULAauhFB+jrKC0hUa3Fz0Lis8e+OVUCwvqzT00d+UVOlTjmcOj0rcAnY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ddyyL2PL; 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="ddyyL2PL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7AC1B1F000E9; Mon, 24 Aug 2026 11:19:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570356; bh=g2qCRhgwlWX9/P0bA+PS5udzVG7MD/qZuekO4L1dWDw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ddyyL2PL6PLlLW2iTVSFLpwL31ciMD1OtXzckowGASVMaHIBQftZZtBcrA6dpJde0 3PED2Nx9td5DG6bc1rfuu2cy7nYpHTM7rG0OGzZR+Bcv1NvcHFVXwGqruAx8iJZcY8 nbyAgsN+a2UPQsn/4JD1pP8Wi7iEJJ983qrVXVHlCCE8kRYDiYX5DM/0euu3UrbV3F reAGHqCJ7hokEDIg7Z0W6HKRWPuFISpCoii6Tqgo8yaDxWgBBO0PG396MVzYq+gmUK LvrzOtGNtSVB+lGLkCcdo8tTecH7GJqPBztpS46zsNN38Y1nmEWVgUG6c47hGzmAmW Hs2NvTcg28Jjw== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:17:59 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-7-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Oliver Mangold X-Mailer: b4 0.16-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/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiGte6nRf1GGg67rqtbls0poYCjepi/36kWc slXezf4KL6JAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowohgAKCRD6UCkIqsW9 0OZCD/9GWNXi6liRGGfVUwBnKuaEtuSErfHkn2qvDVM+dTxnOquHRan4YHZYXQ4qunwLh8y8u/U JZwTvQs24s5rEK+6xInqoHJS8puDoaiKifJOC7OIdBZGS5KqAN35ooAygyrWes4euyktz/Xvf1a 6lUMTqjkoMvDsAqpVlqRQgFCDDLC4zWKtWqdFofPv+4LszXFFEG/AlakaWSMmqgclVvtKMSB0Jk OsmTGWz1NJtIjjnipsQVQHE414ZdSjkcHhuN3NQLjzMi162AR5+cyvRvzUtFbm2CFkw41Ho2/Od Q/vonYDVt7xMizZjtT3+Y1Plb7WNFxGk84GJt3hxD1hrEceZh6rZiDKcqLQSk+XG0J/kDQ/mAcg jquu1u7FKiFA7+PYC0MKg8gZd4LE10DTlhur+CNOob86e5Zw70TIy4nZXLYXHOt8zTYzijr8n1G uqp5Gse0MxFbKS7T8sfa+DAe+9S2wbDx4J8ECHMbCtblPsyvkeQboTKzX3PB1aFbaQK7bm+RXmL l3s47VWN4n2KeIA12yVKPHXOru1+2U/r0q0VzKGRsWOxohKfz+nDIXXZJcWPwHgafK3o3kSZeDx J+ZnNM3Jlwh+UAaCHoz2mnROkMLxhQAf1cP4ByYZNna9wjBX8eqnBQWCfYiMNzUmdftJDgb5jnc WuqiGpOoSN4WLWA== 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 Sep 28 08:45:51 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 5A02B408602; Mon, 24 Aug 2026 11:20: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=1787570425; cv=none; b=kUy5bsi/qQ9Pz4E6C8ShwTWl4htNd4qve1NdwgAfesRYRO0n2VzB+YwM3Sw7xdNZoulkqBO0qFC6hlLfDbCX4vAOEMPCrNf1DXQ1Irs5+ASqDwh/sJOYa6sjcetqVykePfWLmhM3DiPmz9/cQlxWSvBrXRub6r2ZiJinO5+2rS0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787570425; c=relaxed/simple; bh=vSOqJFayRfX2VpqkoQBcpBdLMfaWMqIb6v/l01/Pb14=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AC82DknoJ3d9xUDmSBz4qsBqhQkBJxLNxkePwBwIY158adW+dNfDYSk3qUAJuhfy0Y3V176q7Ui93wb54ZbXAoSnktC8dDCACeuzxqyo+O202NjbMmuuzLOCP4rQrJQqp3qZNArRKEy7EXkS/nsNWXAbvITgijtZp9CQ4yMmEc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=T9EW113i; 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="T9EW113i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 56B1E1F000E9; Mon, 24 Aug 2026 11:20:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787570424; bh=gsf4C31WIGEdvjURLO6bh8+KS225jhHsASFOIqCjPTM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=T9EW113i0F7o9cpyn0NKMrr4qzmRV5ZF8U/NZoyuc8hneKIS+m7cpuDvzSVgPWLv3 UZ/T59ijq/leurmQCv1iHl0cmEuk1NIzbIWD6fJx8EeAGt6U1JI1XyOxMxA5DDGolk cgOQmWmEn9qSTztT73EmE54JnIvSFMBXxz1qP+EiXrnNjG8t7VS3q0HgSuto+OVHb5 K1G1+3cT4C6dI3/1VVHMRa7YVVcSo8rBEa8pYN4f07pLSh1dQdd8A+63hq+JoW803b 2R0aVMMZrfm+rKheifoo5O0r8MXv+DayvLLCFDSDOnBonW+N25ZJmtopKH8uu/+ZSn N3LkyVXe2gdQA== From: Andreas Hindborg Date: Mon, 24 Aug 2026 13:18:00 +0200 Subject: [PATCH v20 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: <20260824-unique-ref-v20-8-490735672187@kernel.org> References: <20260824-unique-ref-v20-0-490735672187@kernel.org> In-Reply-To: <20260824-unique-ref-v20-0-490735672187@kernel.org> To: Danilo Krummrich , Lorenzo Stoakes , Vlastimil Babka , "Liam R. Howlett" , Uladzislau Rezki , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Lyude Paul , Greg Kroah-Hartman , =?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?= , Todd Kjos , Christian Brauner , Carlos Llamas , "Rafael J. Wysocki" , Dave Ertman , Leon Romanovsky , Paul Moore , Serge Hallyn , David Airlie , Simona Vetter , Alexander Viro , Jan Kara , Igor Korotin , Viresh Kumar , Nishanth Menon , Stephen Boyd , Bjorn Helgaas , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Pavel Tikhomirov , Michal Wilczynski , Ira Weiny , Ira Weiny Cc: Andreas Hindborg , Philipp Stanner , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, driver-core@lists.linux.dev, linux-block@vger.kernel.org, linux-security-module@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fsdevel@vger.kernel.org, linux-pm@vger.kernel.org, linux-pci@vger.kernel.org, linux-pwm@vger.kernel.org, linux-usb@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1324; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=wkOYacmcCbns70mMJJNOqXe3g11b+kHYA0S0dbdXM7c=; b=owEBbQKS/ZANAwAKAfpQKQiqxb3QAcsmYgBqjCiGqEXZYrPpUe2ITj4yrNHK12u5/qghuV8op wHiEF9/CzyJAjMEAAEKAB0WIQRXitnI2WZ2JirAaob6UCkIqsW90AUCaowohgAKCRD6UCkIqsW9 0FasEACY3/FKckvX+qb6nS6iG9Xov+RkCghkBwWrcp/pKjcC9tE3uc6u5dni0Jlv0phoXM9ZRCq 4Oiskvu/fzDYM3OpBsN5yPrYo5z4pHMgQ1iyZ/E4PT2Qt3U5csMyACtNOfzK20rc5GW+JFzxdSm GIwUm1bZmMmmNMMZRB+8ErW6F9CbksrWSHSDwxAJMAQE9ePY1NSP3y5e06cyaZzR5dJmIbd8Qhr iaKt2yKFZKa4w9XJTygaZ1X1ufWNpW0NaoqexhZ0Gw1ms6cMuvFEjI4/N/xLlD5YPdiEhExs0NT qqL2XTiWvEQ6MqT3NkIe0DeoXtWwmA/KXc72ctatlG4NwhOrqjPanKOBFztt2qMEGDM8l4FIZlL DpzZe+X6qPhXJBkNVuMQxBhztKCpOjbSfd32N6Lj/sZX6MIrzjOvvAX/lkZodnyZAqNctVA6OEx cEtPjNHNN86XW5r6RbLvk/5f2Xz9Ma85CmnI7b9PMULgpQ4y9DKOXgxQqXwyqph6gf4Hpz0DZ5N 3Vci9dlrdolAiJLda0B0TkW4nnyv76G3i538Khhkr6C/u8tAJfA7Bb6K/GM3QJew6tJBXduGUdx YYs+T2vtUZz9CkjJrbvnHCPMJFQMH9cbMvEkos3w8s+D6i03ispYF0phnZ+cSWLIoLItRLQxpFZ cqeuQ7JvqxT38Fg== 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 e807ffe3cfef..32dd030c8315 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -144,6 +144,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