diff options
author | Peter Boonstoppel <pboonstoppel@nvidia.com> | 2012-03-01 16:04:27 -0800 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-07-16 20:13:37 -0700 |
commit | 8c813763e8fe5928cbd7babbee4d5080ba4bb9d5 (patch) | |
tree | a0071c76302ed14774bd313888ee4105f8348621 /drivers/cpufreq/cpufreq_stats.c | |
parent | e6e9afa497611669b26b805302ec5642a18a57a6 (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>
Diffstat (limited to 'drivers/cpufreq/cpufreq_stats.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 28 |
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) |