diff options
author | Avi Kivity <avi@qumranet.com> | 2007-05-24 06:03:52 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 05:05:51 -0400 |
commit | 1b6c016818a562aaea22b1a1b05b15c796b0c2f0 (patch) | |
tree | e8b96f2992164705b17e5ad3dcf0fa35a9f852da /drivers/kvm/kvm_main.c | |
parent | a52b1752c077cb919b71167c54968a0b91673281 (diff) |
KVM: Keep track of which cpus have virtualization enabled
By keeping track of which cpus have virtualization enabled, we
prevent double-enable or double-disable during hotplug, which is a
very fatal oops.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index ea027190a658..3226ad4bce7c 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -50,8 +50,12 @@ MODULE_LICENSE("GPL"); | |||
50 | static DEFINE_SPINLOCK(kvm_lock); | 50 | static DEFINE_SPINLOCK(kvm_lock); |
51 | static LIST_HEAD(vm_list); | 51 | static LIST_HEAD(vm_list); |
52 | 52 | ||
53 | static cpumask_t cpus_hardware_enabled; | ||
54 | |||
53 | struct kvm_arch_ops *kvm_arch_ops; | 55 | struct kvm_arch_ops *kvm_arch_ops; |
54 | 56 | ||
57 | static void hardware_disable(void *ignored); | ||
58 | |||
55 | #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) | 59 | #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) |
56 | 60 | ||
57 | static struct kvm_stats_debugfs_item { | 61 | static struct kvm_stats_debugfs_item { |
@@ -2930,7 +2934,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val, | |||
2930 | * in vmx root mode. | 2934 | * in vmx root mode. |
2931 | */ | 2935 | */ |
2932 | printk(KERN_INFO "kvm: exiting hardware virtualization\n"); | 2936 | printk(KERN_INFO "kvm: exiting hardware virtualization\n"); |
2933 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); | 2937 | on_each_cpu(hardware_disable, NULL, 0, 1); |
2934 | } | 2938 | } |
2935 | return NOTIFY_OK; | 2939 | return NOTIFY_OK; |
2936 | } | 2940 | } |
@@ -2973,6 +2977,27 @@ static void decache_vcpus_on_cpu(int cpu) | |||
2973 | spin_unlock(&kvm_lock); | 2977 | spin_unlock(&kvm_lock); |
2974 | } | 2978 | } |
2975 | 2979 | ||
2980 | static void hardware_enable(void *junk) | ||
2981 | { | ||
2982 | int cpu = raw_smp_processor_id(); | ||
2983 | |||
2984 | if (cpu_isset(cpu, cpus_hardware_enabled)) | ||
2985 | return; | ||
2986 | cpu_set(cpu, cpus_hardware_enabled); | ||
2987 | kvm_arch_ops->hardware_enable(NULL); | ||
2988 | } | ||
2989 | |||
2990 | static void hardware_disable(void *junk) | ||
2991 | { | ||
2992 | int cpu = raw_smp_processor_id(); | ||
2993 | |||
2994 | if (!cpu_isset(cpu, cpus_hardware_enabled)) | ||
2995 | return; | ||
2996 | cpu_clear(cpu, cpus_hardware_enabled); | ||
2997 | decache_vcpus_on_cpu(cpu); | ||
2998 | kvm_arch_ops->hardware_disable(NULL); | ||
2999 | } | ||
3000 | |||
2976 | static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, | 3001 | static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, |
2977 | void *v) | 3002 | void *v) |
2978 | { | 3003 | { |
@@ -2985,16 +3010,13 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, | |||
2985 | case CPU_UP_CANCELED_FROZEN: | 3010 | case CPU_UP_CANCELED_FROZEN: |
2986 | printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", | 3011 | printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", |
2987 | cpu); | 3012 | cpu); |
2988 | decache_vcpus_on_cpu(cpu); | 3013 | smp_call_function_single(cpu, hardware_disable, NULL, 0, 1); |
2989 | smp_call_function_single(cpu, kvm_arch_ops->hardware_disable, | ||
2990 | NULL, 0, 1); | ||
2991 | break; | 3014 | break; |
2992 | case CPU_ONLINE: | 3015 | case CPU_ONLINE: |
2993 | case CPU_ONLINE_FROZEN: | 3016 | case CPU_ONLINE_FROZEN: |
2994 | printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", | 3017 | printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", |
2995 | cpu); | 3018 | cpu); |
2996 | smp_call_function_single(cpu, kvm_arch_ops->hardware_enable, | 3019 | smp_call_function_single(cpu, hardware_enable, NULL, 0, 1); |
2997 | NULL, 0, 1); | ||
2998 | break; | 3020 | break; |
2999 | } | 3021 | } |
3000 | return NOTIFY_OK; | 3022 | return NOTIFY_OK; |
@@ -3088,14 +3110,13 @@ static void kvm_exit_debug(void) | |||
3088 | 3110 | ||
3089 | static int kvm_suspend(struct sys_device *dev, pm_message_t state) | 3111 | static int kvm_suspend(struct sys_device *dev, pm_message_t state) |
3090 | { | 3112 | { |
3091 | decache_vcpus_on_cpu(raw_smp_processor_id()); | 3113 | on_each_cpu(hardware_disable, NULL, 0, 0); |
3092 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); | ||
3093 | return 0; | 3114 | return 0; |
3094 | } | 3115 | } |
3095 | 3116 | ||
3096 | static int kvm_resume(struct sys_device *dev) | 3117 | static int kvm_resume(struct sys_device *dev) |
3097 | { | 3118 | { |
3098 | on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); | 3119 | on_each_cpu(hardware_disable, NULL, 0, 0); |
3099 | return 0; | 3120 | return 0; |
3100 | } | 3121 | } |
3101 | 3122 | ||
@@ -3136,7 +3157,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) | |||
3136 | if (r < 0) | 3157 | if (r < 0) |
3137 | goto out; | 3158 | goto out; |
3138 | 3159 | ||
3139 | on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); | 3160 | on_each_cpu(hardware_enable, NULL, 0, 1); |
3140 | r = register_cpu_notifier(&kvm_cpu_notifier); | 3161 | r = register_cpu_notifier(&kvm_cpu_notifier); |
3141 | if (r) | 3162 | if (r) |
3142 | goto out_free_1; | 3163 | goto out_free_1; |
@@ -3168,7 +3189,7 @@ out_free_2: | |||
3168 | unregister_reboot_notifier(&kvm_reboot_notifier); | 3189 | unregister_reboot_notifier(&kvm_reboot_notifier); |
3169 | unregister_cpu_notifier(&kvm_cpu_notifier); | 3190 | unregister_cpu_notifier(&kvm_cpu_notifier); |
3170 | out_free_1: | 3191 | out_free_1: |
3171 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); | 3192 | on_each_cpu(hardware_disable, NULL, 0, 1); |
3172 | kvm_arch_ops->hardware_unsetup(); | 3193 | kvm_arch_ops->hardware_unsetup(); |
3173 | out: | 3194 | out: |
3174 | kvm_arch_ops = NULL; | 3195 | kvm_arch_ops = NULL; |
@@ -3182,7 +3203,7 @@ void kvm_exit_arch(void) | |||
3182 | sysdev_class_unregister(&kvm_sysdev_class); | 3203 | sysdev_class_unregister(&kvm_sysdev_class); |
3183 | unregister_reboot_notifier(&kvm_reboot_notifier); | 3204 | unregister_reboot_notifier(&kvm_reboot_notifier); |
3184 | unregister_cpu_notifier(&kvm_cpu_notifier); | 3205 | unregister_cpu_notifier(&kvm_cpu_notifier); |
3185 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); | 3206 | on_each_cpu(hardware_disable, NULL, 0, 1); |
3186 | kvm_arch_ops->hardware_unsetup(); | 3207 | kvm_arch_ops->hardware_unsetup(); |
3187 | kvm_arch_ops = NULL; | 3208 | kvm_arch_ops = NULL; |
3188 | } | 3209 | } |