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