Skip to content

Commit efad424

Browse files
committed
cpufreq: stats: Add memory barrier to store_reset()
There is nothing to prevent the CPU or the compiler from reordering the writes to stats->reset_time and stats->reset_pending in store_reset(), in which case the readers of stats->reset_time may see a stale value. Moreover, on 32-bit arches the write to reset_time cannot be completed in one go, so the readers of it may see a partially updated value in that case. To prevent that from happening, add a write memory barrier between the writes to stats->reset_time and stats->reset_pending in store_reset() and corresponding read memory barrier in the readers of stats->reset_time. Fixes: 40c3bd4 ("cpufreq: stats: Defer stats update to cpufreq_stats_record_transition()") Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
1 parent 86836ba commit efad424

1 file changed

Lines changed: 18 additions & 2 deletions

File tree

drivers/cpufreq/cpufreq_stats.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ static void cpufreq_stats_reset_table(struct cpufreq_stats *stats)
4747

4848
/* Adjust for the time elapsed since reset was requested */
4949
WRITE_ONCE(stats->reset_pending, 0);
50+
/*
51+
* Prevent the reset_time read from being reordered before the
52+
* reset_pending accesses in cpufreq_stats_record_transition().
53+
*/
54+
smp_rmb();
5055
cpufreq_stats_update(stats, READ_ONCE(stats->reset_time));
5156
}
5257

@@ -71,10 +76,16 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
7176

7277
for (i = 0; i < stats->state_num; i++) {
7378
if (pending) {
74-
if (i == stats->last_index)
79+
if (i == stats->last_index) {
80+
/*
81+
* Prevent the reset_time read from occurring
82+
* before the reset_pending read above.
83+
*/
84+
smp_rmb();
7585
time = get_jiffies_64() - READ_ONCE(stats->reset_time);
76-
else
86+
} else {
7787
time = 0;
88+
}
7889
} else {
7990
time = stats->time_in_state[i];
8091
if (i == stats->last_index)
@@ -99,6 +110,11 @@ static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
99110
* avoid races.
100111
*/
101112
WRITE_ONCE(stats->reset_time, get_jiffies_64());
113+
/*
114+
* The memory barrier below is to prevent the readers of reset_time from
115+
* seeing a stale or partially updated value.
116+
*/
117+
smp_wmb();
102118
WRITE_ONCE(stats->reset_pending, 1);
103119

104120
return count;

0 commit comments

Comments
 (0)