forked from Minki/linux
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>
This commit is contained in:
parent
a52b1752c0
commit
1b6c016818
@ -50,8 +50,12 @@ MODULE_LICENSE("GPL");
|
|||||||
static DEFINE_SPINLOCK(kvm_lock);
|
static DEFINE_SPINLOCK(kvm_lock);
|
||||||
static LIST_HEAD(vm_list);
|
static LIST_HEAD(vm_list);
|
||||||
|
|
||||||
|
static cpumask_t cpus_hardware_enabled;
|
||||||
|
|
||||||
struct kvm_arch_ops *kvm_arch_ops;
|
struct kvm_arch_ops *kvm_arch_ops;
|
||||||
|
|
||||||
|
static void hardware_disable(void *ignored);
|
||||||
|
|
||||||
#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
|
#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
|
||||||
|
|
||||||
static struct kvm_stats_debugfs_item {
|
static struct kvm_stats_debugfs_item {
|
||||||
@ -2930,7 +2934,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
|
|||||||
* in vmx root mode.
|
* in vmx root mode.
|
||||||
*/
|
*/
|
||||||
printk(KERN_INFO "kvm: exiting hardware virtualization\n");
|
printk(KERN_INFO "kvm: exiting hardware virtualization\n");
|
||||||
on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
|
on_each_cpu(hardware_disable, NULL, 0, 1);
|
||||||
}
|
}
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
}
|
}
|
||||||
@ -2973,6 +2977,27 @@ static void decache_vcpus_on_cpu(int cpu)
|
|||||||
spin_unlock(&kvm_lock);
|
spin_unlock(&kvm_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hardware_enable(void *junk)
|
||||||
|
{
|
||||||
|
int cpu = raw_smp_processor_id();
|
||||||
|
|
||||||
|
if (cpu_isset(cpu, cpus_hardware_enabled))
|
||||||
|
return;
|
||||||
|
cpu_set(cpu, cpus_hardware_enabled);
|
||||||
|
kvm_arch_ops->hardware_enable(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hardware_disable(void *junk)
|
||||||
|
{
|
||||||
|
int cpu = raw_smp_processor_id();
|
||||||
|
|
||||||
|
if (!cpu_isset(cpu, cpus_hardware_enabled))
|
||||||
|
return;
|
||||||
|
cpu_clear(cpu, cpus_hardware_enabled);
|
||||||
|
decache_vcpus_on_cpu(cpu);
|
||||||
|
kvm_arch_ops->hardware_disable(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
|
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
|
||||||
void *v)
|
void *v)
|
||||||
{
|
{
|
||||||
@ -2985,16 +3010,13 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
|
|||||||
case CPU_UP_CANCELED_FROZEN:
|
case CPU_UP_CANCELED_FROZEN:
|
||||||
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
|
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
|
||||||
cpu);
|
cpu);
|
||||||
decache_vcpus_on_cpu(cpu);
|
smp_call_function_single(cpu, hardware_disable, NULL, 0, 1);
|
||||||
smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
|
|
||||||
NULL, 0, 1);
|
|
||||||
break;
|
break;
|
||||||
case CPU_ONLINE:
|
case CPU_ONLINE:
|
||||||
case CPU_ONLINE_FROZEN:
|
case CPU_ONLINE_FROZEN:
|
||||||
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
|
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
|
||||||
cpu);
|
cpu);
|
||||||
smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
|
smp_call_function_single(cpu, hardware_enable, NULL, 0, 1);
|
||||||
NULL, 0, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
@ -3088,14 +3110,13 @@ static void kvm_exit_debug(void)
|
|||||||
|
|
||||||
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
|
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
|
||||||
{
|
{
|
||||||
decache_vcpus_on_cpu(raw_smp_processor_id());
|
on_each_cpu(hardware_disable, NULL, 0, 0);
|
||||||
on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_resume(struct sys_device *dev)
|
static int kvm_resume(struct sys_device *dev)
|
||||||
{
|
{
|
||||||
on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
|
on_each_cpu(hardware_disable, NULL, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3136,7 +3157,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
|
on_each_cpu(hardware_enable, NULL, 0, 1);
|
||||||
r = register_cpu_notifier(&kvm_cpu_notifier);
|
r = register_cpu_notifier(&kvm_cpu_notifier);
|
||||||
if (r)
|
if (r)
|
||||||
goto out_free_1;
|
goto out_free_1;
|
||||||
@ -3168,7 +3189,7 @@ out_free_2:
|
|||||||
unregister_reboot_notifier(&kvm_reboot_notifier);
|
unregister_reboot_notifier(&kvm_reboot_notifier);
|
||||||
unregister_cpu_notifier(&kvm_cpu_notifier);
|
unregister_cpu_notifier(&kvm_cpu_notifier);
|
||||||
out_free_1:
|
out_free_1:
|
||||||
on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
|
on_each_cpu(hardware_disable, NULL, 0, 1);
|
||||||
kvm_arch_ops->hardware_unsetup();
|
kvm_arch_ops->hardware_unsetup();
|
||||||
out:
|
out:
|
||||||
kvm_arch_ops = NULL;
|
kvm_arch_ops = NULL;
|
||||||
@ -3182,7 +3203,7 @@ void kvm_exit_arch(void)
|
|||||||
sysdev_class_unregister(&kvm_sysdev_class);
|
sysdev_class_unregister(&kvm_sysdev_class);
|
||||||
unregister_reboot_notifier(&kvm_reboot_notifier);
|
unregister_reboot_notifier(&kvm_reboot_notifier);
|
||||||
unregister_cpu_notifier(&kvm_cpu_notifier);
|
unregister_cpu_notifier(&kvm_cpu_notifier);
|
||||||
on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
|
on_each_cpu(hardware_disable, NULL, 0, 1);
|
||||||
kvm_arch_ops->hardware_unsetup();
|
kvm_arch_ops->hardware_unsetup();
|
||||||
kvm_arch_ops = NULL;
|
kvm_arch_ops = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user