summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2018-03-23 17:58:17 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-03-27 06:01:47 -0400
commit07cde313b2d21f728cec2836db7cdb55476f7a26 (patch)
tree88e450ffab9354ddc069700898fb9d7d21c192b3
parent13cc36d76bc4f5a9801ae32630bc8240ba0cc522 (diff)
x86/msr: Allow rdmsr_safe_on_cpu() to schedule
High latencies can be observed caused by a daemon periodically reading various MSR on all cpus. On KASAN enabled kernels ~10ms latencies can be observed simply reading one MSR. Even without KASAN, sending an IPI to a CPU, which is in a deep sleep state or in a long hard IRQ disabled section, waiting for the answer can consume hundreds of microseconds. All usage sites are in preemptible context, convert rdmsr_safe_on_cpu() to use a completion instead of busy polling. Overall daemon cpu usage was reduced by 35 %, and latencies caused by msr_read() disappeared. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ingo Molnar <mingo@kernel.org> Cc: Hugh Dickins <hughd@google.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Eric Dumazet <eric.dumazet@gmail.com> Link: https://lkml.kernel.org/r/20180323215818.127774-1-edumazet@google.com
-rw-r--r--arch/x86/lib/msr-smp.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c
index 693cce0be82d..761ba062afda 100644
--- a/arch/x86/lib/msr-smp.c
+++ b/arch/x86/lib/msr-smp.c
@@ -2,6 +2,7 @@
2#include <linux/export.h> 2#include <linux/export.h>
3#include <linux/preempt.h> 3#include <linux/preempt.h>
4#include <linux/smp.h> 4#include <linux/smp.h>
5#include <linux/completion.h>
5#include <asm/msr.h> 6#include <asm/msr.h>
6 7
7static void __rdmsr_on_cpu(void *info) 8static void __rdmsr_on_cpu(void *info)
@@ -143,13 +144,19 @@ void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
143} 144}
144EXPORT_SYMBOL(wrmsr_on_cpus); 145EXPORT_SYMBOL(wrmsr_on_cpus);
145 146
147struct msr_info_completion {
148 struct msr_info msr;
149 struct completion done;
150};
151
146/* These "safe" variants are slower and should be used when the target MSR 152/* These "safe" variants are slower and should be used when the target MSR
147 may not actually exist. */ 153 may not actually exist. */
148static void __rdmsr_safe_on_cpu(void *info) 154static void __rdmsr_safe_on_cpu(void *info)
149{ 155{
150 struct msr_info *rv = info; 156 struct msr_info_completion *rv = info;
151 157
152 rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); 158 rv->msr.err = rdmsr_safe(rv->msr.msr_no, &rv->msr.reg.l, &rv->msr.reg.h);
159 complete(&rv->done);
153} 160}
154 161
155static void __wrmsr_safe_on_cpu(void *info) 162static void __wrmsr_safe_on_cpu(void *info)
@@ -161,17 +168,26 @@ static void __wrmsr_safe_on_cpu(void *info)
161 168
162int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) 169int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
163{ 170{
171 struct msr_info_completion rv;
172 call_single_data_t csd = {
173 .func = __rdmsr_safe_on_cpu,
174 .info = &rv,
175 };
164 int err; 176 int err;
165 struct msr_info rv;
166 177
167 memset(&rv, 0, sizeof(rv)); 178 memset(&rv, 0, sizeof(rv));
179 init_completion(&rv.done);
180 rv.msr.msr_no = msr_no;
168 181
169 rv.msr_no = msr_no; 182 err = smp_call_function_single_async(cpu, &csd);
170 err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); 183 if (!err) {
171 *l = rv.reg.l; 184 wait_for_completion(&rv.done);
172 *h = rv.reg.h; 185 err = rv.msr.err;
186 }
187 *l = rv.msr.reg.l;
188 *h = rv.msr.reg.h;
173 189
174 return err ? err : rv.err; 190 return err;
175} 191}
176EXPORT_SYMBOL(rdmsr_safe_on_cpu); 192EXPORT_SYMBOL(rdmsr_safe_on_cpu);
177 193