aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-02-12 03:54:47 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 12:48:41 -0500
commit774c47f1d78e373a6bd2964f4e278d1ce26c21cb (patch)
tree665fe9939425d7b4a16b97241e784f4183bd9558
parent8d0be2b3bf4a55606967d7d84e56c52521e94333 (diff)
[PATCH] KVM: cpu hotplug support
On hotplug, we execute the hardware extension enable sequence. On unplug, we decache any vcpus that last ran on the exiting cpu, and execute the hardware extension disable sequence. Signed-off-by: Avi Kivity <avi@qumranet.com> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/kvm/kvm.h1
-rw-r--r--drivers/kvm/kvm_main.c64
-rw-r--r--drivers/kvm/svm.c5
-rw-r--r--drivers/kvm/vmx.c8
4 files changed, 77 insertions, 1 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index c48cebf8511d..04574a9d4430 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -341,6 +341,7 @@ struct kvm_arch_ops {
341 341
342 struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu); 342 struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
343 void (*vcpu_put)(struct kvm_vcpu *vcpu); 343 void (*vcpu_put)(struct kvm_vcpu *vcpu);
344 void (*vcpu_decache)(struct kvm_vcpu *vcpu);
344 345
345 int (*set_guest_debug)(struct kvm_vcpu *vcpu, 346 int (*set_guest_debug)(struct kvm_vcpu *vcpu,
346 struct kvm_debug_guest *dbg); 347 struct kvm_debug_guest *dbg);
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index a6cd1c1fe29a..291d298868fc 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -34,6 +34,7 @@
34#include <linux/highmem.h> 34#include <linux/highmem.h>
35#include <linux/file.h> 35#include <linux/file.h>
36#include <asm/desc.h> 36#include <asm/desc.h>
37#include <linux/cpu.h>
37 38
38#include "x86_emulate.h" 39#include "x86_emulate.h"
39#include "segment_descriptor.h" 40#include "segment_descriptor.h"
@@ -2039,6 +2040,64 @@ static struct notifier_block kvm_reboot_notifier = {
2039 .priority = 0, 2040 .priority = 0,
2040}; 2041};
2041 2042
2043/*
2044 * Make sure that a cpu that is being hot-unplugged does not have any vcpus
2045 * cached on it.
2046 */
2047static void decache_vcpus_on_cpu(int cpu)
2048{
2049 struct kvm *vm;
2050 struct kvm_vcpu *vcpu;
2051 int i;
2052
2053 spin_lock(&kvm_lock);
2054 list_for_each_entry(vm, &vm_list, vm_list)
2055 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
2056 vcpu = &vm->vcpus[i];
2057 /*
2058 * If the vcpu is locked, then it is running on some
2059 * other cpu and therefore it is not cached on the
2060 * cpu in question.
2061 *
2062 * If it's not locked, check the last cpu it executed
2063 * on.
2064 */
2065 if (mutex_trylock(&vcpu->mutex)) {
2066 if (vcpu->cpu == cpu) {
2067 kvm_arch_ops->vcpu_decache(vcpu);
2068 vcpu->cpu = -1;
2069 }
2070 mutex_unlock(&vcpu->mutex);
2071 }
2072 }
2073 spin_unlock(&kvm_lock);
2074}
2075
2076static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
2077 void *v)
2078{
2079 int cpu = (long)v;
2080
2081 switch (val) {
2082 case CPU_DEAD:
2083 case CPU_UP_CANCELED:
2084 decache_vcpus_on_cpu(cpu);
2085 smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
2086 NULL, 0, 1);
2087 break;
2088 case CPU_UP_PREPARE:
2089 smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
2090 NULL, 0, 1);
2091 break;
2092 }
2093 return NOTIFY_OK;
2094}
2095
2096static struct notifier_block kvm_cpu_notifier = {
2097 .notifier_call = kvm_cpu_hotplug,
2098 .priority = 20, /* must be > scheduler priority */
2099};
2100
2042static __init void kvm_init_debug(void) 2101static __init void kvm_init_debug(void)
2043{ 2102{
2044 struct kvm_stats_debugfs_item *p; 2103 struct kvm_stats_debugfs_item *p;
@@ -2085,6 +2144,9 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
2085 return r; 2144 return r;
2086 2145
2087 on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); 2146 on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
2147 r = register_cpu_notifier(&kvm_cpu_notifier);
2148 if (r)
2149 goto out_free_1;
2088 register_reboot_notifier(&kvm_reboot_notifier); 2150 register_reboot_notifier(&kvm_reboot_notifier);
2089 2151
2090 kvm_chardev_ops.owner = module; 2152 kvm_chardev_ops.owner = module;
@@ -2099,6 +2161,8 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
2099 2161
2100out_free: 2162out_free:
2101 unregister_reboot_notifier(&kvm_reboot_notifier); 2163 unregister_reboot_notifier(&kvm_reboot_notifier);
2164 unregister_cpu_notifier(&kvm_cpu_notifier);
2165out_free_1:
2102 on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); 2166 on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
2103 kvm_arch_ops->hardware_unsetup(); 2167 kvm_arch_ops->hardware_unsetup();
2104 return r; 2168 return r;
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 4fa50bd0dceb..83da4ea150a3 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -609,6 +609,10 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
609 put_cpu(); 609 put_cpu();
610} 610}
611 611
612static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
613{
614}
615
612static void svm_cache_regs(struct kvm_vcpu *vcpu) 616static void svm_cache_regs(struct kvm_vcpu *vcpu)
613{ 617{
614 vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax; 618 vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
@@ -1677,6 +1681,7 @@ static struct kvm_arch_ops svm_arch_ops = {
1677 1681
1678 .vcpu_load = svm_vcpu_load, 1682 .vcpu_load = svm_vcpu_load,
1679 .vcpu_put = svm_vcpu_put, 1683 .vcpu_put = svm_vcpu_put,
1684 .vcpu_decache = svm_vcpu_decache,
1680 1685
1681 .set_guest_debug = svm_guest_debug, 1686 .set_guest_debug = svm_guest_debug,
1682 .get_msr = svm_get_msr, 1687 .get_msr = svm_get_msr,
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 28da0cae64a7..1e640b899175 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -250,6 +250,11 @@ static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
250 put_cpu(); 250 put_cpu();
251} 251}
252 252
253static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
254{
255 vcpu_clear(vcpu);
256}
257
253static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) 258static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
254{ 259{
255 return vmcs_readl(GUEST_RFLAGS); 260 return vmcs_readl(GUEST_RFLAGS);
@@ -509,7 +514,7 @@ static __init int vmx_disabled_by_bios(void)
509 return (msr & 5) == 1; /* locked but not enabled */ 514 return (msr & 5) == 1; /* locked but not enabled */
510} 515}
511 516
512static __init void hardware_enable(void *garbage) 517static void hardware_enable(void *garbage)
513{ 518{
514 int cpu = raw_smp_processor_id(); 519 int cpu = raw_smp_processor_id();
515 u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); 520 u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
@@ -2023,6 +2028,7 @@ static struct kvm_arch_ops vmx_arch_ops = {
2023 2028
2024 .vcpu_load = vmx_vcpu_load, 2029 .vcpu_load = vmx_vcpu_load,
2025 .vcpu_put = vmx_vcpu_put, 2030 .vcpu_put = vmx_vcpu_put,
2031 .vcpu_decache = vmx_vcpu_decache,
2026 2032
2027 .set_guest_debug = set_guest_debug, 2033 .set_guest_debug = set_guest_debug,
2028 .get_msr = vmx_get_msr, 2034 .get_msr = vmx_get_msr,