Re: [PATCH] drm/amdgpu: fix hang and race in userq destroy

Alex Deucher <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <CADnq5_PY20QzNikfEy-BZ7ZsOD3YATx9hZDGATi_dEfEgw+z_Q@mail.gmail.com>
On Fri, Aug 14, 2026 at 6:55 AM Zhu Lingshan <[email protected]> wrote:
>
> When a queue is hung, the hang_detect_work is the
> only way to recover it. However in amdgpu_userq_destroy(),
> the hang_detect_work is cancelled too early,
> resulting in amdgpu_userq_wait_for_last_fence()
> may never return, leaving an uninterruptible dma_fence_wait()
> hang there.
>
> To fix this problem, this commit moves the cancelling of
> hang_detect_work after amdgpu_userq_wait_for_last_fence(), and it has
> to be before the unmap helper, because hang_detect_work resets the
> queue, so it races with amdgpu_userq_unmap_helper() for MES operations
> and queue state.
>
> This commit splits amdgpu_userq_cleanup() into two parts:
>
> 1) amdgpu_userq_detach_doorbell(), which detaches the queue from
> userq_doorbell_xa. This has to be called before the cancel, otherwise
> the IRQ handlers (for example amdgpu_userq_process_fence_irq)
> can re-schedule the hang_detect_work and the cancel is not final.
>
> 2) amdgpu_userq_fence_driver_free(), this has to be called after the
> unmap helper, because it can release the seq64 slot that the GPU
> writes fence values to.
>
> Only one cancel_delayed_work_sync(&queue->hang_detect_work) is needed,
> so other redundancies are removed.
>
> Signed-off-by: Zhu Lingshan <[email protected]>

Acked-by: Alex Deucher <[email protected]>

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 23 ++++++++---------------
>  1 file changed, 8 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> index 17cc48d87c4d..24adad7be251 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
> @@ -418,19 +418,12 @@ static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue
>         dma_fence_wait(f, false);
>  }
>
> -static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
> +static void amdgpu_userq_detach_doorbell(struct amdgpu_usermode_queue *queue)
>  {
> -       struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
> -       struct amdgpu_device *adev = uq_mgr->adev;
> +       struct amdgpu_device *adev = queue->userq_mgr->adev;
>
> -       /* Wait for mode-1 reset to complete */
>         down_read(&adev->reset_domain->sem);
> -
> -       /* Use interrupt-safe locking since IRQ handlers may access these XArrays */
>         xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
> -       amdgpu_userq_fence_driver_free(queue);
> -       queue->fence_drv = NULL;
> -
>         up_read(&adev->reset_domain->sem);
>  }
>
> @@ -551,18 +544,19 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
>
>         cancel_delayed_work_sync(&uq_mgr->resume_work);
>
> -       /* Cancel any pending hang detection work and cleanup */
> -       cancel_delayed_work_sync(&queue->hang_detect_work);
> -
>         mutex_lock(&uq_mgr->userq_mutex);
>         amdgpu_userq_wait_for_last_fence(queue);
>
> +       amdgpu_userq_detach_doorbell(queue);
> +       cancel_delayed_work_sync(&queue->hang_detect_work);
> +
>  #if defined(CONFIG_DEBUG_FS)
>         debugfs_remove_recursive(queue->debugfs_queue);
>  #endif
>         r = amdgpu_userq_unmap_helper(queue);
>         atomic_dec(&uq_mgr->userq_count[queue->queue_type]);
> -       amdgpu_userq_cleanup(queue);
> +       amdgpu_userq_fence_driver_free(queue);
> +       queue->fence_drv = NULL;
>         mutex_unlock(&uq_mgr->userq_mutex);
>
>         /*
> @@ -574,7 +568,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
>         if (r)
>                 queue_work(adev->reset_domain->wq, &uq_mgr->reset_work);
>
> -       cancel_delayed_work_sync(&queue->hang_detect_work);
>         uq_funcs->mqd_destroy(queue);
>         queue->userq_mgr = NULL;
>
> @@ -748,7 +741,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
>             ((queue->queue_type != AMDGPU_HW_IP_GFX) &&
>              (queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
>                 /* Serialize the map against an in-progress GPU reset (MES is
> -                * unresponsive during recovery), matching amdgpu_userq_cleanup().
> +                * unresponsive during recovery), matching amdgpu_userq_detach_doorbell().
>                  */
>                 down_read(&adev->reset_domain->sem);
>                 r = amdgpu_userq_map_helper(queue);
> --
> 2.53.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.