From d0185861e20a93a9b398cbd85870686467443fa9 Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Tue, 15 Sep 2026 22:21:36 -0400 Subject: [PATCH] drm/amdgpu: Fix race on ualink_handle_lo in UALink handle export amdgpu_ualink_export_handle() tests robj->ualink_handle_lo and stores the generated handle into it without any lock; xa_lock only covers handle generation and the xarray insert. Two threads can therefore both observe a zero handle for the same BO and both allocate an exporter node, take an amdgpu_bo_ref() and insert into exp_xa, with the last store to ualink_handle_lo winning. Teardown only erases the handle recorded in the BO, so the losing node keeps its BO reference and pinned VRAM until device teardown. Each racing thread still generates its own handle and inserts its own node, but the handle is published to the BO under the BO reservation lock after re-checking that ualink_handle_lo is still zero. Exactly one thread makes that transition; the others find a non-zero value, roll back their node (erase from exp_xa, drop the DMABuf and BO references, free it) and return -EAGAIN so the caller retries and picks up the winning handle. This keeps a single exporter node per BO. Fixes: c67cb19811ec ("drm/amdgpu: Implement UALink handle export") Reported-by: Sashiko-bot Closes: https://sashiko.dev/#/patchset/20260914054604.12850-1-kmehltretter@gmail.com?part=1 Signed-off-by: Mukul Joshi Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 31 +++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c index 6e937f31a5b1..39b7cc8bc1c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c @@ -4023,9 +4023,7 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, if (IS_ERR(exp_xa_node->dmabuf)) { r = PTR_ERR(exp_xa_node->dmabuf); dev_err(adev->dev, "Failed to generate DMABuf for the BO\n"); - amdgpu_bo_unref(&exp_xa_node->bo); - kfree(exp_xa_node); - goto out; + goto err_unref_bo; } xa_lock(&adev->ualink.exp_xa); @@ -4036,13 +4034,22 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, xa_unlock(&adev->ualink.exp_xa); if (r) { dev_err(adev->dev, "Failed to insert exp_xa_node into XA: %d\n", r); - dma_buf_put(exp_xa_node->dmabuf); - amdgpu_bo_unref(&exp_xa_node->bo); - kfree(exp_xa_node); - goto out; + goto err_put_dmabuf; + } + + r = amdgpu_bo_reserve(robj, false); + if (r) + goto err_erase_xa; + + if (robj->ualink_handle_lo) { + amdgpu_bo_unreserve(robj); + r = -EAGAIN; + goto err_erase_xa; } robj->ualink_handle_lo = handle.handle_lo; + amdgpu_bo_unreserve(robj); + /* Return the generated handle back to the caller */ *handle_out = handle; } else { @@ -4059,6 +4066,16 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, handle_out->handle_hi = exp_xa_node->handle.handle_hi; } + drm_gem_object_put(gobj); + return 0; + +err_erase_xa: + xa_erase(&adev->ualink.exp_xa, handle.handle_lo); +err_put_dmabuf: + dma_buf_put(exp_xa_node->dmabuf); +err_unref_bo: + amdgpu_bo_unref(&exp_xa_node->bo); + kfree(exp_xa_node); out: drm_gem_object_put(gobj); return r;