From: Michael Ellerman <mpe@xxxxxxxxxxxxxx> This patch adds kvm_cpu__run_on_all_cpus() to run a task on each vCPU. This infrastructure uses signals to signal the vCPU to allow a task to be added to each vCPU's task. The vCPU executes any pending tasks in the cpu run loop Signed-off-by: Balbir Singh <bsingharora@xxxxxxxxx> Signed-off-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx> --- arm/include/arm-common/kvm-cpu-arch.h | 1 + include/kvm/kvm-cpu.h | 6 +++ include/kvm/kvm.h | 1 + kvm-cpu.c | 73 +++++++++++++++++++++++++++++++++++ mips/include/kvm/kvm-cpu-arch.h | 1 + powerpc/include/kvm/kvm-cpu-arch.h | 1 + x86/include/kvm/kvm-cpu-arch.h | 1 + 7 files changed, 84 insertions(+) diff --git a/arm/include/arm-common/kvm-cpu-arch.h b/arm/include/arm-common/kvm-cpu-arch.h index 329979a..8a6a6e7 100644 --- a/arm/include/arm-common/kvm-cpu-arch.h +++ b/arm/include/arm-common/kvm-cpu-arch.h @@ -17,6 +17,7 @@ struct kvm_cpu { struct kvm *kvm; int vcpu_fd; struct kvm_run *kvm_run; + struct kvm_cpu_task *task; u8 is_running; u8 paused; diff --git a/include/kvm/kvm-cpu.h b/include/kvm/kvm-cpu.h index aa0cb54..4481096 100644 --- a/include/kvm/kvm-cpu.h +++ b/include/kvm/kvm-cpu.h @@ -4,6 +4,11 @@ #include "kvm/kvm-cpu-arch.h" #include <stdbool.h> +struct kvm_cpu_task { + void (*func)(struct kvm_cpu *vcpu, void *data); + void *data; +}; + int kvm_cpu__init(struct kvm *kvm); int kvm_cpu__exit(struct kvm *kvm); struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id); @@ -23,5 +28,6 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu); void kvm_cpu__show_registers(struct kvm_cpu *vcpu); void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu); void kvm_cpu__arch_nmi(struct kvm_cpu *cpu); +void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task); #endif /* KVM__KVM_CPU_H */ diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index 37155db..731abee 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -15,6 +15,7 @@ #define SIGKVMEXIT (SIGRTMIN + 0) #define SIGKVMPAUSE (SIGRTMIN + 1) +#define SIGKVMTASK (SIGRTMIN + 2) #define KVM_PID_FILE_PATH "/.lkvm/" #define HOME_DIR getenv("HOME") diff --git a/kvm-cpu.c b/kvm-cpu.c index ad4441b..4b202f8 100644 --- a/kvm-cpu.c +++ b/kvm-cpu.c @@ -4,9 +4,12 @@ #include "kvm/util.h" #include "kvm/kvm.h" #include "kvm/virtio.h" +#include "kvm/mutex.h" +#include "kvm/barrier.h" #include <sys/ioctl.h> #include <sys/mman.h> +#include <sys/eventfd.h> #include <signal.h> #include <stdlib.h> #include <string.h> @@ -52,6 +55,8 @@ static void kvm_cpu_signal_handler(int signum) } else if (signum == SIGKVMPAUSE) { current_kvm_cpu->paused = 1; } + + /* For SIGKVMTASK cpu->task is already set */ } static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu) @@ -83,6 +88,62 @@ void kvm_cpu__reboot(struct kvm *kvm) } } +static DEFINE_MUTEX(task_lock); +static int task_eventfd; + +static void kvm_cpu__run_task(struct kvm_cpu *cpu) +{ + u64 inc = 1; + + pr_debug("Running task %p on cpu %lu", cpu->task, cpu->cpu_id); + + /* Make sure we see the store to cpu->task */ + rmb(); + cpu->task->func(cpu, cpu->task->data); + + /* Clear task before we signal completion */ + cpu->task = NULL; + wmb(); + + if (write(task_eventfd, &inc, sizeof(inc)) < 0) + die("Failed notifying of completed task."); +} + +void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task) +{ + int i, done = 0; + + pr_debug("Running task %p on all cpus", task); + + mutex_lock(&task_lock); + + for (i = 0; i < kvm->nrcpus; i++) { + if (kvm->cpus[i]->task) { + /* Should never happen */ + die("CPU %d already has a task pending!", i); + } + + kvm->cpus[i]->task = task; + wmb(); + + if (kvm->cpus[i] == current_kvm_cpu) + kvm_cpu__run_task(current_kvm_cpu); + else + pthread_kill(kvm->cpus[i]->thread, SIGKVMTASK); + } + + while (done < kvm->nrcpus) { + u64 count; + + if (read(task_eventfd, &count, sizeof(count)) < 0) + die("Failed reading task eventfd"); + + done += count; + } + + mutex_unlock(&task_lock); +} + int kvm_cpu__start(struct kvm_cpu *cpu) { sigset_t sigset; @@ -94,6 +155,7 @@ int kvm_cpu__start(struct kvm_cpu *cpu) signal(SIGKVMEXIT, kvm_cpu_signal_handler); signal(SIGKVMPAUSE, kvm_cpu_signal_handler); + signal(SIGKVMTASK, kvm_cpu_signal_handler); kvm_cpu__reset_vcpu(cpu); @@ -111,6 +173,9 @@ int kvm_cpu__start(struct kvm_cpu *cpu) cpu->needs_nmi = 0; } + if (cpu->task) + kvm_cpu__run_task(cpu); + kvm_cpu__run(cpu); switch (cpu->kvm_run->exit_reason) { @@ -217,6 +282,12 @@ int kvm_cpu__init(struct kvm *kvm) kvm->nrcpus = kvm->cfg.nrcpus; + task_eventfd = eventfd(0, 0); + if (task_eventfd < 0) { + pr_warning("Couldn't create task_eventfd"); + return task_eventfd; + } + /* Alloc one pointer too many, so array ends up 0-terminated */ kvm->cpus = calloc(kvm->nrcpus + 1, sizeof(void *)); if (!kvm->cpus) { @@ -264,6 +335,8 @@ int kvm_cpu__exit(struct kvm *kvm) kvm->nrcpus = 0; + close(task_eventfd); + return r; } core_exit(kvm_cpu__exit); diff --git a/mips/include/kvm/kvm-cpu-arch.h b/mips/include/kvm/kvm-cpu-arch.h index 3db7f2b..45e69f6 100644 --- a/mips/include/kvm/kvm-cpu-arch.h +++ b/mips/include/kvm/kvm-cpu-arch.h @@ -15,6 +15,7 @@ struct kvm_cpu { struct kvm *kvm; /* parent KVM */ int vcpu_fd; /* For VCPU ioctls() */ struct kvm_run *kvm_run; + struct kvm_cpu_task *task; struct kvm_regs regs; diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h index 01eafdf..f2bfbb5 100644 --- a/powerpc/include/kvm/kvm-cpu-arch.h +++ b/powerpc/include/kvm/kvm-cpu-arch.h @@ -48,6 +48,7 @@ struct kvm_cpu { struct kvm *kvm; /* parent KVM */ int vcpu_fd; /* For VCPU ioctls() */ struct kvm_run *kvm_run; + struct kvm_cpu_task *task; struct kvm_regs regs; struct kvm_sregs sregs; diff --git a/x86/include/kvm/kvm-cpu-arch.h b/x86/include/kvm/kvm-cpu-arch.h index 89c8059..05e5bb6 100644 --- a/x86/include/kvm/kvm-cpu-arch.h +++ b/x86/include/kvm/kvm-cpu-arch.h @@ -18,6 +18,7 @@ struct kvm_cpu { struct kvm *kvm; /* parent KVM */ int vcpu_fd; /* For VCPU ioctls() */ struct kvm_run *kvm_run; + struct kvm_cpu_task *task; struct kvm_regs regs; struct kvm_sregs sregs; -- 2.5.5 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html