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.

Serialize the check-generate-store sequence on a new per-device mutex.
The BO reservation lock cannot be used, since
drm_gem_prime_handle_to_dmabuf() reserves the BO itself via
ttm_bo_setup_export().

Fixes: 6b1a5ad90778 ("drm/amdgpu: Implement UALink handle export")
Reported-by: Sashiko-bot <[email protected]>
Signed-off-by: Mukul Joshi <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 12 +++++++++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h |  5 +++++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index a7ae9ffde1b5..32443bdfc594 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -3991,6 +3991,8 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, 
struct drm_file *filp,
                goto out;
        }
 
+       mutex_lock(&adev->ualink.exp_lock);
+
        if (!robj->ualink_handle_lo) {
                /* If no ualink handle generated for BO, then generate one and
                 * add it to the exporter Xarray.
@@ -3999,7 +4001,7 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, 
struct drm_file *filp,
                if (!exp_xa_node) {
                        dev_err(adev->dev, "Failed to allocate exp_xa_node\n");
                        r = -ENOMEM;
-                       goto out;
+                       goto unlock;
                }
 
                amdgpu_bo_ref(robj);
@@ -4025,7 +4027,7 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, 
struct drm_file *filp,
                        dev_err(adev->dev, "Failed to generate DMABuf for the 
BO\n");
                        amdgpu_bo_unref(&robj);
                        kfree(exp_xa_node);
-                       goto out;
+                       goto unlock;
                }
 
                xa_lock(&adev->ualink.exp_xa);
@@ -4039,7 +4041,7 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, 
struct drm_file *filp,
                        dma_buf_put(exp_xa_node->dmabuf);
                        amdgpu_bo_unref(&robj);
                        kfree(exp_xa_node);
-                       goto out;
+                       goto unlock;
                }
 
                robj->ualink_handle_lo = handle.handle_lo;
@@ -4059,6 +4061,8 @@ int amdgpu_ualink_export_handle(struct drm_device *dev, 
struct drm_file *filp,
                        handle_out->handle_hi = exp_xa_node->handle.handle_hi;
        }
 
+unlock:
+       mutex_unlock(&adev->ualink.exp_lock);
 out:
        drm_gem_object_put(gobj);
        return r;
@@ -4139,6 +4143,7 @@ int amdgpu_ualink_manager_start(struct amdgpu_device 
*adev)
        adev->mmhub.funcs->setup_vm_pt_regs(adev, adev->vm_manager.npa_vmid,
                        amdgpu_gmc_pd_addr(adev->ualink.npa_vm.root.bo));
 
+       mutex_init(&adev->ualink.exp_lock);
        xa_init(&adev->ualink.exp_xa);
        xa_init(&adev->ualink.imp_xa);
        xa_init(&adev->ualink.handle_invalid_xa);
@@ -4272,6 +4277,7 @@ void amdgpu_ualink_manager_stop(struct amdgpu_device 
*adev)
        xa_destroy(&adev->ualink.exp_xa);
        xa_destroy(&adev->ualink.imp_xa);
        xa_destroy(&adev->ualink.handle_invalid_xa);
+       mutex_destroy(&adev->ualink.exp_lock);
 
        for (i = 0; i < AMDGPU_UALINK_ACCEL_MAX; i++)
                mutex_destroy(&adev->ualink.conn_state[i].lock);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
index 85c9a9634a4b..2a6be8b9d5b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
@@ -336,6 +336,11 @@ struct amdgpu_ualink_mgr {
        /* handle irq from ualink client of remote GPUs */
        struct amdgpu_irq_src irq;
 
+       /* Serializes handle allocation in amdgpu_ualink_export_handle() so
+        * that a BO gets at most one exporter xarray node.
+        */
+       struct mutex    exp_lock;
+
        /* Xarray to store info about exported BOs */
        struct xarray   exp_xa;
 
-- 
2.55.0

Reply via email to