* [PATCH 0/3] rust: sync: Introduce Rcu*Box
@ 2026-06-05 13:35 Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: add RcuBox type Boqun Feng
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
(this series is based on Alice's RFC [1] and discussion around Philipp's
patches [2], [3])
As an easy way to provide RCU-protected allocation, two major types are
provided:
- `RcuBox<T, A>`, inner T will be dropped and after a grace period.
Users: binder with maple_tree and dma_fence.
- `RcuFreeBox<T, A>`, inner T will be cleaned up immmediately and freed
after a grace period. (Name suggestion is welcome). This is an attempt
to consolidate Alice's `PollCondVarBox` [4] into a generic
implementation, InPlaceInit support is still missing, but I want to
get some feedback on the trait `RcuFreeSafe`.
[1]: https://lore.kernel.org/rust-for-linux/20260116-rcu-box-v1-0-38ebfbcd53f0@google.com/
[2]: https://lore.kernel.org/rust-for-linux/20260530143541.229628-2-phasta@kernel.org/
[3]: https://lore.kernel.org/rust-for-linux/20260520131725.266014-2-phasta@kernel.org/
[4]: https://lore.kernel.org/rust-for-linux/20260523-upgrade-poll-v4-0-f5b4c747eac2@google.com/
Regards,
Boqun
Alice Ryhl (2):
rust: rcu: Add RcuBox type
rust: maple_tree: Add load_rcu()
Boqun Feng (1):
rust: rcu: Introduce RcuFreeBox
rust/bindings/bindings_helper.h | 1 +
rust/kernel/maple_tree.rs | 52 ++++++
rust/kernel/sync/rcu.rs | 65 ++++++-
rust/kernel/sync/rcu/rcu_box.rs | 290 ++++++++++++++++++++++++++++++++
4 files changed, 407 insertions(+), 1 deletion(-)
create mode 100644 rust/kernel/sync/rcu/rcu_box.rs
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/3] rust: rcu: add RcuBox type
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
@ 2026-06-05 13:35 ` Boqun Feng
2026-06-05 13:38 ` Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: Add " Boqun Feng
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
From: Alice Ryhl <aliceryhl@google.com>
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 <aliceryhl@google.com>
[boqun: Make RcuBox generic over Allocator and add tests]
[boqun: Add type alias for Rcu*Box]
Co-developed-by: Boqun Feng <boqun@kernel.org>
Signed-off-by: Boqun Feng <boqun@kernel.org>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/sync/rcu.rs | 34 ++++-
rust/kernel/sync/rcu/rcu_box.rs | 230 ++++++++++++++++++++++++++++++++
3 files changed, 264 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_helper.h
index 446dbeaf0866..2011645c7cfb 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -80,6 +80,7 @@
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/random.h>
+#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
index a32bef6e490b..7da6b8d22277 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)
-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;
/// Evidence that the RCU read side lock is held on the current thread/CPU.
///
@@ -50,3 +62,23 @@ fn drop(&mut self) {
pub fn read_lock() -> Guard {
Guard::new()
}
+
+/// 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>;
+
+ /// Borrows a foreign-owned object immutably for an rcu grace period.
+ ///
+ /// This method provides a way to access a foreign-owned rcu-safe value 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..943fe3e8974e
--- /dev/null
+++ b/rust/kernel/sync/rcu/rcu_box.rs
@@ -0,0 +1,230 @@
+// 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<T>` allocated with `A`.
+/// * This `RcuBox` holds exclusive permissions to rcu free the allocation.
+pub struct RcuBox<T: Send, A: Allocator>(NonNull<RcuBoxInner<T>>, PhantomData<A>);
+
+/// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuKBox};
+/// let rb = RcuKBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuKBox<T> = RcuBox<T, Kmalloc>;
+
+/// Type alias for [`RcuBox`] with a [`Vmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuVBox};
+/// let rb = RcuVBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuVBox<T> = RcuBox<T, Vmalloc>;
+
+/// Type alias for [`RcuBox`] with a [`KVmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuKVBox};
+/// let rb = RcuKVBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuKVBox<T> = RcuBox<T, KVmalloc>;
+
+struct RcuBoxInner<T> {
+ rcu_head: bindings::callback_head,
+ value: T,
+}
+
+// Note that `T: Sync` is required since when moving an `RcuBox<T, A>`, the previous owner may
+// still access `&T` for one grace period.
+//
+// SAFETY: Ownership of the `RcuBox<T, A>` allows for `&T` and dropping the `T`, so `T: Send +
+// Sync` implies `RcuBox<T, A>: Send`.
+unsafe impl<T: Send + Sync, A: Allocator> Send for RcuBox<T, A> {}
+
+// SAFETY: `&RcuBox<T, A>` allows for no operations other than those permitted by `&T`, so `T:
+// Sync` implies `RcuBox<T, A>: Sync`.
+unsafe impl<T: Send + Sync, A: Allocator> Sync for RcuBox<T, A> {}
+
+impl<T: Send, A: Allocator> RcuBox<T, A> {
+ /// Create a new `RcuBox`.
+ pub fn new(x: T, flags: alloc::Flags) -> Result<Self, AllocError> {
+ let b = 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<T: Send, A: Allocator> Deref for RcuBox<T, A> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ // SAFETY: While the `RcuBox<T>` exists, the value remains valid.
+ unsafe { &(*self.0.as_ptr()).value }
+ }
+}
+
+// SAFETY:
+// * The `RcuBoxInner<T>` was allocated with `A`.
+// * `NonNull::as_ptr` returns a non-null pointer.
+unsafe impl<T: Send + 'static, A: Allocator> ForeignOwnable for RcuBox<T, A> {
+ const FOREIGN_ALIGN: usize = <Box<RcuBoxInner<T>, A> as ForeignOwnable>::FOREIGN_ALIGN;
+
+ type Borrowed<'a> = &'a T;
+ type BorrowedMut<'a> = &'a T;
+
+ fn into_foreign(self) -> *mut c_void {
+ self.0.as_ptr().cast()
+ }
+
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self {
+ // INVARIANT: Pointer returned by `into_foreign, A` carries same invariants as `RcuBox<T>`.
+ // 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 {
+ // SAFETY: Caller ensures that `'a` is short enough.
+ unsafe { &(*ptr.cast::<RcuBoxInner<T>>()).value }
+ }
+
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T {
+ // SAFETY: `borrow_mut` has strictly stronger preconditions than `borrow`.
+ unsafe { Self::borrow(ptr) }
+ }
+}
+
+impl<T: Send + 'static, A: Allocator> ForeignOwnableRcu for RcuBox<T, A> {
+ type RcuBorrowed<'a> = &'a T;
+
+ unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> &'a T {
+ // SAFETY: `RcuBox::drop` can only run after `from_foreign` is called, and the value is
+ // valid until `RcuBox::drop` plus one grace period.
+ unsafe { &(*ptr.cast::<RcuBoxInner<T>>()).value }
+ }
+}
+
+impl<T: Send, A: Allocator> Drop for RcuBox<T, A> {
+ 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 };
+ if core::mem::needs_drop::<T>() {
+ // 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::<T, A>)) };
+ } 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()) };
+ }
+ }
+}
+
+/// Free this `RcuBoxInner<T>`.
+///
+/// # Safety
+///
+/// `head` references the `rcu_head` field of an `RcuBoxInner<T>` that has no references to it.
+/// Ownership of the `Box<RcuBoxInner<T>, A>` must be passed.
+unsafe extern "C" fn drop_rcu_box<T, A: Allocator>(head: *mut bindings::callback_head) {
+ // SAFETY: Caller provides a pointer to the `rcu_head` field of a `RcuBoxInner<T>`.
+ let box_inner = unsafe { crate::container_of!(head, RcuBoxInner<T>, 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 = 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.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 1/3] rust: rcu: Add RcuBox type
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: add RcuBox type Boqun Feng
@ 2026-06-05 13:35 ` Boqun Feng
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: add load_rcu() Boqun Feng
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
From: Alice Ryhl <aliceryhl@google.com>
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 <aliceryhl@google.com>
[boqun: Make RcuBox generic over Allocator and add tests]
[boqun: Add type alias for Rcu*Box]
Co-developed-by: Boqun Feng <boqun@kernel.org>
Signed-off-by: Boqun Feng <boqun@kernel.org>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/sync/rcu.rs | 34 ++++-
rust/kernel/sync/rcu/rcu_box.rs | 230 ++++++++++++++++++++++++++++++++
3 files changed, 264 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_helper.h
index 446dbeaf0866..2011645c7cfb 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -80,6 +80,7 @@
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/random.h>
+#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
index a32bef6e490b..7da6b8d22277 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)
-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;
/// Evidence that the RCU read side lock is held on the current thread/CPU.
///
@@ -50,3 +62,23 @@ fn drop(&mut self) {
pub fn read_lock() -> Guard {
Guard::new()
}
+
+/// 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>;
+
+ /// Borrows a foreign-owned object immutably for an rcu grace period.
+ ///
+ /// This method provides a way to access a foreign-owned rcu-safe value 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..943fe3e8974e
--- /dev/null
+++ b/rust/kernel/sync/rcu/rcu_box.rs
@@ -0,0 +1,230 @@
+// 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<T>` allocated with `A`.
+/// * This `RcuBox` holds exclusive permissions to rcu free the allocation.
+pub struct RcuBox<T: Send, A: Allocator>(NonNull<RcuBoxInner<T>>, PhantomData<A>);
+
+/// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuKBox};
+/// let rb = RcuKBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuKBox<T> = RcuBox<T, Kmalloc>;
+
+/// Type alias for [`RcuBox`] with a [`Vmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuVBox};
+/// let rb = RcuVBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuVBox<T> = RcuBox<T, Vmalloc>;
+
+/// Type alias for [`RcuBox`] with a [`KVmalloc`] allocator.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::sync::rcu::{self, RcuKVBox};
+/// let rb = RcuKVBox::new(42, GFP_KERNEL)?;
+///
+/// assert_eq!(*rb, 42);
+/// assert_eq!(*rb.with_rcu(&rcu::read_lock()), 42);
+/// # Ok::<(), Error>(())
+/// ```
+pub type RcuKVBox<T> = RcuBox<T, KVmalloc>;
+
+struct RcuBoxInner<T> {
+ rcu_head: bindings::callback_head,
+ value: T,
+}
+
+// Note that `T: Sync` is required since when moving an `RcuBox<T, A>`, the previous owner may
+// still access `&T` for one grace period.
+//
+// SAFETY: Ownership of the `RcuBox<T, A>` allows for `&T` and dropping the `T`, so `T: Send +
+// Sync` implies `RcuBox<T, A>: Send`.
+unsafe impl<T: Send + Sync, A: Allocator> Send for RcuBox<T, A> {}
+
+// SAFETY: `&RcuBox<T, A>` allows for no operations other than those permitted by `&T`, so `T:
+// Sync` implies `RcuBox<T, A>: Sync`.
+unsafe impl<T: Send + Sync, A: Allocator> Sync for RcuBox<T, A> {}
+
+impl<T: Send, A: Allocator> RcuBox<T, A> {
+ /// Create a new `RcuBox`.
+ pub fn new(x: T, flags: alloc::Flags) -> Result<Self, AllocError> {
+ let b = 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<T: Send, A: Allocator> Deref for RcuBox<T, A> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ // SAFETY: While the `RcuBox<T>` exists, the value remains valid.
+ unsafe { &(*self.0.as_ptr()).value }
+ }
+}
+
+// SAFETY:
+// * The `RcuBoxInner<T>` was allocated with `A`.
+// * `NonNull::as_ptr` returns a non-null pointer.
+unsafe impl<T: Send + 'static, A: Allocator> ForeignOwnable for RcuBox<T, A> {
+ const FOREIGN_ALIGN: usize = <Box<RcuBoxInner<T>, A> as ForeignOwnable>::FOREIGN_ALIGN;
+
+ type Borrowed<'a> = &'a T;
+ type BorrowedMut<'a> = &'a T;
+
+ fn into_foreign(self) -> *mut c_void {
+ self.0.as_ptr().cast()
+ }
+
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self {
+ // INVARIANT: Pointer returned by `into_foreign, A` carries same invariants as `RcuBox<T>`.
+ // 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 {
+ // SAFETY: Caller ensures that `'a` is short enough.
+ unsafe { &(*ptr.cast::<RcuBoxInner<T>>()).value }
+ }
+
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T {
+ // SAFETY: `borrow_mut` has strictly stronger preconditions than `borrow`.
+ unsafe { Self::borrow(ptr) }
+ }
+}
+
+impl<T: Send + 'static, A: Allocator> ForeignOwnableRcu for RcuBox<T, A> {
+ type RcuBorrowed<'a> = &'a T;
+
+ unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> &'a T {
+ // SAFETY: `RcuBox::drop` can only run after `from_foreign` is called, and the value is
+ // valid until `RcuBox::drop` plus one grace period.
+ unsafe { &(*ptr.cast::<RcuBoxInner<T>>()).value }
+ }
+}
+
+impl<T: Send, A: Allocator> Drop for RcuBox<T, A> {
+ 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 };
+ if core::mem::needs_drop::<T>() {
+ // 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::<T, A>)) };
+ } 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()) };
+ }
+ }
+}
+
+/// Free this `RcuBoxInner<T>`.
+///
+/// # Safety
+///
+/// `head` references the `rcu_head` field of an `RcuBoxInner<T>` that has no references to it.
+/// Ownership of the `Box<RcuBoxInner<T>, A>` must be passed.
+unsafe extern "C" fn drop_rcu_box<T, A: Allocator>(head: *mut bindings::callback_head) {
+ // SAFETY: Caller provides a pointer to the `rcu_head` field of a `RcuBoxInner<T>`.
+ let box_inner = unsafe { crate::container_of!(head, RcuBoxInner<T>, 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 = 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.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] rust: maple_tree: add load_rcu()
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: add RcuBox type Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: Add " Boqun Feng
@ 2026-06-05 13:35 ` Boqun Feng
2026-06-05 13:38 ` Boqun Feng
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: Add load_rcu() Boqun Feng
2026-06-05 13:35 ` [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox Boqun Feng
4 siblings, 1 reply; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
From: Alice Ryhl <aliceryhl@google.com>
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 <aliceryhl@google.com>
---
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},
};
@@ -233,6 +237,54 @@ pub fn erase(&self, index: usize) -> Option<T> {
unsafe { T::try_from_foreign(ret) }
}
+ /// Load the value at the given index with rcu.
+ ///
+ /// # Examples
+ ///
+ /// Read the value under an rcu read lock. Even if the value is removed, it remains accessible
+ /// for one rcu grace period.
+ ///
+ /// ```ignore
+ /// use kernel::{
+ /// maple_tree::MapleTree,
+ /// sync::rcu::{self, RcuBox},
+ /// };
+ ///
+ /// let tree = KBox::pin_init(MapleTree::<RcuBox<i32>>::new(), GFP_KERNEL)?;
+ ///
+ /// let ten = RcuBox::new(10, GFP_KERNEL)?;
+ /// tree.insert(100, ten, GFP_KERNEL)?;
+ ///
+ /// let rcu_read_lock = rcu::Guard::new();
+ /// let ten = tree.load_rcu(100, &rcu_read_lock);
+ /// assert_eq!(ten, Some(&10));
+ ///
+ /// // Even if the value gets removed, we may continue to access it for 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<T::RcuBorrowed<'rcu>>
+ where
+ T: ForeignOwnableRcu,
+ {
+ // SAFETY: `self.tree` contains a valid maple tree.
+ let ret = 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 this 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> {
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] rust: maple_tree: Add load_rcu()
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
` (2 preceding siblings ...)
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: add load_rcu() Boqun Feng
@ 2026-06-05 13:35 ` Boqun Feng
2026-06-05 13:35 ` [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox Boqun Feng
4 siblings, 0 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
From: Alice Ryhl <aliceryhl@google.com>
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 <aliceryhl@google.com>
---
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},
};
@@ -233,6 +237,54 @@ pub fn erase(&self, index: usize) -> Option<T> {
unsafe { T::try_from_foreign(ret) }
}
+ /// Load the value at the given index with rcu.
+ ///
+ /// # Examples
+ ///
+ /// Read the value under an rcu read lock. Even if the value is removed, it remains accessible
+ /// for one rcu grace period.
+ ///
+ /// ```ignore
+ /// use kernel::{
+ /// maple_tree::MapleTree,
+ /// sync::rcu::{self, RcuBox},
+ /// };
+ ///
+ /// let tree = KBox::pin_init(MapleTree::<RcuBox<i32>>::new(), GFP_KERNEL)?;
+ ///
+ /// let ten = RcuBox::new(10, GFP_KERNEL)?;
+ /// tree.insert(100, ten, GFP_KERNEL)?;
+ ///
+ /// let rcu_read_lock = rcu::Guard::new();
+ /// let ten = tree.load_rcu(100, &rcu_read_lock);
+ /// assert_eq!(ten, Some(&10));
+ ///
+ /// // Even if the value gets removed, we may continue to access it for 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<T::RcuBorrowed<'rcu>>
+ where
+ T: ForeignOwnableRcu,
+ {
+ // SAFETY: `self.tree` contains a valid maple tree.
+ let ret = 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 this 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> {
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
` (3 preceding siblings ...)
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: Add load_rcu() Boqun Feng
@ 2026-06-05 13:35 ` Boqun Feng
2026-06-05 14:04 ` Alice Ryhl
2026-06-05 14:04 ` Boqun Feng
4 siblings, 2 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:35 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
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<T: RcuFreeSafe>` 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 <boqun@kernel.org>
---
rust/kernel/sync/rcu.rs | 31 +++++++++++++++
rust/kernel/sync/rcu/rcu_box.rs | 68 +++++++++++++++++++++++++++++++--
2 files changed, 95 insertions(+), 4 deletions(-)
diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
index 7da6b8d22277..7c26591bb318 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)
+use core::pin::Pin;
+
use crate::{
bindings,
types::{
@@ -82,3 +84,32 @@ 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 + one 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 `Self` has non-trivial
+/// `drop()` function.
+pub unsafe trait RcuFreeSafe {
+ fn drop_before_gp(self: Pin<&mut Self>);
+}
+
+macro_rules! impl_not_drop {
+ ($($t:ty, )*) => {
+ // SAFETY: Dropping `T` has no side effect means `T` is always ready 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 943fe3e8974e..8f52bb472daf 100644
--- a/rust/kernel/sync/rcu/rcu_box.rs
+++ b/rust/kernel/sync/rcu/rcu_box.rs
@@ -6,6 +6,7 @@
use core::{
marker::PhantomData,
+ mem::ManuallyDrop,
ops::Deref,
ptr::NonNull, //
};
@@ -29,17 +30,18 @@
use super::{
ForeignOwnableRcu,
- Guard, //
+ Guard,
+ RcuFreeSafe, //
};
-/// 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<T>` allocated 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<T: Send, A: Allocator>(NonNull<RcuBoxInner<T>>, PhantomData<A>);
/// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator.
@@ -205,6 +207,50 @@ fn drop(&mut self) {
drop(unsafe { Box::<_, A>::from_raw(box_inner) });
}
+/// A box that is freed with RCU.
+///
+/// Currently we require `T` being `Send` because of an implementation limitation. 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<T: Send + RcuFreeSafe, A: Allocator>(RcuBox<ManuallyDrop<T>, A>);
+
+impl<T: Send + RcuFreeSafe, A: Allocator> RcuFreeBox<T, A> {
+ /// Create a new `RcuFreeBox`.
+ pub fn new(x: T, flags: alloc::Flags) -> Result<Self, AllocError> {
+ Ok(Self(RcuBox::new(ManuallyDrop::new(x), flags)?))
+ }
+
+ /// Access the value for a grace period.
+ pub fn with_rcu<'rcu>(&self, read_guard: &'rcu Guard) -> &'rcu T {
+ self.0.with_rcu(read_guard)
+ }
+}
+
+impl<T: Send + RcuFreeSafe, A: Allocator> Deref for RcuFreeBox<T, A> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ self.0.deref()
+ }
+}
+
+impl<T: Send + RcuFreeSafe, A: Allocator> Drop for RcuFreeBox<T, A> {
+ fn drop(&mut self) {
+ // CAST: `ManuallyDrop<T>` is transparet to `T`, adn `RcuBox` owns the object per type
+ // invariants.
+ let ptr = self.0 .0.as_ptr().cast::<T>();
+
+ // SAFETY: Per the invariants of `RcuBox`, `ptr` owns the pointed object. And we are not
+ // going to move it.
+ let pin = unsafe { Pin::new_unchecked(&mut *ptr) };
+
+ pin.drop_before_gp();
+
+ // `needs_drop::<ManuallyDrop>()` returns `false`, hence `kvfree_call_rcu()` will be called
+ // and free the underlying data after a gracer period.
+ }
+}
+
#[kunit_tests(rust_rcu_box)]
mod tests {
use super::*;
@@ -218,6 +264,13 @@ fn rcu_box_basic() -> Result {
drop(rb);
+ let rb = RcuFreeBox::<_, 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);
@@ -225,6 +278,13 @@ fn rcu_box_basic() -> Result {
drop(rb);
+ let rb = RcuFreeBox::<_, 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.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] rust: rcu: add RcuBox type
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: add RcuBox type Boqun Feng
@ 2026-06-05 13:38 ` Boqun Feng
0 siblings, 0 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:38 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Liam R. Howlett, Andrew Ballance, Paul E. McKenney,
Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 05, 2026 at 06:35:37AM -0700, Boqun Feng wrote:
> From: Alice Ryhl <aliceryhl@google.com>
>
> 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 <aliceryhl@google.com>
> [boqun: Make RcuBox generic over Allocator and add tests]
> [boqun: Add type alias for Rcu*Box]
> Co-developed-by: Boqun Feng <boqun@kernel.org>
> Signed-off-by: Boqun Feng <boqun@kernel.org>
> ---
Please ignore this duplication...
Regards,
Boqun
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/3] rust: maple_tree: add load_rcu()
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: add load_rcu() Boqun Feng
@ 2026-06-05 13:38 ` Boqun Feng
0 siblings, 0 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 13:38 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Liam R. Howlett, Andrew Ballance, Paul E. McKenney,
Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 05, 2026 at 06:35:39AM -0700, Boqun Feng wrote:
> From: Alice Ryhl <aliceryhl@google.com>
>
> 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 <aliceryhl@google.com>
> ---
Please ignore this duplication...
Regards,
Boqun
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox
2026-06-05 13:35 ` [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox Boqun Feng
@ 2026-06-05 14:04 ` Alice Ryhl
2026-06-05 14:20 ` Boqun Feng
2026-06-05 14:04 ` Boqun Feng
1 sibling, 1 reply; 12+ messages in thread
From: Alice Ryhl @ 2026-06-05 14:04 UTC (permalink / raw)
To: Boqun Feng
Cc: linux-kernel, rust-for-linux, rcu, Miguel Ojeda, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 05, 2026 at 06:35:41AM -0700, Boqun Feng wrote:
> 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<T: RcuFreeSafe>` 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 <boqun@kernel.org>
> ---
> rust/kernel/sync/rcu.rs | 31 +++++++++++++++
> rust/kernel/sync/rcu/rcu_box.rs | 68 +++++++++++++++++++++++++++++++--
> 2 files changed, 95 insertions(+), 4 deletions(-)
>
> diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> index 7da6b8d22277..7c26591bb318 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)
>
> +use core::pin::Pin;
> +
> use crate::{
> bindings,
> types::{
> @@ -82,3 +84,32 @@ 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 + one 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 `Self` has non-trivial
> +/// `drop()` function.
> +pub unsafe trait RcuFreeSafe {
> + fn drop_before_gp(self: Pin<&mut Self>);
> +}
Should this have an associated type for the rcu-safe view?
pub unsafe trait RcuFreeSafe {
type RcuView<'a>;
/// Access this value in a manner that is safe after
/// `drop_before_gp` for one grace period.
fn rcu_view<'a>(self: Pin<&'a Self>, _rcu: &'a RcuGuard) -> Self::RcuView<'a>;
/// Drop this value in a manner where it may still be accessed via
/// `rcu_view` for one grace period.
///
/// # Safety
///
/// All other accesses to this value must happen before the call to this
/// method, except for accesses using `rcu_view`.
fn drop_before_gp(self: Pin<&mut Self>);
}
The idea being that once you call `drop_before_gp()`, the value
immediately becomes unusable as the type itself, but you can still use
it via `rcu_view`. The `RcuView` type can then be a type that has a
subset of the type's methods that is safe to use for one grace period
after `drop_before_gp`.
If you define the trait like this, then PollCondVar becomes RcuFreeSafe.
It can't be RcuFreeSafe today because you must not create new waiters after
`drop_before_gp()` is called. With this modified trait, it can simply
not provide methods for registering new waiters from the RcuView type.
Alice
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox
2026-06-05 13:35 ` [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox Boqun Feng
2026-06-05 14:04 ` Alice Ryhl
@ 2026-06-05 14:04 ` Boqun Feng
1 sibling, 0 replies; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 14:04 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, rcu
Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Liam R. Howlett, Andrew Ballance, Paul E. McKenney,
Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 05, 2026 at 06:35:41AM -0700, Boqun Feng wrote:
> 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<T: RcuFreeSafe>` 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 <boqun@kernel.org>
> ---
> rust/kernel/sync/rcu.rs | 31 +++++++++++++++
> rust/kernel/sync/rcu/rcu_box.rs | 68 +++++++++++++++++++++++++++++++--
> 2 files changed, 95 insertions(+), 4 deletions(-)
>
> diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> index 7da6b8d22277..7c26591bb318 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)
>
> +use core::pin::Pin;
> +
> use crate::{
> bindings,
> types::{
> @@ -82,3 +84,32 @@ 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 + one 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 `Self` has non-trivial
> +/// `drop()` function.
> +pub unsafe trait RcuFreeSafe {
> + fn drop_before_gp(self: Pin<&mut Self>);
> +}
> +
> +macro_rules! impl_not_drop {
> + ($($t:ty, )*) => {
> + // SAFETY: Dropping `T` has no side effect means `T` is always ready 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 943fe3e8974e..8f52bb472daf 100644
> --- a/rust/kernel/sync/rcu/rcu_box.rs
> +++ b/rust/kernel/sync/rcu/rcu_box.rs
> @@ -6,6 +6,7 @@
>
> use core::{
> marker::PhantomData,
> + mem::ManuallyDrop,
> ops::Deref,
> ptr::NonNull, //
> };
> @@ -29,17 +30,18 @@
>
> use super::{
> ForeignOwnableRcu,
> - Guard, //
> + Guard,
> + RcuFreeSafe, //
> };
>
> -/// 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<T>` allocated 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<T: Send, A: Allocator>(NonNull<RcuBoxInner<T>>, PhantomData<A>);
>
> /// Type alias for [`RcuBox`] with a [`Kmalloc`] allocator.
> @@ -205,6 +207,50 @@ fn drop(&mut self) {
> drop(unsafe { Box::<_, A>::from_raw(box_inner) });
> }
>
> +/// A box that is freed with RCU.
> +///
> +/// Currently we require `T` being `Send` because of an implementation limitation. 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<T: Send + RcuFreeSafe, A: Allocator>(RcuBox<ManuallyDrop<T>, A>);
> +
> +impl<T: Send + RcuFreeSafe, A: Allocator> RcuFreeBox<T, A> {
> + /// Create a new `RcuFreeBox`.
> + pub fn new(x: T, flags: alloc::Flags) -> Result<Self, AllocError> {
> + Ok(Self(RcuBox::new(ManuallyDrop::new(x), flags)?))
> + }
> +
> + /// Access the value for a grace period.
> + pub fn with_rcu<'rcu>(&self, read_guard: &'rcu Guard) -> &'rcu T {
> + self.0.with_rcu(read_guard)
> + }
> +}
> +
> +impl<T: Send + RcuFreeSafe, A: Allocator> Deref for RcuFreeBox<T, A> {
> + type Target = T;
> +
> + fn deref(&self) -> &T {
> + self.0.deref()
> + }
> +}
> +
> +impl<T: Send + RcuFreeSafe, A: Allocator> Drop for RcuFreeBox<T, A> {
> + fn drop(&mut self) {
> + // CAST: `ManuallyDrop<T>` is transparet to `T`, adn `RcuBox` owns the object per type
> + // invariants.
> + let ptr = self.0 .0.as_ptr().cast::<T>();
> +
> + // SAFETY: Per the invariants of `RcuBox`, `ptr` owns the pointed object. And we are not
> + // going to move it.
> + let pin = unsafe { Pin::new_unchecked(&mut *ptr) };
> +
This part needs to be:
// CAST: `ManuallyDrop<RcuBoxInner<T>>` is transparent to `RcuBoxInner<T>`, and `RcuBox`
// owns the object per type invariants.
let inner: *mut RcuBoxInner<T> = self.0 .0.as_ptr().cast();
// SAFETY: Per the invariants of `RcuBox`, `inner` owns the pointed object. And we are not
// going to move it.
let pin = unsafe { Pin::new_unchecked(&mut (*inner).value) };
Fixed locally.
Regards,
Boqun
> + pin.drop_before_gp();
> +
> + // `needs_drop::<ManuallyDrop>()` returns `false`, hence `kvfree_call_rcu()` will be called
> + // and free the underlying data after a gracer period.
> + }
> +}
> +
> #[kunit_tests(rust_rcu_box)]
> mod tests {
> use super::*;
> @@ -218,6 +264,13 @@ fn rcu_box_basic() -> Result {
>
> drop(rb);
>
> + let rb = RcuFreeBox::<_, 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);
> @@ -225,6 +278,13 @@ fn rcu_box_basic() -> Result {
>
> drop(rb);
>
> + let rb = RcuFreeBox::<_, 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.51.0
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox
2026-06-05 14:04 ` Alice Ryhl
@ 2026-06-05 14:20 ` Boqun Feng
2026-06-05 14:54 ` Alice Ryhl
0 siblings, 1 reply; 12+ messages in thread
From: Boqun Feng @ 2026-06-05 14:20 UTC (permalink / raw)
To: Alice Ryhl
Cc: linux-kernel, rust-for-linux, rcu, Miguel Ojeda, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 05, 2026 at 02:04:08PM +0000, Alice Ryhl wrote:
> On Fri, Jun 05, 2026 at 06:35:41AM -0700, Boqun Feng wrote:
> > 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<T: RcuFreeSafe>` 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 <boqun@kernel.org>
> > ---
> > rust/kernel/sync/rcu.rs | 31 +++++++++++++++
> > rust/kernel/sync/rcu/rcu_box.rs | 68 +++++++++++++++++++++++++++++++--
> > 2 files changed, 95 insertions(+), 4 deletions(-)
> >
> > diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> > index 7da6b8d22277..7c26591bb318 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)
> >
> > +use core::pin::Pin;
> > +
> > use crate::{
> > bindings,
> > types::{
> > @@ -82,3 +84,32 @@ 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 + one 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 `Self` has non-trivial
> > +/// `drop()` function.
> > +pub unsafe trait RcuFreeSafe {
> > + fn drop_before_gp(self: Pin<&mut Self>);
> > +}
>
> Should this have an associated type for the rcu-safe view?
>
> pub unsafe trait RcuFreeSafe {
> type RcuView<'a>;
>
> /// Access this value in a manner that is safe after
> /// `drop_before_gp` for one grace period.
> fn rcu_view<'a>(self: Pin<&'a Self>, _rcu: &'a RcuGuard) -> Self::RcuView<'a>;
>
> /// Drop this value in a manner where it may still be accessed via
> /// `rcu_view` for one grace period.
> ///
> /// # Safety
> ///
> /// All other accesses to this value must happen before the call to this
> /// method, except for accesses using `rcu_view`.
> fn drop_before_gp(self: Pin<&mut Self>);
> }
>
> The idea being that once you call `drop_before_gp()`, the value
> immediately becomes unusable as the type itself, but you can still use
> it via `rcu_view`. The `RcuView` type can then be a type that has a
> subset of the type's methods that is safe to use for one grace period
> after `drop_before_gp`.
>
> If you define the trait like this, then PollCondVar becomes RcuFreeSafe.
> It can't be RcuFreeSafe today because you must not create new waiters after
> `drop_before_gp()` is called. With this modified trait, it can simply
> not provide methods for registering new waiters from the RcuView type.
>
Good point! But I guess I could keep RcuFreeSafe as it is but remove the
`RcuFreeSafe::with_rcu()`, and this should be sufficient for
PollCondVar. I do want to wait for a meaningful usage of `rcu_view()` to
add that, but I think your idea of that is great. Or maybe you have a
potential usage in mind?
Regards,
Boqun
> Alice
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox
2026-06-05 14:20 ` Boqun Feng
@ 2026-06-05 14:54 ` Alice Ryhl
0 siblings, 0 replies; 12+ messages in thread
From: Alice Ryhl @ 2026-06-05 14:54 UTC (permalink / raw)
To: Boqun Feng
Cc: linux-kernel, rust-for-linux, rcu, Miguel Ojeda, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Liam R. Howlett, Andrew Ballance,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Sumit Semwal,
Christian König, maple-tree, linux-mm, linux-media,
dri-devel, Philipp Stanner, Lyude Paul, Daniel Almeida,
Onur Özkan
On Fri, Jun 5, 2026 at 4:20 PM Boqun Feng <boqun@kernel.org> wrote:
>
> On Fri, Jun 05, 2026 at 02:04:08PM +0000, Alice Ryhl wrote:
> > On Fri, Jun 05, 2026 at 06:35:41AM -0700, Boqun Feng wrote:
> > > 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<T: RcuFreeSafe>` 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 <boqun@kernel.org>
> > > ---
> > > rust/kernel/sync/rcu.rs | 31 +++++++++++++++
> > > rust/kernel/sync/rcu/rcu_box.rs | 68 +++++++++++++++++++++++++++++++--
> > > 2 files changed, 95 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> > > index 7da6b8d22277..7c26591bb318 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)
> > >
> > > +use core::pin::Pin;
> > > +
> > > use crate::{
> > > bindings,
> > > types::{
> > > @@ -82,3 +84,32 @@ 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 + one 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 `Self` has non-trivial
> > > +/// `drop()` function.
> > > +pub unsafe trait RcuFreeSafe {
> > > + fn drop_before_gp(self: Pin<&mut Self>);
> > > +}
> >
> > Should this have an associated type for the rcu-safe view?
> >
> > pub unsafe trait RcuFreeSafe {
> > type RcuView<'a>;
> >
> > /// Access this value in a manner that is safe after
> > /// `drop_before_gp` for one grace period.
> > fn rcu_view<'a>(self: Pin<&'a Self>, _rcu: &'a RcuGuard) -> Self::RcuView<'a>;
> >
> > /// Drop this value in a manner where it may still be accessed via
> > /// `rcu_view` for one grace period.
> > ///
> > /// # Safety
> > ///
> > /// All other accesses to this value must happen before the call to this
> > /// method, except for accesses using `rcu_view`.
> > fn drop_before_gp(self: Pin<&mut Self>);
> > }
> >
> > The idea being that once you call `drop_before_gp()`, the value
> > immediately becomes unusable as the type itself, but you can still use
> > it via `rcu_view`. The `RcuView` type can then be a type that has a
> > subset of the type's methods that is safe to use for one grace period
> > after `drop_before_gp`.
> >
> > If you define the trait like this, then PollCondVar becomes RcuFreeSafe.
> > It can't be RcuFreeSafe today because you must not create new waiters after
> > `drop_before_gp()` is called. With this modified trait, it can simply
> > not provide methods for registering new waiters from the RcuView type.
> >
>
> Good point! But I guess I could keep RcuFreeSafe as it is but remove the
> `RcuFreeSafe::with_rcu()`, and this should be sufficient for
> PollCondVar. I do want to wait for a meaningful usage of `rcu_view()` to
> add that, but I think your idea of that is great. Or maybe you have a
> potential usage in mind?
For the dma fence, the fence context would let you access the name c
string via the rcu view.
Alice
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-06-05 14:54 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-05 13:35 [PATCH 0/3] rust: sync: Introduce Rcu*Box Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: add RcuBox type Boqun Feng
2026-06-05 13:38 ` Boqun Feng
2026-06-05 13:35 ` [PATCH 1/3] rust: rcu: Add " Boqun Feng
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: add load_rcu() Boqun Feng
2026-06-05 13:38 ` Boqun Feng
2026-06-05 13:35 ` [PATCH 2/3] rust: maple_tree: Add load_rcu() Boqun Feng
2026-06-05 13:35 ` [RFC PATCH 3/3] rust: rcu: Introduce RcuFreeBox Boqun Feng
2026-06-05 14:04 ` Alice Ryhl
2026-06-05 14:20 ` Boqun Feng
2026-06-05 14:54 ` Alice Ryhl
2026-06-05 14:04 ` Boqun Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox