[PATCH v2] rust: maple_tree: implement Send and Sync for MapleTree
COLD21d
REVIEWED: 25 (25M)
From: Eliot Courtney <hidden>
Date: 2026-09-08 09:54:50
Also in:
lkml, rust-for-linux
Subsystem:
maple tree, rust, the rest · Maintainers:
Liam R. Howlett, Miguel Ojeda, Linus Torvalds
3 review trailers (3 from subsystem maintainers).
From: Joel Fernandes <joelagnelf@nvidia.com>
The C maple_tree struct contains a *mut c_void, which prevents Rust from
auto-deriving Send/Sync. Following is an example error message when using
MapleTree in nova-core's Vmm.
This propagates up through MapleTreeAlloc to Vmm, BarUser, Gpu, and NovaCore,
causing NovaCore to fail the Send bound required by pci::Driver:
error[E0277]: `*mut c_void` cannot be sent between threads safely
--> drivers/gpu/nova-core/driver.rs:77:22
|
77 | impl pci::Driver for NovaCore {
| ^^^^^^^^ `*mut c_void` cannot be sent between threads safely
|
= help: within `MapleTreeAlloc<()>`, the trait `Send` is not implemented for `*mut c_void`
note: required because it appears within the type `kernel::bindings::maple_tree`
note: required because it appears within the type `Opaque<kernel::bindings::maple_tree>`
note: required because it appears within the type `MapleTree<()>`
note: required because it appears within the type `MapleTreeAlloc<()>`
= note: required for `Box<MapleTreeAlloc<()>, Kmalloc>` to implement `Send`
note: required because it appears within the type `core::pin::Pin<Box<MapleTreeAlloc<()>, Kmalloc>>`
note: required because it appears within the type `Vmm`
note: required because it appears within the type `BarUser`
note: required because it appears within the type `Gpu`
note: required because it appears within the type `NovaCore`
note: required by a bound in `kernel::pci::Driver`
--> rust/kernel/pci.rs:294:19
Implement Send and Sync for MapleTree. The tree contains no thread-local
state, and all shared access goes through the internal ma_lock spinlock.
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Reviewed-by: Boqun Feng <boqun@kernel.org>
[ecourtney: also require T: Sync for the Sync impl]
Signed-off-by: Eliot Courtney <redacted>
---
This is a repost of Joel's v3 [1]. The upcoming nova-core memory
management changes depend on it.
Compared to v3, I've added Boqun's Reviewed-by from the v2 thread [2],
which v3 didn't pick up.
This is based on drm-rust-next.
[1] https://lore.kernel.org/all/20260511143604.3848176-1-joelagnelf@nvidia.com/ (local)
[2] https://lore.kernel.org/all/aftiZGt3HQe0Bf_x@tardis.local/ (local)
[3] https://lore.kernel.org/all/CAH5fLgh_TQiqKxXsz_DVcQxkCaEw+q0JyTh4e4Tnp28V0JDmYg@mail.gmail.com/ (local)
---
Changes in v2:
- Also require `T: Sync` for the `Sync` impl, so that shared borrows of
entries (e.g. future RCU readers) are sound [3]. (Alice)
- Kept Reviewed-by tags since e.g. Boqun also suggested the same `Sync`
change [4] and Gary was asking around the same kind of thing [5]
- Link to v1: https://patch.msgid.link/20260908-maple-tree-send-sync-v1-1-43adcd4a16e8@nvidia.com
[4] https://lore.kernel.org/all/aepRx2jgIKmoRp-r@tardis.local/ (local)
[5] https://lore.kernel.org/all/DHYYDQWP4FZ7.3MK090FH4HWID@garyguo.net/ (local)
---
rust/kernel/maple_tree.rs | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/rust/kernel/maple_tree.rs b/rust/kernel/maple_tree.rs
index 265d6396a78a..7abe41228cb7 100644
--- a/rust/kernel/maple_tree.rs
+++ b/rust/kernel/maple_tree.rs@@ -16,7 +16,11 @@ alloc::Flags, error::to_result, prelude::*, - types::{ForeignOwnable, Opaque}, + types::{ + ForeignOwnable, + NotThreadSafe, + Opaque, // + }, }; /// A maple tree optimized for storing non-overlapping ranges.
@@ -240,7 +244,10 @@ pub fn lock(&self) -> MapleGuard<'_, T> { unsafe { bindings::spin_lock(self.ma_lock()) }; // INVARIANT: We just took the spinlock. - MapleGuard(self) + MapleGuard { + tree: self, + _not_send: NotThreadSafe, + } } #[inline]
@@ -302,19 +309,30 @@ fn drop(mut self: Pin<&mut Self>) { } } +// SAFETY: `MapleTree<T>` is `Send` if `T` is `Send` because `MapleTree` owns its elements. +unsafe impl<T: ForeignOwnable + Send> Send for MapleTree<T> {} + +// SAFETY: `&MapleTree<T>` allows inserting and erasing entries from any thread, so `T: Send` is +// required, and shared borrows of entries require `T: Sync`. +unsafe impl<T: ForeignOwnable + Send + Sync> Sync for MapleTree<T> {} + /// A reference to a [`MapleTree`] that owns the inner lock. /// /// # Invariants /// /// This guard owns the inner spinlock. #[must_use = "if unused, the lock will be immediately unlocked"] -pub struct MapleGuard<'tree, T: ForeignOwnable>(&'tree MapleTree<T>); +pub struct MapleGuard<'tree, T: ForeignOwnable> { + tree: &'tree MapleTree<T>, + // A held spinlock must be released on the same CPU that acquired it. + _not_send: NotThreadSafe, +} impl<'tree, T: ForeignOwnable> Drop for MapleGuard<'tree, T> { #[inline] fn drop(&mut self) { // SAFETY: By the type invariants, we hold this spinlock. - unsafe { bindings::spin_unlock(self.0.ma_lock()) }; + unsafe { bindings::spin_unlock(self.tree.ma_lock()) }; } }
@@ -323,7 +341,7 @@ impl<'tree, T: ForeignOwnable> MapleGuard<'tree, T> { pub fn ma_state(&mut self, first: usize, end: usize) -> MaState<'_, T> { // SAFETY: The `MaState` borrows this `MapleGuard`, so it can also borrow the `MapleGuard`s // read/write permissions to the maple tree. - unsafe { MaState::new_raw(self.0, first, end) } + unsafe { MaState::new_raw(self.tree, first, end) } } /// Load the value at the given index.
@@ -375,7 +393,7 @@ pub fn ma_state(&mut self, first: usize, end: usize) -> MaState<'_, T> { #[inline] pub fn load(&mut self, index: usize) -> Option<T::BorrowedMut<'_>> { // SAFETY: `self.tree` contains a valid maple tree. - let ret = unsafe { bindings::mtree_load(self.0.tree.get(), index) }; + let ret = unsafe { bindings::mtree_load(self.tree.tree.get(), index) }; if ret.is_null() { return None; }
--- base-commit: e6a2c988ed96a5a3af51ed97ecba980521bf2fc0 change-id: 20260907-maple-tree-send-sync-a1479d1ab302 Best regards, -- Eliot Courtney [off-list ref]