OSDN Git Service

drm/amdkfd: Fix a circular lock dependency
authorFelix Kuehling <Felix.Kuehling@amd.com>
Wed, 24 Apr 2019 03:32:56 +0000 (23:32 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 24 May 2019 17:21:03 +0000 (12:21 -0500)
Fix a circular lock dependency exposed under userptr memory pressure.
The DQM lock is the only one taken inside the MMU notifier. We need
to make sure that no reclaim is done under this lock, and that
no other locks are taken under which reclaim is possible.

Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Reviewed-by: Philip Yang <Philip.Yang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c

index 1562590..0bfdb14 100644 (file)
@@ -794,10 +794,14 @@ static int register_process(struct device_queue_manager *dqm,
        retval = dqm->asic_ops.update_qpd(dqm, qpd);
 
        dqm->processes_count++;
-       kfd_inc_compute_active(dqm->dev);
 
        dqm_unlock(dqm);
 
+       /* Outside the DQM lock because under the DQM lock we can't do
+        * reclaim or take other locks that others hold while reclaiming.
+        */
+       kfd_inc_compute_active(dqm->dev);
+
        return retval;
 }
 
@@ -818,7 +822,6 @@ static int unregister_process(struct device_queue_manager *dqm,
                        list_del(&cur->list);
                        kfree(cur);
                        dqm->processes_count--;
-                       kfd_dec_compute_active(dqm->dev);
                        goto out;
                }
        }
@@ -826,6 +829,13 @@ static int unregister_process(struct device_queue_manager *dqm,
        retval = 1;
 out:
        dqm_unlock(dqm);
+
+       /* Outside the DQM lock because under the DQM lock we can't do
+        * reclaim or take other locks that others hold while reclaiming.
+        */
+       if (!retval)
+               kfd_dec_compute_active(dqm->dev);
+
        return retval;
 }
 
@@ -1519,6 +1529,7 @@ static int process_termination_nocpsch(struct device_queue_manager *dqm,
        struct queue *q, *next;
        struct device_process_node *cur, *next_dpn;
        int retval = 0;
+       bool found = false;
 
        dqm_lock(dqm);
 
@@ -1537,12 +1548,19 @@ static int process_termination_nocpsch(struct device_queue_manager *dqm,
                        list_del(&cur->list);
                        kfree(cur);
                        dqm->processes_count--;
-                       kfd_dec_compute_active(dqm->dev);
+                       found = true;
                        break;
                }
        }
 
        dqm_unlock(dqm);
+
+       /* Outside the DQM lock because under the DQM lock we can't do
+        * reclaim or take other locks that others hold while reclaiming.
+        */
+       if (found)
+               kfd_dec_compute_active(dqm->dev);
+
        return retval;
 }
 
@@ -1588,6 +1606,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm,
        struct device_process_node *cur, *next_dpn;
        enum kfd_unmap_queues_filter filter =
                KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES;
+       bool found = false;
 
        retval = 0;
 
@@ -1624,7 +1643,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm,
                        list_del(&cur->list);
                        kfree(cur);
                        dqm->processes_count--;
-                       kfd_dec_compute_active(dqm->dev);
+                       found = true;
                        break;
                }
        }
@@ -1638,6 +1657,12 @@ static int process_termination_cpsch(struct device_queue_manager *dqm,
 
        dqm_unlock(dqm);
 
+       /* Outside the DQM lock because under the DQM lock we can't do
+        * reclaim or take other locks that others hold while reclaiming.
+        */
+       if (found)
+               kfd_dec_compute_active(dqm->dev);
+
        /* Lastly, free mqd resources.
         * Do uninit_mqd() after dqm_unlock to avoid circular locking.
         */