]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: ufs: core: Fix error handler host_sem issue
authorPeter Wang <peter.wang@mediatek.com>
Wed, 8 Oct 2025 06:55:43 +0000 (14:55 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 22 Oct 2025 00:50:28 +0000 (20:50 -0400)
Fix the issue where host_sem is not released due to a new return path in
commit f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error
deadlock").

Check pm_op_in_progress before acquiring hba->host_sem to prevent
deadlocks and ensure proper resource management during error
handling. Add comment for use ufshcd_rpm_get_noresume() to safely
perform link recovery without interfering with ongoing PM operations.

Fixes: f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error deadlock")
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Signed-off-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251008065651.1589614-2-peter.wang@mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufshcd.c

index 8339fec975b9230c67cc6c5338fed2fbf01af2af..8f4e884892a90265e02d758738bc574045f12814 100644 (file)
@@ -6673,6 +6673,20 @@ static void ufshcd_err_handler(struct work_struct *work)
                 hba->saved_uic_err, hba->force_reset,
                 ufshcd_is_link_broken(hba) ? "; link is broken" : "");
 
+       /*
+        * Use ufshcd_rpm_get_noresume() here to safely perform link recovery
+        * even if an error occurs during runtime suspend or runtime resume.
+        * This avoids potential deadlocks that could happen if we tried to
+        * resume the device while a PM operation is already in progress.
+        */
+       ufshcd_rpm_get_noresume(hba);
+       if (hba->pm_op_in_progress) {
+               ufshcd_link_recovery(hba);
+               ufshcd_rpm_put(hba);
+               return;
+       }
+       ufshcd_rpm_put(hba);
+
        down(&hba->host_sem);
        spin_lock_irqsave(hba->host->host_lock, flags);
        if (ufshcd_err_handling_should_stop(hba)) {
@@ -6684,14 +6698,6 @@ static void ufshcd_err_handler(struct work_struct *work)
        }
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
-       ufshcd_rpm_get_noresume(hba);
-       if (hba->pm_op_in_progress) {
-               ufshcd_link_recovery(hba);
-               ufshcd_rpm_put(hba);
-               return;
-       }
-       ufshcd_rpm_put(hba);
-
        ufshcd_err_handling_prepare(hba);
 
        spin_lock_irqsave(hba->host->host_lock, flags);