accel/amdxdna: Fix potential deadlock in BO open and close callbacks

In amdxdna_gem_obj_open(), abo->lock is held when calling
amdxdna_gem_add_bo_usage(), which then acquires client->mm_lock.

However, the heap update path may acquire these locks in the reverse
order, creating a potential deadlock.

Fix this by saving the client pointer locally before acquiring abo->lock,
and releasing abo->lock before calling amdxdna_gem_add_bo_usage().

Apply the same change to amdxdna_gem_obj_close().

Fixes: 1f513a3ec3 ("accel/amdxdna: Add per-process BO memory usage query support")
Reviewed-by: Max Zhen <max.zhen@amd.com>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://patch.msgid.link/20260902180955.3999242-2-lizhi.hou@amd.com
This commit is contained in:
Lizhi Hou committed 2026-09-11 08:19:14 -07:00
1 parent d0c0ffdba9
commit 1bc13a9d93
1 file changed
+22 -12
+22 -12
View File
@@ -641,10 +641,8 @@ amdxdna_gem_skip_bo_usage(struct amdxdna_gem_obj *abo)
}
static void
amdxdna_gem_add_bo_usage(struct amdxdna_gem_obj *abo)
amdxdna_gem_add_bo_usage(struct amdxdna_client *client, struct amdxdna_gem_obj *abo)
{
struct amdxdna_client *client = abo->client;
if (amdxdna_gem_skip_bo_usage(abo))
return;
@@ -656,10 +654,8 @@ amdxdna_gem_add_bo_usage(struct amdxdna_gem_obj *abo)
}
static void
amdxdna_gem_del_bo_usage(struct amdxdna_gem_obj *abo)
amdxdna_gem_del_bo_usage(struct amdxdna_client *client, struct amdxdna_gem_obj *abo)
{
struct amdxdna_client *client = abo->client;
if (amdxdna_gem_skip_bo_usage(abo))
return;
@@ -694,14 +690,20 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi
{
struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev);
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
struct amdxdna_client *client;
int ret;
guard(mutex)(&abo->lock);
if (abo->open_ref > 0 && filp->driver_priv != abo->client)
mutex_lock(&abo->lock);
if (abo->open_ref > 0 && filp->driver_priv != abo->client) {
mutex_unlock(&abo->lock);
return -EPERM;
}
abo->open_ref++;
if (abo->open_ref > 1)
if (abo->open_ref > 1) {
mutex_unlock(&abo->lock);
return 0;
}
/* Attached to the client when first opened by it. */
abo->client = filp->driver_priv;
@@ -712,26 +714,34 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi
if (ret) {
abo->open_ref--;
abo->client = NULL;
mutex_unlock(&abo->lock);
return ret;
}
}
client = abo->client;
mutex_unlock(&abo->lock);
amdxdna_gem_add_bo_usage(abo);
amdxdna_gem_add_bo_usage(client, abo);
return 0;
}
static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *filp)
{
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
struct amdxdna_client *client = NULL;
guard(mutex)(&abo->lock);
mutex_lock(&abo->lock);
abo->open_ref--;
if (abo->open_ref == 0) {
amdxdna_gem_del_bo_usage(abo);
/* Detach from the client when last closed by it. */
client = abo->client;
abo->client = NULL;
}
mutex_unlock(&abo->lock);
if (client)
amdxdna_gem_del_bo_usage(client, abo);
}
static int amdxdna_gem_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)