[PATCH v2 3/4] drm/gem: Stop exposing the racy/unsafe drm_gem_lru_remove() helper
From: Boris Brezillon
Date: Fri May 08 2026 - 06:43:21 EST
The only place where it's safe to call drm_gem_lru_remove() is when
we know the drm_gem_object::lru field can't be concurrently updated,
which we know is the case when the drm_gem_object is destroyed.
Rather than trying to make that safe, let's kill the function and inline
its content in drm_gem_object_release().
Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx>
---
drivers/gpu/drm/drm_gem.c | 90 ++++++++++++++++++++---------------------------
include/drm/drm_gem.h | 1 -
2 files changed, 39 insertions(+), 52 deletions(-)
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 0e087c770883..c85a39b8b163 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1108,6 +1108,15 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
idr_destroy(&file_private->object_idr);
}
+static void
+drm_gem_lru_remove_locked(struct drm_gem_object *obj)
+{
+ obj->lru->count -= obj->size >> PAGE_SHIFT;
+ WARN_ON(obj->lru->count < 0);
+ list_del(&obj->lru_node);
+ obj->lru = NULL;
+}
+
/**
* drm_gem_object_release - release GEM buffer object resources
* @obj: GEM buffer object
@@ -1118,13 +1127,42 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
void
drm_gem_object_release(struct drm_gem_object *obj)
{
+ struct drm_gem_lru *lru;
+
if (obj->filp)
fput(obj->filp);
drm_gem_private_object_fini(obj);
drm_gem_free_mmap_offset(obj);
- drm_gem_lru_remove(obj);
+
+ /*
+ * We do the lru != NULL check without the lru->lock held, which
+ * means we might end up with a stale lru value by the time the
+ * lock is acquired.
+ *
+ * This is deemed safe because:
+ * 1. the LRU is assumed to outlive any GEM object it was attached
+ * (LRUs are usually bound to a drm_device). So even if obj->lru
+ * has become NULL, it still point to a valid object that can
+ * safely be dereferenced to get the lock.
+ *
+ * 2. all LRUs a GEM object might be attached to must share the same
+ * lock (lock that's usually part of the driver-specific device
+ * object), so taking the lock on the 'old' LRU is equivalent
+ * to taking it on the new one (if any)
+ */
+ lru = obj->lru;
+ if (lru) {
+ guard(mutex)(lru->lock);
+
+ /* Check a second time with the lock held to make sure we're
+ * not racing with the drm_gem_lru_remove_locked() call in
+ * drm_gem_lru_scan().
+ */
+ if (obj->lru)
+ drm_gem_lru_remove_locked(obj);
+ }
}
EXPORT_SYMBOL(drm_gem_object_release);
@@ -1552,56 +1590,6 @@ drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock)
}
EXPORT_SYMBOL(drm_gem_lru_init);
-static void
-drm_gem_lru_remove_locked(struct drm_gem_object *obj)
-{
- obj->lru->count -= obj->size >> PAGE_SHIFT;
- WARN_ON(obj->lru->count < 0);
- list_del(&obj->lru_node);
- obj->lru = NULL;
-}
-
-/**
- * drm_gem_lru_remove - remove object from whatever LRU it is in
- *
- * If the object is currently in any LRU, remove it.
- *
- * @obj: The GEM object to remove from current LRU
- */
-void
-drm_gem_lru_remove(struct drm_gem_object *obj)
-{
- struct drm_gem_lru *lru = obj->lru;
-
- /*
- * We do the lru != NULL check without the lru->lock held, which
- * means we might end up with a stale lru value by the time the
- * lock is acquired.
- *
- * This is deemed safe because:
- * 1. the LRU is assumed to outlive any GEM object it was attached
- * (LRUs are usually bound to a drm_device). So even if obj->lru
- * has become NULL, it still point to a valid object that can
- * safely be dereferenced to get the lock.
- *
- * 2. all LRUs a GEM object might be attached to must share the same
- * lock (lock that's usually part of the driver-specific device
- * object), so taking the lock on the 'old' LRU is equivalent
- * to taking it on the new one (if any)
- */
- if (!lru)
- return;
-
- mutex_lock(lru->lock);
- /* Check a second time with the lock held to make sure we're not racing
- * with another drm_gem_lru_remove[_locked]() call.
- */
- if (obj->lru)
- drm_gem_lru_remove_locked(obj);
- mutex_unlock(lru->lock);
-}
-EXPORT_SYMBOL(drm_gem_lru_remove);
-
/**
* drm_gem_lru_move_tail_locked - move the object to the tail of the LRU
*
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 86f5846154f7..d527df98d142 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -611,7 +611,6 @@ int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
u32 handle, u64 *offset);
void drm_gem_lru_init(struct drm_gem_lru *lru, struct mutex *lock);
-void drm_gem_lru_remove(struct drm_gem_object *obj);
void drm_gem_lru_move_tail_locked(struct drm_gem_lru *lru, struct drm_gem_object *obj);
void drm_gem_lru_move_tail(struct drm_gem_lru *lru, struct drm_gem_object *obj);
unsigned long
--
2.54.0