--- a/sys/dev/drm/radeon/radeon_gem.c +++ b/sys/dev/drm/radeon/radeon_gem.c @@ -547,10 +547,12 @@ int radeon_gem_get_tiling_ioctl(struct d /** * radeon_gem_va_update_vm -update the bo_va in its VM * * @rdev: radeon_device pointer - * @bo_va: bo_va to update + * @vm: vm of the calling file + * @rbo: radeon_bo the ioctl operates on (ref held by the caller's + * drm_gem_object_lookup()) * - * Update the bo_va directly after setting it's address. Errors are not - * vital here, so they are not reported back to userspace. + * Update the bo_va directly after setting its address. Errors are not + * vital here, so they are not reported back to userspace. + * + * Must not be handed a raw bo_va: see radeon_gem_va_ioctl(). */ static void radeon_gem_va_update_vm(struct radeon_device *rdev, - struct radeon_bo_va *bo_va) + struct radeon_vm *vm, + struct radeon_bo *rbo) { struct ttm_validate_buffer tv, *entry; struct radeon_bo_list *vm_bos; @@ -563,7 +565,7 @@ static void radeon_gem_va_update_vm(stru - tv.bo = &bo_va->bo->tbo; + tv.bo = &rbo->tbo; tv.shared = true; list_add(&tv.head, &list); - vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list); + vm_bos = radeon_vm_get_bos(rdev, vm, &list); if (!vm_bos) return; r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL); if (r) goto error_free; + /* + * radeon_vm_bo_set_addr() dropped the BO reservation on return, so a + * concurrent GEM_CLOSE on this file could already have removed (and + * freed) the bo_va. Re-lookup under the reservation just established + * by ttm_eu_reserve_buffers(); if it is gone there is nothing left to + * update. + */ + bo_va = radeon_vm_bo_find(vm, rbo); + if (!bo_va) + goto error_unreserve; + list_for_each_entry(entry, &list, head) { domain = radeon_mem_type_to_domain(entry->bo->mem.mem_type); /* if anything is swapped out don't swap it in here, @@ -582,9 +584,9 @@ static void radeon_gem_va_update_vm(stru if (r) goto error_unlock; if (bo_va->it.start) r = radeon_vm_bo_update(rdev, bo_va, &bo_va->bo->tbo.mem); error_unlock: - mutex_unlock(&bo_va->vm->mutex); + mutex_unlock(&vm->mutex); error_unreserve: ttm_eu_backoff_reservation(&ticket, &list); @@ -698,7 +700,7 @@ int radeon_gem_va_ioctl(struct drm_devic r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0); break; } if (!r) - radeon_gem_va_update_vm(rdev, bo_va); + radeon_gem_va_update_vm(rdev, &fpriv->vm, rbo); args->operation = RADEON_VA_RESULT_OK; if (r) { args->operation = RADEON_VA_RESULT_ERROR;