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 0E144CD6E69 for ; Wed, 3 Jun 2026 09:33:44 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4EE4F10FABF; Wed, 3 Jun 2026 09:33:44 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; secure) header.d=mailbox.org header.i=@mailbox.org header.b="rXa3OMm6"; dkim-atps=neutral Received: from mout-p-103.mailbox.org (mout-p-103.mailbox.org [80.241.56.161]) by gabe.freedesktop.org (Postfix) with ESMTPS id 760E210FABF for ; Wed, 3 Jun 2026 09:33:42 +0000 (UTC) Received: from smtp1.mailbox.org (smtp1.mailbox.org [10.196.197.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4gVjDz3Ydbz9typ; Wed, 3 Jun 2026 11:33:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailbox.org; s=mail20150812; t=1780479219; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uxlvNgzFhuUMFy3AJQAJ/mexbnuvDP26gexhGmIyYvU=; b=rXa3OMm69ylL0XEsry/z6aRsOURXk8Xj2riKqb4JOiuuHN+oLPpAZiNogTMnOVLWV10kpc 9znbIUj1gQVgnt8l3X+1AhLKxhI5G7wU9VfPd5TKi2UvZetCiBTCCqBH+7klFZipO/0j8c 0aErQSElVtS5HEqiwxm8h5SYpMts7M0hQm1DxjWE1y+yw50LiODJyhii/TzGA4n6VHL5kj liLRiC7Kj83tGFmryDFiZK5DnaPOTiFJx7ZVUVWZN679Gpzz89xMeatn25Kl8mqGp5kASq OSsPfUT0Euzqy9MW3fUaVpN8TVpuwog+dT3SMibUX9g96SwvlVyWGSolMdmd8w== Message-ID: <441fccce521857ab82b84bb8e5ab539ee3810a36.camel@mailbox.org> Subject: Re: [PATCH 2/4] rust: rcu: add RcuBox type From: Philipp Stanner To: Boqun Feng , phasta@kernel.org 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 Date: Wed, 03 Jun 2026 11:33:27 +0200 In-Reply-To: References: <20260530143541.229628-2-phasta@kernel.org> <20260530143541.229628-4-phasta@kernel.org> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-MBO-RS-ID: 761970c1ee4b5674507 X-MBO-RS-META: f3jc7cwj7qd9k4gjs764r7kez9kkqwib 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: , Reply-To: phasta@kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On Mon, 2026-06-01 at 06:41 -0700, Boqun Feng wrote: > On Mon, Jun 01, 2026 at 09:56:23AM +0200, Philipp Stanner wrote: > > On Sat, 2026-05-30 at 08:08 -0700, Boqun Feng wrote: > > > On Sat, May 30, 2026 at 04:35:10PM +0200, Philipp Stanner wrote: > > > > From: Alice Ryhl > > > >=20 > > > > This adds an RcuBox container, which is like KBox except that the v= alue > > > > is freed with kfree_rcu. > > > >=20 > > > > To allow containers to rely on the rcu properties of RcuBox, an > > > > extension of ForeignOwnable is added. > > > >=20 > > > > Signed-off-by: Alice Ryhl > > > > --- > > >=20 > > > I have the following on top of Alice's patch. @Alice, @Danilo, though= ts? > > >=20 > > > Then we can have: > > >=20 > > > type RcuKBox =3D RcuBox; > > > type RcuVBox =3D RcuBox; > >=20 > > No objections by me. > >=20 > > I just think we have to decide how the treat the namespaces, though. > > Probably Alice wrote it like that so that it's very apparent that this > > is not a normal box. It still breaks the naming convention in my > > opinion. > >=20 > > rcu::Box vs rcu::RcuBox > >=20 > > With all other subsystems, naming like that seems not allowed. > >=20 > > dma::Fence vs dma::DmaFence > >=20 > >=20 > > I probably would allow the user to decide whether he wants to just use > > it as `rcu::Box` in all his code. > >=20 > > But no hard feelings. > >=20 >=20 > For this I think that rcu::RcuBox is a bit different than dma::Fence, > because Box has its widely-accepted meaning through all Rust code, > while `Fence` doesn't. Hence my current thought is rcu::RcuBox and > dma::Fence. My personal preference is using namespace as much as we > could until there might be some misleading. Yoah, probably better we're safer rather than hyper-consistent. >=20 > >=20 > >=20 > > >=20 > > > and Philipp can use the `RcuKBox` in this patchset. We also need to i= mpl > > > InPlaceInit for RcuBox, but that can be added later. > >=20 > > So shall we merge my series with Alice's patch, and later we add your > > patch and other features, or would you prefer to have the additional > > boxes from your patch from the get-go? > >=20 >=20 > I would like to have it from the get-go mainly because of RcuBox vs > RcuKBox naming. Thank you! Fine by me. Just process-wise: how should we do it? I could include your patch on top of Alice's. Would be a bit more consistent regarding the git-workflow if we'd squash the two patches, but then you two would have to agree on authorship. All is fine by me, but I wanted to ask instead of just do A or B. P. >=20 > Regards, > Boqun >=20 > >=20 > > P. > >=20 > > >=20 > > > Regards, > > > Boqun > > >=20 > > > ------------->8 > > > Subject: [PATCH] rust: rcu: Make RcuBox generic over Allocator > > >=20 > > > 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 b= oth > > > allocations. > > >=20 > > > While we are at it, add some basic test cases. > > >=20 > > > Signed-off-by: Boqun Feng > > > --- > > > =C2=A0rust/kernel/sync/rcu/rcu_box.rs | 96 +++++++++++++++++++++++---= ------- > > > =C2=A01 file changed, 67 insertions(+), 29 deletions(-) > > >=20 > > > diff --git a/rust/kernel/sync/rcu/rcu_box.rs b/rust/kernel/sync/rcu/r= cu_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 @@ > > > =C2=A0 > > > =C2=A0//! Provides the `RcuBox` type for Rust allocations that live f= or a grace period. > > > =C2=A0 > > > -use core::{ops::Deref, ptr::NonNull}; > > > +use core::{ > > > +=C2=A0=C2=A0=C2=A0 marker::PhantomData, > > > +=C2=A0=C2=A0=C2=A0 ops::Deref, > > > +=C2=A0=C2=A0=C2=A0 ptr::NonNull, // > > > +}; > > > =C2=A0 > > > =C2=A0use kernel::{ > > > -=C2=A0=C2=A0=C2=A0 alloc::{self, AllocError}, > > > +=C2=A0=C2=A0=C2=A0 alloc::{ > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 self, > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 AllocError, > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Allocator, // > > > +=C2=A0=C2=A0=C2=A0 }, > > > =C2=A0=C2=A0=C2=A0=C2=A0 bindings, > > > =C2=A0=C2=A0=C2=A0=C2=A0 ffi::c_void, > > > =C2=A0=C2=A0=C2=A0=C2=A0 prelude::*, > > > -=C2=A0=C2=A0=C2=A0 sync::rcu::{ForeignOwnableRcu, Guard}, > > > =C2=A0=C2=A0=C2=A0=C2=A0 types::ForeignOwnable, > > > =C2=A0}; > > > =C2=A0 > > > +use super::{ > > > +=C2=A0=C2=A0=C2=A0 ForeignOwnableRcu, > > > +=C2=A0=C2=A0=C2=A0 Guard, // > > > +}; > > > + > > > =C2=A0/// A box that is freed with rcu. > > > =C2=A0/// > > > =C2=A0/// The value must be `Send`, as rcu may drop it on another thr= ead. > > > =C2=A0/// > > > =C2=A0/// # Invariants > > > =C2=A0/// > > > -/// * The pointer is valid and references a pinned `RcuBoxInner` = allocated with `kmalloc`. > > > +/// * The pointer is valid and references a pinned `RcuBoxInner` = allocated with `A`. > > > =C2=A0/// * This `RcuBox` holds exclusive permissions to rcu free the= allocation. > > > -pub struct RcuBox(NonNull>); > > > +pub struct RcuBox(NonNull>, Ph= antomData); > > > =C2=A0 > > > =C2=A0struct RcuBoxInner { > > > =C2=A0=C2=A0=C2=A0=C2=A0 value: T, > > > =C2=A0=C2=A0=C2=A0=C2=A0 rcu_head: bindings::callback_head, > > > =C2=A0} > > > =C2=A0 > > > -// 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. > > > =C2=A0// > > > -// 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 dropp= ing the `T`, so `T: Send + > > > +// Sync` implies `RcuBox: Send`. > > > +unsafe impl Send for RcuBox {} > > > =C2=A0 > > > -// SAFETY: `&RcuBox` allows for no operations other than those pe= rmitted 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 {} > > > =C2=A0 > > > -impl RcuBox { > > > +impl RcuBox { > > > =C2=A0=C2=A0=C2=A0=C2=A0 /// Create a new `RcuBox`. > > > =C2=A0=C2=A0=C2=A0=C2=A0 pub fn new(x: T, flags: alloc::Flags) -> Res= ult { > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 let b =3D KBox::new( > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 let b =3D Box::<_, A>::ne= w( > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 RcuBoxInner { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 value: x, > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 rcu_head: Default::default(), > > > @@ -53,9 +65,9 @@ pub fn new(x: T, flags: alloc::Flags) -> Result { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 )?; > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // INVARIANT: > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // * The pointer contains= a valid `RcuBoxInner` allocated with `kmalloc`. > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // * The pointer contains= a valid `RcuBoxInner` allocated with `A`. > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // * We just allocat= ed it, so we own free permissions. > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Ok(RcuBox(NonNull::from(K= Box::leak(b)))) > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Ok(RcuBox(NonNull::from(B= ox::leak(b)), PhantomData)) > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 /// Access the value for a grace period. > > > @@ -66,7 +78,7 @@ pub fn with_rcu<'rcu>(&self, _read_guard: &'rcu Gua= rd) -> &'rcu T { > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0} > > > =C2=A0 > > > -impl Deref for RcuBox { > > > +impl Deref for RcuBox { > > > =C2=A0=C2=A0=C2=A0=C2=A0 type Target =3D T; > > > =C2=A0=C2=A0=C2=A0=C2=A0 fn deref(&self) -> &T { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // SAFETY: While the= `RcuBox` exists, the value remains valid. > > > @@ -75,10 +87,10 @@ fn deref(&self) -> &T { > > > =C2=A0} > > > =C2=A0 > > > =C2=A0// SAFETY: > > > -// * The `RcuBoxInner` was allocated with `kmalloc`. > > > +// * The `RcuBoxInner` was allocated with `A`. > > > =C2=A0// * `NonNull::as_ptr` returns a non-null pointer. > > > -unsafe impl ForeignOwnable for RcuBox { > > > -=C2=A0=C2=A0=C2=A0 const FOREIGN_ALIGN: usize =3D > as ForeignOwnable>::FOREIGN_ALIGN; > > > +unsafe impl ForeignOwnable for RcuB= ox { > > > +=C2=A0=C2=A0=C2=A0 const FOREIGN_ALIGN: usize =3D , A> as ForeignOwnable>::FOREIGN_ALIGN; > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 type Borrowed<'a> =3D &'a T; > > > =C2=A0=C2=A0=C2=A0=C2=A0 type BorrowedMut<'a> =3D &'a T; > > > @@ -88,9 +100,9 @@ fn into_foreign(self) -> *mut c_void { > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 unsafe fn from_foreign(ptr: *mut c_void) -> = Self { > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // INVARIANT: Pointer ret= urned by `into_foreign` carries same invariants as `RcuBox`. > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // INVARIANT: Pointer ret= urned by `into_foreign, A` carries same invariants as `RcuBox`. > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // SAFETY: `into_for= eign` never returns a null pointer. > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Self(unsafe { NonNull::ne= w_unchecked(ptr.cast()) }) > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Self(unsafe { NonNull::ne= w_unchecked(ptr.cast()) }, PhantomData) > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 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 { > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0} > > > =C2=A0 > > > -impl ForeignOwnableRcu for RcuBox { > > > +impl ForeignOwnableRcu for RcuBox { > > > =C2=A0=C2=A0=C2=A0=C2=A0 type RcuBorrowed<'a> =3D &'a T; > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 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 { > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0} > > > =C2=A0 > > > -impl Drop for RcuBox { > > > +impl Drop for RcuBox { > > > =C2=A0=C2=A0=C2=A0=C2=A0 fn drop(&mut self) { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // SAFETY: The `rcu_= head` field is in-bounds of a valid allocation. > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 let rcu_head =3D uns= afe { &raw mut (*self.0.as_ptr()).rcu_head }; > > > @@ -122,9 +134,11 @@ fn drop(&mut self) { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 // SAFETY: `rcu_head` is the `rcu_head` field of `RcuBoxInner`. All = users will be > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 // gone in an rcu grace period. This is the destructor, so we may pass = ownership of the > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 // allocation. > > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 u= nsafe { bindings::call_rcu(rcu_head, Some(drop_rcu_box::)) }; > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 u= nsafe { bindings::call_rcu(rcu_head, Some(drop_rcu_box::)) }; > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else { > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 // SAFETY: All users will be gone in an rcu grace period. > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /= / TODO: We are luckily since `kvfree_call_rcu()` works on both kmalloc and = vmalloc, > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /= / maybe a new `Allocator` method is needed. > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 unsafe { bindings::kvfree_call_rcu(rcu_head, self.0.as_ptr().cast()) }; > > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } > > > =C2=A0=C2=A0=C2=A0=C2=A0 } > > > @@ -135,11 +149,35 @@ fn drop(&mut self) { > > > =C2=A0/// # Safety > > > =C2=A0/// > > > =C2=A0/// `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_h= ead) { > > > +/// Ownership of the `Box, A>` must be passed. > > > +unsafe extern "C" fn drop_rcu_box(head: *mut bindin= gs::callback_head) { > > > =C2=A0=C2=A0=C2=A0=C2=A0 // SAFETY: Caller provides a pointer to the = `rcu_head` field of a `RcuBoxInner`. > > > =C2=A0=C2=A0=C2=A0=C2=A0 let box_inner =3D unsafe { crate::container_= of!(head, RcuBoxInner, rcu_head) }; > > > =C2=A0 > > > =C2=A0=C2=A0=C2=A0=C2=A0 // SAFETY: Caller ensures exclusive access a= nd passed ownership. > > > -=C2=A0=C2=A0=C2=A0 drop(unsafe { KBox::from_raw(box_inner) }); > > > +=C2=A0=C2=A0=C2=A0 drop(unsafe { Box::<_, A>::from_raw(box_inner) })= ; > > > +} > > > + > > > +#[kunit_tests(rust_rcu_box)] > > > +mod tests { > > > +=C2=A0=C2=A0=C2=A0 use super::*; > > > + > > > +=C2=A0=C2=A0=C2=A0 #[test] > > > +=C2=A0=C2=A0=C2=A0 fn rcu_box_basic() -> Result { > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 let rb =3D RcuBox::<_, al= loc::allocator::Kmalloc>::new(42i32, alloc::flags::GFP_KERNEL)?; > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 assert_eq!(*rb, 42); > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 assert_eq!(*rb.with_rcu(&= Guard::new()), 42); > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 drop(rb); > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 let rb =3D RcuBox::<_, al= loc::allocator::Vmalloc>::new(42i32, alloc::flags::GFP_KERNEL)?; > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 assert_eq!(*rb, 42); > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 assert_eq!(*rb.with_rcu(&= Guard::new()), 42); > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 drop(rb); > > > + > > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Ok(()) > > > +=C2=A0=C2=A0=C2=A0 } > > > =C2=A0}