diff options
| author | Viresh Kumar <viresh.kumar@linaro.org> | 2013-09-12 07:36:33 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-17 18:01:27 -0400 |
| commit | 9c8f1ee40b6368e6b2775c9c9f816e2a5dca3c07 (patch) | |
| tree | 40ecbfa5c590cb9b04f13ec9f62ac6a209233834 | |
| parent | 272b98c6455f00884f0350f775c5342358ebb73f (diff) | |
cpufreq: Clear policy->cpus bits in __cpufreq_remove_dev_finish()
This broke after a recent change "cedb70a cpufreq: Split __cpufreq_remove_dev()
into two parts" from Srivatsa.
Consider a scenario where we have two CPUs in a policy (0 & 1) and we are
removing CPU 1. On the call to __cpufreq_remove_dev_prepare() we have cleared 1
from policy->cpus and now on a call to __cpufreq_remove_dev_finish() we read
cpumask_weight of policy->cpus, which will come as 1 and this code will behave
as if we are removing the last CPU from policy :)
Fix it by clearing the CPU mask in __cpufreq_remove_dev_finish() instead of
__cpufreq_remove_dev_prepare().
Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Reviewed-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 43c24aa756f6..dbfe219667d3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -1125,7 +1125,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, | |||
| 1125 | int ret; | 1125 | int ret; |
| 1126 | 1126 | ||
| 1127 | /* first sibling now owns the new sysfs dir */ | 1127 | /* first sibling now owns the new sysfs dir */ |
| 1128 | cpu_dev = get_cpu_device(cpumask_first(policy->cpus)); | 1128 | cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); |
| 1129 | 1129 | ||
| 1130 | /* Don't touch sysfs files during light-weight tear-down */ | 1130 | /* Don't touch sysfs files during light-weight tear-down */ |
| 1131 | if (frozen) | 1131 | if (frozen) |
| @@ -1189,12 +1189,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
| 1189 | policy->governor->name, CPUFREQ_NAME_LEN); | 1189 | policy->governor->name, CPUFREQ_NAME_LEN); |
| 1190 | #endif | 1190 | #endif |
| 1191 | 1191 | ||
| 1192 | WARN_ON(lock_policy_rwsem_write(cpu)); | 1192 | lock_policy_rwsem_read(cpu); |
| 1193 | cpus = cpumask_weight(policy->cpus); | 1193 | cpus = cpumask_weight(policy->cpus); |
| 1194 | 1194 | unlock_policy_rwsem_read(cpu); | |
| 1195 | if (cpus > 1) | ||
| 1196 | cpumask_clear_cpu(cpu, policy->cpus); | ||
| 1197 | unlock_policy_rwsem_write(cpu); | ||
| 1198 | 1195 | ||
| 1199 | if (cpu != policy->cpu) { | 1196 | if (cpu != policy->cpu) { |
| 1200 | if (!frozen) | 1197 | if (!frozen) |
| @@ -1237,9 +1234,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev, | |||
| 1237 | return -EINVAL; | 1234 | return -EINVAL; |
| 1238 | } | 1235 | } |
| 1239 | 1236 | ||
| 1240 | lock_policy_rwsem_read(cpu); | 1237 | WARN_ON(lock_policy_rwsem_write(cpu)); |
| 1241 | cpus = cpumask_weight(policy->cpus); | 1238 | cpus = cpumask_weight(policy->cpus); |
| 1242 | unlock_policy_rwsem_read(cpu); | 1239 | |
| 1240 | if (cpus > 1) | ||
| 1241 | cpumask_clear_cpu(cpu, policy->cpus); | ||
| 1242 | unlock_policy_rwsem_write(cpu); | ||
| 1243 | 1243 | ||
| 1244 | /* If cpu is last user of policy, free policy */ | 1244 | /* If cpu is last user of policy, free policy */ |
| 1245 | if (cpus == 1) { | 1245 | if (cpus == 1) { |
