amdgpu_vm_pt_alloc() drops the eviction lock while it creates the new
page table. When the VM started to get evicted in the meantime,
amdgpu_vm_begin_critical() returns -EBUSY and we jump to error_free_pt
before pt_bo is assigned. That unreferences an uninitialized pointer,
leaks the new page table (still pinned for NPA VMs) and returns 0 since
r is the result of the successful page table creation.

With vm->evicting set right after amdgpu_vm_pt_create() (what
amdgpu_vm_evictable() does when TTM evicts one of the VM page tables in
that window), the first GEM_VA map that needs a new page table oopses:

  BUG: kernel NULL pointer dereference, address: 0000000000000460
  RIP: 0010:amdgpu_bo_unref+0x27/0x70 [amdgpu]
  Call Trace:
   amdgpu_vm_ptes_update+0xa4e/0xa60 [amdgpu]
   amdgpu_vm_update_range+0x2eb/0x970 [amdgpu]
   amdgpu_vm_bo_update+0x325/0x6d0 [amdgpu]
   amdgpu_gem_va_update_vm+0xdb/0x1c0 [amdgpu]
   amdgpu_gem_va_ioctl+0x86c/0x940 [amdgpu]

Assign pt_bo first, unpin and free the new page table and return the
error from amdgpu_vm_begin_critical().

Fixes: 1e0041e2ac56 ("drm/amdgpu: rework eviction lock handling into critical 
section v3")
Signed-off-by: Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
index c03327f1242d..599c0085cdd9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
@@ -531,13 +531,16 @@ static int amdgpu_vm_pt_alloc(struct 
amdgpu_vm_update_params *p,
        r2 = amdgpu_vm_begin_critical(p);
        if (r)
                return r;
-       if (r2)
-               goto error_free_pt;
+
+       pt_bo = &pt->bo;
+       if (r2) {
+               r = r2;
+               goto error_unpin;
+       }
 
        /* Keep a reference to the root directory to avoid
         * freeing them up in the wrong order.
         */
-       pt_bo = &pt->bo;
        pt_bo->parent = amdgpu_bo_ref(cursor->parent->bo);
        amdgpu_vm_bo_base_init(entry, p->vm, pt_bo);
        r = amdgpu_vm_pt_clear(p->adev, p->vm, pt, p->immediate);
@@ -549,7 +552,6 @@ static int amdgpu_vm_pt_alloc(struct 
amdgpu_vm_update_params *p,
 error_unpin:
        if (p->vm->is_npa)
                amdgpu_bo_unpin(pt_bo);
-error_free_pt:
        amdgpu_bo_unref(&pt_bo);
        return r;
 }
-- 
2.50.1

Reply via email to