On 2026-09-23 17:20, Mukul Joshi wrote:
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: 6b1a5ad90778 ("drm/amdgpu: Implement UALink handle export") Reported-by: Sashiko-bot <[email protected]> Signed-off-by: Mukul Joshi <[email protected]>
Reviewed-by: Felix Kuehling <[email protected]>
--- v1->v2: - Use amdgpu_bo_reserve() to update the ualink_handle_lo in the BO. If it is not zero, then roll back the changes. 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;
