From: Vitaly Prosyak <[email protected]> During amd_deadlock userq reset testing, the restore worker reached amdgpu_evf_mgr_rearm() with a locked reservation object whose fence list had been rebuilt after validation. When all previous fences had completed, the rebuilt list contained no active fences and dma_resv_reset_max_fences() left num_fences and max_fences at zero. dma_resv_add_fence() then triggered:
BUG_ON(fobj->num_fences >= fobj->max_fences) while adding the replacement BOOKKEEP eviction fence. The v1 proposal attempted to call dma_resv_reserve_fences() from inside amdgpu_evf_mgr_rearm(), immediately before dma_resv_add_fence(). This is not valid. dma_resv_reserve_fences() may allocate memory and replace the reservation-fence list. If the replacement eviction fence has already been created by rearm, that allocation can invalidate the newly created fence state again. This is the ordering problem identified by Christian during review. v2 reserves the slot in the restore caller, before rearm creates the replacement fence. After validation and GART work have completed, the caller still owns every reservation through the DRM execution context. It refreshes one slot for every locked object, allowing all possible reservation-list allocations to finish before amdgpu_evf_mgr_rearm() creates and attaches the new BOOKKEEP fence. The reservation remains caller-side. The eviction-fence helper does not reserve memory and only consumes capacity prepared by its caller. The initial caller-side preparation is still required for WPTR BOs and VM BOs, because it covers validation and migration fences; the final refresh is required because later validation can rebuild a reservation list and discard unused capacity. This v2 supersedes the v1 helper-side approach and the intermediate caller-side allocation commits that did not refresh capacity after validation. Fixes: 91a358fe99d86 (drm/amdgpu: dont pin wptr bo instead use eviction fence) Reported-by: IGT amd_deadlock test Cc: Christian König <[email protected]> Cc: Alex Deucher <[email protected]> Cc: Prike Liang <[email protected]> Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Vitaly Prosyak <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 75d5ceaa53c6..a1b6ce8b348e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1034,6 +1034,7 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) struct amdgpu_bo_va *bo_va; struct amdgpu_usermode_queue *queue; struct amdgpu_bo *bo; + struct drm_gem_object *obj; struct drm_exec exec; struct xarray xa; int ret; @@ -1210,6 +1211,13 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(bo); } + /* Re-reserve the rearm slot after validation may have rebuilt the lists. */ + drm_exec_for_each_locked_object(&exec, tmp_key, obj) { + ret = dma_resv_reserve_fences(obj->resv, 1); + if (ret) + goto unlock_all; + } + ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec); if (ret) { drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n"); -- 2.43.0
