Rust for Linux List
 help / color / mirror / Atom feed
* [PATCH v1] rust: rcu: Add abstraction for call_rcu()
@ 2026-05-20 13:17 Philipp Stanner
  2026-05-20 13:59 ` Boqun Feng
  2026-05-27  7:42 ` Alvin Sun
  0 siblings, 2 replies; 9+ messages in thread
From: Philipp Stanner @ 2026-05-20 13:17 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Paul E. McKenney, Frederic Weisbecker,
	Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Uladzislau Rezki,
	Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, Zqiang,
	Joel Fernandes (NVIDIA), Philipp Stanner, Peter Zijlstra (Intel),
	Tamir Duberstein
  Cc: rust-for-linux, linux-kernel, rcu

call_rcu() can be expected to be needed by a great variety of users.
This functionality is almost always used for deallocating resources
after all accessors are gone. Hence, it appears reasonable to implement
the abstractions in such a way that the user merely passes data, which
is later (after a grace period) dropped.

In the rare cases where the user needs special action to take place,
this could be achieved through implementing a custom drop() method.

Implement a first minimal abstraction for call_rcu().

Signed-off-by: Philipp Stanner <phasta@kernel.org>
---
 rust/helpers/rcu.c      |  1 +
 rust/kernel/sync.rs     |  1 +
 rust/kernel/sync/rcu.rs | 89 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c
index 481274c05857..c9cfc99c93d5 100644
--- a/rust/helpers/rcu.c
+++ b/rust/helpers/rcu.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#include <linux/types.h> /* for callback_head */
 #include <linux/rcupdate.h>
 
 __rust_helper void rust_helper_rcu_read_lock(void)
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index 993dbf2caa0e..1ddca3847b19 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -31,6 +31,7 @@
 pub use locked_by::LockedBy;
 pub use refcount::Refcount;
 pub use set_once::SetOnce;
+pub use rcu::Callback;
 
 /// Represents a lockdep class.
 ///
diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
index a32bef6e490b..caf71fa46f5e 100644
--- a/rust/kernel/sync/rcu.rs
+++ b/rust/kernel/sync/rcu.rs
@@ -4,7 +4,15 @@
 //!
 //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h)
 
-use crate::{bindings, types::NotThreadSafe};
+use crate::{
+    bindings,
+    prelude::*,
+    types::{
+        NotThreadSafe,
+        Opaque,
+    },
+    alloc::Flags,
+};
 
 /// Evidence that the RCU read side lock is held on the current thread/CPU.
 ///
@@ -50,3 +58,82 @@ fn drop(&mut self) {
 pub fn read_lock() -> Guard {
     Guard::new()
 }
+
+
+/// An RCU callback object. Carries the user's data to drop() it once a grace period ellapsed.
+///
+/// This object serves to implement C's `call_rcu()` method. Since it is almost
+/// always used to free a resource once a grace period ellapsed, the only thing
+/// this implementation does is drop the user's data. In the rare cases in which
+/// the user needs more action to take place, said actions need to be implemented
+/// on the user's data via the [`Drop`] trait.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::sync::rcu::Callback;
+///
+/// struct Foo {};
+///
+/// impl Drop for Foo {
+///     fn drop(&mut self) {
+///         pr_info!("rcu::Foo Dropping.\n");
+///     }
+/// }
+///
+/// let data = Foo {};
+///
+/// let cb = Callback::new(data, GFP_KERNEL)?;
+/// cb.submit();
+///
+/// Ok::<(), Error>(())
+/// ```
+#[repr(C)]
+#[pin_data]
+pub struct Callback<T: Send + 'static> {
+    /// The RCU head. Only used (and initialized) by the C backend.
+    #[pin]
+    inner: Opaque<bindings::callback_head>,
+    /// The user's data. This should implement [`Drop`] if the user wants specific
+    /// actions, besides mere deallocation, to happen.
+    #[pin]
+    data: T,
+}
+
+impl<T: Send + 'static> Callback<T> {
+    /// Create a new callback.
+    pub fn new(data: impl PinInit<T>, flags: Flags) -> Result<Pin<KBox<Self>>> {
+        let cb = try_pin_init!(Self {
+            inner: Opaque::uninit(), // Only needed for the C backend, who will initialize it.
+            data <- data,
+        });
+
+        KBox::pin_init(cb, flags)
+    }
+
+    extern "C" fn callback(rcu_head: *mut bindings::callback_head) {
+        let cb_ptr = rcu_head as *mut Self;
+
+        // SAFETY: All [`Callback`] objects in this module are always created
+        // as `Pin<KBox<Self>>`. `Pin` is a transparent container. The action
+        // below merely serves re-creating the KBox so that it can drop properly.
+        let _cb = unsafe { KBox::from_raw(cb_ptr) };
+
+        // Self::data drops, ensuring the desired cleanup operation.
+    }
+
+    fn as_raw(&self) -> *mut bindings::callback_head {
+        self.inner.get()
+    }
+
+    /// Arm a [`Callback`]. One grace period after this function was called,
+    /// the callback object will be dropped.
+    pub fn submit(self: Pin<KBox<Self>>) {
+        // SAFETY: The memory is not moved by this code or the C backend.
+        let cb = unsafe { Pin::into_inner_unchecked(self) };
+        let ptr = KBox::into_raw(cb);
+        // SAFETY: `ptr` was just created validly above. `Self::callback` relies
+        // on the RCU module / code never being unloaded.
+        unsafe { bindings::call_rcu((*ptr).as_raw(), Some(Self::callback)) };
+    }
+}
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-20 13:17 [PATCH v1] rust: rcu: Add abstraction for call_rcu() Philipp Stanner
@ 2026-05-20 13:59 ` Boqun Feng
  2026-05-21  7:25   ` Philipp Stanner
  2026-05-27  7:42 ` Alvin Sun
  1 sibling, 1 reply; 9+ messages in thread
From: Boqun Feng @ 2026-05-20 13:59 UTC (permalink / raw)
  To: Philipp Stanner
  Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu

Hi Philipp,

On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> call_rcu() can be expected to be needed by a great variety of users.
> This functionality is almost always used for deallocating resources
> after all accessors are gone. Hence, it appears reasonable to implement
> the abstractions in such a way that the user merely passes data, which
> is later (after a grace period) dropped.
> 
> In the rare cases where the user needs special action to take place,
> this could be achieved through implementing a custom drop() method.
> 
> Implement a first minimal abstraction for call_rcu().
> 

Thanks for the patch! Do you have have any reference usage of this new
API, maybe contains how RCU readers will read the data?

Compared to Alice's RcuBox proposal:

	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/

I do have a design question: is support data type like Arc<CallBack<T>>
or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
be like? A separate new() and submit() function or a separate data type?
If not, what's the main difference between Callback API and RcuBox?

Regards,
Boqun

> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
>  rust/helpers/rcu.c      |  1 +
>  rust/kernel/sync.rs     |  1 +
>  rust/kernel/sync/rcu.rs | 89 ++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 90 insertions(+), 1 deletion(-)
> 
> diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c
> index 481274c05857..c9cfc99c93d5 100644
> --- a/rust/helpers/rcu.c
> +++ b/rust/helpers/rcu.c
> @@ -1,5 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0
>  
> +#include <linux/types.h> /* for callback_head */
>  #include <linux/rcupdate.h>
>  
>  __rust_helper void rust_helper_rcu_read_lock(void)
> diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> index 993dbf2caa0e..1ddca3847b19 100644
> --- a/rust/kernel/sync.rs
> +++ b/rust/kernel/sync.rs
> @@ -31,6 +31,7 @@
>  pub use locked_by::LockedBy;
>  pub use refcount::Refcount;
>  pub use set_once::SetOnce;
> +pub use rcu::Callback;
>  
>  /// Represents a lockdep class.
>  ///
> diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> index a32bef6e490b..caf71fa46f5e 100644
> --- a/rust/kernel/sync/rcu.rs
> +++ b/rust/kernel/sync/rcu.rs
> @@ -4,7 +4,15 @@
>  //!
>  //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h)
>  
> -use crate::{bindings, types::NotThreadSafe};
> +use crate::{
> +    bindings,
> +    prelude::*,
> +    types::{
> +        NotThreadSafe,
> +        Opaque,
> +    },
> +    alloc::Flags,
> +};
>  
>  /// Evidence that the RCU read side lock is held on the current thread/CPU.
>  ///
> @@ -50,3 +58,82 @@ fn drop(&mut self) {
>  pub fn read_lock() -> Guard {
>      Guard::new()
>  }
> +
> +
> +/// An RCU callback object. Carries the user's data to drop() it once a grace period ellapsed.
> +///
> +/// This object serves to implement C's `call_rcu()` method. Since it is almost
> +/// always used to free a resource once a grace period ellapsed, the only thing
> +/// this implementation does is drop the user's data. In the rare cases in which
> +/// the user needs more action to take place, said actions need to be implemented
> +/// on the user's data via the [`Drop`] trait.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::sync::rcu::Callback;
> +///
> +/// struct Foo {};
> +///
> +/// impl Drop for Foo {
> +///     fn drop(&mut self) {
> +///         pr_info!("rcu::Foo Dropping.\n");
> +///     }
> +/// }
> +///
> +/// let data = Foo {};
> +///
> +/// let cb = Callback::new(data, GFP_KERNEL)?;
> +/// cb.submit();
> +///
> +/// Ok::<(), Error>(())
> +/// ```
> +#[repr(C)]
> +#[pin_data]
> +pub struct Callback<T: Send + 'static> {
> +    /// The RCU head. Only used (and initialized) by the C backend.
> +    #[pin]
> +    inner: Opaque<bindings::callback_head>,
> +    /// The user's data. This should implement [`Drop`] if the user wants specific
> +    /// actions, besides mere deallocation, to happen.
> +    #[pin]
> +    data: T,
> +}
> +
> +impl<T: Send + 'static> Callback<T> {
> +    /// Create a new callback.
> +    pub fn new(data: impl PinInit<T>, flags: Flags) -> Result<Pin<KBox<Self>>> {
> +        let cb = try_pin_init!(Self {
> +            inner: Opaque::uninit(), // Only needed for the C backend, who will initialize it.
> +            data <- data,
> +        });
> +
> +        KBox::pin_init(cb, flags)
> +    }
> +
> +    extern "C" fn callback(rcu_head: *mut bindings::callback_head) {
> +        let cb_ptr = rcu_head as *mut Self;
> +
> +        // SAFETY: All [`Callback`] objects in this module are always created
> +        // as `Pin<KBox<Self>>`. `Pin` is a transparent container. The action
> +        // below merely serves re-creating the KBox so that it can drop properly.
> +        let _cb = unsafe { KBox::from_raw(cb_ptr) };
> +
> +        // Self::data drops, ensuring the desired cleanup operation.
> +    }
> +
> +    fn as_raw(&self) -> *mut bindings::callback_head {
> +        self.inner.get()
> +    }
> +
> +    /// Arm a [`Callback`]. One grace period after this function was called,
> +    /// the callback object will be dropped.
> +    pub fn submit(self: Pin<KBox<Self>>) {
> +        // SAFETY: The memory is not moved by this code or the C backend.
> +        let cb = unsafe { Pin::into_inner_unchecked(self) };
> +        let ptr = KBox::into_raw(cb);
> +        // SAFETY: `ptr` was just created validly above. `Self::callback` relies
> +        // on the RCU module / code never being unloaded.
> +        unsafe { bindings::call_rcu((*ptr).as_raw(), Some(Self::callback)) };
> +    }
> +}
> -- 
> 2.49.0
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-20 13:59 ` Boqun Feng
@ 2026-05-21  7:25   ` Philipp Stanner
  2026-05-26 16:10     ` Boqun Feng
  0 siblings, 1 reply; 9+ messages in thread
From: Philipp Stanner @ 2026-05-21  7:25 UTC (permalink / raw)
  To: Boqun Feng, Philipp Stanner
  Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

[+cc Boris]

On Wed, 2026-05-20 at 06:59 -0700, Boqun Feng wrote:
> Hi Philipp,

Hi Boqun; hope you're doing well

> 
> On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> > call_rcu() can be expected to be needed by a great variety of users.
> > This functionality is almost always used for deallocating resources
> > after all accessors are gone. Hence, it appears reasonable to implement
> > the abstractions in such a way that the user merely passes data, which
> > is later (after a grace period) dropped.
> > 
> > In the rare cases where the user needs special action to take place,
> > this could be achieved through implementing a custom drop() method.
> > 
> > Implement a first minimal abstraction for call_rcu().
> > 
> 
> Thanks for the patch! Do you have have any reference usage of this new
> API, maybe contains how RCU readers will read the data?

Read the data? This design does not intend to have any readers.

I want it as some sort of trash-bin container that does nothing but
defer a drop(). Intended user will be this section here:

https://gitlab.freedesktop.org/pstanner/linux-drm-work/-/merge_requests/1/diffs#5ef8add7e1b3375ce9a0b47595b531244bf98dce_0_611


> 
> Compared to Alice's RcuBox proposal:
> 
> 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> 
> I do have a design question: is support data type like Arc<CallBack<T>>
> or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> be like? A separate new() and submit() function or a separate data type?

I wasn't aware of Alice's proposal. Let me try whether I can make it
work for my purposes.

The idea behind my code here would be to have some minimalist RCU
wrapper that merely defers dropping data. So it's a fire-and-forget
mechanism that would not support Arc: take over ownership of the data,
have it be unaccessible, and drop it after a grace period.

Reason is that call_rcu() is most commonly needed for delaying a free()
operation.

Alice's idea seems more generic.

But I agree that large allocations, aka VBox, should be supported.


P.

> If not, what's the main difference between Callback API and RcuBox?
> 
> Regards,
> Boqun
> 
> > Signed-off-by: Philipp Stanner <phasta@kernel.org>
> > ---
> >  rust/helpers/rcu.c      |  1 +
> >  rust/kernel/sync.rs     |  1 +
> >  rust/kernel/sync/rcu.rs | 89 ++++++++++++++++++++++++++++++++++++++++-
> >  3 files changed, 90 insertions(+), 1 deletion(-)
> > 
> > diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c
> > index 481274c05857..c9cfc99c93d5 100644
> > --- a/rust/helpers/rcu.c
> > +++ b/rust/helpers/rcu.c
> > @@ -1,5 +1,6 @@
> >  // SPDX-License-Identifier: GPL-2.0
> >  
> > +#include <linux/types.h> /* for callback_head */
> >  #include <linux/rcupdate.h>
> >  
> >  __rust_helper void rust_helper_rcu_read_lock(void)
> > diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> > index 993dbf2caa0e..1ddca3847b19 100644
> > --- a/rust/kernel/sync.rs
> > +++ b/rust/kernel/sync.rs
> > @@ -31,6 +31,7 @@
> >  pub use locked_by::LockedBy;
> >  pub use refcount::Refcount;
> >  pub use set_once::SetOnce;
> > +pub use rcu::Callback;
> >  
> >  /// Represents a lockdep class.
> >  ///
> > diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> > index a32bef6e490b..caf71fa46f5e 100644
> > --- a/rust/kernel/sync/rcu.rs
> > +++ b/rust/kernel/sync/rcu.rs
> > @@ -4,7 +4,15 @@
> >  //!
> >  //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h)
> >  
> > -use crate::{bindings, types::NotThreadSafe};
> > +use crate::{
> > +    bindings,
> > +    prelude::*,
> > +    types::{
> > +        NotThreadSafe,
> > +        Opaque,
> > +    },
> > +    alloc::Flags,
> > +};
> >  
> >  /// Evidence that the RCU read side lock is held on the current thread/CPU.
> >  ///
> > @@ -50,3 +58,82 @@ fn drop(&mut self) {
> >  pub fn read_lock() -> Guard {
> >      Guard::new()
> >  }
> > +
> > +
> > +/// An RCU callback object. Carries the user's data to drop() it once a grace period ellapsed.
> > +///
> > +/// This object serves to implement C's `call_rcu()` method. Since it is almost
> > +/// always used to free a resource once a grace period ellapsed, the only thing
> > +/// this implementation does is drop the user's data. In the rare cases in which
> > +/// the user needs more action to take place, said actions need to be implemented
> > +/// on the user's data via the [`Drop`] trait.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// use kernel::sync::rcu::Callback;
> > +///
> > +/// struct Foo {};
> > +///
> > +/// impl Drop for Foo {
> > +///     fn drop(&mut self) {
> > +///         pr_info!("rcu::Foo Dropping.\n");
> > +///     }
> > +/// }
> > +///
> > +/// let data = Foo {};
> > +///
> > +/// let cb = Callback::new(data, GFP_KERNEL)?;
> > +/// cb.submit();
> > +///
> > +/// Ok::<(), Error>(())
> > +/// ```
> > +#[repr(C)]
> > +#[pin_data]
> > +pub struct Callback<T: Send + 'static> {
> > +    /// The RCU head. Only used (and initialized) by the C backend.
> > +    #[pin]
> > +    inner: Opaque<bindings::callback_head>,
> > +    /// The user's data. This should implement [`Drop`] if the user wants specific
> > +    /// actions, besides mere deallocation, to happen.
> > +    #[pin]
> > +    data: T,
> > +}
> > +
> > +impl<T: Send + 'static> Callback<T> {
> > +    /// Create a new callback.
> > +    pub fn new(data: impl PinInit<T>, flags: Flags) -> Result<Pin<KBox<Self>>> {
> > +        let cb = try_pin_init!(Self {
> > +            inner: Opaque::uninit(), // Only needed for the C backend, who will initialize it.
> > +            data <- data,
> > +        });
> > +
> > +        KBox::pin_init(cb, flags)
> > +    }
> > +
> > +    extern "C" fn callback(rcu_head: *mut bindings::callback_head) {
> > +        let cb_ptr = rcu_head as *mut Self;
> > +
> > +        // SAFETY: All [`Callback`] objects in this module are always created
> > +        // as `Pin<KBox<Self>>`. `Pin` is a transparent container. The action
> > +        // below merely serves re-creating the KBox so that it can drop properly.
> > +        let _cb = unsafe { KBox::from_raw(cb_ptr) };
> > +
> > +        // Self::data drops, ensuring the desired cleanup operation.
> > +    }
> > +
> > +    fn as_raw(&self) -> *mut bindings::callback_head {
> > +        self.inner.get()
> > +    }
> > +
> > +    /// Arm a [`Callback`]. One grace period after this function was called,
> > +    /// the callback object will be dropped.
> > +    pub fn submit(self: Pin<KBox<Self>>) {
> > +        // SAFETY: The memory is not moved by this code or the C backend.
> > +        let cb = unsafe { Pin::into_inner_unchecked(self) };
> > +        let ptr = KBox::into_raw(cb);
> > +        // SAFETY: `ptr` was just created validly above. `Self::callback` relies
> > +        // on the RCU module / code never being unloaded.
> > +        unsafe { bindings::call_rcu((*ptr).as_raw(), Some(Self::callback)) };
> > +    }
> > +}
> > -- 
> > 2.49.0
> > 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-21  7:25   ` Philipp Stanner
@ 2026-05-26 16:10     ` Boqun Feng
  2026-05-27  5:52       ` Alice Ryhl
  0 siblings, 1 reply; 9+ messages in thread
From: Boqun Feng @ 2026-05-26 16:10 UTC (permalink / raw)
  To: phasta
  Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

On Thu, May 21, 2026 at 09:25:28AM +0200, Philipp Stanner wrote:
> [+cc Boris]
> 
> On Wed, 2026-05-20 at 06:59 -0700, Boqun Feng wrote:
> > Hi Philipp,
> 
> Hi Boqun; hope you're doing well
> 
> > 
> > On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> > > call_rcu() can be expected to be needed by a great variety of users.
> > > This functionality is almost always used for deallocating resources
> > > after all accessors are gone. Hence, it appears reasonable to implement
> > > the abstractions in such a way that the user merely passes data, which
> > > is later (after a grace period) dropped.
> > > 
> > > In the rare cases where the user needs special action to take place,
> > > this could be achieved through implementing a custom drop() method.
> > > 
> > > Implement a first minimal abstraction for call_rcu().
> > > 
> > 
> > Thanks for the patch! Do you have have any reference usage of this new
> > API, maybe contains how RCU readers will read the data?
> 
> Read the data? This design does not intend to have any readers.
> 

Please understand that from the perspective of an RCU maintainer, I
would like to examine how the current design would work with a more
general case, otherwise it's going to be a maintenance nightmare.

> I want it as some sort of trash-bin container that does nothing but
> defer a drop(). Intended user will be this section here:
> 
> https://gitlab.freedesktop.org/pstanner/linux-drm-work/-/merge_requests/1/diffs#5ef8add7e1b3375ce9a0b47595b531244bf98dce_0_611
> 

The fact that you need a "defer" means that there are readers, right?

You don't need to worry about here because the readers are in the
callback of fences.

> 
> > 
> > Compared to Alice's RcuBox proposal:
> > 
> > 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> > 
> > I do have a design question: is support data type like Arc<CallBack<T>>
> > or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> > be like? A separate new() and submit() function or a separate data type?
> 
> I wasn't aware of Alice's proposal. Let me try whether I can make it
> work for my purposes.
> 
> The idea behind my code here would be to have some minimalist RCU
> wrapper that merely defers dropping data. So it's a fire-and-forget
> mechanism that would not support Arc: take over ownership of the data,
> have it be unaccessible, and drop it after a grace period.
> 

Maybe then name this data structure `RcuDeferDropBox<T>` or something?
Because if the design goal is not to support a general RCU usage (with
readers), than it probably shouldn't take the rcu::Callback name.

Or maybe keep the `Callback<T>`, but only implement `new()` (with a
return type as `impl PinInit<Callback<T>>` and the rcu_head accessor of
it. Then based on it you can implement the `RcuDeferDropBox<T>`, in this
way, we could both support your usage and move towards a full-featured
RCU implementation. Thoughts?

Plus, I think Alice's patch here [1] would also benefit from having a
basic rcu::Callback (to replace `PollCondVarBoxInner`).

[1]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-1-f5b4c747eac2@google.com/

Regards,
Boqun

> Reason is that call_rcu() is most commonly needed for delaying a free()
> operation.
> 
> Alice's idea seems more generic.
> 
> But I agree that large allocations, aka VBox, should be supported.
> 
> 
> P.
> 
> > If not, what's the main difference between Callback API and RcuBox?
> > 
> > Regards,
> > Boqun
> > 
> > > Signed-off-by: Philipp Stanner <phasta@kernel.org>
> > > ---
> > >  rust/helpers/rcu.c      |  1 +
> > >  rust/kernel/sync.rs     |  1 +
> > >  rust/kernel/sync/rcu.rs | 89 ++++++++++++++++++++++++++++++++++++++++-
> > >  3 files changed, 90 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c
> > > index 481274c05857..c9cfc99c93d5 100644
> > > --- a/rust/helpers/rcu.c
> > > +++ b/rust/helpers/rcu.c
> > > @@ -1,5 +1,6 @@
> > >  // SPDX-License-Identifier: GPL-2.0
> > >  
> > > +#include <linux/types.h> /* for callback_head */
> > >  #include <linux/rcupdate.h>
> > >  
> > >  __rust_helper void rust_helper_rcu_read_lock(void)
> > > diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> > > index 993dbf2caa0e..1ddca3847b19 100644
> > > --- a/rust/kernel/sync.rs
> > > +++ b/rust/kernel/sync.rs
> > > @@ -31,6 +31,7 @@
> > >  pub use locked_by::LockedBy;
> > >  pub use refcount::Refcount;
> > >  pub use set_once::SetOnce;
> > > +pub use rcu::Callback;
> > >  
> > >  /// Represents a lockdep class.
> > >  ///
> > > diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> > > index a32bef6e490b..caf71fa46f5e 100644
> > > --- a/rust/kernel/sync/rcu.rs
> > > +++ b/rust/kernel/sync/rcu.rs
> > > @@ -4,7 +4,15 @@
> > >  //!
> > >  //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h)
> > >  
> > > -use crate::{bindings, types::NotThreadSafe};
> > > +use crate::{
> > > +    bindings,
> > > +    prelude::*,
> > > +    types::{
> > > +        NotThreadSafe,
> > > +        Opaque,
> > > +    },
> > > +    alloc::Flags,
> > > +};
> > >  
> > >  /// Evidence that the RCU read side lock is held on the current thread/CPU.
> > >  ///
> > > @@ -50,3 +58,82 @@ fn drop(&mut self) {
> > >  pub fn read_lock() -> Guard {
> > >      Guard::new()
> > >  }
> > > +
> > > +
> > > +/// An RCU callback object. Carries the user's data to drop() it once a grace period ellapsed.
> > > +///
> > > +/// This object serves to implement C's `call_rcu()` method. Since it is almost
> > > +/// always used to free a resource once a grace period ellapsed, the only thing
> > > +/// this implementation does is drop the user's data. In the rare cases in which
> > > +/// the user needs more action to take place, said actions need to be implemented
> > > +/// on the user's data via the [`Drop`] trait.
> > > +///
> > > +/// # Examples
> > > +///
> > > +/// ```
> > > +/// use kernel::sync::rcu::Callback;
> > > +///
> > > +/// struct Foo {};
> > > +///
> > > +/// impl Drop for Foo {
> > > +///     fn drop(&mut self) {
> > > +///         pr_info!("rcu::Foo Dropping.\n");
> > > +///     }
> > > +/// }
> > > +///
> > > +/// let data = Foo {};
> > > +///
> > > +/// let cb = Callback::new(data, GFP_KERNEL)?;
> > > +/// cb.submit();
> > > +///
> > > +/// Ok::<(), Error>(())
> > > +/// ```
> > > +#[repr(C)]
> > > +#[pin_data]
> > > +pub struct Callback<T: Send + 'static> {
> > > +    /// The RCU head. Only used (and initialized) by the C backend.
> > > +    #[pin]
> > > +    inner: Opaque<bindings::callback_head>,
> > > +    /// The user's data. This should implement [`Drop`] if the user wants specific
> > > +    /// actions, besides mere deallocation, to happen.
> > > +    #[pin]
> > > +    data: T,
> > > +}
> > > +
> > > +impl<T: Send + 'static> Callback<T> {
> > > +    /// Create a new callback.
> > > +    pub fn new(data: impl PinInit<T>, flags: Flags) -> Result<Pin<KBox<Self>>> {
> > > +        let cb = try_pin_init!(Self {
> > > +            inner: Opaque::uninit(), // Only needed for the C backend, who will initialize it.
> > > +            data <- data,
> > > +        });
> > > +
> > > +        KBox::pin_init(cb, flags)
> > > +    }
> > > +
> > > +    extern "C" fn callback(rcu_head: *mut bindings::callback_head) {
> > > +        let cb_ptr = rcu_head as *mut Self;
> > > +
> > > +        // SAFETY: All [`Callback`] objects in this module are always created
> > > +        // as `Pin<KBox<Self>>`. `Pin` is a transparent container. The action
> > > +        // below merely serves re-creating the KBox so that it can drop properly.
> > > +        let _cb = unsafe { KBox::from_raw(cb_ptr) };
> > > +
> > > +        // Self::data drops, ensuring the desired cleanup operation.
> > > +    }
> > > +
> > > +    fn as_raw(&self) -> *mut bindings::callback_head {
> > > +        self.inner.get()
> > > +    }
> > > +
> > > +    /// Arm a [`Callback`]. One grace period after this function was called,
> > > +    /// the callback object will be dropped.
> > > +    pub fn submit(self: Pin<KBox<Self>>) {
> > > +        // SAFETY: The memory is not moved by this code or the C backend.
> > > +        let cb = unsafe { Pin::into_inner_unchecked(self) };
> > > +        let ptr = KBox::into_raw(cb);
> > > +        // SAFETY: `ptr` was just created validly above. `Self::callback` relies
> > > +        // on the RCU module / code never being unloaded.
> > > +        unsafe { bindings::call_rcu((*ptr).as_raw(), Some(Self::callback)) };
> > > +    }
> > > +}
> > > -- 
> > > 2.49.0
> > > 
> 
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-26 16:10     ` Boqun Feng
@ 2026-05-27  5:52       ` Alice Ryhl
  2026-05-27  5:59         ` Boqun Feng
  0 siblings, 1 reply; 9+ messages in thread
From: Alice Ryhl @ 2026-05-27  5:52 UTC (permalink / raw)
  To: Boqun Feng
  Cc: phasta, Miguel Ojeda, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

On Tue, May 26, 2026 at 09:10:07AM -0700, Boqun Feng wrote:
> On Thu, May 21, 2026 at 09:25:28AM +0200, Philipp Stanner wrote:
> > [+cc Boris]
> > 
> > On Wed, 2026-05-20 at 06:59 -0700, Boqun Feng wrote:
> > > Hi Philipp,
> > 
> > Hi Boqun; hope you're doing well
> > 
> > > 
> > > On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> > > > call_rcu() can be expected to be needed by a great variety of users.
> > > > This functionality is almost always used for deallocating resources
> > > > after all accessors are gone. Hence, it appears reasonable to implement
> > > > the abstractions in such a way that the user merely passes data, which
> > > > is later (after a grace period) dropped.
> > > > 
> > > > In the rare cases where the user needs special action to take place,
> > > > this could be achieved through implementing a custom drop() method.
> > > > 
> > > > Implement a first minimal abstraction for call_rcu().
> > > > 
> > > 
> > > Thanks for the patch! Do you have have any reference usage of this new
> > > API, maybe contains how RCU readers will read the data?
> > 
> > Read the data? This design does not intend to have any readers.
> > 
> 
> Please understand that from the perspective of an RCU maintainer, I
> would like to examine how the current design would work with a more
> general case, otherwise it's going to be a maintenance nightmare.
> 
> > I want it as some sort of trash-bin container that does nothing but
> > defer a drop(). Intended user will be this section here:
> > 
> > https://gitlab.freedesktop.org/pstanner/linux-drm-work/-/merge_requests/1/diffs#5ef8add7e1b3375ce9a0b47595b531244bf98dce_0_611
> > 
> 
> The fact that you need a "defer" means that there are readers, right?
> 
> You don't need to worry about here because the readers are in the
> callback of fences.
> 
> > 
> > > 
> > > Compared to Alice's RcuBox proposal:
> > > 
> > > 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> > > 
> > > I do have a design question: is support data type like Arc<CallBack<T>>
> > > or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> > > be like? A separate new() and submit() function or a separate data type?
> > 
> > I wasn't aware of Alice's proposal. Let me try whether I can make it
> > work for my purposes.
> > 
> > The idea behind my code here would be to have some minimalist RCU
> > wrapper that merely defers dropping data. So it's a fire-and-forget
> > mechanism that would not support Arc: take over ownership of the data,
> > have it be unaccessible, and drop it after a grace period.
> > 
> 
> Maybe then name this data structure `RcuDeferDropBox<T>` or something?
> Because if the design goal is not to support a general RCU usage (with
> readers), than it probably shouldn't take the rcu::Callback name.
> 
> Or maybe keep the `Callback<T>`, but only implement `new()` (with a
> return type as `impl PinInit<Callback<T>>` and the rcu_head accessor of
> it. Then based on it you can implement the `RcuDeferDropBox<T>`, in this
> way, we could both support your usage and move towards a full-featured
> RCU implementation. Thoughts?
> 
> Plus, I think Alice's patch here [1] would also benefit from having a
> basic rcu::Callback (to replace `PollCondVarBoxInner`).
> 
> [1]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-1-f5b4c747eac2@google.com/

My patch specifically uses kvfree_call_rcu(), which I think is important
that it keeps using over call_rcu().

Alice

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-27  5:52       ` Alice Ryhl
@ 2026-05-27  5:59         ` Boqun Feng
  2026-05-27  6:31           ` Philipp Stanner
  0 siblings, 1 reply; 9+ messages in thread
From: Boqun Feng @ 2026-05-27  5:59 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: phasta, Miguel Ojeda, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

On Wed, May 27, 2026 at 05:52:21AM +0000, Alice Ryhl wrote:
> On Tue, May 26, 2026 at 09:10:07AM -0700, Boqun Feng wrote:
> > On Thu, May 21, 2026 at 09:25:28AM +0200, Philipp Stanner wrote:
> > > [+cc Boris]
> > > 
> > > On Wed, 2026-05-20 at 06:59 -0700, Boqun Feng wrote:
> > > > Hi Philipp,
> > > 
> > > Hi Boqun; hope you're doing well
> > > 
> > > > 
> > > > On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> > > > > call_rcu() can be expected to be needed by a great variety of users.
> > > > > This functionality is almost always used for deallocating resources
> > > > > after all accessors are gone. Hence, it appears reasonable to implement
> > > > > the abstractions in such a way that the user merely passes data, which
> > > > > is later (after a grace period) dropped.
> > > > > 
> > > > > In the rare cases where the user needs special action to take place,
> > > > > this could be achieved through implementing a custom drop() method.
> > > > > 
> > > > > Implement a first minimal abstraction for call_rcu().
> > > > > 
> > > > 
> > > > Thanks for the patch! Do you have have any reference usage of this new
> > > > API, maybe contains how RCU readers will read the data?
> > > 
> > > Read the data? This design does not intend to have any readers.
> > > 
> > 
> > Please understand that from the perspective of an RCU maintainer, I
> > would like to examine how the current design would work with a more
> > general case, otherwise it's going to be a maintenance nightmare.
> > 
> > > I want it as some sort of trash-bin container that does nothing but
> > > defer a drop(). Intended user will be this section here:
> > > 
> > > https://gitlab.freedesktop.org/pstanner/linux-drm-work/-/merge_requests/1/diffs#5ef8add7e1b3375ce9a0b47595b531244bf98dce_0_611
> > > 
> > 
> > The fact that you need a "defer" means that there are readers, right?
> > 
> > You don't need to worry about here because the readers are in the
> > callback of fences.
> > 
> > > 
> > > > 
> > > > Compared to Alice's RcuBox proposal:
> > > > 
> > > > 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> > > > 
> > > > I do have a design question: is support data type like Arc<CallBack<T>>
> > > > or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> > > > be like? A separate new() and submit() function or a separate data type?
> > > 
> > > I wasn't aware of Alice's proposal. Let me try whether I can make it
> > > work for my purposes.
> > > 
> > > The idea behind my code here would be to have some minimalist RCU
> > > wrapper that merely defers dropping data. So it's a fire-and-forget
> > > mechanism that would not support Arc: take over ownership of the data,
> > > have it be unaccessible, and drop it after a grace period.
> > > 
> > 
> > Maybe then name this data structure `RcuDeferDropBox<T>` or something?
> > Because if the design goal is not to support a general RCU usage (with
> > readers), than it probably shouldn't take the rcu::Callback name.
> > 
> > Or maybe keep the `Callback<T>`, but only implement `new()` (with a
> > return type as `impl PinInit<Callback<T>>` and the rcu_head accessor of
> > it. Then based on it you can implement the `RcuDeferDropBox<T>`, in this
> > way, we could both support your usage and move towards a full-featured
> > RCU implementation. Thoughts?
> > 
> > Plus, I think Alice's patch here [1] would also benefit from having a
> > basic rcu::Callback (to replace `PollCondVarBoxInner`).
> > 
> > [1]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-1-f5b4c747eac2@google.com/
> 
> My patch specifically uses kvfree_call_rcu(), which I think is important
> that it keeps using over call_rcu().
> 

Of course, but note that using call_rcu() for your case was not my
suggestion. We can reuse a general `Callback<T>` which is not tied to
call_rcu() or kvfree_call_rcu() to represent a container type with a
rcu_head for both cases (your and Philipp's).

Regards,
Boqun

> Alice

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-27  5:59         ` Boqun Feng
@ 2026-05-27  6:31           ` Philipp Stanner
  2026-05-28 15:06             ` Boqun Feng
  0 siblings, 1 reply; 9+ messages in thread
From: Philipp Stanner @ 2026-05-27  6:31 UTC (permalink / raw)
  To: Boqun Feng, Alice Ryhl
  Cc: phasta, Miguel Ojeda, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

On Tue, 2026-05-26 at 22:59 -0700, Boqun Feng wrote:
> On Wed, May 27, 2026 at 05:52:21AM +0000, Alice Ryhl wrote:
> > On Tue, May 26, 2026 at 09:10:07AM -0700, Boqun Feng wrote:
> > > On Thu, May 21, 2026 at 09:25:28AM +0200, Philipp Stanner wrote:
> > > > [+cc Boris]
> > > > 
> > > > On Wed, 2026-05-20 at 06:59 -0700, Boqun Feng wrote:
> > > > > Hi Philipp,
> > > > 
> > > > Hi Boqun; hope you're doing well
> > > > 
> > > > > 
> > > > > On Wed, May 20, 2026 at 03:17:26PM +0200, Philipp Stanner wrote:
> > > > > > call_rcu() can be expected to be needed by a great variety of users.
> > > > > > This functionality is almost always used for deallocating resources
> > > > > > after all accessors are gone. Hence, it appears reasonable to implement
> > > > > > the abstractions in such a way that the user merely passes data, which
> > > > > > is later (after a grace period) dropped.
> > > > > > 
> > > > > > In the rare cases where the user needs special action to take place,
> > > > > > this could be achieved through implementing a custom drop() method.
> > > > > > 
> > > > > > Implement a first minimal abstraction for call_rcu().
> > > > > > 
> > > > > 
> > > > > Thanks for the patch! Do you have have any reference usage of this new
> > > > > API, maybe contains how RCU readers will read the data?
> > > > 
> > > > Read the data? This design does not intend to have any readers.
> > > > 
> > > 
> > > Please understand that from the perspective of an RCU maintainer, I
> > > would like to examine how the current design would work with a more
> > > general case, otherwise it's going to be a maintenance nightmare.
> > > 
> > > > I want it as some sort of trash-bin container that does nothing but
> > > > defer a drop(). Intended user will be this section here:
> > > > 
> > > > https://gitlab.freedesktop.org/pstanner/linux-drm-work/-/merge_requests/1/diffs#5ef8add7e1b3375ce9a0b47595b531244bf98dce_0_611
> > > > 
> > > 
> > > The fact that you need a "defer" means that there are readers, right?
> > > 
> > > You don't need to worry about here because the readers are in the
> > > callback of fences.
> > > 
> > > > 
> > > > > 
> > > > > Compared to Alice's RcuBox proposal:
> > > > > 
> > > > > 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> > > > > 
> > > > > I do have a design question: is support data type like Arc<CallBack<T>>
> > > > > or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> > > > > be like? A separate new() and submit() function or a separate data type?
> > > > 
> > > > I wasn't aware of Alice's proposal. Let me try whether I can make it
> > > > work for my purposes.
> > > > 
> > > > The idea behind my code here would be to have some minimalist RCU
> > > > wrapper that merely defers dropping data. So it's a fire-and-forget
> > > > mechanism that would not support Arc: take over ownership of the data,
> > > > have it be unaccessible, and drop it after a grace period.
> > > > 
> > > 
> > > Maybe then name this data structure `RcuDeferDropBox<T>` or something?
> > > Because if the design goal is not to support a general RCU usage (with
> > > readers), than it probably shouldn't take the rcu::Callback name.
> > > 
> > > Or maybe keep the `Callback<T>`, but only implement `new()` (with a
> > > return type as `impl PinInit<Callback<T>>` and the rcu_head accessor of
> > > it. Then based on it you can implement the `RcuDeferDropBox<T>`, in this
> > > way, we could both support your usage and move towards a full-featured
> > > RCU implementation. Thoughts?
> > > 
> > > Plus, I think Alice's patch here [1] would also benefit from having a
> > > basic rcu::Callback (to replace `PollCondVarBoxInner`).
> > > 
> > > [1]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-1-f5b4c747eac2@google.com/
> > 
> > My patch specifically uses kvfree_call_rcu(), which I think is important
> > that it keeps using over call_rcu().
> > 
> 
> Of course, but note that using call_rcu() for your case was not my
> suggestion. We can reuse a general `Callback<T>` which is not tied to
> call_rcu() or kvfree_call_rcu() to represent a container type with a
> rcu_head for both cases (your and Philipp's).

I have given Alice's code a spin and concluded that it would be fully
usable for my intended use-case. The trick would then be to force users
of my API to pass their data in an RcuBox, which Rust can certainly
enforce. Has the great advantage of me not having to allocate again
just to drop something, so this is a far cleaner design.

From my side, only minor details would remain open regarding Alice's
draft, like Boqun's question about how to implement VBox maybe.

But in principle you can regard my patch here to be withdrawn :)

Regards
P.

> 
> Regards,
> Boqun
> 
> > Alice


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-20 13:17 [PATCH v1] rust: rcu: Add abstraction for call_rcu() Philipp Stanner
  2026-05-20 13:59 ` Boqun Feng
@ 2026-05-27  7:42 ` Alvin Sun
  1 sibling, 0 replies; 9+ messages in thread
From: Alvin Sun @ 2026-05-27  7:42 UTC (permalink / raw)
  To: Philipp Stanner, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein
  Cc: rust-for-linux, linux-kernel, rcu


On 5/20/26 21:17, Philipp Stanner wrote:
> call_rcu() can be expected to be needed by a great variety of users.
> This functionality is almost always used for deallocating resources
> after all accessors are gone. Hence, it appears reasonable to implement
> the abstractions in such a way that the user merely passes data, which
> is later (after a grace period) dropped.
>
> In the rare cases where the user needs special action to take place,
> this could be achieved through implementing a custom drop() method.
>
> Implement a first minimal abstraction for call_rcu().
>
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
> ---
>   rust/helpers/rcu.c      |  1 +
>   rust/kernel/sync.rs     |  1 +
>   rust/kernel/sync/rcu.rs | 89 ++++++++++++++++++++++++++++++++++++++++-
>   3 files changed, 90 insertions(+), 1 deletion(-)
>
> diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c
> index 481274c05857..c9cfc99c93d5 100644
> --- a/rust/helpers/rcu.c
> +++ b/rust/helpers/rcu.c
> @@ -1,5 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0
>   
> +#include <linux/types.h> /* for callback_head */
>   #include <linux/rcupdate.h>
>   
>   __rust_helper void rust_helper_rcu_read_lock(void)
> diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> index 993dbf2caa0e..1ddca3847b19 100644
> --- a/rust/kernel/sync.rs
> +++ b/rust/kernel/sync.rs
> @@ -31,6 +31,7 @@
>   pub use locked_by::LockedBy;
>   pub use refcount::Refcount;
>   pub use set_once::SetOnce;
> +pub use rcu::Callback;
>   
>   /// Represents a lockdep class.
>   ///
> diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> index a32bef6e490b..caf71fa46f5e 100644
> --- a/rust/kernel/sync/rcu.rs
> +++ b/rust/kernel/sync/rcu.rs
> @@ -4,7 +4,15 @@
>   //!
>   //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h)
>   
> -use crate::{bindings, types::NotThreadSafe};
> +use crate::{
> +    bindings,
> +    prelude::*,
> +    types::{
> +        NotThreadSafe,
> +        Opaque,

Suggestion: Append `//` after the last item in each use braces to
prevent rustfmt from condensing lines, since `imports_layout =
"Vertical"` is not yet stable.

Best regards,
Alvin

> +    },
> +    alloc::Flags,
> +};
>   
>   /// Evidence that the RCU read side lock is held on the current thread/CPU.
>   ///
> @@ -50,3 +58,82 @@ fn drop(&mut self) {
>   pub fn read_lock() -> Guard {
>       Guard::new()
>   }
> +
> +
> +/// An RCU callback object. Carries the user's data to drop() it once a grace period ellapsed.
> +///
> +/// This object serves to implement C's `call_rcu()` method. Since it is almost
> +/// always used to free a resource once a grace period ellapsed, the only thing
> +/// this implementation does is drop the user's data. In the rare cases in which
> +/// the user needs more action to take place, said actions need to be implemented
> +/// on the user's data via the [`Drop`] trait.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::sync::rcu::Callback;
> +///
> +/// struct Foo {};
> +///
> +/// impl Drop for Foo {
> +///     fn drop(&mut self) {
> +///         pr_info!("rcu::Foo Dropping.\n");
> +///     }
> +/// }
> +///
> +/// let data = Foo {};
> +///
> +/// let cb = Callback::new(data, GFP_KERNEL)?;
> +/// cb.submit();
> +///
> +/// Ok::<(), Error>(())
> +/// ```
> +#[repr(C)]
> +#[pin_data]
> +pub struct Callback<T: Send + 'static> {
> +    /// The RCU head. Only used (and initialized) by the C backend.
> +    #[pin]
> +    inner: Opaque<bindings::callback_head>,
> +    /// The user's data. This should implement [`Drop`] if the user wants specific
> +    /// actions, besides mere deallocation, to happen.
> +    #[pin]
> +    data: T,
> +}
> +
> +impl<T: Send + 'static> Callback<T> {
> +    /// Create a new callback.
> +    pub fn new(data: impl PinInit<T>, flags: Flags) -> Result<Pin<KBox<Self>>> {
> +        let cb = try_pin_init!(Self {
> +            inner: Opaque::uninit(), // Only needed for the C backend, who will initialize it.
> +            data <- data,
> +        });
> +
> +        KBox::pin_init(cb, flags)
> +    }
> +
> +    extern "C" fn callback(rcu_head: *mut bindings::callback_head) {
> +        let cb_ptr = rcu_head as *mut Self;
> +
> +        // SAFETY: All [`Callback`] objects in this module are always created
> +        // as `Pin<KBox<Self>>`. `Pin` is a transparent container. The action
> +        // below merely serves re-creating the KBox so that it can drop properly.
> +        let _cb = unsafe { KBox::from_raw(cb_ptr) };
> +
> +        // Self::data drops, ensuring the desired cleanup operation.
> +    }
> +
> +    fn as_raw(&self) -> *mut bindings::callback_head {
> +        self.inner.get()
> +    }
> +
> +    /// Arm a [`Callback`]. One grace period after this function was called,
> +    /// the callback object will be dropped.
> +    pub fn submit(self: Pin<KBox<Self>>) {
> +        // SAFETY: The memory is not moved by this code or the C backend.
> +        let cb = unsafe { Pin::into_inner_unchecked(self) };
> +        let ptr = KBox::into_raw(cb);
> +        // SAFETY: `ptr` was just created validly above. `Self::callback` relies
> +        // on the RCU module / code never being unloaded.
> +        unsafe { bindings::call_rcu((*ptr).as_raw(), Some(Self::callback)) };
> +    }
> +}

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] rust: rcu: Add abstraction for call_rcu()
  2026-05-27  6:31           ` Philipp Stanner
@ 2026-05-28 15:06             ` Boqun Feng
  0 siblings, 0 replies; 9+ messages in thread
From: Boqun Feng @ 2026-05-28 15:06 UTC (permalink / raw)
  To: phasta
  Cc: Alice Ryhl, Miguel Ojeda, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
	Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
	Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
	Mathieu Desnoyers, Lai Jiangshan, Zqiang, Joel Fernandes (NVIDIA),
	Peter Zijlstra (Intel), Tamir Duberstein, rust-for-linux,
	linux-kernel, rcu, Boris Brezillon

On Wed, May 27, 2026 at 08:31:44AM +0200, Philipp Stanner wrote:
[..]
> > > > > 
> > > > > > 
> > > > > > Compared to Alice's RcuBox proposal:
> > > > > > 
> > > > > > 	https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-1-38ebfbcd53f0@google.com/
> > > > > > 
> > > > > > I do have a design question: is support data type like Arc<CallBack<T>>
> > > > > > or Pin<VBox<Callback<T>> in the plan of this API? If so, how would that
> > > > > > be like? A separate new() and submit() function or a separate data type?
> > > > > 
> > > > > I wasn't aware of Alice's proposal. Let me try whether I can make it
> > > > > work for my purposes.
> > > > > 
> > > > > The idea behind my code here would be to have some minimalist RCU
> > > > > wrapper that merely defers dropping data. So it's a fire-and-forget
> > > > > mechanism that would not support Arc: take over ownership of the data,
> > > > > have it be unaccessible, and drop it after a grace period.
> > > > > 
> > > > 
> > > > Maybe then name this data structure `RcuDeferDropBox<T>` or something?
> > > > Because if the design goal is not to support a general RCU usage (with
> > > > readers), than it probably shouldn't take the rcu::Callback name.
> > > > 
> > > > Or maybe keep the `Callback<T>`, but only implement `new()` (with a
> > > > return type as `impl PinInit<Callback<T>>` and the rcu_head accessor of
> > > > it. Then based on it you can implement the `RcuDeferDropBox<T>`, in this
> > > > way, we could both support your usage and move towards a full-featured
> > > > RCU implementation. Thoughts?
> > > > 
> > > > Plus, I think Alice's patch here [1] would also benefit from having a
> > > > basic rcu::Callback (to replace `PollCondVarBoxInner`).
> > > > 
> > > > [1]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-1-f5b4c747eac2@google.com/
> > > 
> > > My patch specifically uses kvfree_call_rcu(), which I think is important
> > > that it keeps using over call_rcu().
> > > 
> > 
> > Of course, but note that using call_rcu() for your case was not my
> > suggestion. We can reuse a general `Callback<T>` which is not tied to
> > call_rcu() or kvfree_call_rcu() to represent a container type with a
> > rcu_head for both cases (your and Philipp's).
> 
> I have given Alice's code a spin and concluded that it would be fully
> usable for my intended use-case. The trick would then be to force users
> of my API to pass their data in an RcuBox, which Rust can certainly

Note that we can extend RcuBox to implement `InPlaceInit` similar as a
normal Box, that way you can ask user to pass the `impl PinInit<T>`
instead of the data.

> enforce. Has the great advantage of me not having to allocate again
> just to drop something, so this is a far cleaner design.
> 
> From my side, only minor details would remain open regarding Alice's
> draft, like Boqun's question about how to implement VBox maybe.
> 

I think we can make RcuBox generic over Allocator, i.e.
`RcuBox<T, A: Allocator>` then we should be able to support vmalloc as
well.

Regards,
Boqun

> But in principle you can regard my patch here to be withdrawn :)
> 
> Regards
> P.
> 
> > 
> > Regards,
> > Boqun
> > 
> > > Alice
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-05-28 15:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-20 13:17 [PATCH v1] rust: rcu: Add abstraction for call_rcu() Philipp Stanner
2026-05-20 13:59 ` Boqun Feng
2026-05-21  7:25   ` Philipp Stanner
2026-05-26 16:10     ` Boqun Feng
2026-05-27  5:52       ` Alice Ryhl
2026-05-27  5:59         ` Boqun Feng
2026-05-27  6:31           ` Philipp Stanner
2026-05-28 15:06             ` Boqun Feng
2026-05-27  7:42 ` Alvin Sun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox