Skip to content

Commit d9df61a

Browse files
Zhongqiu Hangregkh
authored andcommitted
scsi: ufs: core: Fix data race in CPU latency PM QoS request handling
[ Upstream commit 79dde5f ] The cpu_latency_qos_add/remove/update_request interfaces lack internal synchronization by design, requiring the caller to ensure thread safety. The current implementation relies on the 'pm_qos_enabled' flag, which is insufficient to prevent concurrent access and cannot serve as a proper synchronization mechanism. This has led to data races and list corruption issues. A typical race condition call trace is: [Thread A] ufshcd_pm_qos_exit() --> cpu_latency_qos_remove_request() --> cpu_latency_qos_apply(); --> pm_qos_update_target() --> plist_del <--(1) delete plist node --> memset(req, 0, sizeof(*req)); --> hba->pm_qos_enabled = false; [Thread B] ufshcd_devfreq_target --> ufshcd_devfreq_scale --> ufshcd_scale_clks --> ufshcd_pm_qos_update <--(2) pm_qos_enabled is true --> cpu_latency_qos_update_request --> pm_qos_update_target --> plist_del <--(3) plist node use-after-free Introduces a dedicated mutex to serialize PM QoS operations, preventing data races and ensuring safe access to PM QoS resources, including sysfs interface reads. Fixes: 2777e73 ("scsi: ufs: core: Add CPU latency QoS support for UFS driver") Signed-off-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Tested-by: Huan Tang <tanghuan@vivo.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 1898631 commit d9df61a

File tree

3 files changed

+14
-0
lines changed

3 files changed

+14
-0
lines changed

drivers/ufs/core/ufs-sysfs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ static ssize_t pm_qos_enable_show(struct device *dev,
512512
{
513513
struct ufs_hba *hba = dev_get_drvdata(dev);
514514

515+
guard(mutex)(&hba->pm_qos_mutex);
516+
515517
return sysfs_emit(buf, "%d\n", hba->pm_qos_enabled);
516518
}
517519

drivers/ufs/core/ufshcd.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,7 @@ EXPORT_SYMBOL_GPL(ufshcd_is_hba_active);
10451045
*/
10461046
void ufshcd_pm_qos_init(struct ufs_hba *hba)
10471047
{
1048+
guard(mutex)(&hba->pm_qos_mutex);
10481049

10491050
if (hba->pm_qos_enabled)
10501051
return;
@@ -1061,6 +1062,8 @@ void ufshcd_pm_qos_init(struct ufs_hba *hba)
10611062
*/
10621063
void ufshcd_pm_qos_exit(struct ufs_hba *hba)
10631064
{
1065+
guard(mutex)(&hba->pm_qos_mutex);
1066+
10641067
if (!hba->pm_qos_enabled)
10651068
return;
10661069

@@ -1075,6 +1078,8 @@ void ufshcd_pm_qos_exit(struct ufs_hba *hba)
10751078
*/
10761079
static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
10771080
{
1081+
guard(mutex)(&hba->pm_qos_mutex);
1082+
10781083
if (!hba->pm_qos_enabled)
10791084
return;
10801085

@@ -10756,6 +10761,10 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1075610761
mutex_init(&hba->ee_ctrl_mutex);
1075710762

1075810763
mutex_init(&hba->wb_mutex);
10764+
10765+
/* Initialize mutex for PM QoS request synchronization */
10766+
mutex_init(&hba->pm_qos_mutex);
10767+
1075910768
init_rwsem(&hba->clk_scaling_lock);
1076010769

1076110770
ufshcd_init_clk_gating(hba);

include/ufs/ufshcd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ enum ufshcd_mcq_opr {
963963
* @ufs_rtc_update_work: A work for UFS RTC periodic update
964964
* @pm_qos_req: PM QoS request handle
965965
* @pm_qos_enabled: flag to check if pm qos is enabled
966+
* @pm_qos_mutex: synchronizes PM QoS request and status updates
966967
* @critical_health_count: count of critical health exceptions
967968
* @dev_lvl_exception_count: count of device level exceptions since last reset
968969
* @dev_lvl_exception_id: vendor specific information about the
@@ -1136,6 +1137,8 @@ struct ufs_hba {
11361137
struct delayed_work ufs_rtc_update_work;
11371138
struct pm_qos_request pm_qos_req;
11381139
bool pm_qos_enabled;
1140+
/* synchronizes PM QoS request and status updates */
1141+
struct mutex pm_qos_mutex;
11391142

11401143
int critical_health_count;
11411144
atomic_t dev_lvl_exception_count;

0 commit comments

Comments
 (0)