aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-05-24 06:03:52 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:51 -0400
commit1b6c016818a562aaea22b1a1b05b15c796b0c2f0 (patch)
treee8b96f2992164705b17e5ad3dcf0fa35a9f852da /drivers/kvm
parenta52b1752c077cb919b71167c54968a0b91673281 (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')
-rw-r--r--drivers/kvm/kvm_main.c45
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");
50static DEFINE_SPINLOCK(kvm_lock); 50static DEFINE_SPINLOCK(kvm_lock);
51static LIST_HEAD(vm_list); 51static LIST_HEAD(vm_list);
52 52
53static cpumask_t cpus_hardware_enabled;
54
53struct kvm_arch_ops *kvm_arch_ops; 55struct kvm_arch_ops *kvm_arch_ops;
54 56
57static 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
57static struct kvm_stats_debugfs_item { 61static 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
2980static 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
2990static 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
2976static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, 3001static 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
3089static int kvm_suspend(struct sys_device *dev, pm_message_t state) 3111static 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
3096static int kvm_resume(struct sys_device *dev) 3117static 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);
3170out_free_1: 3191out_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();
3173out: 3194out:
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}