Commit 98586ed8 authored by steven finney's avatar steven finney Committed by Dave Jones

[CPUFREQ] Fix memory leak in cpufreq_stat

When a CPU is taken offline in an SMP system, cpufreq_remove_dev()
nulls out the per-cpu policy before cpufreq_stats_free_table() can
make use of it.  cpufreq_stats_free_table() then skips the
call to sysfs_remove_group(), leaving about 100 bytes of sysfs-related
memory unclaimed each time a CPU-removal occurs. Break up
cpu_stats_free_table into sysfs and table portions, and
call the sysfs portion early.
Signed-off-by: default avatarSteven Finney <steven.finney@palm.com>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
Cc: stable@kernel.org
parent 335dc333
...@@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) ...@@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1; return -1;
} }
/* should be called late in the CPU removal sequence so that the stats
* memory is still available in case someone tries to use it.
*/
static void cpufreq_stats_free_table(unsigned int cpu) static void cpufreq_stats_free_table(unsigned int cpu)
{ {
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
if (policy && policy->cpu == cpu)
sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (stat) { if (stat) {
kfree(stat->time_in_state); kfree(stat->time_in_state);
kfree(stat); kfree(stat);
} }
per_cpu(cpufreq_stats_table, cpu) = NULL; per_cpu(cpufreq_stats_table, cpu) = NULL;
}
/* must be called early in the CPU removal sequence (before
* cpufreq_remove_dev) so that policy is still valid.
*/
static void cpufreq_stats_free_sysfs(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
if (policy && policy->cpu == cpu)
sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (policy) if (policy)
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
} }
...@@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, ...@@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
case CPU_ONLINE_FROZEN: case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu); cpufreq_update_policy(cpu);
break; break;
case CPU_DOWN_PREPARE:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD: case CPU_DEAD:
case CPU_DEAD_FROZEN: case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu); cpufreq_stats_free_table(cpu);
...@@ -324,9 +337,11 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, ...@@ -324,9 +337,11 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK; return NOTIFY_OK;
} }
/* priority=1 so this will get called before cpufreq_remove_dev */
static struct notifier_block cpufreq_stat_cpu_notifier __refdata = static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
{ {
.notifier_call = cpufreq_stat_cpu_callback, .notifier_call = cpufreq_stat_cpu_callback,
.priority = 1,
}; };
static struct notifier_block notifier_policy_block = { static struct notifier_block notifier_policy_block = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment