diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-11-12 20:15:39 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-13 22:42:39 -0500 |
| commit | b29c6ef7bb1257853c1e31616d84f55e561cf631 (patch) | |
| tree | dd055a870644df922f4274fdd093b37240268f4f | |
| parent | 99306dfc067e6098365d395168b6fd5db3095292 (diff) | |
x86 / CPU: Avoid unnecessary IPIs in arch_freq_get_on_cpu()
Even though aperfmperf_snapshot_khz() caches the samples.khz value to
return if called again in a sufficiently short time, its caller,
arch_freq_get_on_cpu(), still uses smp_call_function_single() to run it
which may allow user space to trigger an IPI storm by reading from the
scaling_cur_freq cpufreq sysfs file in a tight loop.
To avoid that, move the decision on whether or not to return the cached
samples.khz value to arch_freq_get_on_cpu().
This change was part of commit 941f5f0f6ef5 ("x86: CPU: Fix up "cpu MHz"
in /proc/cpuinfo"), but it was not the reason for the revert and it
remains applicable.
Fixes: 4815d3c56d1e (cpufreq: x86: Make scaling_cur_freq behave more as expected)
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: WANG Chao <chao.wang@ucloud.cn>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/kernel/cpu/aperfmperf.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c index 0ee83321a313..957813e0180d 100644 --- a/arch/x86/kernel/cpu/aperfmperf.c +++ b/arch/x86/kernel/cpu/aperfmperf.c | |||
| @@ -42,10 +42,6 @@ static void aperfmperf_snapshot_khz(void *dummy) | |||
| 42 | s64 time_delta = ktime_ms_delta(now, s->time); | 42 | s64 time_delta = ktime_ms_delta(now, s->time); |
| 43 | unsigned long flags; | 43 | unsigned long flags; |
| 44 | 44 | ||
| 45 | /* Don't bother re-computing within the cache threshold time. */ | ||
| 46 | if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS) | ||
| 47 | return; | ||
| 48 | |||
| 49 | local_irq_save(flags); | 45 | local_irq_save(flags); |
| 50 | rdmsrl(MSR_IA32_APERF, aperf); | 46 | rdmsrl(MSR_IA32_APERF, aperf); |
| 51 | rdmsrl(MSR_IA32_MPERF, mperf); | 47 | rdmsrl(MSR_IA32_MPERF, mperf); |
| @@ -74,6 +70,7 @@ static void aperfmperf_snapshot_khz(void *dummy) | |||
| 74 | 70 | ||
| 75 | unsigned int arch_freq_get_on_cpu(int cpu) | 71 | unsigned int arch_freq_get_on_cpu(int cpu) |
| 76 | { | 72 | { |
| 73 | s64 time_delta; | ||
| 77 | unsigned int khz; | 74 | unsigned int khz; |
| 78 | 75 | ||
| 79 | if (!cpu_khz) | 76 | if (!cpu_khz) |
| @@ -82,6 +79,12 @@ unsigned int arch_freq_get_on_cpu(int cpu) | |||
| 82 | if (!static_cpu_has(X86_FEATURE_APERFMPERF)) | 79 | if (!static_cpu_has(X86_FEATURE_APERFMPERF)) |
| 83 | return 0; | 80 | return 0; |
| 84 | 81 | ||
| 82 | /* Don't bother re-computing within the cache threshold time. */ | ||
| 83 | time_delta = ktime_ms_delta(ktime_get(), per_cpu(samples.time, cpu)); | ||
| 84 | khz = per_cpu(samples.khz, cpu); | ||
| 85 | if (khz && time_delta < APERFMPERF_CACHE_THRESHOLD_MS) | ||
| 86 | return khz; | ||
| 87 | |||
| 85 | smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); | 88 | smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); |
| 86 | khz = per_cpu(samples.khz, cpu); | 89 | khz = per_cpu(samples.khz, cpu); |
| 87 | if (khz) | 90 | if (khz) |
