Patch "scsi: ufs: core: Fix devfreq deadlocks" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    scsi: ufs: core: Fix devfreq deadlocks

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     scsi-ufs-core-fix-devfreq-deadlocks.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit f90533938563343b53eca6629f1cf99332a5e1d8
Author: Johan Hovold <johan+linaro@xxxxxxxxxx>
Date:   Mon Jan 16 17:12:01 2023 +0100

    scsi: ufs: core: Fix devfreq deadlocks
    
    [ Upstream commit ba81043753fffbc2ad6e0c5ff2659f12ac2f46b4 ]
    
    There is a lock inversion and rwsem read-lock recursion in the devfreq
    target callback which can lead to deadlocks.
    
    Specifically, ufshcd_devfreq_scale() already holds a clk_scaling_lock
    read lock when toggling the write booster, which involves taking the
    dev_cmd mutex before taking another clk_scaling_lock read lock.
    
    This can lead to a deadlock if another thread:
    
      1) tries to acquire the dev_cmd and clk_scaling locks in the correct
         order, or
    
      2) takes a clk_scaling write lock before the attempt to take the
         clk_scaling read lock a second time.
    
    Fix this by dropping the clk_scaling_lock before toggling the write booster
    as was done before commit 0e9d4ca43ba8 ("scsi: ufs: Protect some contexts
    from unexpected clock scaling").
    
    While the devfreq callbacks are already serialised, add a second
    serialising mutex to handle the unlikely case where a callback triggered
    through the devfreq sysfs interface is racing with a request to disable
    clock scaling through the UFS controller 'clkscale_enable' sysfs
    attribute. This could otherwise lead to the write booster being left
    disabled after having disabled clock scaling.
    
    Also take the new mutex in ufshcd_clk_scaling_allow() to make sure that any
    pending write booster update has completed on return.
    
    Note that this currently only affects Qualcomm platforms since commit
    87bd05016a64 ("scsi: ufs: core: Allow host driver to disable wb toggling
    during clock scaling").
    
    The lock inversion (i.e. 1 above) was reported by lockdep as:
    
     ======================================================
     WARNING: possible circular locking dependency detected
     6.1.0-next-20221216 #211 Not tainted
     ------------------------------------------------------
     kworker/u16:2/71 is trying to acquire lock:
     ffff076280ba98a0 (&hba->dev_cmd.lock){+.+.}-{3:3}, at: ufshcd_query_flag+0x50/0x1c0
    
     but task is already holding lock:
     ffff076280ba9cf0 (&hba->clk_scaling_lock){++++}-{3:3}, at: ufshcd_devfreq_scale+0x2b8/0x380
    
     which lock already depends on the new lock.
    [  +0.011606]
     the existing dependency chain (in reverse order) is:
    
     -> #1 (&hba->clk_scaling_lock){++++}-{3:3}:
            lock_acquire+0x68/0x90
            down_read+0x58/0x80
            ufshcd_exec_dev_cmd+0x70/0x2c0
            ufshcd_verify_dev_init+0x68/0x170
            ufshcd_probe_hba+0x398/0x1180
            ufshcd_async_scan+0x30/0x320
            async_run_entry_fn+0x34/0x150
            process_one_work+0x288/0x6c0
            worker_thread+0x74/0x450
            kthread+0x118/0x120
            ret_from_fork+0x10/0x20
    
     -> #0 (&hba->dev_cmd.lock){+.+.}-{3:3}:
            __lock_acquire+0x12a0/0x2240
            lock_acquire.part.0+0xcc/0x220
            lock_acquire+0x68/0x90
            __mutex_lock+0x98/0x430
            mutex_lock_nested+0x2c/0x40
            ufshcd_query_flag+0x50/0x1c0
            ufshcd_query_flag_retry+0x64/0x100
            ufshcd_wb_toggle+0x5c/0x120
            ufshcd_devfreq_scale+0x2c4/0x380
            ufshcd_devfreq_target+0xf4/0x230
            devfreq_set_target+0x84/0x2f0
            devfreq_update_target+0xc4/0xf0
            devfreq_monitor+0x38/0x1f0
            process_one_work+0x288/0x6c0
            worker_thread+0x74/0x450
            kthread+0x118/0x120
            ret_from_fork+0x10/0x20
    
     other info that might help us debug this:
      Possible unsafe locking scenario:
            CPU0                    CPU1
            ----                    ----
       lock(&hba->clk_scaling_lock);
                                    lock(&hba->dev_cmd.lock);
                                    lock(&hba->clk_scaling_lock);
       lock(&hba->dev_cmd.lock);
    
      *** DEADLOCK ***
    
    Fixes: 0e9d4ca43ba8 ("scsi: ufs: Protect some contexts from unexpected clock scaling")
    Cc: stable@xxxxxxxxxxxxxxx      # 5.12
    Cc: Can Guo <quic_cang@xxxxxxxxxxx>
    Tested-by: Andrew Halaney <ahalaney@xxxxxxxxxx>
    Signed-off-by: Johan Hovold <johan+linaro@xxxxxxxxxx>
    Reviewed-by: Bart Van Assche <bvanassche@xxxxxxx>
    Link: https://lore.kernel.org/r/20230116161201.16923-1-johan+linaro@xxxxxxxxxx
    Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0b06223f5714..120831428ec6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1185,12 +1185,14 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
 	 * clock scaling is in progress
 	 */
 	ufshcd_scsi_block_requests(hba);
+	mutex_lock(&hba->wb_mutex);
 	down_write(&hba->clk_scaling_lock);
 
 	if (!hba->clk_scaling.is_allowed ||
 	    ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
 		ret = -EBUSY;
 		up_write(&hba->clk_scaling_lock);
+		mutex_unlock(&hba->wb_mutex);
 		ufshcd_scsi_unblock_requests(hba);
 		goto out;
 	}
@@ -1202,12 +1204,15 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
 	return ret;
 }
 
-static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
+static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool scale_up)
 {
-	if (writelock)
-		up_write(&hba->clk_scaling_lock);
-	else
-		up_read(&hba->clk_scaling_lock);
+	up_write(&hba->clk_scaling_lock);
+
+	/* Enable Write Booster if we have scaled up else disable it */
+	ufshcd_wb_toggle(hba, scale_up);
+
+	mutex_unlock(&hba->wb_mutex);
+
 	ufshcd_scsi_unblock_requests(hba);
 	ufshcd_release(hba);
 }
@@ -1224,7 +1229,6 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
 static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
 {
 	int ret = 0;
-	bool is_writelock = true;
 
 	ret = ufshcd_clock_scaling_prepare(hba);
 	if (ret)
@@ -1253,13 +1257,8 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
 		}
 	}
 
-	/* Enable Write Booster if we have scaled up else disable it */
-	downgrade_write(&hba->clk_scaling_lock);
-	is_writelock = false;
-	ufshcd_wb_toggle(hba, scale_up);
-
 out_unprepare:
-	ufshcd_clock_scaling_unprepare(hba, is_writelock);
+	ufshcd_clock_scaling_unprepare(hba, ret, scale_up);
 	return ret;
 }
 
@@ -5919,9 +5918,11 @@ static void ufshcd_force_error_recovery(struct ufs_hba *hba)
 
 static void ufshcd_clk_scaling_allow(struct ufs_hba *hba, bool allow)
 {
+	mutex_lock(&hba->wb_mutex);
 	down_write(&hba->clk_scaling_lock);
 	hba->clk_scaling.is_allowed = allow;
 	up_write(&hba->clk_scaling_lock);
+	mutex_unlock(&hba->wb_mutex);
 }
 
 static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
@@ -9480,6 +9481,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 	/* Initialize mutex for exception event control */
 	mutex_init(&hba->ee_ctrl_mutex);
 
+	mutex_init(&hba->wb_mutex);
 	init_rwsem(&hba->clk_scaling_lock);
 
 	ufshcd_init_clk_gating(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d470a52ff24c..c8513cc6c2bd 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -763,6 +763,7 @@ struct ufs_hba_monitor {
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
  *  device is known or not.
+ * @wb_mutex: used to serialize devfreq and sysfs write booster toggling
  * @scsi_block_reqs_cnt: reference counting for scsi block requests
  * @crypto_capabilities: Content of crypto capabilities register (0x100)
  * @crypto_cap_array: Array of crypto capabilities
@@ -892,6 +893,7 @@ struct ufs_hba {
 	enum bkops_status urgent_bkops_lvl;
 	bool is_urgent_bkops_lvl_checked;
 
+	struct mutex wb_mutex;
 	struct rw_semaphore clk_scaling_lock;
 	unsigned char desc_size[QUERY_DESC_IDN_MAX];
 	atomic_t scsi_block_reqs_cnt;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux