summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Boonstoppel <pboonstoppel@nvidia.com>2012-03-01 16:04:27 -0800
committerSimone Willett <swillett@nvidia.com>2012-07-16 20:13:37 -0700
commit8c813763e8fe5928cbd7babbee4d5080ba4bb9d5 (patch)
treea0071c76302ed14774bd313888ee4105f8348621
parente6e9afa497611669b26b805302ec5642a18a57a6 (diff)
cpufreq: protect cpufreq_stats_free_table with spinlock
Prevents crash on cpufreq_stat_notifier_trans when cpufreq_stats_table has been freed due to a core being hotplugged out. Bug 948348 Change-Id: I2640a9a23c9a79cad8c76bfefd243a07162d2004 Signed-off-by: Peter Boonstoppel <pboonstoppel@nvidia.com> (cherry picked from commit 03070a4b0b8eb74825c99c6bbfb108ddb36a041c) Reviewed-on: http://git-master/r/114248 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--drivers/cpufreq/cpufreq_stats.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 1957eee7549e..d0344284a7d8 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -59,6 +59,11 @@ static int cpufreq_stats_update(unsigned int cpu)
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, cpu);
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
+ return 0;
+ }
+
if (stat->time_in_state && stat->last_index >= 0)
stat->time_in_state[stat->last_index] =
cputime64_add(stat->time_in_state[stat->last_index],
@@ -170,12 +175,17 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
*/
static void cpufreq_stats_free_table(unsigned int cpu)
{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+ struct cpufreq_stats *stat;
+
+ spin_lock(&cpufreq_stats_lock);
+ stat = per_cpu(cpufreq_stats_table, cpu);
+ per_cpu(cpufreq_stats_table, cpu) = NULL;
+ spin_unlock(&cpufreq_stats_lock);
+
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
- per_cpu(cpufreq_stats_table, cpu) = NULL;
}
/* must be called early in the CPU removal sequence (before
@@ -299,19 +309,23 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
if (val != CPUFREQ_POSTCHANGE)
return 0;
+ cpufreq_stats_update(freq->cpu);
+
+ spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, freq->cpu);
- if (!stat)
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
- cpufreq_stats_update(freq->cpu);
-
- if (old_index == new_index)
+ if (old_index == new_index) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
- spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
if (old_index >= 0 && new_index >= 0)