[PATCH 3/6] drm/i915: Require the object lock for vma destruction

Thomas Hellström thomas.hellstrom at linux.intel.com
Fri Feb 4 21:58:19 UTC 2022


The only place we can destroy a vma with the object alive without
holding the object lock is __i915_vm_close(). Fix that so that we
can rely on vmas staying alive while we hold the object lock and
thus be ok to remove the vma refcount.

Since i915_gem_object_unbind() might race with i915_vm_close() in which case
i915_gem_object_unbind() skips the unbind and returns -EAGAIN, hoping that
i915_vm_close() will make progress. Now It won't since we now hold the object
lock, but we can now instead allow i915_gem_object_unbind() to proceed.

Signed-off-by: Thomas Hellström <thomas.hellstrom at linux.intel.com>
---
 drivers/gpu/drm/i915/gt/intel_gtt.c | 16 ++++++++++++++++
 drivers/gpu/drm/i915/i915_gem.c     | 13 ++++++-------
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index c9a24b021a7e..c115dc82de3c 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -102,6 +102,7 @@ void __i915_vm_close(struct i915_address_space *vm)
 	if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
 		return;
 
+retry:
 	list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
 		struct drm_i915_gem_object *obj = vma->obj;
 
@@ -117,7 +118,22 @@ void __i915_vm_close(struct i915_address_space *vm)
 		}
 
 		/* Keep the obj (and hence the vma) alive as _we_ destroy it */
+		if (!i915_gem_object_trylock(obj, NULL)) {
+			/*
+			 * We need to unlock the vm->mutex to maintain locking
+			 * order wrt object lock, and then restart the loop.
+			 */
+			mutex_unlock(&vm->mutex);
+			i915_gem_object_lock(obj, NULL);
+			mutex_lock(&vm->mutex);
+			i915_vma_destroy_locked(vma);
+			i915_gem_object_unlock(obj);
+			i915_gem_object_put(obj);
+			goto retry;
+		}
+
 		i915_vma_destroy_locked(vma);
+		i915_gem_object_unlock(obj);
 		i915_gem_object_put(obj);
 	}
 	GEM_BUG_ON(!list_empty(&vm->bound_list));
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e3a2c2a0e156..0129ed8ee09f 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -139,8 +139,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,
 						       struct i915_vma,
 						       obj_link))) {
-		struct i915_address_space *vm = vma->vm;
-
 		list_move_tail(&vma->obj_link, &still_in_list);
 		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))
 			continue;
@@ -150,14 +148,16 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 			break;
 		}
 
-		ret = -EAGAIN;
-		if (!i915_vm_tryopen(vm))
-			break;
+		/*
+		 * We might race with a i915_vm_close() or a i915_vma_close,
+		 * but since we hold the object lock, they will block on this
+		 * object. Hence, the vma will stay alive, and since the vma
+		 * has a reference on the vm, so will the vm.
+		 */
 
 		/* Prevent vma being freed by i915_vma_parked as we unbind */
 		vma = __i915_vma_get(vma);
 		spin_unlock(&obj->vma.lock);
-
 		if (vma) {
 			bool vm_trylock = !!(flags & I915_GEM_OBJECT_UNBIND_VM_TRYLOCK);
 			ret = -EBUSY;
@@ -183,7 +183,6 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,
 			__i915_vma_put(vma);
 		}
 
-		i915_vm_close(vm);
 		spin_lock(&obj->vma.lock);
 	}
 	list_splice_init(&still_in_list, &obj->vma.list);
-- 
2.34.1



More information about the Intel-gfx-trybot mailing list