RE: [PATCH] amdkfd: fix deadlock in set_perfcount

"Welton, Benjamin" <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <LV9PR12MB98314F6236D1379301497BD8F0DB2@LV9PR12MB9831.namprd12.prod.outlook.com>
AMD General

Interesting, wonder how this was dropped. This has been present and been used by customers for a while (and this is an issue they would absolutely hit).

There was some weirdness in the migration if I remember correctly from DKMS -> Public when  a migration for the PTL work took place and I suspect that maybe the change just wasn’t picked up or was dropped as part of that migration. What two branches do you need to check here?

Ben

From: Kuehling, Felix <[email protected]>
Sent: Tuesday, August 4, 2026 3:41 PM
To: Zhu, Lingshan <[email protected]>; Deucher, Alexander <[email protected]>; Koenig, Christian <[email protected]>; Welton, Benjamin <[email protected]>
Cc: Huang, Ray <[email protected]>; [email protected]
Subject: Re: [PATCH] amdkfd: fix deadlock in set_perfcount


[+Benjamin]
On 2026-07-31 05:51, Zhu Lingshan wrote:

set_perfcount holds the DQM lock (dqm_lock(dqm)

while walking queues, but pqm_update_mqd

calls update_queue, which acquires the

same lock by dqm_lock(dqm), causing deadlocks.



This commit introduces update_queue_locked which assumes

the dqm lock is already held, and update_queue calls it

with proper lockings.



set_perfcount calls update_queue_locked instead of pqm_update_mqd,

therefore the deadlock is fixed.

I think the patch looks fine to me. I'm just wondering how this bug was not noticed in developer testing of this feature. I see a very similar patch already exists on the DKMS branch but somehow it's missing in amd-staging-drm-next:

commit 5cd0710732a45527b6398f8b522289f9adca708b

Author:     Benjamin Welton <[email protected]><mailto:[email protected]>

AuthorDate: Mon Jan 6 10:30:01 2025 -0800

Commit:     Chengjun Yao <[email protected]><mailto:[email protected]>

CommitDate: Mon Jun 22 12:51:06 2026 +0800



    amd/amdkfd: fix double lock aquisition in set_perfcount



    Seperates out locking from update_queue to allow updating

    of queues by code already holding the mqd lock. Fixes a

    hang in set_perfcount. This change was in the original

    mailing list commit for set_perfcount but was not included

    in gerrit.



    Fixes: b58289f0abf7 ("Add kfd_ioctl_profiler to contain profiler kernel driver changes")



    Signed-off-by: Benjamin Welton <[email protected]><mailto:[email protected]>

    Acked-by: Kent Russell <[email protected]><mailto:[email protected]>



Benjamin, do you know what's going on here? I think the above patch just needs to be ported to amd-staging-drm-next. But then I'm wondering what else is missing. Or maybe the whole feature was submitted to amd-staging-drm-next by mistake.

Regards,
  Felix







Signed-off-by: Zhu Lingshan <[email protected]><mailto:[email protected]>

---

 .../drm/amd/amdkfd/kfd_device_queue_manager.c | 44 ++++++++++++-------

 1 file changed, 27 insertions(+), 17 deletions(-)



diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

index 51ee9c39104b..c34c5f6a5541 100644

--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

@@ -77,6 +77,9 @@ static struct queue *find_queue_by_doorbell_offset(struct device_queue_manager *

 static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q,

                        struct qcm_process_device *qpd);

 static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q);

+static int update_queue_locked(struct device_queue_manager *dqm,

+                       struct queue *q,

+                       struct mqd_update_info *minfo);



 static inline

 enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)

@@ -341,8 +344,7 @@ static void set_perfcount(struct device_queue_manager *dqm, int enable)

  list_for_each_entry(cur, &dqm->queues, list) {

         qpd = cur->qpd;

         list_for_each_entry(q, &qpd->queues_list, list) {

-                pqm_update_mqd(qpd->pqm, q->properties.queue_id,

-                                 &minfo);

+                update_queue_locked(dqm, q, &minfo);

         }

  }

  dqm_unlock(dqm);

@@ -1059,8 +1061,9 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm,

  return retval;

 }



-static int update_queue(struct device_queue_manager *dqm, struct queue *q,

-                struct mqd_update_info *minfo)

+static int update_queue_locked(struct device_queue_manager *dqm,

+                       struct queue *q,

+                       struct mqd_update_info *minfo)

 {

  int retval = 0;

  struct device *dev = dqm->dev->adev->dev;

@@ -1068,12 +1071,11 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q,

  struct kfd_process_device *pdd;

  bool prev_active = false;



- dqm_lock(dqm);

+ lockdep_assert_held(&dqm->lock_hidden);

+

  pdd = kfd_get_process_device_data(q->device, q->process);

- if (!pdd) {

-        retval = -ENODEV;

-        goto out_unlock;

- }

+ if (!pdd)

+        return -ENODEV;

  mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(

                 q->properties.type)];



@@ -1089,14 +1091,12 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q,

                 retval = remove_queue_mes(dqm, q, &pdd->qpd);



         /* queue is reset so inaccessable  */

-        if (pdd->has_reset_queue) {

-                retval = -EACCES;

-                goto out_unlock;

-        }

+        if (pdd->has_reset_queue)

+                return -EACCES;



         if (retval) {

                 dev_err(dev, "unmap queue failed\n");

-                goto out_unlock;

+                return retval;

         }

  } else if (prev_active &&

            (q->properties.type == KFD_QUEUE_TYPE_COMPUTE ||

@@ -1105,7 +1105,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q,



         if (!dqm->sched_running) {

                 WARN_ONCE(1, "Update non-HWS queue while stopped\n");

-                goto out_unlock;

+                return -EIO;

         }



         retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd,

@@ -1115,7 +1115,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q,

                   KFD_UNMAP_LATENCY_MS, q->pipe, q->queue);

         if (retval) {

                 dev_err(dev, "destroy mqd failed\n");

-                goto out_unlock;

+                return retval;

         }

  }



@@ -1163,8 +1163,18 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q,

                                           &q->properties, current->mm);

  }



-out_unlock:

+ return retval;

+}

+

+static int update_queue(struct device_queue_manager *dqm, struct queue *q,

+                struct mqd_update_info *minfo)

+{

+ int retval;

+

+ dqm_lock(dqm);

+ retval = update_queue_locked(dqm, q, minfo);

  dqm_unlock(dqm);

+

  return retval;

 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.