summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq_stats.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2015-01-06 16:39:11 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-01-23 23:06:44 +0100
commita685c6d023c77303ca8700f37bf06eb85ffbf06a (patch)
treefc2cdcee6690d4ac5282423f9f3c1f98d9691d47 /drivers/cpufreq/cpufreq_stats.c
parentcpufreq: remove CPUFREQ_UPDATE_POLICY_CPU notifications (diff)
downloadlinux-a685c6d023c77303ca8700f37bf06eb85ffbf06a.tar.xz
linux-a685c6d023c77303ca8700f37bf06eb85ffbf06a.zip
cpufreq: stats: create sysfs group once we are ready
Userspace is free to read value of any file from cpufreq/stats directory once they are created. __cpufreq_stats_create_table() is creating the sysfs files first and then allocating resources for them. Though it would be quite difficult to trigger the racy situation here, but for the sake of keeping sensible code lets create sysfs entries only after we are ready to go. This also does some makeup to the routine to make it look better. Reviewed-by: Prarit Bhargava <prarit@redhat.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/cpufreq_stats.c')
-rw-r--r--drivers/cpufreq/cpufreq_stats.c44
1 files changed, 25 insertions, 19 deletions
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index e1fe0a945639..5d7bf9b1dfc5 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,12 +164,13 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
- unsigned int i, count = 0, ret = 0;
+ unsigned int i = 0, count = 0, ret = -ENOMEM;
struct cpufreq_stats *stats;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
struct cpufreq_frequency_table *pos, *table;
+ /* We need cpufreq table for creating stats table */
table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table))
return 0;
@@ -179,15 +180,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
return -EEXIST;
stats = kzalloc(sizeof(*stats), GFP_KERNEL);
- if ((stats) == NULL)
+ if (!stats)
return -ENOMEM;
- ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
- if (ret)
- goto error_out;
-
- policy->stats = stats;
-
+ /* Find total allocation size */
cpufreq_for_each_valid_entry(pos, table)
count++;
@@ -196,32 +192,42 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int);
#endif
- stats->max_state = count;
+
+ /* Allocate memory for time_in_state/freq_table/trans_table in one go */
stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
- if (!stats->time_in_state) {
- ret = -ENOMEM;
- goto error_alloc;
- }
+ if (!stats->time_in_state)
+ goto free_stat;
+
stats->freq_table = (unsigned int *)(stats->time_in_state + count);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stats->trans_table = stats->freq_table + count;
#endif
- i = 0;
+
+ stats->max_state = count;
+
+ /* Find valid-unique entries */
cpufreq_for_each_valid_entry(pos, table)
if (freq_table_get_index(stats, pos->frequency) == -1)
stats->freq_table[i++] = pos->frequency;
stats->state_num = i;
+
spin_lock(&cpufreq_stats_lock);
stats->last_time = get_jiffies_64();
stats->last_index = freq_table_get_index(stats, policy->cur);
spin_unlock(&cpufreq_stats_lock);
- return 0;
-error_alloc:
- sysfs_remove_group(&policy->kobj, &stats_attr_group);
-error_out:
- kfree(stats);
+
+ policy->stats = stats;
+ ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
+ if (!ret)
+ return 0;
+
+ /* We failed, release resources */
policy->stats = NULL;
+ kfree(stats->time_in_state);
+free_stat:
+ kfree(stats);
+
return ret;
}