rust: maple_tree: implement Send and Sync for MapleTree

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.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Boqun Feng <boqun@kernel.org>
[ecourtney: also require T: Sync for the Sync impl]
Acked-by: Danilo Krummrich <dakr@kernel.org>
Acked-by: Liam R. Howlett (Oracle) <liam@infradead.org>
Link: https://patch.msgid.link/20260908-maple-tree-send-sync-v2-1-24aae5b3a990@nvidia.com
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
This commit is contained in:
Joel Fernandes 2026-09-08 18:54:12 +09:00 committed by Eliot Courtney
parent 73e5616f3d
commit 9cf1bc8bbc

View File

@ -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;
}