6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liao Chang liaochang1@huawei.com
[ Upstream commit 61bfbf7951ba561dcbdd5357702d3cbc2d447812 ]
The field 'transition_task' of policy structure is used to track the task which is performing the frequency transition. Using this field to print a warning once detect a case where the same task is calling _begin() again before completing the preivous frequency transition via the _end().
However, there is a potential race condition in _end() and _begin() APIs while updating the field 'transition_task' of policy, the scenario is depicted below:
Task A Task B
/* 1st freq transition */ Invoke _begin() { ... ... } /* 2nd freq transition */ Invoke _begin() { ... //waiting for A to ... //clear ... //transition_ongoing ... //in _end() for ... //the 1st transition | Change the frequency | | Invoke _end() { | ... | ... | transition_ongoing = false; V transition_ongoing = true; transition_task = current; transition_task = NULL; ... //A overwrites the task ... //performing the transition ... //result in error warning. }
To fix this race condition, the transition_lock of policy structure is now acquired before updating policy structure in _end() API. Which ensure that only one task can update the 'transition_task' field at a time.
Link: https://lore.kernel.org/all/b3c61d8a-d52d-3136-fbf0-d1de9f1ba411@huawei.com/ Fixes: ca654dc3a93d ("cpufreq: Catch double invocations of cpufreq_freq_transition_begin/end") Signed-off-by: Liao Chang liaochang1@huawei.com Acked-by: Viresh Kumar viresh.kumar@linaro.org Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/cpufreq/cpufreq.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 285ba51b31f60..c8912756fc06d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -450,8 +450,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, policy->cur, policy->cpuinfo.max_freq);
+ spin_lock(&policy->transition_lock); policy->transition_ongoing = false; policy->transition_task = NULL; + spin_unlock(&policy->transition_lock);
wake_up(&policy->transition_wait); }