From nobody Sat Jul 25 04:29: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 6CDF434D4DE; Sat, 18 Jul 2026 05:32:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352781; cv=none; b=qxQ7xXOL/9273dzUJea3rvhQYzl88rhV7tUYVia/aQo8mQH4abOs5gVjLQIh4WFn8gtR5ibAbCnL3d5evjUuCb6dZqKukMEJovgSaWJhiJs+ZPpI28bgooq2sfbBze8En8D6lc4rxtB3Z9nIOPxm6pQJzlcbvd6me6LPi/IvMI8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352781; c=relaxed/simple; bh=gBSF6HTvlP8QoHhv6ajLL8wrlqNkDC+cdCgNg5zylp8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pmxlNeG10TJZ/EaqmaS5K4jI0rbo9yM4DWl/vlscpqNxG6KbBzAvK0b/U0PxhGvdl/m/EJMV7VRzf49nm3pDEazVTkj+5JtWWHl/YPbZ73baRc8H6AF6g8gblXqEETUiI7lRFtsJv42kC++gizAnabU9dNC+q9uijLXbpaWvjnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LuAm/eZW; 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="LuAm/eZW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 015831F00A3F; Sat, 18 Jul 2026 05:32:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784352779; bh=siyOnS6l4OgE+SqBMQ+V/Oxq7Qn3CqbcWz13kbHYzvY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=LuAm/eZWD7/asTYwGGHjQla5wF7zdbYTWEDTOJizwNsZJLFi/sxjExNO1OJhUp1/8 EpTzxCSUXwpmLXkvJlQieQdLJiFgyDBDxZWXumLFrPWbufhiNw+mC4VW9/qFIPiTKw K5dhTCG0HyCwbbNr9TIU+oApgo/vUxvXUhoRt2TBZ8Y5OwrUJUo/RifwjOFTzBWkGk H9imvG+WKWk25X4xN3hk9v+pCznv7mhMQnbKGyZsn3+BX4BHfI8z+bHYKD2ki6B4LU 9VgHrpC2mXlmtwC6vEWyi4TNWeAPDxirEJfQGf7jGNpjOpPYgt/s6GE9PypnPvv8FL A0a0gIg+9KuXA== Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfauth.phl.internal (Postfix) with ESMTP id 28E26F4006A; Sat, 18 Jul 2026 01:32:57 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Sat, 18 Jul 2026 01:32:57 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTE3j4lQBeju3HcweDJLEhgBazSdYdANC00q2qr0s4koYeBtdPShv70v8pi3tGI1gb rI8gxibm6pg/EQlIbC5FCYfXYVoSlDO/lTkmwnSzTVXyDHp0bfUhA0XAFwbqJvrGefhv0r XUnOrITJ3N4nqMI0h7+jzGq32g0S5vfV61f6E12mCvHFBAfvexQj6fIzJszAZ9rfBYqYfO T6OIfII3tTQkjZZVd1g1QAoU9kPbui+CHn/TMFHwriLkDlU60ZMdQktApUZbVe8QEyUYr3 jVEpI07EG25Rz4jWtBQdqLQWlPbWtXp4KaGcuyKCPxFukwJtrryv/3hqo9da0SnjgWsXR5 r634v+PE6k1OOxPqJGPC6mLQ2SHFvEjMbkLTHDB2JAngHD5Xb2TlmvMt5+deZLEFky8MTp +pZ6vDgd1ct7pb24/9mOaEE4bzmFLaxvMSjZqNWGE36StaJFzQ7OhQswbLfkdihoypCLJO wVah/j4nT8Tv8JoxYMGrX08FYk3Vu3BOCb5PlbFyBTIg+gmWbN7az9X0FdnG6gtttdtOSO ZfqnYHBkPgYnV2p1bQV0o85xip/4UU1y5gZplGT/oIUI0zqVr4nfnYtzGq9aRg4Pkk4A+b gMq2pVnWbONZT/jamHXyJA/y6YTQ11zB6QsVeP78ZsiyEKnUDmeC7sew4kKg X-ME-Proxy: Feedback-ID: i8dbe485b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 18 Jul 2026 01:32:56 -0400 (EDT) From: Boqun Feng To: rust-for-linux@vger.kernel.org, rcu@vger.kernel.org Cc: Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?UTF-8?q?Onur=20=C3=96zkan?= , "Liam R. Howlett" , Andrew Ballance , Alexander Viro , Christian Brauner , Jan Kara , Lyude Paul , "Paul E. McKenney" , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Sumit Semwal , =?UTF-8?q?Christian=20K=C3=B6nig?= , Greg Kroah-Hartman , "Yury Norov (NVIDIA)" , Asahi Lina , Matthew Maurer , Lorenzo Stoakes , linux-kernel@vger.kernel.org, maple-tree@lists.infradead.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [RFC PATCH v2 1/4] rust: rcu: Add RcuBox type Date: Fri, 17 Jul 2026 22:32:44 -0700 Message-ID: <20260718053247.25154-2-boqun@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260718053247.25154-1-boqun@kernel.org> References: <20260718053247.25154-1-boqun@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Alice Ryhl This adds an RcuBox container, which is like Box except that the value is freed after waiting for one grace period (via {kvfree_,}call_rcu()). To allow containers to rely on the RCU properties of RcuBox, an extension of ForeignOwnable is added. Signed-off-by: Alice Ryhl [boqun: Make RcuBox generic over Allocator and add tests] [boqun: Add type alias for Rcu*Box] [boqun: Adjust the ForeignOwnable changes on `T` not being `:'static`] Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng --- rust/bindings/bindings_helper.h | 1 + rust/kernel/sync/rcu.rs | 36 ++++- rust/kernel/sync/rcu/rcu_box.rs | 248 ++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/sync/rcu/rcu_box.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 1124785e210b..3e3f1799a49f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs index 2bae76d229f0..42f6bbc83f71 100644 --- a/rust/kernel/sync/rcu.rs +++ b/rust/kernel/sync/rcu.rs @@ -4,7 +4,19 @@ //! //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.= h) =20 -use crate::{bindings, types::NotThreadSafe}; +use crate::{ + bindings, + types::{ + ForeignOwnable, + NotThreadSafe, // + }, // +}; + +mod rcu_box; +pub use self::rcu_box::RcuBox; +pub use self::rcu_box::RcuKBox; +pub use self::rcu_box::RcuKVBox; +pub use self::rcu_box::RcuVBox; =20 /// Evidence that the RCU read side lock is held on the current thread/CPU. /// @@ -66,3 +78,25 @@ pub fn synchronize_rcu() { // SAFETY: `synchronize_rcu()` is always safe to be called from proces= s context. unsafe { bindings::synchronize_rcu() }; } + +/// Declares that a pointer type is rcu safe. +pub trait ForeignOwnableRcu: ForeignOwnable { + /// Type used to immutably borrow an rcu-safe value that is currently = foreign-owned. + type RcuBorrowed<'a> + where + Self: 'a; + + /// Borrows a foreign-owned object immutably for an rcu grace period. + /// + /// This method provides a way to access a foreign-owned rcu-safe valu= e from Rust immutably. + /// + /// # Safety + /// + /// * The provided pointer must have been returned by a previous call = to [`into_foreign`]. + /// * If [`from_foreign`] is called, then `'a` must not end after the = call to `from_foreign` + /// plus one rcu grace period. + /// + /// [`into_foreign`]: ForeignOwnable::into_foreign + /// [`from_foreign`]: ForeignOwnable::from_foreign + unsafe fn rcu_borrow<'a>(ptr: *mut ffi::c_void) -> Self::RcuBorrowed<'= a>; +} diff --git a/rust/kernel/sync/rcu/rcu_box.rs b/rust/kernel/sync/rcu/rcu_box= .rs new file mode 100644 index 000000000000..cb1fd422480a --- /dev/null +++ b/rust/kernel/sync/rcu/rcu_box.rs @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2026 Google LLC. + +//! Provides the `RcuBox` type for Rust allocations that live for a grace = period. + +use core::{ + marker::PhantomData, + ops::Deref, + ptr::NonNull, // +}; + +use crate::{ + alloc::{ + self, + allocator::{ + KVmalloc, + Kmalloc, + Vmalloc, // + }, + AllocError, + Allocator, // + }, + bindings, + ffi::c_void, + prelude::*, + types::ForeignOwnable, +}; + +use super::{ + ForeignOwnableRcu, + Guard, // +}; + +/// A box that is freed with rcu. +/// +/// The value must be `Send`, as rcu may drop it on another thread. +/// +/// # Invariants +/// +/// * The pointer is valid and references a pinned `RcuBoxInner` alloca= ted with `A`. +/// * This `RcuBox` holds exclusive permissions to rcu free the allocation. +pub struct RcuBox(NonNull>, PhantomD= ata); + +/// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// # use kernel::sync::rcu::{self, RcuKBox}; +/// let rb =3D RcuKBox::new(42, GFP_KERNEL)?; +/// +/// assert_eq!(*rb, 42); +/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42); +/// # Ok::<(), Error>(()) +/// ``` +pub type RcuKBox =3D RcuBox; + +/// Type alias for [`RcuBox`] with a [`Vmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// # use kernel::sync::rcu::{self, RcuVBox}; +/// let rb =3D RcuVBox::new(42, GFP_KERNEL)?; +/// +/// assert_eq!(*rb, 42); +/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42); +/// # Ok::<(), Error>(()) +/// ``` +pub type RcuVBox =3D RcuBox; + +/// Type alias for [`RcuBox`] with a [`KVmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// # use kernel::sync::rcu::{self, RcuKVBox}; +/// let rb =3D RcuKVBox::new(42, GFP_KERNEL)?; +/// +/// assert_eq!(*rb, 42); +/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42); +/// # Ok::<(), Error>(()) +/// ``` +pub type RcuKVBox =3D RcuBox; + +struct RcuBoxInner { + rcu_head: bindings::callback_head, + value: T, +} + +// Note that `T: Sync` is required since when moving an `RcuBox`, th= e previous owner may +// still access `&T` for one grace period. +// +// SAFETY: Ownership of the `RcuBox` allows for `&T` and dropping th= e `T`, so `T: Send + +// Sync` implies `RcuBox: Send`. +unsafe impl Send for RcuBox {} + +// SAFETY: `&RcuBox` allows for no operations other than those permi= tted by `&T`, so `T: +// Sync` implies `RcuBox: Sync`. +unsafe impl Sync for RcuBox {} + +impl RcuBox { + /// Create a new `RcuBox`. + pub fn new(x: T, flags: alloc::Flags) -> Result { + let b =3D Box::<_, A>::new( + RcuBoxInner { + value: x, + rcu_head: Default::default(), + }, + flags, + )?; + + // INVARIANT: + // * The pointer contains a valid `RcuBoxInner` allocated with `A`. + // * We just allocated it, so we own free permissions. + Ok(RcuBox(NonNull::from(Box::leak(b)), PhantomData)) + } + + /// Access the value for a grace period. + pub fn with_rcu<'rcu>(&self, _read_guard: &'rcu Guard) -> &'rcu T { + // SAFETY: The `RcuBox` has not been dropped yet, so the value is = valid for at least one + // grace period. + unsafe { &(*self.0.as_ptr()).value } + } +} + +impl Deref for RcuBox { + type Target =3D T; + fn deref(&self) -> &T { + // SAFETY: While the `RcuBox` exists, the value remains valid. + unsafe { &(*self.0.as_ptr()).value } + } +} + +// SAFETY: +// * The `RcuBoxInner` was allocated with `A`. +// * `NonNull::as_ptr` returns a non-null pointer. +unsafe impl ForeignOwnable for RcuBox { + const FOREIGN_ALIGN: usize =3D , A> as ForeignOwnab= le>::FOREIGN_ALIGN; + + type Borrowed<'a> + =3D &'a T + where + Self: 'a; + type BorrowedMut<'a> + =3D &'a T + where + Self: 'a; + + fn into_foreign(self) -> *mut c_void { + core::mem::ManuallyDrop::new(self).0.as_ptr().cast() + } + + unsafe fn from_foreign(ptr: *mut c_void) -> Self { + // INVARIANT: Pointer returned by `into_foreign, A` carries same i= nvariants as `RcuBox`. + // SAFETY: `into_foreign` never returns a null pointer. + Self(unsafe { NonNull::new_unchecked(ptr.cast()) }, PhantomData) + } + + unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T + where + Self: 'a, + { + // SAFETY: Caller ensures that `'a` is short enough. + unsafe { &(*ptr.cast::>()).value } + } + + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T + where + Self: 'a, + { + // SAFETY: `borrow_mut` has strictly stronger preconditions than `= borrow`. + unsafe { Self::borrow(ptr) } + } +} + +impl ForeignOwnableRcu for RcuBox { + type RcuBorrowed<'a> + =3D &'a T + where + Self: 'a; + + unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> &'a T + where + Self: 'a, + { + // SAFETY: `RcuBox::drop` can only run after `from_foreign` is cal= led, and the value is + // valid until `RcuBox::drop` plus one grace period. + unsafe { &(*ptr.cast::>()).value } + } +} + +impl Drop for RcuBox { + fn drop(&mut self) { + // SAFETY: The `rcu_head` field is in-bounds of a valid allocation. + let rcu_head =3D unsafe { &raw mut (*self.0.as_ptr()).rcu_head }; + if core::mem::needs_drop::() { + // SAFETY: `rcu_head` is the `rcu_head` field of `RcuBoxInner<= T>`. All users will be + // gone in an rcu grace period. This is the destructor, so we = may pass ownership of the + // allocation. + unsafe { bindings::call_rcu(rcu_head, Some(drop_rcu_box::)) }; + } else { + // SAFETY: All users will be gone in an rcu grace period. + // TODO: We are luckily since `kvfree_call_rcu()` works on bot= h kmalloc and vmalloc, + // maybe a new `Allocator` method is needed. + unsafe { bindings::kvfree_call_rcu(rcu_head, self.0.as_ptr().c= ast()) }; + } + } +} + +/// Free this `RcuBoxInner`. +/// +/// # Safety +/// +/// `head` references the `rcu_head` field of an `RcuBoxInner` that has= no references to it. +/// Ownership of the `Box, A>` must be passed. +unsafe extern "C" fn drop_rcu_box(head: *mut bindings::ca= llback_head) { + // SAFETY: Caller provides a pointer to the `rcu_head` field of a `Rcu= BoxInner`. + let box_inner =3D unsafe { crate::container_of!(head, RcuBoxInner, = rcu_head) }; + + // SAFETY: Caller ensures exclusive access and passed ownership. + drop(unsafe { Box::<_, A>::from_raw(box_inner) }); +} + +#[kunit_tests(rust_rcu_box)] +mod tests { + use super::*; + + #[test] + fn rcu_box_basic() -> Result { + let rb =3D RcuBox::<_, alloc::allocator::Kmalloc>::new(42i32, allo= c::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + assert_eq!(*rb.with_rcu(&Guard::new()), 42); + + drop(rb); + + let rb =3D RcuBox::<_, alloc::allocator::Vmalloc>::new(42i32, allo= c::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + assert_eq!(*rb.with_rcu(&Guard::new()), 42); + + drop(rb); + + Ok(()) + } +} --=20 2.50.1 (Apple Git-155) From nobody Sat Jul 25 04:29: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 84C982F7AC1; Sat, 18 Jul 2026 05:33:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352786; cv=none; b=eosuWWLhCBkHCa9Ta1FrNGmaIf/8I2RIfaQJrheNzBdxQ7sfHqwwFTAnGi5ymBlSs6vurKDxHpFqR+1ZlMnLSsKHZCFyMsjVpYAbee8/xe9yEjANWHaPO2dYla15ZjGIubv+vv/qlq+jhwbxYhQfTW6DPYJ2cYeuVXWNz/rQARs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352786; c=relaxed/simple; bh=RropZ+T/dGINlBe84vu+qQwX7oVepWLhj2IWwnrpf9s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M1cp/ECpSN8PPVuA2zH44gzu/oCoB76e14ONQxTgOW+BHoGe6GhnP18rmEmxAlnYnQUK+z86AbtV6JoHXha++72P2xFpZuAAlIB/Mt+f4HhGT5fFtEYlpVtth5JY2uM2GJN1Mnt018rrpX1WkGbVMZFPSy1HAZ9rB/X1uaCkry4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=S74oZ+Kf; 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="S74oZ+Kf" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5221E1F00A3A; Sat, 18 Jul 2026 05:33:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784352782; bh=ANkivdWz9zJi28Ji5ZKsqedVfMZZkLTBuL3A5HXMgG4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=S74oZ+Kf+W9DaTE/adZxHs/zT3jTY86uvo9csra4zk1fxvcoz87SLmi1zDEP3fW6b Rw/M7sccrpOA8NtpIc08mzE2JKpo/HJ4QhVOGiKUiqL7rZMilH6rjPXcZK2h72INHZ eaByKrAaXmSI0JgJqSEX9epJnXZTLTMWo3l3sXweHIaVeqBOpc4mFqgP8nefQV9KgW KQUhG8FlOnBNUuY9F94SLEDqTQEb6EfXuXpW0KDIhyvDL9fTwbeUKIMsoNCIcfo+rf ZxjDumuq+1trxbnnafqMpPzyLbP7QQQGWmyQrw6BKmcrSta+myUC9UXGq18JeLPJD8 03/0Bnn2jrosg== Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfauth.phl.internal (Postfix) with ESMTP id 82E0EF40067; Sat, 18 Jul 2026 01:33:00 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Sat, 18 Jul 2026 01:33:00 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTEgEAJxx43zj+N2HexbcXxXpr8iZewHIC+wBoUe/3kHvIsxmf0uovnwyzmQf22fh5 PbBpjLE4M1x+gkTl4x5OuQgzkddFgVOLc7SPm8OVC3wj6PmDWqpG/wyzm0HbMF//9RDtvM cqERhXH8fRAethPTEdiPCDM2biIjvo2duSrcDNiRwIZ4PJTMN9f05eRQvmRRsxcI1+ZGXR GIOp0pU8kR4mYsSetTdmMF1Q09Qod6lgNc4Vx07svlwAfyl7KUdd5xFGJoXDRG1kaoRL4T /VNW+87mn/mN1dMvhE363j1dLxUYIFMMuhRaBTcK4fjHHNruAjFs082R/vn5pb6pwik6pX 3SHkN1ACEiezX0mrwyw4KfdbjmcRDjPvFlZoRAWQNQEQ3EJoP/wDviNR1nZpBknlDVOTAm 5dYtVMhKPL3ejT4Z+9iLU6DN6wRmWI4z6RdrjcnbevPeUXCNjW/MmqIagNfqcNHcvysGxf F03b3aVMnfh3U5HgzIMSYBanXCwMagUxvz5GKBlhVYIyKFcLfT6NwEhyGaJIOzCGE3faVH ZMdtpcaeMbwqM2mvR0yLwIk6IcpchHNeCuWKsiYXXPQcx8PqDKoFg2G0cPq0x543bCm8PT Sy+F7A9BzGFg985bJyfOkZcS3quFI+ZuDrrtYiKBfrcVpYvLCLmguRzokYZg X-ME-Proxy: Feedback-ID: i8dbe485b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 18 Jul 2026 01:32:59 -0400 (EDT) From: Boqun Feng To: rust-for-linux@vger.kernel.org, rcu@vger.kernel.org Cc: Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?UTF-8?q?Onur=20=C3=96zkan?= , "Liam R. Howlett" , Andrew Ballance , Alexander Viro , Christian Brauner , Jan Kara , Lyude Paul , "Paul E. McKenney" , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Sumit Semwal , =?UTF-8?q?Christian=20K=C3=B6nig?= , Greg Kroah-Hartman , "Yury Norov (NVIDIA)" , Asahi Lina , Matthew Maurer , Lorenzo Stoakes , linux-kernel@vger.kernel.org, maple-tree@lists.infradead.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [RFC PATCH v2 2/4] rust: maple_tree: Add load_rcu() Date: Fri, 17 Jul 2026 22:32:45 -0700 Message-ID: <20260718053247.25154-3-boqun@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260718053247.25154-1-boqun@kernel.org> References: <20260718053247.25154-1-boqun@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Alice Ryhl Now that we have a concept of rcu-safe containers, we may add a load_rcu() method to MapleTree that does not take the spinlock. Signed-off-by: Alice Ryhl --- rust/kernel/maple_tree.rs | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/rust/kernel/maple_tree.rs b/rust/kernel/maple_tree.rs index 265d6396a78a..1499191b8935 100644 --- a/rust/kernel/maple_tree.rs +++ b/rust/kernel/maple_tree.rs @@ -16,6 +16,10 @@ alloc::Flags, error::to_result, prelude::*, + sync::rcu::{ + self, + ForeignOwnableRcu, // + }, types::{ForeignOwnable, Opaque}, }; =20 @@ -233,6 +237,54 @@ pub fn erase(&self, index: usize) -> Option { unsafe { T::try_from_foreign(ret) } } =20 + /// Load the value at the given index with rcu. + /// + /// # Examples + /// + /// Read the value under an rcu read lock. Even if the value is remove= d, it remains accessible + /// for one rcu grace period. + /// + /// ```ignore + /// use kernel::{ + /// maple_tree::MapleTree, + /// sync::rcu::{self, RcuBox}, + /// }; + /// + /// let tree =3D KBox::pin_init(MapleTree::>::new(), GFP_K= ERNEL)?; + /// + /// let ten =3D RcuBox::new(10, GFP_KERNEL)?; + /// tree.insert(100, ten, GFP_KERNEL)?; + /// + /// let rcu_read_lock =3D rcu::Guard::new(); + /// let ten =3D tree.load_rcu(100, &rcu_read_lock); + /// assert_eq!(ten, Some(&10)); + /// + /// // Even if the value gets removed, we may continue to access it fo= r one rcu grace period. + /// tree.erase(100); + /// assert_eq!(ten, Some(&10)); + /// # Ok::<_, Error>(()) + /// ``` + #[inline] + pub fn load_rcu<'rcu>( + &self, + index: usize, + _rcu: &'rcu rcu::Guard, + ) -> Option> + where + T: ForeignOwnableRcu, + { + // SAFETY: `self.tree` contains a valid maple tree. + let ret =3D unsafe { bindings::mtree_load(self.tree.get(), index) = }; + if ret.is_null() { + return None; + } + + // SAFETY: If the pointer is not null, then it references a valid = instance of `T`. It is + // safe to borrow the instance for 'rcu because the signature of t= his function enforces that + // the borrow does not outlive an rcu grace period. + Some(unsafe { T::rcu_borrow(ret) }) + } + /// Lock the internal spinlock. #[inline] pub fn lock(&self) -> MapleGuard<'_, T> { --=20 2.50.1 (Apple Git-155) From nobody Sat Jul 25 04:29: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 A657019AD5C; Sat, 18 Jul 2026 05:33: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=1784352786; cv=none; b=D2Rw8/r2yZIclbIy0rrDNHz33E+y+K82e66EaSWge+KEET9xvAj/ktub7Y7XWw7WmpRq67o1LV/uYHcWu5c/FKLt4Jehws9oDHXHfbb3tN1hkkTGH231OeOlBEbotQPBL07IYgzbsfXafO7t4cQKmpALvM8SOV1AMElOMQi/O1M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352786; c=relaxed/simple; bh=TNn/jDEr9CbQuxOMUVdYM2YyDJveN3eRBuNASoulf4M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sE4pkh2FHMPc7lw+yRVX8AdG7qGPSlGNYYcdkttmww8rglqu5nxqGD1VNUF1tNSX8NwQd9xfxRAJ/ZaAZO0r8Ax1yOLTwjJkQbhXNRjckb8dXp+LK5bETXUFeXd3WtkfvS5wJiiHitM+JHg4jD28RFjSMM7t3RkdTxm79uT2rKU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fU1ozw21; 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="fU1ozw21" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5FA6C1F00A3F; Sat, 18 Jul 2026 05:33:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784352784; bh=YumMbTuFN39udjMu2dZ9HB8drw55p7kF/M9QUGWthnc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fU1ozw21g3OiLiw32hofDBp594Bnbsf4fggg3vRf2B3N20vySW14GDyXM3Zd/55Ok BmJK5lEN2a99FJFR76Qi3qYkDMDW3cHPMF8Bvj8jMoQV9iSH4/6LBnBLYjyOC79N5R xJMGDMUaJLqd4falmtUhigxSUtYOVjqdrtuzz+7aYaGkqC1atbUT8mFPrGJ6UE2Y0z RxaOO2ZGETbyVDjQTdX9lP7YHALngdas1wuaWSXYQ2PeB39r8ikeVge1fjNQ8Uw7L3 VuX21L+Cz0hlaj+NgKXsQ29XGBGKGJ5NeRxFeU9ygADtXeSGVUXNqV51RZqQOduFFk SaAbYGWIhwReg== Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfauth.phl.internal (Postfix) with ESMTP id 910F2F4006A; Sat, 18 Jul 2026 01:33:02 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Sat, 18 Jul 2026 01:33:02 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTEe1tEuSFJRyejgcADWwC1Q31VcIulMbzlwxQxSwM7p7NELQtXxoL4t9u3P3h6szL wb7v4Y1Nfd9PJf44pRYto2n4BU3w63GmouT4LNR6cMb94hByhC4T19UClHqFpzwzazj5Vf A8YkKW1UUR0TJ8dV49ki0VbHb8uMKM6KId0g8EWioE2qFZQpDctdLDeip2hFqPq5d3ACH5 qO7/M64UwGhfkVp49Uw1mz7RUEmunGbHxCq20xcQsFHR4VpiWV6KRY8BvJYxsbWtxpbsKA SwMJCFL53Iue2y6cUSY74fyEj9Wo66A5FNIdAV9MLOMsDNkZ9FUjwGTU+R2pAhU2dl3BiV 3I6CxXPrsaR7ob/+XwDdwE1bYBvmRiUsRk7/rUs+UYDvdKLKB7I6Eu1kIAIIDcE1+a4imU YHcJetBuL/vOAIOYwH6aaoJDy+GJIhenv+zw/dHzAIgAqqJYpd3e5O78/+ODcs2txRksBs Ewqmdqb5NZoKU++D/70ThHKygiJvh5+z3zklLGIVDfh1OjUh01ut04C68MFuC2qz3KMABj JuDPLErNsJpKDu8I1saGiCQEKmgO8R0Vw8A3yJBeComoPpSEVZJI3K6KXgBdSdFOGDn2KY d8uzNvMiS6CBun5S29KMsO3+5Is6UApvD+5wrf+PGpBpTm2rIsuZVK74ylLQ X-ME-Proxy: Feedback-ID: i8dbe485b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 18 Jul 2026 01:33:01 -0400 (EDT) From: Boqun Feng To: rust-for-linux@vger.kernel.org, rcu@vger.kernel.org Cc: Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?UTF-8?q?Onur=20=C3=96zkan?= , "Liam R. Howlett" , Andrew Ballance , Alexander Viro , Christian Brauner , Jan Kara , Lyude Paul , "Paul E. McKenney" , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Sumit Semwal , =?UTF-8?q?Christian=20K=C3=B6nig?= , Greg Kroah-Hartman , "Yury Norov (NVIDIA)" , Asahi Lina , Matthew Maurer , Lorenzo Stoakes , linux-kernel@vger.kernel.org, maple-tree@lists.infradead.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [RFC PATCH v2 3/4] rust: rcu: Introduce RcuFreeBox Date: Fri, 17 Jul 2026 22:32:46 -0700 Message-ID: <20260718053247.25154-4-boqun@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260718053247.25154-1-boqun@kernel.org> References: <20260718053247.25154-1-boqun@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The current RcuBox will call the `drop()` function after a grace period inside an RCU callback. This suffices for maintaining a RCU-protected object: RcuBox::drop(): call_rcu( |..| { // <- call back after one grace period. T::drop(); // <- call the destructor of the inner object. } ) However, to support a different RCU usage pattern as below we need to extend RcuBox: 1. clean up the object, and unshare it from future RCU readers. 2. wait for an RCU grace period. 3. no other RCU readers, we can free the memory. An `RcuFreeBox` is introduced to provide support for this: RcuFreeBox::drop(): T::drop_before_gp(); // clean up and ushare. kfree_call_rcu(..); // free it after one grace period. Signed-off-by: Boqun Feng --- rust/kernel/sync/rcu.rs | 34 ++++++++++++++++ rust/kernel/sync/rcu/rcu_box.rs | 72 +++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs index 42f6bbc83f71..e781a5044de9 100644 --- a/rust/kernel/sync/rcu.rs +++ b/rust/kernel/sync/rcu.rs @@ -4,6 +4,8 @@ //! //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.= h) =20 +use core::pin::Pin; + use crate::{ bindings, types::{ @@ -18,6 +20,8 @@ pub use self::rcu_box::RcuKVBox; pub use self::rcu_box::RcuVBox; =20 +pub use self::rcu_box::RcuFreeBox; + /// Evidence that the RCU read side lock is held on the current thread/CPU. /// /// The type is explicitly not `Send` because this property is per-thread/= CPU. @@ -100,3 +104,33 @@ pub trait ForeignOwnableRcu: ForeignOwnable { /// [`from_foreign`]: ForeignOwnable::from_foreign unsafe fn rcu_borrow<'a>(ptr: *mut ffi::c_void) -> Self::RcuBorrowed<'= a>; } + +/// Declares a struct is safe to free after a grace period if all readers = are guarded by RCU. +/// +/// # Safety +/// +/// Implementation must guarantee `drop_before_gp()` makes sure no future = RCU reader will access +/// any part of [`Self`], as a result, after `drop_before_gp()` return + o= ne grace period, no RCU +/// reader will be on the object, and it's safe to free it. +/// +/// Notes for implementators: implementing this trait in general requires = `Self` being a +/// [`UnsafePinned`], i.e. a `&mut Self` is not a noalias reference if `Se= lf` has non-trivial +/// `drop()` function. +pub unsafe trait RcuFreeSafe { + /// Clean up `Self` and make it ready to be RCU freed. + fn drop_before_gp(self: Pin<&mut Self>); +} + +macro_rules! impl_not_drop { + ($($t:ty, )*) =3D> { + // SAFETY: Dropping `T` has no side effect means `T` is always rea= dy to be freed. And an + // empty `drop_before_gp()` suffices. + $(unsafe impl RcuFreeSafe for $t { + fn drop_before_gp(self: Pin<&mut Self>) { + $crate::const_assert!(!core::mem::needs_drop::<$t>()); + } + })* + } +} + +impl_not_drop! {i8,u8,i16,u16,i32,u32,isize,usize,i64,u64,} diff --git a/rust/kernel/sync/rcu/rcu_box.rs b/rust/kernel/sync/rcu/rcu_box= .rs index cb1fd422480a..ab4e9b2a4444 100644 --- a/rust/kernel/sync/rcu/rcu_box.rs +++ b/rust/kernel/sync/rcu/rcu_box.rs @@ -6,6 +6,7 @@ =20 use core::{ marker::PhantomData, + mem::ManuallyDrop, ops::Deref, ptr::NonNull, // }; @@ -29,17 +30,18 @@ =20 use super::{ ForeignOwnableRcu, - Guard, // + Guard, + RcuFreeSafe, // }; =20 -/// A box that is freed with rcu. +/// A box that is drop with RCU. /// -/// The value must be `Send`, as rcu may drop it on another thread. +/// The value must be `Send`, as RCU may drop it on another thread. /// /// # Invariants /// /// * The pointer is valid and references a pinned `RcuBoxInner` alloca= ted with `A`. -/// * This `RcuBox` holds exclusive permissions to rcu free the allocation. +/// * This `RcuBox` holds exclusive permissions to RCU-free the allocation. pub struct RcuBox(NonNull>, PhantomD= ata); =20 /// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator. @@ -223,6 +225,56 @@ fn drop(&mut self) { drop(unsafe { Box::<_, A>::from_raw(box_inner) }); } =20 +/// A box that is freed with RCU. +/// +/// Currently we require `T` being `Send` because of an implementation lim= itation. In theory we can +/// support `T` being `!Send`, since the RCU callback is only used to free= the memory, not dropping +/// `T`. +pub struct RcuFreeBox(RcuBox, A>); + +impl RcuFreeBox { + /// Create a new `RcuFreeBox`. + pub fn new(x: T, flags: alloc::Flags) -> Result { + Ok(Self(RcuBox::new(ManuallyDrop::new(x), flags)?)) + } +} + +impl Deref for RcuFreeBox { + type Target =3D T; + + fn deref(&self) -> &T { + self.0.deref() + } +} + +impl Drop for RcuFreeBox { + fn drop(&mut self) { + // CAST: `ManuallyDrop>` is transparent to `RcuBoxI= nner`, and `RcuBox` + // owns the object per type invariants. + let inner: *mut RcuBoxInner =3D self.0 .0.as_ptr().cast(); + + // SAFETY: Per the invariants of `RcuBox`, `inner` owns the pointe= d object. And we are not + // going to move it. + let pin =3D unsafe { Pin::new_unchecked(&mut (*inner).value) }; + + pin.drop_before_gp(); + + // `needs_drop::()` returns `false`, hence `kvfree_c= all_rcu()` will be called + // and free the underlying data after a grace period. + } +} + +// Note that `T: Sync` is required since when moving an `RcuFreeBox`= , the previous owner may +// still access `&T` for one grace period. +// +// SAFETY: Ownership of the `RcuFreeBox` allows for `&T` and droppin= g the `T`, so `T: Send + +// Sync` implies `RcuFreeBox: Send`. +unsafe impl Send for RcuFreeBo= x {} + +// SAFETY: `&RcuFreeBox` allows for no operations other than those p= ermitted by `&T`, so `T: +// Sync` implies `RcuFreeBox: Sync`. +unsafe impl Sync for RcuFreeBo= x {} + #[kunit_tests(rust_rcu_box)] mod tests { use super::*; @@ -236,6 +288,12 @@ fn rcu_box_basic() -> Result { =20 drop(rb); =20 + let rb =3D RcuFreeBox::<_, alloc::allocator::Kmalloc>::new(42i32, = alloc::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + + drop(rb); + let rb =3D RcuBox::<_, alloc::allocator::Vmalloc>::new(42i32, allo= c::flags::GFP_KERNEL)?; =20 assert_eq!(*rb, 42); @@ -243,6 +301,12 @@ fn rcu_box_basic() -> Result { =20 drop(rb); =20 + let rb =3D RcuFreeBox::<_, alloc::allocator::Vmalloc>::new(42i32, = alloc::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + + drop(rb); + Ok(()) } } --=20 2.50.1 (Apple Git-155) From nobody Sat Jul 25 04:29: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 C9414363C7C; Sat, 18 Jul 2026 05:33:06 +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=1784352797; cv=none; b=buEPtIedhuvT8apNK387wwNUxs8qghVnIxMs/hm/k7oWNPIHF6RwwIgJtP53IsUzu8jjBbDMNWcdZePruKnMHlFLsvq62TQdf9es29GmXzD53nOPgbov4ZEIbXejZEydxwAeLGTZSeF5ORpeyJjr60sqcsIyvV3zg3TXHUxu1Sc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784352797; c=relaxed/simple; bh=uIFlwPvC9oMy6KK/16uEdJeefp5bhJkW7mFN++IULVU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Uc/0e+BSZb97ZdXZb40hYW6Ef2wyrptqtKJtnojianBF7EFzEjah/vUTyT0wEtPUNE0atzhXpnO5bg3ThHBS9hX2nqJasG5+WwyA/1+M6ltZZO089tu4gUWfsY27tWhayW60AN87Po+bYeYv9Fwyet6amxwAwgy4LBSgNx7b53U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MwbqhS59; 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="MwbqhS59" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2322F1F00ACA; Sat, 18 Jul 2026 05:33:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784352786; bh=agZo2XMu3L0K2ubakxGylN/JFYjmY5Vh7gaRmN8isS0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MwbqhS59pHFX2y1bjCbULv/pCDqqg/3CNZTpDqkOxuqIBllpv6JuP2ceX0z4ojwaC hFcGSdyF26rxMWJerVgJwtbmAMxEaiNAZRCba8S6mwOIsS1xmVj0mRmaV9xuhV2YMi BVgHXSxVwuvhrdOqZ1zuvlp+lIhZbP8Et1IjKpLehemcIMVQm5B82uXKWjO/8IdEhs +MsHZn4wxWxhILUdNXdR8MeVp5F4MHKZjegrurQn2HatPRi4P1YswdCYvni7/ombXc sVC1628sS6njMIV6WsvNjc2olUvHZlDljdFAlSQj63c1HcaWsn4q3UExFh6mwES36f sYOXLcAJwL4BQ== Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfauth.phl.internal (Postfix) with ESMTP id 4D860F40067; Sat, 18 Jul 2026 01:33:04 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Sat, 18 Jul 2026 01:33:04 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTEgEAJxx43zj+N2HexbcXxXpr8iZewHIC+wBoUe/3kHvIsxmf0uovnwyzmQf22fh5 PbBpjLE4M1x+gkTl4x5OuQgzkddFgVOLc7SPm8OVC3wj6PmDWqpG/wyzm0HbMF//9RDtvM cqERhXH8fRAethPTEdiPCDM2biIjvo2duSrcDNiRwIZ4PJTMN9f05eRQvmRRsxcI1+ZGXR GIOp0pU8kR4mYsSetTdmMF1Q09Qod6lgNc4Vx07svlwAfyl7KUdd5xFGJoXDRG1kaoRL4T /VNW+87mn/mN1dMvhE363j1dLxUYIFMMuhRaBTcK4fjHHNruAjFs082R/vn5pb6pwik6oO i02M8fONfup6UUyVvWAj3LIiaccJx79xi00AFE7MEV3WF030lZ8xA8SpsEi6Gl4rTphLm7 W85qiFkiPnFPEyGQsPlpzBH5SC88pTqTl7zHOgB1UizF1X8HWy0pjCGlfqlb5KhMIGeksB BM77F8Iz5gz4nm5AaBX89I/O5EsTxlSPFMjiVPNKun4nrYJZwlRKq2rf9JutxjHhCePeF2 ZUczb4x89X5B2J5KgEEM0Ar+g8NYdZYNAfHEmuK+asohxaGqvLq7z5ddhcnnsaaXdjRYl3 r6LYJ4YMNhLSLVbKF0j9W9SxoIz0cRSZGuTCLSTBHjntmeBEzvh958UnZESQ X-ME-Proxy: Feedback-ID: i8dbe485b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 18 Jul 2026 01:33:03 -0400 (EDT) From: Boqun Feng To: rust-for-linux@vger.kernel.org, rcu@vger.kernel.org Cc: Miguel Ojeda , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?UTF-8?q?Onur=20=C3=96zkan?= , "Liam R. Howlett" , Andrew Ballance , Alexander Viro , Christian Brauner , Jan Kara , Lyude Paul , "Paul E. McKenney" , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Sumit Semwal , =?UTF-8?q?Christian=20K=C3=B6nig?= , Greg Kroah-Hartman , "Yury Norov (NVIDIA)" , Asahi Lina , Matthew Maurer , Lorenzo Stoakes , linux-kernel@vger.kernel.org, maple-tree@lists.infradead.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [NOT FOR MERGE] [RFC PATCH v2 4/4] rust: poll: use kfree_rcu() for PollCondVar Date: Fri, 17 Jul 2026 22:32:47 -0700 Message-ID: <20260718053247.25154-5-boqun@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260718053247.25154-1-boqun@kernel.org> References: <20260718053247.25154-1-boqun@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Alice Ryhl Rust Binder currently uses PollCondVar, but it calls synchronize_rcu() in the destructor, which we would like to avoid. Add a variation of PollCondVar that kfree_rcu() instead. One could avoid the `rcu` field and allocate the rcu_head on drop using a fallback to synchronize_rcu() on ENOMEM. However, I'd prefer to avoid the potential for synchronize_rcu(), and Binder will only use this for a small fraction of processes, so even if it changes which kmalloc bucket it falls into, the extra memory is not a problem. Signed-off-by: Alice Ryhl [boqun: Use RcuFreeSafe] Signed-off-by: Boqun Feng --- rust/kernel/sync/poll.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs index 5aa0ce9ba01b..830a4763a5c1 100644 --- a/rust/kernel/sync/poll.rs +++ b/rust/kernel/sync/poll.rs @@ -9,12 +9,19 @@ fs::File, prelude::*, sync::{ - rcu::synchronize_rcu, + rcu::{ + synchronize_rcu, // + RcuFreeSafe, + }, CondVar, LockClassKey, // }, // }; -use core::{marker::PhantomData, ops::Deref}; + +use core::{ + marker::PhantomData, + ops::Deref, // +}; =20 /// Creates a [`PollCondVar`] initialiser with the given name and a newly-= created lock class. #[macro_export] @@ -70,6 +77,7 @@ pub fn register_wait(&self, file: &File, cv: &PollCondVar= ) { /// /// [`CondVar`]: crate::sync::CondVar #[pin_data(PinnedDrop)] +#[repr(transparent)] pub struct PollCondVar { #[pin] inner: CondVar, @@ -97,12 +105,20 @@ fn deref(&self) -> &CondVar { impl PinnedDrop for PollCondVar { #[inline] fn drop(self: Pin<&mut Self>) { + self.drop_before_gp(); + + // Wait for epoll items to be properly removed. + synchronize_rcu(); + } +} + +// SAFETY: __wake_up_pollfree() guarantees all the epoll items on the wait= list will be gone after +// one grace period. +unsafe impl RcuFreeSafe for PollCondVar { + fn drop_before_gp(self: Pin<&mut Self>) { // Clear anything registered using `register_wait`. // // SAFETY: The pointer points at a valid `wait_queue_head`. unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.g= et()) }; - - // Wait for epoll items to be properly removed. - synchronize_rcu(); } } --=20 2.50.1 (Apple Git-155)