diff options
-rw-r--r-- | drivers/kvm/kvm.h | 1 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 64 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 5 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 8 |
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 | */ | ||
2047 | static 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 | |||
2076 | static 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 | |||
2096 | static struct notifier_block kvm_cpu_notifier = { | ||
2097 | .notifier_call = kvm_cpu_hotplug, | ||
2098 | .priority = 20, /* must be > scheduler priority */ | ||
2099 | }; | ||
2100 | |||
2042 | static __init void kvm_init_debug(void) | 2101 | static __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 | ||
2100 | out_free: | 2162 | out_free: |
2101 | unregister_reboot_notifier(&kvm_reboot_notifier); | 2163 | unregister_reboot_notifier(&kvm_reboot_notifier); |
2164 | unregister_cpu_notifier(&kvm_cpu_notifier); | ||
2165 | out_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 | ||
612 | static void svm_vcpu_decache(struct kvm_vcpu *vcpu) | ||
613 | { | ||
614 | } | ||
615 | |||
612 | static void svm_cache_regs(struct kvm_vcpu *vcpu) | 616 | static 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 | ||
253 | static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) | ||
254 | { | ||
255 | vcpu_clear(vcpu); | ||
256 | } | ||
257 | |||
253 | static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) | 258 | static 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 | ||
512 | static __init void hardware_enable(void *garbage) | 517 | static 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, |