* Claude review: rust: drm: gem: Introduce shmem::Object::sg_table()
2026-05-26 21:28 ` [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-05-27 4:05 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-05-27 4:05 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Issues found, core design is sound**
The overall architecture is well-thought-out:
- `LazyInit<Devres<SGTableMap<T>>>` stores the devres-managed mapping
- `Devres` ensures revocation on driver-unbind
- `LazyInit` ensures one-time initialization
- The self-referential `NonNull<Object<T>>` in `SGTableMap` is safe because `Object` is pinned
**The `free_callback` reordering is correct and important:**
```rust
+ unsafe { Pin::new_unchecked(&mut (*this).sgt_res) }.reset();
+
+ unsafe { bindings::drm_gem_shmem_release(base) };
```
Resetting `sgt_res` before releasing the GEM object ensures the SGTable is freed while the GEM object is still valid. Then `drm_gem_shmem_release` sees `shmem->sgt == NULL` (set by `__drm_gem_shmem_free_sgt_locked`) and skips the now-unnecessary cleanup. No double-free.
**The `sg_table()` method is clean:**
```rust
+ pub fn sg_table<'a>(
+ &'a self,
+ dev: &'a device::Device<Bound>,
+ ) -> Result<&'a scatterlist::SGTable> {
+ if dev.as_raw() != self.dev().as_ref().as_raw() {
+ return Err(EINVAL);
+ }
+ match self.sgt_res.init(Devres::new(dev, SGTableMap::new(self))) {
+ Ok(ret) | Err(LazyInitError::AlreadyInit(ret)) => Ok(ret.access(dev)?),
+ Err(LazyInitError::DuringInit(e)) => Err(e),
+ }
+ }
```
The device identity check before `init` prevents creating a `Devres` bound to the wrong device. The `LazyInit::init` return handling correctly distinguishes first-init from already-init.
**Issue 1: Test type mismatch.** `create_drm_dev` takes `name: &'static CStr` but is called with `Some(c"Kunit")`:
```rust
+ fn create_drm_dev(
+ name: &'static CStr,
+ ) -> ...
+ let (dev, drm) = create_drm_dev(Some(c"Kunit"))?;
+ let (wrong_dev, wrong_drm) = create_drm_dev(Some(c"EvilKunit"))?;
```
`Some(c"Kunit")` is `Option<&'static CStr>`, not `&'static CStr`. This won't compile. Either the function signature should be `name: Option<&'static CStr>` (if a dependency changed `faux::Registration::new` to take optional name), or the calls should pass `c"Kunit"` directly without `Some()`.
**Issue 2: Unused variable.** `wrong_drm` is bound but never used:
```rust
+ let (wrong_dev, wrong_drm) = create_drm_dev(Some(c"EvilKunit"))?;
```
This will produce a compiler warning. Should be `_wrong_drm` or `_`.
**Minor: SGTableMap::new discards the sgt pointer.** This is intentional (using `drm_gem_shmem_get_pages_sgt` for its side effect of populating `shmem->sgt`), but a brief comment would help readers understand why the result of `from_err_ptr` is discarded:
```rust
+ fn new(obj: &Object<T>) -> impl Init<Self, Error> {
+ from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
+ Ok(Self { obj: obj.into() })
+ }
```
The `Send`/`Sync` impls for `SGTableMap` are justified by the GEM object's thread-safety guarantees.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v15 0/6] Rust bindings for gem shmem
@ 2026-05-29 18:33 Lyude Paul
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:33 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
Most of this patch series has already been pushed upstream, this is just
the second half of the patch series that has not been pushed yet + some
additional changes which were required to implement changes requested by
the mailing list. This patch series is originally from Asahi, previously
posted by Daniel Almeida.
The previous version of the patch series can be found here:
https://patchwork.freedesktop.org/series/164580/
Branch with patches applied available here:
https://gitlab.freedesktop.org/lyudess/linux/-/commits/rust/gem-shmem
This patch series applies on top of drm-rust-next with the following
dependencies applied:
https://lore.kernel.org/rust-for-linux/20260529173137.303717-1-lyude@redhat.com/T/#t
Lyude Paul (6):
rust: gem: shmem: Fix Default implementation for ObjectConfig
rust: drm: gem/shmem: Add DmaResvGuard helper
rust: drm: gem: Add vmap functions to shmem bindings
rust: faux: Allow retrieving a bound Device
drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked()
rust: drm: gem: Introduce shmem::Object::sg_table()
drivers/gpu/drm/drm_gem_shmem_helper.c | 32 +-
include/drm/drm_gem_shmem_helper.h | 1 +
rust/kernel/drm/gem/shmem.rs | 497 ++++++++++++++++++++++++-
rust/kernel/faux.rs | 7 +-
4 files changed, 512 insertions(+), 25 deletions(-)
base-commit: 0e42ec83d46ab8877d38d37493328ed7d1a24de8
prerequisite-patch-id: c8ade07eec6e9c9e875800b114137c459d362e4e
prerequisite-patch-id: c38da06dbc4cfd2589bf2e7e9f0ebaa4da521ddf
--
2.54.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
@ 2026-05-29 18:33 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
` (5 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:33 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
I completely forgot when coming up with this type that #[derive(Default)]
only works if all generics mentioned in the type implement Default (and T
usually doesn't). This being said: We don't use `T` for anything besides
using it for a reference type, so whether or not it implements `Default`
shouldn't actually need to matter.
So, fix this by just manually implementing Default instead of deriving it.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
rust/kernel/drm/gem/shmem.rs | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index e1b648920d2f6..8b7de136ab1f9 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -39,7 +39,6 @@
///
/// This is used with [`Object::new()`] to control various properties that can only be set when
/// initially creating a shmem-backed GEM object.
-#[derive(Default)]
pub struct ObjectConfig<'a, T: DriverObject> {
/// Whether to set the write-combine map flag.
pub map_wc: bool,
@@ -50,6 +49,16 @@ pub struct ObjectConfig<'a, T: DriverObject> {
pub parent_resv_obj: Option<&'a Object<T>>,
}
+impl<'a, T: DriverObject> Default for ObjectConfig<'a, T> {
+ #[inline(always)]
+ fn default() -> Self {
+ Self {
+ map_wc: false,
+ parent_resv_obj: None,
+ }
+ }
+}
+
/// A shmem-backed GEM object.
///
/// # Invariants
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
@ 2026-05-29 18:34 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings Lyude Paul
` (4 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:34 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
Just a temporary holdover to make locking/unlocking the dma_resv lock much
easier.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Co-authored-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
rust/kernel/drm/gem/shmem.rs | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 8b7de136ab1f9..a116b0752e46a 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -27,7 +27,10 @@
Deref,
DerefMut, //
},
- ptr::NonNull,
+ ptr::{
+ self,
+ NonNull, //
+ },
};
use gem::{
BaseObjectPrivate,
@@ -233,3 +236,29 @@ impl<T: DriverObject> driver::AllocImpl for Object<T> {
dumb_map_offset: None,
};
}
+
+/// Private helper-type for holding the `dma_resv` object for a GEM shmem object.
+///
+/// When this is dropped, the `dma_resv` lock is dropped as well.
+///
+// TODO: This should be replace with a WwMutex equivalent once we have such bindings in the kernel.
+struct DmaResvGuard<'a, T: DriverObject>(&'a Object<T>);
+
+impl<'a, T: DriverObject> DmaResvGuard<'a, T> {
+ #[inline(always)]
+ #[expect(unused)]
+ fn new(obj: &'a Object<T>) -> Self {
+ // SAFETY: This lock is initialized throughout the lifetime of `object`.
+ unsafe { bindings::dma_resv_lock(obj.raw_dma_resv(), ptr::null_mut()) };
+
+ Self(obj)
+ }
+}
+
+impl<'a, T: DriverObject> Drop for DmaResvGuard<'a, T> {
+ #[inline(always)]
+ fn drop(&mut self) {
+ // SAFETY: We are releasing the lock grabbed during the creation of this object.
+ unsafe { bindings::dma_resv_unlock(self.0.raw_dma_resv()) };
+ }
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
2026-05-29 18:34 ` [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
@ 2026-05-29 18:34 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
` (3 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:34 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
One of the more obvious use cases for gem shmem objects is the ability to
create mappings into their contents. So, let's hook this up in our rust
bindings.
Similar to how we handle SGTables, we make sure there's two different types
of mappings: owned mappings (kernel::drm::gem::shmem::VMap) and borrowed
mappings (kernel::drm::gem::shmem::VMapRef).
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
V7:
* Switch over to the new iosys map bindings that use the Io trait
V8:
* Get rid of iosys_map bindings for now, only support non-iomem types
* s/as_shmem()/as_raw_shmem()
V9:
* Get rid of some outdated comments I missed
* Add missing SIZE check to raw_vmap()
* Add a proper unit test that ensures that we actually validate SIZE at
compile-time.
Turns out it takes only 34 lines to make a boilerplate DRM driver for a
kunit test :)
* Add unit tests
* Add some missing #[inline]s
V10:
* Correct issue with iomem error path
We previously called raw_vunmap() if we got an iomem allocation, but
raw_vunmap() was written such that it assumed all allocations were sysmem
allocations. Fix this by just making raw_vunmap() accept a iosys_map.
V11:
* Use Alexandre's clever solution to remove the macros we were using for
maintaining two different VMap types.
* Change the order of items in Object<T> to ensure that sgt_res is always
dropped before obj.
* Fix typo in Object.raw_vmap()
* s/raw_vmap()/make_vmap()/
Deduplicate code a bit more as well by using more generics here
V15:
* Add these patches back
* We only have one VMap type now!
* Use ObjectConfig::default() in unit tests since we unbroke it.
rust/kernel/drm/gem/shmem.rs | 433 +++++++++++++++++++++++++++++++++--
1 file changed, 418 insertions(+), 15 deletions(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index a116b0752e46a..494e0d0d8d0d6 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -11,18 +11,39 @@
use crate::{
container_of,
+ device::{
+ self,
+ Bound, //
+ },
+ devres::*,
drm::{
- device,
driver,
gem,
- private::Sealed, //
+ private::Sealed,
+ Device, //
+ },
+ error::{
+ from_err_ptr,
+ to_result, //
+ },
+ io::{
+ Io,
+ IoCapable,
+ IoKnownSize, //
},
- error::to_result,
prelude::*,
- sync::aref::ARef,
+ scatterlist,
+ sync::{
+ aref::ARef,
+ new_lazy_init,
+ LazyInit,
+ LazyInitError, //
+ },
types::Opaque, //
};
use core::{
+ ffi::c_void,
+ mem::MaybeUninit, //
ops::{
Deref,
DerefMut, //
@@ -33,6 +54,7 @@
},
};
use gem::{
+ BaseObject,
BaseObjectPrivate,
DriverObject,
IntoGEMObject, //
@@ -75,6 +97,9 @@ pub struct Object<T: DriverObject> {
obj: Opaque<bindings::drm_gem_shmem_object>,
/// Parent object that owns this object's DMA reservation object.
parent_resv_obj: Option<ARef<Object<T>>>,
+ /// Devres object for unmapping any SGTable on driver-unbind.
+ #[pin]
+ sgt_res: LazyInit<Devres<SGTableMap<T>>>,
#[pin]
inner: T,
}
@@ -118,7 +143,7 @@ fn as_raw_shmem(&self) -> *mut bindings::drm_gem_shmem_object {
///
/// Additional config options can be specified using `config`.
pub fn new(
- dev: &device::Device<T::Driver>,
+ dev: &Device<T::Driver>,
size: usize,
config: ObjectConfig<'_, T>,
args: T::Args,
@@ -127,6 +152,7 @@ pub fn new(
try_pin_init!(Self {
obj <- Opaque::init_zeroed(),
parent_resv_obj: config.parent_resv_obj.map(|p| p.into()),
+ sgt_res <- new_lazy_init!(),
inner <- T::new(dev, size, args),
}),
GFP_KERNEL,
@@ -160,9 +186,9 @@ pub fn new(
}
/// Returns the `Device` that owns this GEM object.
- pub fn dev(&self) -> &device::Device<T::Driver> {
+ pub fn dev(&self) -> &Device<T::Driver> {
// SAFETY: `dev` will have been initialized in `Self::new()` by `drm_gem_shmem_init()`.
- unsafe { device::Device::from_raw((*self.as_raw()).dev) }
+ unsafe { Device::from_raw((*self.as_raw()).dev) }
}
extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
@@ -170,22 +196,123 @@ extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
// - DRM always passes a valid gem object here
// - We used drm_gem_shmem_create() in our create_gem_object callback, so we know that
// `obj` is contained within a drm_gem_shmem_object
- let this = unsafe { container_of!(obj, bindings::drm_gem_shmem_object, base) };
-
- // SAFETY:
- // - We're in free_callback - so this function is safe to call.
- // - We won't be using the gem resources on `this` after this call.
- unsafe { bindings::drm_gem_shmem_release(this) };
+ let base = unsafe { container_of!(obj, bindings::drm_gem_shmem_object, base) };
// SAFETY:
// - We verified above that `obj` is valid, which makes `this` valid
// - This function is set in AllocOps, so we know that `this` is contained within a
// `Object<T>`
- let this = unsafe { container_of!(Opaque::cast_from(this), Self, obj) }.cast_mut();
+ let this = unsafe { container_of!(Opaque::cast_from(base), Self, obj) }.cast_mut();
+
+ // We need to reset `sgt_res` first, since doing so requires that the GEM object is still
+ // alive.
+ // SAFETY:
+ // - We verified above that `this` is valid.
+ // - `&mut (*this)` does not implement Unpin.
+ unsafe { Pin::new_unchecked(&mut (*this).sgt_res) }.reset();
+
+ // SAFETY:
+ // - We're in free_callback - so this function is safe to call.
+ // - We won't be using the gem resources on `this` after this call.
+ unsafe { bindings::drm_gem_shmem_release(base) };
// SAFETY: We're recovering the Kbox<> we created in gem_create_object()
let _ = unsafe { KBox::from_raw(this) };
}
+
+ /// Attempt to create a vmap from the gem object, and confirm the size of said vmap.
+ fn make_vmap<'a, R, const SIZE: usize>(&'a self) -> Result<VMap<T, R, SIZE>>
+ where
+ R: Deref<Target = Self> + From<&'a Self>,
+ {
+ // INVARIANT: We check here that the gem object is at least as large as `SIZE`.
+ if self.size() < SIZE {
+ return Err(ENOSPC);
+ }
+
+ let mut map: MaybeUninit<bindings::iosys_map> = MaybeUninit::uninit();
+ let guard = DmaResvGuard::new(self);
+
+ // SAFETY: drm_gem_shmem_vmap can be called with the DMA reservation lock held
+ to_result(unsafe {
+ bindings::drm_gem_shmem_vmap_locked(self.as_raw_shmem(), map.as_mut_ptr())
+ })?;
+
+ // Drop the guard explicitly here, since we may need to call raw_vunmap() (which re-acquires
+ // the lock).
+ drop(guard);
+
+ // SAFETY: The call to drm_gem_shmem_vmap_locked succeeded above, so we are guaranteed that
+ // map is properly initialized.
+ let map = unsafe { map.assume_init() };
+
+ // XXX: We don't currently support iomem allocations
+ if map.is_iomem {
+ // SAFETY:
+ // - The vmap operation above succeeded, guaranteeing that `map` points to a valid
+ // memory mapping.
+ // - We checked that this is an iomem allocation, making it safe to read vaddr_iomem
+ unsafe { self.raw_vunmap(map) };
+
+ Err(ENOTSUPP)
+ } else {
+ Ok(VMap {
+ // SAFETY: We checked that this is not an iomem allocation, making it safe to read
+ // vaddr
+ addr: unsafe { map.__bindgen_anon_1.vaddr },
+ owner: self.into(),
+ })
+ }
+ }
+
+ /// Unmap a vmap from the gem object.
+ ///
+ /// # Safety
+ ///
+ /// - The caller promises that `map` is a valid vmap on this gem object.
+ /// - The caller promises that the memory pointed to by map will no longer be accesed through
+ /// this instance.
+ unsafe fn raw_vunmap(&self, mut map: bindings::iosys_map) {
+ let _guard = DmaResvGuard::new(self);
+
+ // SAFETY:
+ // - This function is safe to call with the DMA reservation lock held.
+ // - Our `ARef` is proof that the underlying gem object here is initialized and thus safe to
+ // dereference.
+ unsafe { bindings::drm_gem_shmem_vunmap_locked(self.as_raw_shmem(), &mut map) };
+ }
+
+ /// Creates and returns a virtual kernel memory mapping for this object.
+ #[inline]
+ pub fn vmap<const SIZE: usize>(&self) -> Result<VMapRef<'_, T, SIZE>> {
+ self.make_vmap()
+ }
+
+ /// Creates and returns an owned reference to a virtual kernel memory mapping for this object.
+ #[inline]
+ pub fn owned_vmap<const SIZE: usize>(&self) -> Result<VMapOwned<T, SIZE>> {
+ self.make_vmap()
+ }
+
+ /// Creates (if necessary) and returns an immutable reference to a scatter-gather table of DMA
+ /// pages for this object.
+ ///
+ /// This will pin the object in memory. It is expected that `dev` should be a pointer to the
+ /// same [`device::Device`] which `self` belongs to, otherwise this function will return
+ /// `Err(EINVAL)`.
+ pub fn sg_table<'a>(
+ &'a self,
+ dev: &'a device::Device<Bound>,
+ ) -> Result<&'a scatterlist::SGTable> {
+ if dev.as_raw() != self.dev().as_ref().as_raw() {
+ return Err(EINVAL);
+ }
+
+ match self.sgt_res.init(Devres::new(dev, SGTableMap::new(self))) {
+ Ok(ret) | Err(LazyInitError::AlreadyInit(ret)) => Ok(ret.access(dev)?),
+ Err(LazyInitError::DuringInit(e)) => Err(e),
+ }
+ }
}
impl<T: DriverObject> Deref for Object<T> {
@@ -246,7 +373,6 @@ impl<T: DriverObject> driver::AllocImpl for Object<T> {
impl<'a, T: DriverObject> DmaResvGuard<'a, T> {
#[inline(always)]
- #[expect(unused)]
fn new(obj: &'a Object<T>) -> Self {
// SAFETY: This lock is initialized throughout the lifetime of `object`.
unsafe { bindings::dma_resv_lock(obj.raw_dma_resv(), ptr::null_mut()) };
@@ -262,3 +388,280 @@ fn drop(&mut self) {
unsafe { bindings::dma_resv_unlock(self.0.raw_dma_resv()) };
}
}
+
+macro_rules! impl_vmap_io_capable {
+ ($impl:ident, $ty:ty) => {
+ impl<D, R, const SIZE: usize> IoCapable<$ty> for $impl<D, R, SIZE>
+ where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+ {
+ #[inline(always)]
+ unsafe fn io_read(&self, address: usize) -> $ty {
+ let ptr = address as *mut $ty;
+
+ // SAFETY: The safety contract of `io_read` guarantees that address is a valid
+ // address within the bounds of `Self` of at least the size of $ty, and is properly
+ // aligned.
+ unsafe { ptr::read(ptr) }
+ }
+
+ #[inline(always)]
+ unsafe fn io_write(&self, value: $ty, address: usize) {
+ let ptr = address as *mut $ty;
+
+ // SAFETY: The safety contract of `io_write` guarantees that address is a valid
+ // address within the bounds of `Self` of at least the size of $ty, and is properly
+ // aligned.
+ unsafe { ptr::write(ptr, value) }
+ }
+ }
+ };
+}
+
+/// A reference to a virtual mapping for an shmem-based GEM object in kernel address space.
+///
+/// # Invariants
+///
+/// - The size of `owner` is >= SIZE.
+/// - The memory pointed to by addr remains valid at least until this object is dropped.
+pub struct VMap<D, R, const SIZE: usize = 0>
+where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+{
+ addr: *mut c_void,
+ owner: R,
+}
+
+/// An alias type for a reference to a shmem-based GEM object's VMap.
+pub type VMapRef<'a, D, const SIZE: usize = 0> = VMap<D, &'a Object<D>, SIZE>;
+
+/// An alias type for an owned reference to a shmem-based GEM object's VMap.
+pub type VMapOwned<D, const SIZE: usize = 0> = VMap<D, ARef<Object<D>>, SIZE>;
+
+impl<D, R, const SIZE: usize> VMap<D, R, SIZE>
+where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+{
+ /// Borrows a reference to the object that owns this virtual mapping.
+ #[inline(always)]
+ pub fn owner(&self) -> &Object<D> {
+ &self.owner
+ }
+}
+
+impl<D, R, const SIZE: usize> Drop for VMap<D, R, SIZE>
+where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+{
+ #[inline(always)]
+ fn drop(&mut self) {
+ // SAFETY:
+ // - Our existence is proof that this map was previously created using self.owner.
+ // - Since we are in Drop, we are guaranteed that no one will access the memory
+ // through this mapping after calling this.
+ unsafe {
+ self.owner.raw_vunmap(bindings::iosys_map {
+ is_iomem: false,
+ __bindgen_anon_1: bindings::iosys_map__bindgen_ty_1 { vaddr: self.addr },
+ })
+ };
+ }
+}
+
+impl<D, R, const SIZE: usize> Io for VMap<D, R, SIZE>
+where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+{
+ #[inline(always)]
+ fn addr(&self) -> usize {
+ self.addr as usize
+ }
+
+ #[inline(always)]
+ fn maxsize(&self) -> usize {
+ self.owner.size()
+ }
+}
+
+impl<D, R, const SIZE: usize> IoKnownSize for VMap<D, R, SIZE>
+where
+ D: DriverObject,
+ R: Deref<Target = Object<D>>,
+{
+ const MIN_SIZE: usize = SIZE;
+}
+
+impl_vmap_io_capable!(VMap, u8);
+impl_vmap_io_capable!(VMap, u16);
+impl_vmap_io_capable!(VMap, u32);
+#[cfg(CONFIG_64BIT)]
+impl_vmap_io_capable!(VMap, u64);
+
+/// A reference to a GEM object that is known to have a mapped [`SGTable`].
+///
+/// This is used by the Rust bindings with [`Devres`] in order to ensure that mappings for SGTables
+/// on GEM shmem objects are revoked on driver-unbind.
+///
+/// # Invariants
+///
+/// - `self.obj` always points to a valid GEM object.
+/// - This object is proof that `self.obj.owner.sgt` has an initialized and valid
+/// [`scatterlist::SGTable`].
+pub struct SGTableMap<T: DriverObject> {
+ obj: NonNull<Object<T>>,
+}
+
+impl<T: DriverObject> Deref for SGTableMap<T> {
+ type Target = scatterlist::SGTable;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY:
+ // - The NonNull is guaranteed to be valid via our type invariants.
+ // - The sgt field is guaranteed to be initialized and valid via our type invariants.
+ unsafe { scatterlist::SGTable::from_raw((*self.obj.as_ref().as_raw_shmem()).sgt) }
+ }
+}
+
+impl<T: DriverObject> Drop for SGTableMap<T> {
+ fn drop(&mut self) {
+ // SAFETY: `obj` is always valid via our type invariants
+ let obj = unsafe { self.obj.as_ref() };
+ let _lock = DmaResvGuard::new(obj);
+
+ // SAFETY: We acquired the lock needed for calling this function above
+ unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shmem()) };
+ }
+}
+
+impl<T: DriverObject> SGTableMap<T> {
+ fn new(obj: &Object<T>) -> impl Init<Self, Error> {
+ // INVARIANT:
+ // - We call drm_gem_shmem_get_pages_sgt_locked below and check whether or not it
+ // succeeds, fulfilling the invariant of SGTableMap that the object's `sgt` field is
+ // initialized.
+ // SAFETY:
+ // - `obj` is fully initialized, making this function safe to call.
+ from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
+
+ Ok(Self { obj: obj.into() })
+ }
+}
+
+// SAFETY: The NonNull in SGTableMap is guaranteed valid by our type invariants, and the GEM object
+// it points to is guaranteed to be thread-safe.
+unsafe impl<T: DriverObject> Send for SGTableMap<T> {}
+// SAFETY: The NonNull in SGTableMap is guaranteed valid by our type invariants, and the GEM object
+// it points to is guaranteed to be thread-safe.
+unsafe impl<T: DriverObject> Sync for SGTableMap<T> {}
+
+#[kunit_tests(rust_drm_gem_shmem)]
+mod tests {
+ use super::*;
+ use crate::{
+ drm,
+ faux,
+ page::PAGE_SIZE, //
+ };
+
+ // The bare minimum needed to create a fake drm driver for kunit
+
+ #[pin_data]
+ struct KunitData {}
+ struct KunitDriver;
+ struct KunitFile;
+ #[pin_data]
+ struct KunitObject {}
+
+ const INFO: drm::DriverInfo = drm::DriverInfo {
+ major: 0,
+ minor: 0,
+ patchlevel: 0,
+ name: c"kunit",
+ desc: c"Kunit",
+ };
+
+ impl drm::file::DriverFile for KunitFile {
+ type Driver = KunitDriver;
+
+ fn open(_dev: &drm::Device<KunitDriver>) -> Result<Pin<KBox<Self>>> {
+ Ok(KBox::new(Self, GFP_KERNEL)?.into())
+ }
+ }
+
+ impl gem::DriverObject for KunitObject {
+ type Driver = KunitDriver;
+ type Args = ();
+
+ fn new(
+ _dev: &drm::Device<KunitDriver>,
+ _size: usize,
+ _args: Self::Args,
+ ) -> impl PinInit<Self, Error> {
+ try_pin_init!(KunitObject {})
+ }
+ }
+
+ #[vtable]
+ impl drm::Driver for KunitDriver {
+ type Data = KunitData;
+ type File = KunitFile;
+ type Object = Object<KunitObject>;
+
+ const INFO: drm::DriverInfo = INFO;
+ const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor] = &[];
+ }
+
+ fn create_drm_dev() -> Result<(faux::Registration, ARef<drm::Device<KunitDriver>>)> {
+ // Create a faux DRM device so we can test gem object creation.
+ let data = try_pin_init!(KunitData {});
+ let dev = faux::Registration::new(c"Kunit", None)?;
+ let drm = drm::Device::<KunitDriver>::new(dev.as_ref(), data)?;
+
+ Ok((dev, drm))
+ }
+
+ #[test]
+ fn compile_time_vmap_sizes() -> Result {
+ let (_dev, drm) = create_drm_dev()?;
+
+ let obj = Object::<KunitObject>::new(&drm, PAGE_SIZE, ObjectConfig::default(), ())?;
+
+ // Try creating a normal vmap
+ obj.vmap::<PAGE_SIZE>()?;
+
+ // Try creating a vmap that's smaller then the size we specified
+ obj.vmap::<{ PAGE_SIZE - 100 }>()?;
+
+ // Make sure creating a vmap that's too large fails
+ assert!(obj.vmap::<{ PAGE_SIZE + 200 }>().is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn vmap_io() -> Result {
+ let (_dev, drm) = create_drm_dev()?;
+
+ let obj = Object::<KunitObject>::new(&drm, PAGE_SIZE, ObjectConfig::default(), ())?;
+
+ let vmap = obj.vmap::<PAGE_SIZE>()?;
+
+ vmap.write8(0xDE, 0x0);
+ assert_eq!(vmap.read8(0x0), 0xDE);
+ vmap.write32(0xFFFFFFFF, 0x20);
+
+ assert_eq!(vmap.read32(0x20), 0xFFFFFFFF);
+
+ assert_eq!(vmap.read8(0x20), 0xFF);
+ assert_eq!(vmap.read8(0x21), 0xFF);
+ assert_eq!(vmap.read8(0x22), 0xFF);
+ assert_eq!(vmap.read8(0x23), 0xFF);
+
+ Ok(())
+ }
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
` (2 preceding siblings ...)
2026-05-29 18:34 ` [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings Lyude Paul
@ 2026-05-29 18:34 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
` (2 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:34 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
When writing up some rust code that used faux devices for unit testing, I
noticed that we never actually added the Bound device context to
faux::Registration's AsRef<device::Device> implementation. This being said:
the Registration object itself is proof that a driver is bound to the
device - so this should be safe.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
rust/kernel/faux.rs | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs
index 43b4974f48cd2..e0856b2964a2c 100644
--- a/rust/kernel/faux.rs
+++ b/rust/kernel/faux.rs
@@ -25,7 +25,8 @@
///
/// # Invariants
///
-/// `self.0` always holds a valid pointer to an initialized and registered [`struct faux_device`].
+/// - `self.0` always holds a valid pointer to an initialized and registered [`struct faux_device`].
+/// - This object is proof that the object described by this `Registration` is bound to a device.
///
/// [`struct faux_device`]: srctree/include/linux/device/faux.h
pub struct Registration(NonNull<bindings::faux_device>);
@@ -59,8 +60,8 @@ fn as_raw(&self) -> *mut bindings::faux_device {
}
}
-impl AsRef<device::Device> for Registration {
- fn as_ref(&self) -> &device::Device {
+impl AsRef<device::Device<device::Bound>> for Registration {
+ fn as_ref(&self) -> &device::Device<device::Bound> {
// SAFETY: The underlying `device` in `faux_device` is guaranteed by the C API to be
// a valid initialized `device`.
unsafe { device::Device::from_raw(addr_of_mut!((*self.as_raw()).dev)) }
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked()
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
` (3 preceding siblings ...)
2026-05-29 18:34 ` [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
@ 2026-05-29 18:34 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-04 6:06 ` Claude review: Rust bindings for gem shmem Claude Code Review Bot
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:34 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
One of the complications of trying to use the shmem helpers to create a
scatterlist for shmem objects is that we need to be able to provide a
guarantee that the driver cannot be unbound for the lifetime of the
scatterlist.
The easiest way of handling this seems to be just hooking up an unmap
operation to devres the first time we create a scatterlist, which allows us
to still take advantage of gem shmem facilities without breaking that
guarantee. To allow for this, we extract __drm_gem_shmem_free_sgt_locked()
- which allows a caller (e.g. the rust bindings) to manually unmap the sgt
for a gem object as needed.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
---
V10:
* Fix incorrect function name in documentation for
__drm_gem_shmem_release_sgt_locked()
drivers/gpu/drm/drm_gem_shmem_helper.c | 32 +++++++++++++++++++++-----
include/drm/drm_gem_shmem_helper.h | 1 +
2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 545933c7f7121..c989459eb2159 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -158,6 +158,30 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
+/**
+ * __drm_gem_shmem_release_sgt_locked - Unpin and DMA unmap pages, and release the
+ * cached scatter/gather table for an shmem GEM object.
+ * @shmem: shmem GEM object
+ *
+ * If the passed shmem object has an active scatter/gather table for driver
+ * usage, this function will unmap it and release the memory associated with it.
+ * It is the responsibility of the caller to ensure it holds the dma_resv_lock
+ * for this object.
+ *
+ * Drivers should not need to call this function themselves, it is mainly
+ * intended for usage in the Rust shmem bindings.
+ */
+void __drm_gem_shmem_free_sgt_locked(struct drm_gem_shmem_object *shmem)
+{
+ dma_resv_assert_held(shmem->base.resv);
+
+ dma_unmap_sgtable(shmem->base.dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
+ sg_free_table(shmem->sgt);
+ kfree(shmem->sgt);
+ shmem->sgt = NULL;
+}
+EXPORT_SYMBOL_GPL(__drm_gem_shmem_free_sgt_locked);
+
/**
* drm_gem_shmem_release - Release resources associated with a shmem GEM object.
* @shmem: shmem GEM object
@@ -176,12 +200,8 @@ void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem)
drm_WARN_ON(obj->dev, refcount_read(&shmem->vmap_use_count));
- if (shmem->sgt) {
- dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
- DMA_BIDIRECTIONAL, 0);
- sg_free_table(shmem->sgt);
- kfree(shmem->sgt);
- }
+ if (shmem->sgt)
+ __drm_gem_shmem_free_sgt_locked(shmem);
if (shmem->pages)
drm_gem_shmem_put_pages_locked(shmem);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index 5ccdae21b94a9..b2c23af628e1a 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -111,6 +111,7 @@ int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shme
struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
void drm_gem_shmem_release(struct drm_gem_shmem_object *shmem);
void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem);
+void __drm_gem_shmem_free_sgt_locked(struct drm_gem_shmem_object *shmem);
void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem);
int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem);
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table()
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
` (4 preceding siblings ...)
2026-05-29 18:34 ` [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
@ 2026-05-29 18:34 ` Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-06-04 6:06 ` Claude review: Rust bindings for gem shmem Claude Code Review Bot
6 siblings, 1 reply; 18+ messages in thread
From: Lyude Paul @ 2026-05-29 18:34 UTC (permalink / raw)
To: dri-devel, rust-for-linux, nouveau
Cc: Alexandre Courbot, Gary Guo, Christian König, driver-core,
Miguel Ojeda, Maarten Lankhorst, Alice Ryhl, Simona Vetter,
linux-kernel, Sumit Semwal, linux-media, Rafael J . Wysocki,
Thomas Zimmermann, Maxime Ripard, David Airlie, Benno Lossin,
linaro-mm-sig, Danilo Krummrich, Mukesh Kumar Chaurasiya,
Asahi Lina, Daniel Almeida, Lyude Paul, Greg Kroah-Hartman
In order to do this, we need to be careful to ensure that any interface we
expose for scatterlists ensures that any mappings created from one are
destroyed on driver-unbind. To do this, we introduce a Devres resource into
shmem::Object that we use in order to ensure that we release any SGTable
mappings on driver-unbind.
There's some other slightly unfortunate caveats of this:
* Drivers don't have explicit control at the moment over when unmapping
happens (which is exactly the same as the C side atm, so it might not be
a problem).
* We can't just return `SGTableMap` to the user through an Arc to attempt
to fix the last caveat - because that implies the gem object would need
to hold a reference count to the scatterlist mapping, which just leaves
us with the same problem.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
V3:
* Rename OwnedSGTable to shmem::SGTable. Since the current version of the
SGTable abstractions now has a `Owned` and `Borrowed` variant, I think
renaming this to shmem::SGTable makes things less confusing.
We do however, keep the name of owned_sg_table() as-is.
V4:
* Clarify safety comments for SGTable to explain why the object is
thread-safe.
* Rename from SGTableRef to SGTable
V10:
* Use Devres in order to ensure that SGTables are revocable, and are
unmapped on driver-unbind.
V11:
* s/create_sg_table()/get_sg_table()
* Get rid of extraneous `ret = ` in shmem::Object::get_sg_table()
V12:
* Actually move sgt_res in this patch and not the next one
V13:
* Use DmaResvGuard suggestion from Alexander
* Use Alexander's (much better) solution for get_sg_table()
* Use SetOnce instead of UnsafeCell
* s/SGTableRef/SGTableMap
* Fix typo in SGTableMap documentation
* Create fallible constructor for SGTableMap
* Don't reuse dma_resv lock for protecting Object contents, just use Mutex
+ SetOnce
* Drop use of drm_gem_shmem_get_pages_sgt_locked(), since we don't need to
hold the dma_resv lock ourselves for anything but this function.
* Check that the device we receive in the bounds for sg_table() and
owned_sg_table() that said Device is in fact, the correct device.
* Remove redundant docs in owned_sg_table(), just point it back to
sg_table().
* Implement Deborah's suggestion to fix double-free in
free_callback()
* Restore original order of Object<T>
* Fix doc typo for SGTableMap
V14:
* Use new InitOnce container over the Mutex/SetOnce horror show we had
before.
* Start using LazyInit container for storing Devres for sgt unmap
* Add some kunit tests for sg_table (not sure why I didn't do this before)
using some of the boilerplate code leftover from the vmap bindings
* Get rid of the owned SGTable variant for now, we'll add it back in a
future patch if people actually need it.
* Use new LazyInit container from me to get rid of the horrid
Mutex<SetOnce<>> mess.
* Add the best we can do for unit tests w/r/t SGTable at the moment
rust/kernel/drm/gem/shmem.rs | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 494e0d0d8d0d6..5655c2a1ae8fb 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -664,4 +664,28 @@ fn vmap_io() -> Result {
Ok(())
}
+
+ // TODO: I would love to actually test the success paths of sg_table(), but that would require
+ // also implementing dummy dma_ops so that trying to create a mapping doesn't explode. So, leave
+ // that for someone else.
+
+ // Ensures that passing the wrong device to sg_table() fails as we expect, and also ensure it
+ // skips initializing `sgt_res` since we could otherwise create `sgt_res` with the wrong device
+ // bound to it.
+ #[test]
+ fn fail_sg_table_on_wrong_dev() -> Result {
+ let (_dev, drm) = create_drm_dev()?;
+ let wrong_dev = faux::Registration::new(c"EvilKunit", None)?;
+
+ let obj = Object::<KunitObject>::new(&drm, PAGE_SIZE, ObjectConfig::default(), ())?;
+
+ assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL);
+
+ // If sgt_res was not initialized mistakenly with the wrong device, this should still fail.
+ assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL);
+
+ // TODO: Someday, we should test that creating an sg_table here still succeeds.
+
+ Ok(())
+ }
}
--
2.54.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem: Introduce shmem::Object::sg_table()
2026-06-03 19:42 ` [PATCH v17 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-06-04 1:29 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 1:29 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Verdict: Has concerns that need resolution.**
This is the most complex patch. The overall design (Devres-managed SGTableMap with double-checked locking) is sound, but there are issues.
**Critical: `__drm_gem_shmem_free_sgt_locked()` does not exist in the current kernel tree.**
```rust
impl<T: DriverObject, C: DeviceContext> Drop for SGTableMap<T, C> {
fn drop(&mut self) {
let obj = unsafe { self.obj.as_ref() };
let _lock = DmaResvGuard::new(obj);
unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shmem()) };
}
}
```
I searched the drm-next tree and found no declaration or definition of this function. It must come from a prerequisite patch on drm-rust-next. This function is critical for correctness -- it must NULL out `shmem->sgt` after cleanup, otherwise `drm_gem_shmem_release()` will double-free the sg_table when it runs (it checks `if (shmem->sgt)` and cleans up).
The ordering in `free_callback()` is:
1. `sgt_res.reset()` -- drops SGTableMap, calls `__drm_gem_shmem_free_sgt_locked()`
2. `drm_gem_shmem_release()` -- would double-free if `shmem->sgt` wasn't NULLed
This is a known concern (the V13 changelog mentions "Fix double-free in free_callback()"), but reviewers should verify `__drm_gem_shmem_free_sgt_locked()` NULLs `shmem->sgt`.
**The double-checked locking pattern is correct:**
```rust
pub fn sg_table<'a>(&'a self, dev: &'a device::Device<Bound>) -> Result<&'a scatterlist::SGTable> {
// Fast path
if let Some(sgt_res) = self.sgt_res.as_ref() {
break 'out sgt_res;
}
// Slow path with lock
let _guard = self.sgt_lock.lock();
if let Some(sgt_res) = self.sgt_res.as_ref() {
break 'out sgt_res;
}
self.sgt_res.populate(Devres::new(dev, SGTableMap::new(self))?);
unsafe { self.sgt_res.as_ref().unwrap_unchecked() }
```
The fast path uses `SetOnce::as_ref()` with Acquire ordering, the slow path is guarded by the mutex, and after populate the value is immediately available. This is sound.
**Device identity check is good defensive programming:**
```rust
if dev.as_raw() != self.dev().as_ref().as_raw() {
return Err(EINVAL);
}
```
This prevents creating an SGTable bound to the wrong device, which the test `fail_sg_table_on_wrong_dev` validates.
**SGTableMap self-referential pointer:**
`SGTableMap` stores `NonNull<Object<T, C>>` pointing back to its own containing Object. This is safe because:
- `sgt_res` is explicitly reset in `free_callback()` before `KBox::from_raw(this)` drops the Object
- The Devres revocation on driver-unbind drops the SGTableMap while the Object (refcounted) is still alive
**The `SGTableMap::new()` return type is interesting:**
```rust
fn new(obj: &Object<T, C>) -> impl Init<Self, Error> {
from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
Ok(Self { obj: obj.into() })
}
```
This calls `drm_gem_shmem_get_pages_sgt()` which internally acquires/releases the dma_resv lock and initializes `shmem->sgt`. The returned pointer is discarded -- only the side effect (populating the sgt field) matters. This is correct but could use a brief comment explaining why the returned pointer isn't stored.
**Minor: Send/Sync impls:**
```rust
unsafe impl<T: DriverObject, C: DeviceContext> Send for SGTableMap<T, C> {}
unsafe impl<T: DriverObject, C: DeviceContext> Sync for SGTableMap<T, C> {}
```
The safety justification is that the NonNull points to a GEM object which is inherently thread-safe (refcounted, lock-protected). This is reasonable. The `DriverObject` bound already requires `Send + Sync` for the driver data.
**Test coverage:** The test only covers the failure path (wrong device). The TODO acknowledging the need for dummy dma_ops for success testing is honest and reasonable.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem: Introduce shmem::Object::sg_table()
2026-06-02 17:25 ` [PATCH v16 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-06-04 2:29 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 2:29 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
The most complex patch. Several observations:
**Missing C-side function**: `SGTableMap::drop` calls:
```rust
unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shmem()) };
```
This function does not exist in the current drm-next tree. It presumably lives in the "first half" of the series already pushed to drm-rust-next. If it's missing from the base, this won't compile. This should be verified against the actual base tree.
**Import restructuring**: The patch changes `device` from `crate::drm::device` to `crate::device`:
```rust
+ device::{
+ self,
+ Bound, //
+ },
drm::{
+ driver,
+ gem,
+ private::Sealed,
Device, //
},
```
This changes the meaning of `device::Device<T::Driver>` in the existing `dev()` method. On the actual drm-rust-next base, this may already be reconciled. Worth verifying.
**Double-checked locking in `sg_table()`**: The pattern is correct:
```rust
if let Some(sgt_res) = self.sgt_res.as_ref() { // fast path (Acquire)
break 'out sgt_res;
}
let _guard = self.sgt_lock.lock(); // slow path
if let Some(sgt_res) = self.sgt_res.as_ref() { // re-check
break 'out sgt_res;
}
self.sgt_res.populate(...); // Release
```
The `SetOnce` uses `Acquire` on read and `Release` on write, which provides the necessary happens-before guarantees for the double-checked locking pattern.
**SGTableMap lifetime safety**: `SGTableMap` holds `NonNull<Object<T>>` without an `ARef`:
```rust
pub struct SGTableMap<T: DriverObject> {
obj: NonNull<Object<T>>,
}
```
This is safe because `SGTableMap` is stored inside the `Object<T>` itself (via `sgt_res`), so the object outlives the mapping. The `free_callback` explicitly resets `sgt_res` before releasing the GEM object:
```rust
unsafe { &mut (*this).sgt_res }.reset(); // drops SGTableMap first
unsafe { bindings::drm_gem_shmem_release(base) }; // then releases GEM
let _ = unsafe { KBox::from_raw(this) }; // then frees memory
```
This ordering is correct and critical.
**Device identity check**:
```rust
if dev.as_raw() != self.dev().as_ref().as_raw() {
return Err(EINVAL);
}
```
Comparing raw device pointers to verify the caller passed the correct device is a good defensive check. The test `fail_sg_table_on_wrong_dev` verifies this works.
**`SGTableMap::new` discards the sg_table pointer**:
```rust
fn new(obj: &Object<T>) -> impl Init<Self, Error> {
from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
Ok(Self { obj: obj.into() })
}
```
The returned `sg_table*` is discarded. This is correct because `drm_gem_shmem_get_pages_sgt` stores the SGT internally in `shmem->sgt`, which is what `SGTableMap::deref` reads later.
**Minor style**: The `#[pin]` attribute appears before the doc comment on `sgt_lock`:
```rust
+ #[pin]
+ /// Lock for protecting initialization of `sgt_res`.
+ sgt_lock: Mutex<()>,
```
Convention is doc comments before attributes, though both orderings are valid Rust.
**Test coverage**: The `fail_sg_table_on_wrong_dev` test is good but limited — as the TODOs note, testing the success path requires mock DMA ops. The comment is honest about this limitation, which is appreciated.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: Rust bindings for gem shmem
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
` (5 preceding siblings ...)
2026-05-29 18:34 ` [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
6 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: Rust bindings for gem shmem
Author: Lyude Paul <lyude@redhat.com>
Patches: 7
Reviewed: 2026-06-04T16:06:43.380367
---
This is v15 of the Rust bindings for GEM shmem, adding vmap, scatter-gather table support, and supporting infrastructure (DmaResvGuard, faux device Bound context, and a C-side helper for SGT teardown). The series is well-structured: each patch has a clear purpose, and the overall design around Devres-based revocation for SGTables and lifetime-guarded VMaps is sound. The code has clearly been through extensive review (v15), and the Rust safety invariants are generally well-documented.
There are a few issues to flag, ranging from a documentation name mismatch in the C patch to a missing `shmem->sgt` NULL-guard in the new exported helper.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: gem: shmem: Fix Default implementation for ObjectConfig
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Looks good**
The problem is correctly identified: `#[derive(Default)]` requires all generic type parameters to implement `Default`, but `T: DriverObject` is only used as a phantom type here.
```rust
impl<'a, T: DriverObject> Default for ObjectConfig<'a, T> {
#[inline(always)]
fn default() -> Self {
Self {
map_wc: false,
parent_resv_obj: None,
}
}
}
```
This is straightforward. No issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem/shmem: Add DmaResvGuard helper
2026-05-29 18:34 ` [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Minor observations**
The guard pattern is correct for wrapping `dma_resv_lock` / `dma_resv_unlock`. The return value of `dma_resv_lock` is discarded:
```rust
unsafe { bindings::dma_resv_lock(obj.raw_dma_resv(), ptr::null_mut()) };
```
With a NULL `ww_acquire_ctx`, this reduces to a plain mutex lock which cannot fail (just blocks), so discarding the return value is fine in practice. The `#[expect(unused)]` attribute is appropriate since it's only used starting in patch 3.
The TODO note about replacing this with proper WwMutex bindings is good forward-looking guidance.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem: Add vmap functions to shmem bindings
2026-05-29 18:34 ` [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Looks good overall, minor notes**
This is the largest patch in the series. Key design decisions are sound:
**VMap lifecycle**: The `make_vmap` method acquires the DMA reservation lock, calls `drm_gem_shmem_vmap_locked`, then explicitly drops the guard before potentially calling `raw_vunmap` (which re-acquires the lock). This avoids deadlock:
```rust
let guard = DmaResvGuard::new(self);
to_result(unsafe {
bindings::drm_gem_shmem_vmap_locked(self.as_raw_shmem(), map.as_mut_ptr())
})?;
drop(guard);
```
**iomem rejection**: The iomem path correctly unmaps before returning an error:
```rust
if map.is_iomem {
unsafe { self.raw_vunmap(map) };
Err(ENOTSUPP)
}
```
**SGTableMap and Devres interaction**: The `SGTableMap` is wrapped in `Devres` and stored in a `LazyInit`. On device unbind, Devres drops the SGTableMap which calls `__drm_gem_shmem_free_sgt_locked()` and sets `shmem->sgt = NULL`. In `free_callback`, `sgt_res.reset()` is called before `drm_gem_shmem_release()`, ensuring no double-free since `drm_gem_shmem_release()` checks `if (shmem->sgt)`.
The reordering in `free_callback` is critical and correct — `sgt_res` must be reset while the GEM object's dma_resv is still valid:
```rust
unsafe { Pin::new_unchecked(&mut (*this).sgt_res) }.reset();
unsafe { bindings::drm_gem_shmem_release(base) };
let _ = unsafe { KBox::from_raw(this) };
```
**Device validation in `sg_table()`**: The check that the caller's device matches the GEM object's device is a good safety measure:
```rust
if dev.as_raw() != self.dev().as_ref().as_raw() {
return Err(EINVAL);
}
```
**Test coverage**: The kunit tests are well-structured, covering size validation, IO read/write, and wrong-device rejection.
Minor observation on the vmap_io test: the test uses `0xFFFFFFFF` for write32 and checks individual bytes are all `0xFF` — this works regardless of endianness, which is nice.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: faux: Allow retrieving a bound Device
2026-05-29 18:34 ` [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Looks good**
The change from `AsRef<device::Device>` to `AsRef<device::Device<device::Bound>>` is correct. The invariant reasoning is sound — a `Registration` exists only after successful creation and registration of the device, so it is proof that the device is bound:
```rust
+/// - This object is proof that the object described by this `Registration` is bound to a device.
```
```rust
-impl AsRef<device::Device> for Registration {
- fn as_ref(&self) -> &device::Device {
+impl AsRef<device::Device<device::Bound>> for Registration {
+ fn as_ref(&self) -> &device::Device<device::Bound> {
```
This is a prerequisite for the sg_table() API which requires `&device::Device<Bound>`.
**Note**: This changes the public API of `faux::Registration`. Any existing callers using `AsRef<device::Device>` without the `Bound` parameter would break. Given this is upstream kernel Rust, the caller base should be limited, but it's worth noting for the merge window.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked()
2026-05-29 18:34 ` [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Two issues to flag**
**Issue 1 — kdoc name mismatch**: The kernel-doc comment names the function `__drm_gem_shmem_release_sgt_locked` but the actual function is `__drm_gem_shmem_free_sgt_locked`:
```c
+/**
+ * __drm_gem_shmem_release_sgt_locked - Unpin and DMA unmap pages, and release the
```
vs.
```c
+void __drm_gem_shmem_free_sgt_locked(struct drm_gem_shmem_object *shmem)
```
The V10 changelog says "Fix incorrect function name in documentation" but the mismatch is still present.
**Issue 2 — No NULL check on `shmem->sgt`**: The new exported function does not check for `shmem->sgt == NULL` before dereferencing:
```c
+void __drm_gem_shmem_free_sgt_locked(struct drm_gem_shmem_object *shmem)
+{
+ dma_resv_assert_held(shmem->base.resv);
+
+ dma_unmap_sgtable(shmem->base.dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
```
Both callers currently guard against this (the C side with `if (shmem->sgt)`, the Rust side via SGTableMap type invariants). However, since this is `EXPORT_SYMBOL_GPL` and documented as callable by drivers (specifically the Rust bindings), a defensive NULL check with early return or `WARN_ON` would be prudent. If a future caller misuses this, it will be a NULL pointer dereference in kernel context.
**Note on the kdoc**: The description says "Unpin and DMA unmap pages" but the function doesn't actually unpin pages (it doesn't call `drm_gem_shmem_put_pages_locked()`). It only unmaps the SGTable and frees it. The "unpin" claim is inaccurate.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem: Introduce shmem::Object::sg_table()
2026-05-29 18:34 ` [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-06-04 6:06 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 6:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Status: Looks good**
This patch adds the test for the wrong-device rejection path that was introduced in patch 3. The test is well-structured:
```rust
fn fail_sg_table_on_wrong_dev() -> Result {
let (_dev, drm) = create_drm_dev()?;
let wrong_dev = faux::Registration::new(c"EvilKunit", None)?;
let obj = Object::<KunitObject>::new(&drm, PAGE_SIZE, ObjectConfig::default(), ())?;
assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL);
// If sgt_res was not initialized mistakenly with the wrong device, this should still fail.
assert_eq!(obj.sg_table(wrong_dev.as_ref()).err().unwrap(), EINVAL);
```
The double-call test is a good edge case check — it verifies that `sgt_res` (the `LazyInit`) isn't accidentally initialized with the wrong device on the first call.
The TODO comments about needing dummy dma_ops for success-path testing are reasonable.
---
**Summary**: The series is well-designed and mostly correct. The two actionable items are: (1) fix the kdoc function name in patch 5 to say `__drm_gem_shmem_free_sgt_locked`, and (2) consider adding a NULL guard or `drm_WARN_ON` for `shmem->sgt` in `__drm_gem_shmem_free_sgt_locked()` since it's an exported symbol. The kdoc claim about "unpin" is also inaccurate and should say "DMA unmap and release" instead.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
* Claude review: rust: drm: gem: Introduce shmem::Object::sg_table()
2026-06-04 19:24 ` [PATCH v18 4/4] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
@ 2026-06-04 20:03 ` Claude Code Review Bot
0 siblings, 0 replies; 18+ messages in thread
From: Claude Code Review Bot @ 2026-06-04 20:03 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Most complex patch — warrants careful scrutiny.**
**Drop ordering in `free_callback` is correct:**
```rust
unsafe { ManuallyDrop::drop(&mut (*this).sgt_res) };
unsafe { bindings::drm_gem_shmem_release(base) };
let _ = unsafe { KBox::from_raw(this) };
```
`sgt_res` must drop first because its `Drop` calls `__drm_gem_shmem_free_sgt_locked` which needs the GEM object alive. Then `drm_gem_shmem_release` cleans up the C-side shmem state. Then `KBox::from_raw` drops the remaining Rust fields. The `ManuallyDrop` pattern is the right choice here since `SetOnce::reset()` was removed in v18.
**Double-checked locking in `sg_table()` is correct:**
```rust
if let Some(sgt_res) = self.sgt_res.as_ref() {
break 'out sgt_res;
}
let _guard = self.sgt_lock.lock();
if let Some(sgt_res) = self.sgt_res.as_ref() {
break 'out sgt_res;
}
self.sgt_res.populate(Devres::new(dev, SGTableMap::new(self))?);
```
This requires that `SetOnce::as_ref()` is safe to call without holding `sgt_lock` (i.e., it provides atomic-like visibility). If `SetOnce` is implemented with proper memory ordering (which kernel `SetOnce` should be), this is correct. If not, there's a data race on the fast path.
**`SGTableMap::new` uses `from_err_ptr` with a `?` inside an `Init` returning closure:**
```rust
fn new(obj: &Object<T, C>) -> impl Init<Self, Error> {
from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
Ok(Self { obj: obj.into() })
}
```
This calls `drm_gem_shmem_get_pages_sgt` which acquires/releases `dma_resv` internally (it uses `dma_resv_lock_interruptible`). The return value (an `sg_table*`) is checked for errors via `from_err_ptr` but the actual pointer is then discarded — the implementation relies on the fact that `shmem->sgt` is set as a side effect. This is correct per the C implementation, but the discarded return value deserves a comment explaining this pattern.
**Device identity check:**
```rust
if dev.as_raw() != self.dev().as_ref().as_raw() {
return Err(EINVAL);
}
```
Good — prevents creating a `Devres` bound to the wrong device, which would cause the revocation to fire at the wrong time or not at all.
**`SGTableMap` raw pointer storage:**
```rust
pub struct SGTableMap<T: DriverObject, C: DeviceContext> {
obj: NonNull<Object<T, C>>,
}
```
This stores a non-refcounted pointer to the owning `Object`. The invariant is that `SGTableMap` lives inside the `Object`'s `sgt_res` field, so the object outlives it. The `ManuallyDrop` ensures `sgt_res` is dropped before the object in `free_callback`. This is sound but not self-documenting — a `// INVARIANT:` comment on the `obj` field explaining the lifetime relationship would help future maintainers.
**Test only covers the failure path:**
```rust
fn fail_sg_table_on_wrong_dev() -> Result {
```
The TODO explains that testing the success path would require dummy DMA ops. The failure test is useful — it confirms the device check prevents `sgt_res` from being populated with a wrong device. Good defensive test.
**`Send`/`Sync` for `SGTableMap`:** The safety justification references GEM object thread-safety, which is established by the existing `Send`/`Sync` impls on `Object`. This is correct.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-06-04 20:03 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-05-29 18:34 ` [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-04 6:06 ` Claude review: " Claude Code Review Bot
2026-06-04 6:06 ` Claude review: Rust bindings for gem shmem Claude Code Review Bot
-- strict thread matches above, loose matches on Subject: below --
2026-06-04 19:24 [PATCH v18 0/4] " Lyude Paul
2026-06-04 19:24 ` [PATCH v18 4/4] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-04 20:03 ` Claude review: " Claude Code Review Bot
2026-06-03 19:42 [PATCH v17 0/6] Rust bindings for gem shmem Lyude Paul
2026-06-03 19:42 ` [PATCH v17 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-04 1:29 ` Claude review: " Claude Code Review Bot
2026-06-02 17:24 [PATCH v16 0/6] Rust bindings for gem shmem Lyude Paul
2026-06-02 17:25 ` [PATCH v16 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-04 2:29 ` Claude review: " Claude Code Review Bot
2026-05-26 21:28 [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function Lyude Paul
2026-05-26 21:28 ` [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-05-27 4:05 ` Claude review: " Claude Code Review Bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox