From: Vitaly Prosyak <[email protected]>
cancel_delayed_work_sync() waits for any running work instance to finish.
hang_detect_work takes userq_mutex during its run, so calling
cancel_delayed_work_sync() inside userq_mutex in amdgpu_userq_destroy()
risks deadlock:
amdgpu_userq_destroy holds userq_mutex
-> cancel_delayed_work_sync -> __flush_work (waits for work)
-> hang_detect_work (running) tries to acquire userq_mutex
-> DEADLOCK
WARNING: possible circular locking dependency detected
amd_basic/3761 is trying to acquire lock:
(work_completion)(&(&queue->hang_detect_work)->work), at: __flush_work
but task is already holding lock:
(&userq_mgr->userq_mutex), at: amdgpu_userq_destroy+0x76/0x3e0 [amdgpu]
Move the cancel before mutex_lock() to eliminate this dependency.
Cc: Christian Koenig <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Sunil Khatri <[email protected]>
Signed-off-by: Vitaly Prosyak <[email protected]>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 0a816b3c5ff9..52cd7d1c9f2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -543,12 +543,15 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_usermode_que
trace_amdgpu_userq_destroy_start(queue);
cancel_delayed_work_sync(&uq_mgr->resume_work);
+ /* Cancel before taking userq_mutex: cancel_delayed_work_sync() waits
+ * for any running instance, which itself takes userq_mutex.
+ */
+ cancel_delayed_work_sync(&queue->hang_detect_work);
mutex_lock(&uq_mgr->userq_mutex);
amdgpu_userq_wait_for_last_fence(queue);
amdgpu_userq_detach_doorbell(queue);
- cancel_delayed_work_sync(&queue->hang_detect_work);
#if defined(CONFIG_DEBUG_FS)
debugfs_remove_recursive(queue->debugfs_queue);
--
2.54.0