Skip to content

Commit 79dde5f

Browse files
Zhongqiu Hanmartinkpetersen
authored andcommitted
scsi: ufs: core: Fix data race in CPU latency PM QoS request handling
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 <[email protected]> Reviewed-by: Bart Van Assche <[email protected]> Tested-by: Huan Tang <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 072fdd4 commit 79dde5f

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

@@ -10743,6 +10748,10 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1074310748
mutex_init(&hba->ee_ctrl_mutex);
1074410749

1074510750
mutex_init(&hba->wb_mutex);
10751+
10752+
/* Initialize mutex for PM QoS request synchronization */
10753+
mutex_init(&hba->pm_qos_mutex);
10754+
1074610755
init_rwsem(&hba->clk_scaling_lock);
1074710756

1074810757
ufshcd_init_clk_gating(hba);

include/ufs/ufshcd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,7 @@ enum ufshcd_mcq_opr {
938938
* @ufs_rtc_update_work: A work for UFS RTC periodic update
939939
* @pm_qos_req: PM QoS request handle
940940
* @pm_qos_enabled: flag to check if pm qos is enabled
941+
* @pm_qos_mutex: synchronizes PM QoS request and status updates
941942
* @critical_health_count: count of critical health exceptions
942943
* @dev_lvl_exception_count: count of device level exceptions since last reset
943944
* @dev_lvl_exception_id: vendor specific information about the
@@ -1110,6 +1111,8 @@ struct ufs_hba {
11101111
struct delayed_work ufs_rtc_update_work;
11111112
struct pm_qos_request pm_qos_req;
11121113
bool pm_qos_enabled;
1114+
/* synchronizes PM QoS request and status updates */
1115+
struct mutex pm_qos_mutex;
11131116

11141117
int critical_health_count;
11151118
atomic_t dev_lvl_exception_count;

0 commit comments

Comments
 (0)