* [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function
@ 2026-05-26 21:28 Lyude Paul
2026-05-26 21:28 ` [PATCH v14 1/6] rust: faux: Allow retrieving a bound Device Lyude Paul
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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
(was previously Rust bindings for gem shmem)
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://lkml.org/lkml/2026/5/26/1960
Lyude Paul (6):
rust: faux: Allow retrieving a bound Device
rust: gem: shmem: Fix Default implementation for ObjectConfig
rust: drm: gem: s/device::Device/Device/ for shmem.rs
drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked()
rust: drm: gem/shmem: Add DmaResvGuard helper
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 | 264 +++++++++++++++++++++++--
rust/kernel/faux.rs | 7 +-
4 files changed, 279 insertions(+), 25 deletions(-)
base-commit: 2cf1840b0fa7637b6731fd554529f8d57ea34c04
prerequisite-patch-id: c8ade07eec6e9c9e875800b114137c459d362e4e
prerequisite-patch-id: dc4f750bc885b867842587b994261f43602bc6a8
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v14 1/6] rust: faux: Allow retrieving a bound Device
2026-05-26 21:28 [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
2026-05-26 21:28 ` [PATCH v14 2/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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] 8+ messages in thread
* [PATCH v14 2/6] rust: gem: shmem: Fix Default implementation for ObjectConfig
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 1/6] rust: faux: Allow retrieving a bound Device Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
2026-05-26 21:28 ` [PATCH v14 3/6] rust: drm: gem: s/device::Device/Device/ for shmem.rs Lyude Paul
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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] 8+ messages in thread
* [PATCH v14 3/6] rust: drm: gem: s/device::Device/Device/ for shmem.rs
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 1/6] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-05-26 21:28 ` [PATCH v14 2/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
2026-05-26 21:28 ` [PATCH v14 4/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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
We're about to start explicitly mentioning kernel devices as well in this
file, so this makes it easier to differentiate the two by allowing us to
import `device` as `kernel::device`.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
---
V11:
* Fix location of //
rust/kernel/drm/gem/shmem.rs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 8b7de136ab1f9..116ed0a13eac2 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -12,10 +12,10 @@
use crate::{
container_of,
drm::{
- device,
driver,
gem,
- private::Sealed, //
+ private::Sealed,
+ Device, //
},
error::to_result,
prelude::*,
@@ -115,7 +115,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,
@@ -157,9 +157,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) {
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v14 4/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked()
2026-05-26 21:28 [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function Lyude Paul
` (2 preceding siblings ...)
2026-05-26 21:28 ` [PATCH v14 3/6] rust: drm: gem: s/device::Device/Device/ for shmem.rs Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
2026-05-26 21:28 ` [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
2026-05-26 21:28 ` [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
5 siblings, 0 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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] 8+ messages in thread
* [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper
2026-05-26 21:28 [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function Lyude Paul
` (3 preceding siblings ...)
2026-05-26 21:28 ` [PATCH v14 4/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
2026-05-27 12:16 ` Alice Ryhl
2026-05-26 21:28 ` [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
5 siblings, 1 reply; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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>
---
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 116ed0a13eac2..1b24cb1129a8b 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] 8+ messages in thread
* [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table()
2026-05-26 21:28 [PATCH v14 0/6] rust: drm: gem: shmem: Add sg_table() function Lyude Paul
` (4 preceding siblings ...)
2026-05-26 21:28 ` [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
@ 2026-05-26 21:28 ` Lyude Paul
5 siblings, 0 replies; 8+ messages in thread
From: Lyude Paul @ 2026-05-26 21:28 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 | 214 +++++++++++++++++++++++++++++++++--
1 file changed, 204 insertions(+), 10 deletions(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 1b24cb1129a8b..12307ec6bff07 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -11,15 +11,29 @@
use crate::{
container_of,
+ device::{
+ self,
+ Bound, //
+ },
+ devres::*,
drm::{
driver,
gem,
private::Sealed,
Device, //
},
- error::to_result,
+ error::{
+ from_err_ptr,
+ to_result, //
+ },
prelude::*,
- sync::aref::ARef,
+ scatterlist,
+ sync::{
+ aref::ARef,
+ new_lazy_init,
+ LazyInit,
+ LazyInitError, //
+ },
types::Opaque, //
};
use core::{
@@ -75,6 +89,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,
}
@@ -127,6 +144,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,
@@ -170,22 +188,49 @@ 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) };
}
+
+ /// 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 +291,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 +306,153 @@ fn drop(&mut self) {
unsafe { bindings::dma_resv_unlock(self.0.raw_dma_resv()) };
}
}
+
+/// 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_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(
+ name: &'static CStr,
+ ) -> 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(name, None)?;
+ let drm = drm::Device::<KunitDriver>::new(dev.as_ref(), data)?;
+
+ Ok((dev, drm))
+ }
+
+ // 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(Some(c"Kunit"))?;
+ let (wrong_dev, wrong_drm) = create_drm_dev(Some(c"EvilKunit"))?;
+
+ 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] 8+ messages in thread
* Re: [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper
2026-05-26 21:28 ` [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
@ 2026-05-27 12:16 ` Alice Ryhl
0 siblings, 0 replies; 8+ messages in thread
From: Alice Ryhl @ 2026-05-27 12:16 UTC (permalink / raw)
To: Lyude Paul
Cc: dri-devel, rust-for-linux, nouveau, Alexandre Courbot, Gary Guo,
Christian König, driver-core, Miguel Ojeda,
Maarten Lankhorst, 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,
Greg Kroah-Hartman
On Tue, May 26, 2026 at 05:28:56PM -0400, Lyude Paul wrote:
> 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>
Missing SoB for Alexandre.
> ---
> 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 116ed0a13eac2..1b24cb1129a8b 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>);
Is this missing a NotThreadSafe, or is it safe to unlock on a different
thread than where it was locked?
> +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 [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-05-27 12:16 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 1/6] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-05-26 21:28 ` [PATCH v14 2/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
2026-05-26 21:28 ` [PATCH v14 3/6] rust: drm: gem: s/device::Device/Device/ for shmem.rs Lyude Paul
2026-05-26 21:28 ` [PATCH v14 4/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
2026-05-26 21:28 ` [PATCH v14 5/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
2026-05-27 12:16 ` Alice Ryhl
2026-05-26 21:28 ` [PATCH v14 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox