[PATCH 2/2] rust: gpu: buddy: store the allocator inside the Mutex

From: Ivan Tverdokhleb

Date: Sat Nov 14 2026 - 15:08:05 EST


GpuBuddyInner keeps the C gpu_buddy structure next to a separate
Mutex<()>, so nothing in the type system ties the data to the lock.
A TODO asked to replace Mutex<()> with Mutex<Opaque<..>> once
Mutex::new() accepts a fallible initializer.

That is now possible, so put the Opaque<gpu_buddy> directly inside the
Mutex. The allocator can then only be reached through the lock guard,
which lets the compiler enforce that the lock is held. This also
removes the now unneeded `inner` field from GpuBuddyGuard.

Update the safety comments that referred to the removed `inner` field.

Signed-off-by: Ivan Tverdokhleb <mbkchelofficialdev@xxxxxxxxx>
---
rust/kernel/gpu/buddy.rs | 38 +++++++++++++++-----------------------
1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs
index d502ada6ebbd..3397eb584ead 100644
--- a/rust/kernel/gpu/buddy.rs
+++ b/rust/kernel/gpu/buddy.rs
@@ -313,16 +313,11 @@ pub struct GpuBuddyParams {
///
/// # Invariants
///
-/// The inner [`Opaque`] contains an initialized buddy allocator.
+/// The `lock` field contains an initialized buddy allocator wrapped in `Opaque`.
#[pin_data(PinnedDrop)]
struct GpuBuddyInner {
#[pin]
- inner: Opaque<bindings::gpu_buddy>,
-
- // TODO: Replace `Mutex<()>` with `Mutex<Opaque<..>>` once `Mutex::new()`
- // accepts `impl PinInit<T>`.
- #[pin]
- lock: Mutex<()>,
+ lock: Mutex<Opaque<bindings::gpu_buddy>>,
/// Cached creation parameters (do not change after init).
params: GpuBuddyParams,
}
@@ -338,22 +333,20 @@ fn new(params: GpuBuddyParams) -> impl PinInit<Self, Error> {
// `gpu_buddy_*` APIs. `try_pin_init!` only completes if all fields succeed,
// so the invariant holds when construction finishes.
try_pin_init!(Self {
- inner <- Opaque::try_ffi_init(|ptr| {
- // SAFETY: `ptr` points to valid uninitialized memory from the pin-init
- // infrastructure. `gpu_buddy_init` will initialize the structure.
- to_result(unsafe {
- bindings::gpu_buddy_init(ptr, size, chunk_size.as_usize() as u64)
- })
- }),
- lock <- new_mutex!(()),
- params,
+ lock <- new_mutex!(Opaque::try_ffi_init(|ptr| {
+ // SAFETY: `ptr` points to valid uninitialized memory from the pin-init
+ // infrastructure. `gpu_buddy_init` will initialize the structure.
+ to_result(unsafe {
+ bindings::gpu_buddy_init(ptr, size, chunk_size.as_usize() as u64)
+ })
+ })),
+ params,
})
}

/// Lock the mutex and return a guard for accessing the allocator.
fn lock(&self) -> GpuBuddyGuard<'_> {
GpuBuddyGuard {
- inner: self,
_guard: self.lock.lock(),
}
}
@@ -364,7 +357,7 @@ impl PinnedDrop for GpuBuddyInner {
fn drop(self: Pin<&mut Self>) {
let guard = self.lock();

- // SAFETY: Per the type invariant, `inner` contains an initialized
+ // SAFETY: Per the type invariant, `lock` contains an initialized
// allocator. `guard` provides exclusive access.
unsafe { bindings::gpu_buddy_fini(guard.as_raw()) };
}
@@ -381,14 +374,13 @@ unsafe impl Sync for GpuBuddyInner {}
///
/// The `_guard` holds the lock for the duration of this guard's lifetime.
struct GpuBuddyGuard<'a> {
- inner: &'a GpuBuddyInner,
- _guard: MutexGuard<'a, ()>,
+ _guard: MutexGuard<'a, Opaque<bindings::gpu_buddy>>,
}

impl GpuBuddyGuard<'_> {
/// Get a raw pointer to the underlying C `gpu_buddy` structure.
fn as_raw(&self) -> *mut bindings::gpu_buddy {
- self.inner.inner.get()
+ self._guard.get()
}
}

@@ -428,7 +420,7 @@ pub fn size(&self) -> u64 {
pub fn avail(&self) -> u64 {
let guard = self.0.lock();

- // SAFETY: Per the type invariant, `inner` contains an initialized allocator.
+ // SAFETY: Per the type invariant, `lock` contains an initialized allocator.
// `guard` provides exclusive access.
unsafe { (*guard.as_raw()).avail }
}
@@ -463,7 +455,7 @@ pub fn alloc_blocks(
// Lock while allocating to serialize with concurrent frees.
let guard = buddy.lock();

- // SAFETY: Per the type invariant, `inner` contains an initialized
+ // SAFETY: Per the type invariant, `lock` contains an initialized
// allocator. `guard` provides exclusive access.
to_result(unsafe {
bindings::gpu_buddy_alloc_blocks(
--
2.56.1