From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D939DCD6E49 for ; Sat, 30 May 2026 15:08:57 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D746B112888; Sat, 30 May 2026 15:08:56 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.b="NtS4TnJU"; dkim-atps=neutral Received: from tor.source.kernel.org (tor.source.kernel.org [172.105.4.254]) by gabe.freedesktop.org (Postfix) with ESMTPS id 05188112888 for ; Sat, 30 May 2026 15:08:56 +0000 (UTC) Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by tor.source.kernel.org (Postfix) with ESMTP id F398960121; Sat, 30 May 2026 15:08:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 86EFA1F00898; Sat, 30 May 2026 15:08:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1780153734; bh=Iw0FhbtvjuV1urcZGjkx/qt7+8pTDgXeuj/fbCEH8Z8=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=NtS4TnJUEx6ZBROs3IAYPPCv502M1JnfN+ZrT1IVXgXQBIT1MebRwxZ7OG+kK9q3l whB86kXoIGtoH56GI+7fMrLY6PpiUbm3qBJ/6Fu6qdCXGE6fq5mSmehxcPUCozo1lp HX68MFFGke0ealMF4PiFG/3dYrPqhcymN8rD6CX2iO2IHqUwQMrjIYsfhzhy25CYq2 UmjxB1YKYrptHEfUXhxRGxSZFaJjbTgXIA1tA2moG1Ah0KoB2wefl+m1mOZ19p1fM6 tRjj4J+1UL6AJ9GSYrKilHZY+7C6WGjlsahqoF/Ia4LKCqkk7MjZJlsHdn4cicz+jx mMv8j6twHzsvQ== Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfauth.phl.internal (Postfix) with ESMTP id 9E94EF40084; Sat, 30 May 2026 11:08:52 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Sat, 30 May 2026 11:08:52 -0400 X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGQOkMpaaZDC0BephxAIuGa+jUd9e2JeV56FDIbuJEAWrj+VoXDzFdKUU1lXoKRsW eA93QvoUnLxh6FA5WO25QYu1EOQlA3G3Zi6hzUOFeKjtFdHUG2UbiVP5zvd5SbILAs5gnm 9tAHe3/r5AVsTwU1g3J/RqUIL1wuE2GPUnVUXYf0jdwNh3Ndnb1cRmGWTnjwk3JYi1huuy fRaUt7vQS3ZvhWWMg4bQm372n0OcODf7UBrL3xqg8ateiBTPkCe8aTtchAFZKoHLaS5n1a DJ+bPhozh7nEqV0LXPj0f0wDx8XxYux8+3KzRoPNUZQclpSIe966E7Vt5Mq+wkwaaF5CQO iVX5Tc6DtyBDaCoELDj/LFgplQomGJ4soFWpGvTkdhdpS87/OG/KCLHTKnPE5CVBu1EG/S CqWxyZh04AcncdY5ojIoZc6vD6rW+0yFUpsySbge+xtl3gNr69hgM4G1Y98wagmA4ugxkx 22O4D/yNZ9QnxweYMY03dtgmhgMOYJeYyu6z71hbyK888RHhEtknh7iejtvD5FfqPvjbua Yiu4KtUWy4BpGZB5E2iOJ11TvGp624vG7dGx7a0+NatE/I7KUIi/fN7hc+bJCp2ArZofJb wf+6GSB0QxOoHsdtLs3F6N1LjAGcJPsSdwvmYcxbH0ruTBjpUqtaRn8+aC2A X-ME-Proxy: Feedback-ID: i8dbe485b:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sat, 30 May 2026 11:08:51 -0400 (EDT) Date: Sat, 30 May 2026 08:08:50 -0700 From: Boqun Feng To: Philipp Stanner Cc: Miguel Ojeda , Gary Guo , =?iso-8859-1?Q?Bj=F6rn?= Roy Baron , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Sumit Semwal , Christian =?iso-8859-1?Q?K=F6nig?= , "Paul E. McKenney" , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Daniel Almeida , Greg Kroah-Hartman , Igor Korotin , Lorenzo Stoakes , Alexandre Courbot , FUJITA Tomonori , Krishna Ketan Rai , Shankari Anand , manos@pitsidianak.is, Boris Brezillon , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, rcu@vger.kernel.org Subject: Re: [PATCH 2/4] rust: rcu: add RcuBox type Message-ID: References: <20260530143541.229628-2-phasta@kernel.org> <20260530143541.229628-4-phasta@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260530143541.229628-4-phasta@kernel.org> X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On Sat, May 30, 2026 at 04:35:10PM +0200, Philipp Stanner wrote: > From: Alice Ryhl > > This adds an RcuBox container, which is like KBox except that the value > is freed with kfree_rcu. > > To allow containers to rely on the rcu properties of RcuBox, an > extension of ForeignOwnable is added. > > Signed-off-by: Alice Ryhl > --- I have the following on top of Alice's patch. @Alice, @Danilo, thoughts? Then we can have: type RcuKBox = RcuBox; type RcuVBox = RcuBox; and Philipp can use the `RcuKBox` in this patchset. We also need to impl InPlaceInit for RcuBox, but that can be added later. Regards, Boqun ------------->8 Subject: [PATCH] rust: rcu: Make RcuBox generic over Allocator To support RCU-protected vmalloc allocation, we need to make `RcuBox` generic over `Allocator`. Currently this works since all `Allocator`s are either kmalloc() or vmalloc(), and kvfree_call_rcu() works with both allocations. While we are at it, add some basic test cases. Signed-off-by: Boqun Feng --- rust/kernel/sync/rcu/rcu_box.rs | 96 +++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/rust/kernel/sync/rcu/rcu_box.rs b/rust/kernel/sync/rcu/rcu_box.rs index 2508fdb609ec..5c344d82c0d9 100644 --- a/rust/kernel/sync/rcu/rcu_box.rs +++ b/rust/kernel/sync/rcu/rcu_box.rs @@ -4,47 +4,59 @@ //! Provides the `RcuBox` type for Rust allocations that live for a grace period. -use core::{ops::Deref, ptr::NonNull}; +use core::{ + marker::PhantomData, + ops::Deref, + ptr::NonNull, // +}; use kernel::{ - alloc::{self, AllocError}, + alloc::{ + self, + AllocError, + Allocator, // + }, bindings, ffi::c_void, prelude::*, - sync::rcu::{ForeignOwnableRcu, Guard}, 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` allocated with `kmalloc`. +/// * The pointer is valid and references a pinned `RcuBoxInner` allocated with `A`. /// * This `RcuBox` holds exclusive permissions to rcu free the allocation. -pub struct RcuBox(NonNull>); +pub struct RcuBox(NonNull>, PhantomData); struct RcuBoxInner { value: T, rcu_head: bindings::callback_head, } -// Note that `T: Sync` is required since when moving an `RcuBox`, the previous owner may still -// access `&T` for one grace period. +// Note that `T: Sync` is required since when moving an `RcuBox`, the previous owner may +// still access `&T` for one grace period. // -// SAFETY: Ownership of the `RcuBox` allows for `&T` and dropping the `T`, so `T: Send + Sync` -// implies `RcuBox: Send`. -unsafe impl Send for RcuBox {} +// SAFETY: Ownership of the `RcuBox` allows for `&T` and dropping the `T`, so `T: Send + +// Sync` implies `RcuBox: Send`. +unsafe impl Send for RcuBox {} -// SAFETY: `&RcuBox` allows for no operations other than those permitted by `&T`, so `T: Sync` -// implies `RcuBox: Sync`. -unsafe impl Sync for RcuBox {} +// SAFETY: `&RcuBox` allows for no operations other than those permitted by `&T`, so `T: +// Sync` implies `RcuBox: Sync`. +unsafe impl Sync for RcuBox {} -impl RcuBox { +impl RcuBox { /// Create a new `RcuBox`. pub fn new(x: T, flags: alloc::Flags) -> Result { - let b = KBox::new( + let b = Box::<_, A>::new( RcuBoxInner { value: x, rcu_head: Default::default(), @@ -53,9 +65,9 @@ pub fn new(x: T, flags: alloc::Flags) -> Result { )?; // INVARIANT: - // * The pointer contains a valid `RcuBoxInner` allocated with `kmalloc`. + // * The pointer contains a valid `RcuBoxInner` allocated with `A`. // * We just allocated it, so we own free permissions. - Ok(RcuBox(NonNull::from(KBox::leak(b)))) + Ok(RcuBox(NonNull::from(Box::leak(b)), PhantomData)) } /// Access the value for a grace period. @@ -66,7 +78,7 @@ pub fn with_rcu<'rcu>(&self, _read_guard: &'rcu Guard) -> &'rcu T { } } -impl Deref for RcuBox { +impl Deref for RcuBox { type Target = T; fn deref(&self) -> &T { // SAFETY: While the `RcuBox` exists, the value remains valid. @@ -75,10 +87,10 @@ fn deref(&self) -> &T { } // SAFETY: -// * The `RcuBoxInner` was allocated with `kmalloc`. +// * The `RcuBoxInner` was allocated with `A`. // * `NonNull::as_ptr` returns a non-null pointer. -unsafe impl ForeignOwnable for RcuBox { - const FOREIGN_ALIGN: usize = > as ForeignOwnable>::FOREIGN_ALIGN; +unsafe impl ForeignOwnable for RcuBox { + const FOREIGN_ALIGN: usize = , A> as ForeignOwnable>::FOREIGN_ALIGN; type Borrowed<'a> = &'a T; type BorrowedMut<'a> = &'a T; @@ -88,9 +100,9 @@ fn into_foreign(self) -> *mut c_void { } unsafe fn from_foreign(ptr: *mut c_void) -> Self { - // INVARIANT: Pointer returned by `into_foreign` carries same invariants as `RcuBox`. + // INVARIANT: Pointer returned by `into_foreign, A` carries same invariants as `RcuBox`. // SAFETY: `into_foreign` never returns a null pointer. - Self(unsafe { NonNull::new_unchecked(ptr.cast()) }) + Self(unsafe { NonNull::new_unchecked(ptr.cast()) }, PhantomData) } unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T { @@ -104,7 +116,7 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T { } } -impl ForeignOwnableRcu for RcuBox { +impl ForeignOwnableRcu for RcuBox { type RcuBorrowed<'a> = &'a T; unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> &'a T { @@ -114,7 +126,7 @@ unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> &'a T { } } -impl Drop for RcuBox { +impl Drop for RcuBox { fn drop(&mut self) { // SAFETY: The `rcu_head` field is in-bounds of a valid allocation. let rcu_head = unsafe { &raw mut (*self.0.as_ptr()).rcu_head }; @@ -122,9 +134,11 @@ fn drop(&mut self) { // SAFETY: `rcu_head` is the `rcu_head` field of `RcuBoxInner`. 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::)) }; + 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 both kmalloc and vmalloc, + // maybe a new `Allocator` method is needed. unsafe { bindings::kvfree_call_rcu(rcu_head, self.0.as_ptr().cast()) }; } } @@ -135,11 +149,35 @@ fn drop(&mut self) { /// # Safety /// /// `head` references the `rcu_head` field of an `RcuBoxInner` that has no references to it. -/// Ownership of the `KBox>` must be passed. -unsafe extern "C" fn drop_rcu_box(head: *mut bindings::callback_head) { +/// Ownership of the `Box, A>` must be passed. +unsafe extern "C" fn drop_rcu_box(head: *mut bindings::callback_head) { // SAFETY: Caller provides a pointer to the `rcu_head` field of a `RcuBoxInner`. let box_inner = unsafe { crate::container_of!(head, RcuBoxInner, rcu_head) }; // SAFETY: Caller ensures exclusive access and passed ownership. - drop(unsafe { KBox::from_raw(box_inner) }); + 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 = RcuBox::<_, alloc::allocator::Kmalloc>::new(42i32, alloc::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + assert_eq!(*rb.with_rcu(&Guard::new()), 42); + + drop(rb); + + let rb = RcuBox::<_, alloc::allocator::Vmalloc>::new(42i32, alloc::flags::GFP_KERNEL)?; + + assert_eq!(*rb, 42); + assert_eq!(*rb.with_rcu(&Guard::new()), 42); + + drop(rb); + + Ok(()) + } } -- 2.50.1 (Apple Git-155)