lkml.org 
[lkml]   [2018]   [Mar]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 2/2] x86, cpuid: allow cpuid_read() to schedule
    Date
    I noticed high latencies caused by a daemon periodically reading various
    MSR and cpuid on all cpus. KASAN kernels would see ~10ms latencies
    simply reading one cpuid. Even without KASAN, sending IPI to CPU
    in deep sleep state or blocking hard IRQ in a a long section,
    then waiting for the answer can consume hundreds of usec or more.

    Switching to smp_call_function_single_async() and a completion
    allows to reschedule and not burn cpu cycles.

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Borislav Petkov <bp@alien8.de>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Hugh Dickins <hughd@google.com>
    ---
    arch/x86/kernel/cpuid.c | 34 ++++++++++++++++++++++++++--------
    1 file changed, 26 insertions(+), 8 deletions(-)

    diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
    index 0931a105ffe16cde4640e759efa600b23a756d84..1d300f96df4b316dbe3392c8221467cfd8593272 100644
    --- a/arch/x86/kernel/cpuid.c
    +++ b/arch/x86/kernel/cpuid.c
    @@ -40,6 +40,7 @@
    #include <linux/notifier.h>
    #include <linux/uaccess.h>
    #include <linux/gfp.h>
    +#include <linux/completion.h>

    #include <asm/processor.h>
    #include <asm/msr.h>
    @@ -47,19 +48,27 @@
    static struct class *cpuid_class;
    static enum cpuhp_state cpuhp_cpuid_state;

    +struct cpuid_regs_done {
    + struct cpuid_regs regs;
    + struct completion done;
    +};
    +
    static void cpuid_smp_cpuid(void *cmd_block)
    {
    - struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block;
    + struct cpuid_regs_done *cmd = cmd_block;
    +
    + cpuid_count(cmd->regs.eax, cmd->regs.ecx,
    + &cmd->regs.eax, &cmd->regs.ebx,
    + &cmd->regs.ecx, &cmd->regs.edx);

    - cpuid_count(cmd->eax, cmd->ecx,
    - &cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
    + complete(&cmd->done);
    }

    static ssize_t cpuid_read(struct file *file, char __user *buf,
    size_t count, loff_t *ppos)
    {
    char __user *tmp = buf;
    - struct cpuid_regs cmd;
    + struct cpuid_regs_done cmd;
    int cpu = iminor(file_inode(file));
    u64 pos = *ppos;
    ssize_t bytes = 0;
    @@ -68,19 +77,28 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
    if (count % 16)
    return -EINVAL; /* Invalid chunk size */

    + init_completion(&cmd.done);
    for (; count; count -= 16) {
    - cmd.eax = pos;
    - cmd.ecx = pos >> 32;
    - err = smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1);
    + call_single_data_t csd = {
    + .func = cpuid_smp_cpuid,
    + .info = &cmd,
    + };
    +
    + cmd.regs.eax = pos;
    + cmd.regs.ecx = pos >> 32;
    +
    + err = smp_call_function_single_async(cpu, &csd);
    if (err)
    break;
    - if (copy_to_user(tmp, &cmd, 16)) {
    + wait_for_completion(&cmd.done);
    + if (copy_to_user(tmp, &cmd.regs, 16)) {
    err = -EFAULT;
    break;
    }
    tmp += 16;
    bytes += 16;
    *ppos = ++pos;
    + reinit_completion(&cmd.done);
    }

    return bytes ? bytes : err;
    --
    2.17.0.rc0.231.g781580f067-goog
    \
     
     \ /
      Last update: 2018-03-23 23:00    [W:4.571 / U:0.284 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site