NVIDIA GPU driver infrastructure
 help / color / mirror / Atom feed
* [PATCH] rust: maple_tree: implement Send and Sync for MapleTree
@ 2026-09-08  7:50 Eliot Courtney
  2026-09-08  8:49 ` Alice Ryhl
  0 siblings, 1 reply; 3+ messages in thread
From: Eliot Courtney @ 2026-09-08  7:50 UTC (permalink / raw)
  To: Liam R. Howlett, Alice Ryhl, Andrew Ballance, Danilo Krummrich
  Cc: John Hubbard, Alistair Popple, Timur Tabi, Alexandre Courbot,
	Miguel Ojeda, maple-tree, rust-for-linux, nova-gpu, linux-kernel,
	Joel Fernandes, Gary Guo, Boqun Feng, Eliot Courtney

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>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
This is a repost of Joel's v3 [1] with no code changes. 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/
[2] https://lore.kernel.org/all/aftiZGt3HQe0Bf_x@tardis.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..74cfd5c0fb2a 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>` never hands out `&T`; all entry access is serialized
+// by `ma_lock` or `&mut Guard`, so `T: Send` suffices (`T: Sync` not required).
+unsafe impl<T: ForeignOwnable + Send> 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 <ecourtney@nvidia.com>


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

* Re: [PATCH] rust: maple_tree: implement Send and Sync for MapleTree
  2026-09-08  7:50 [PATCH] rust: maple_tree: implement Send and Sync for MapleTree Eliot Courtney
@ 2026-09-08  8:49 ` Alice Ryhl
  2026-09-08  9:53   ` Eliot Courtney
  0 siblings, 1 reply; 3+ messages in thread
From: Alice Ryhl @ 2026-09-08  8:49 UTC (permalink / raw)
  To: Eliot Courtney
  Cc: Liam R. Howlett, Andrew Ballance, Danilo Krummrich, John Hubbard,
	Alistair Popple, Timur Tabi, Alexandre Courbot, Miguel Ojeda,
	maple-tree, rust-for-linux, nova-gpu, linux-kernel,
	Joel Fernandes, Gary Guo, Boqun Feng

On Tue, Sep 8, 2026 at 9:51 AM Eliot Courtney <ecourtney@nvidia.com> wrote:
> +// SAFETY: `&MapleTree<T>` never hands out `&T`; all entry access is serialized
> +// by `ma_lock` or `&mut Guard`, so `T: Send` suffices (`T: Sync` not required).
> +unsafe impl<T: ForeignOwnable + Send> Sync for MapleTree<T> {}

This is true now, but will change if load_rcu() from
https://lore.kernel.org/all/20260116-rcu-box-v1-2-38ebfbcd53f0@google.com/
got merged.

It might be better to just pre-emptively require T: Sync now?

Alice

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

* Re: [PATCH] rust: maple_tree: implement Send and Sync for MapleTree
  2026-09-08  8:49 ` Alice Ryhl
@ 2026-09-08  9:53   ` Eliot Courtney
  0 siblings, 0 replies; 3+ messages in thread
From: Eliot Courtney @ 2026-09-08  9:53 UTC (permalink / raw)
  To: Alice Ryhl, Eliot Courtney
  Cc: Liam R. Howlett, Andrew Ballance, Danilo Krummrich, John Hubbard,
	Alistair Popple, Timur Tabi, Alexandre Courbot, Miguel Ojeda,
	maple-tree, rust-for-linux, nova-gpu, linux-kernel,
	Joel Fernandes, Gary Guo, Boqun Feng

On Tue Sep 8, 2026 at 5:49 PM JST, Alice Ryhl wrote:
> On Tue, Sep 8, 2026 at 9:51 AM Eliot Courtney <ecourtney@nvidia.com> wrote:
>> +// SAFETY: `&MapleTree<T>` never hands out `&T`; all entry access is serialized
>> +// by `ma_lock` or `&mut Guard`, so `T: Send` suffices (`T: Sync` not required).
>> +unsafe impl<T: ForeignOwnable + Send> Sync for MapleTree<T> {}
>
> This is true now, but will change if load_rcu() from
> https://lore.kernel.org/all/20260116-rcu-box-v1-2-38ebfbcd53f0@google.com/
> got merged.
>
> It might be better to just pre-emptively require T: Sync now?
>
> Alice

Yeah that sounds reasonable to me. Thanks!

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

end of thread, other threads:[~2026-09-08  9:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-08  7:50 [PATCH] rust: maple_tree: implement Send and Sync for MapleTree Eliot Courtney
2026-09-08  8:49 ` Alice Ryhl
2026-09-08  9:53   ` Eliot Courtney

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