diff mbox series

[1/6] drm/i915/gem: Move obj->lut_list under its own lock

Message ID 20200629101256.13039-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show
Series [1/6] drm/i915/gem: Move obj->lut_list under its own lock | expand

Commit Message

Chris Wilson June 29, 2020, 10:12 a.m. UTC
The obj->lut_list is traversed when the object is closed as the file
table is destroyed during process termination. As this occurs before we
kill any outstanding context if, due to some bug or another, the closure
is blocked, then we fail to shootdown any inflight operations
potentially leaving the GPU spinning forever. As we only need to guard
the list against concurrent closures and insertions, the hold is short
and merits being treated as a simple spinlock.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c      | 6 ++----
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c   | 4 ++--
 drivers/gpu/drm/i915/gem/i915_gem_object.c       | 5 +++--
 drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 1 +
 4 files changed, 8 insertions(+), 8 deletions(-)

Comments

Chris Wilson June 29, 2020, 10:50 a.m. UTC | #1
Quoting Chris Wilson (2020-06-29 11:12:51)
> @@ -108,7 +109,7 @@ void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
>         struct i915_lut_handle *lut, *ln;
>         LIST_HEAD(close);
>  
> -       i915_gem_object_lock(obj);
> +       spin_lock(&obj->lut_lock);
>         list_for_each_entry_safe(lut, ln, &obj->lut_list, obj_link) {
>                 struct i915_gem_context *ctx = lut->ctx;
>  
> @@ -118,7 +119,7 @@ void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
>                 i915_gem_context_get(ctx);
>                 list_move(&lut->obj_link, &close);
>         }
> -       i915_gem_object_unlock(obj);
> +       spin_unlock(&obj->lut_lock);

This is only real worry, iterating under the spinlock.

If we worry, we can do something like

+       struct i915_lut_handle bookmark = {};
        LIST_HEAD(close);

        spin_lock(&obj->lut_lock);
        list_for_each_entry_safe(lut, ln, &obj->lut_list, obj_link) {
                struct i915_gem_context *ctx = lut->ctx;

-               if (ctx->file_priv != fpriv)
-                       continue;
+               if (ctx && ctx->file_priv == fpriv) {
+                       i915_gem_context_get(ctx);
+                       list_move(&lut->obj_link, &close);
+               }

-               i915_gem_context_get(ctx);
-               list_move(&lut->obj_link, &close);
+               if (ln != &obj->lut_list) {
+                       list_add(&bookmark->obj_link, &ln->obj_link);
+                       if (cond_resched_lock(&obj->lut_lock))
+                               list_safe_reset_next(&bookmark, ln, obj_link);
+                       list_del_entry(&bookmark->obj_link);
+               }
        }

Might as well worry.
-Chris
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 5c13809dc3c8..6675447a47b9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -112,8 +112,7 @@  static void lut_close(struct i915_gem_context *ctx)
 		if (!kref_get_unless_zero(&obj->base.refcount))
 			continue;
 
-		rcu_read_unlock();
-		i915_gem_object_lock(obj);
+		spin_lock(&obj->lut_lock);
 		list_for_each_entry(lut, &obj->lut_list, obj_link) {
 			if (lut->ctx != ctx)
 				continue;
@@ -124,8 +123,7 @@  static void lut_close(struct i915_gem_context *ctx)
 			list_del(&lut->obj_link);
 			break;
 		}
-		i915_gem_object_unlock(obj);
-		rcu_read_lock();
+		spin_unlock(&obj->lut_lock);
 
 		if (&lut->obj_link != &obj->lut_list) {
 			i915_lut_handle_free(lut);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index c38ab51e82f0..b4862afaaf28 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -789,14 +789,14 @@  static int __eb_add_lut(struct i915_execbuffer *eb,
 		if (err == 0) { /* And nor has this handle */
 			struct drm_i915_gem_object *obj = vma->obj;
 
-			i915_gem_object_lock(obj);
+			spin_lock(&obj->lut_lock);
 			if (idr_find(&eb->file->object_idr, handle) == obj) {
 				list_add(&lut->obj_link, &obj->lut_list);
 			} else {
 				radix_tree_delete(&ctx->handles_vma, handle);
 				err = -ENOENT;
 			}
-			i915_gem_object_unlock(obj);
+			spin_unlock(&obj->lut_lock);
 		}
 		mutex_unlock(&ctx->mutex);
 	}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index b6ec5b50d93b..8222e8b33efd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -61,6 +61,7 @@  void i915_gem_object_init(struct drm_i915_gem_object *obj,
 	INIT_LIST_HEAD(&obj->mm.link);
 
 	INIT_LIST_HEAD(&obj->lut_list);
+	spin_lock_init(&obj->lut_lock);
 
 	spin_lock_init(&obj->mmo.lock);
 	obj->mmo.offsets = RB_ROOT;
@@ -108,7 +109,7 @@  void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
 	struct i915_lut_handle *lut, *ln;
 	LIST_HEAD(close);
 
-	i915_gem_object_lock(obj);
+	spin_lock(&obj->lut_lock);
 	list_for_each_entry_safe(lut, ln, &obj->lut_list, obj_link) {
 		struct i915_gem_context *ctx = lut->ctx;
 
@@ -118,7 +119,7 @@  void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
 		i915_gem_context_get(ctx);
 		list_move(&lut->obj_link, &close);
 	}
-	i915_gem_object_unlock(obj);
+	spin_unlock(&obj->lut_lock);
 
 	spin_lock(&obj->mmo.lock);
 	rbtree_postorder_for_each_entry_safe(mmo, mn, &obj->mmo.offsets, offset)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
index b1f82a11aef2..0fd677ad8ec8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -121,6 +121,7 @@  struct drm_i915_gem_object {
 	 * this translation from object to context->handles_vma.
 	 */
 	struct list_head lut_list;
+	spinlock_t lut_lock; /* guards for lut_list */
 
 	/** Stolen memory for this object, instead of being backed by shmem. */
 	struct drm_mm_node *stolen;