Signed-off-by: Mukul Joshi <[email protected]>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 53 +++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 0d579517c03c..d52bbdc42b31 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -237,6 +237,7 @@ static int amdgpu_gem_object_open(struct
drm_gem_object *obj,
struct amdgpu_bo_va *bo_va;
struct mm_struct *mm;
struct drm_exec exec;
+ bool bo_va_added = false;
int r;
mm = amdgpu_ttm_tt_get_usermm(abo->tbo.ttm);
@@ -264,6 +265,7 @@ static int amdgpu_gem_object_open(struct
drm_gem_object *obj,
bo_va = amdgpu_vm_bo_find(vm, abo);
if (!bo_va) {
bo_va = amdgpu_vm_bo_add(adev, vm, abo);
+ bo_va_added = true;
r = amdgpu_evf_mgr_attach_fence(&fpriv->evf_mgr, abo);
if (r)
goto out_unlock;
@@ -304,9 +306,60 @@ static int amdgpu_gem_object_open(struct
drm_gem_object *obj,
}
}
mutex_unlock(&vm->process_info->lock);
+ if (r)
+ goto out_vm_bo_rollback;
+ return 0;
+
+out_vm_bo_rollback:
+ /*
+ * The open failed after we already mapped the BO into this VM.
Undo
+ * that mapping, otherwise drm_gem_handle_create_tail() aborts the
+ * import and frees the BO while it still has a bo_va attached
+ * (abo->vm_bo != NULL), tripping WARN_ON(abo->vm_bo) in
+ * amdgpu_bo_release_notify() and leaking the bo_va.
+ */
+ drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
+ drm_exec_until_all_locked(&exec) {
+ int r2 = drm_exec_prepare_obj(&exec, &abo->tbo.base, 1);
+
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(r2))
+ goto out_rollback_unlock;
+
+ r2 = amdgpu_vm_lock_pd(vm, &exec, 0);
+ drm_exec_retry_on_contention(&exec);
+ if (unlikely(r2))
+ goto out_rollback_unlock;
+ }
+
+ bo_va = amdgpu_vm_bo_find(vm, abo);
+ if (bo_va) {
+ if (bo_va_added) {
+ if (!amdgpu_vm_is_bo_always_valid(vm, abo))
+ amdgpu_evf_mgr_detach_fence(&fpriv->evf_mgr, abo);
+ amdgpu_vm_bo_del(adev, bo_va);
+ amdgpu_vm_bo_update_shared(abo);
+ } else {
+ --bo_va->ref_count;
+ }
+ }
+
+out_rollback_unlock:
+ drm_exec_fini(&exec);
return r;
out_unlock:
+ /*
+ * If we already added a bo_va (e.g. the eviction fence attach
below
+ * failed), remove it while still holding the reservations so
the BO is
+ * not freed with a dangling abo->vm_bo.
+ */
+ if (bo_va_added) {
+ bo_va = amdgpu_vm_bo_find(vm, abo);
+ if (bo_va)
+ amdgpu_vm_bo_del(adev, bo_va);
+ amdgpu_vm_bo_update_shared(abo);
+ }
drm_exec_fini(&exec);
return r;
}