Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b6c0168 authored by Avi Kivity's avatar Avi Kivity
Browse files

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: default avatarAvi Kivity <avi@qumranet.com>
parent a52b1752
Loading
Loading
Loading
Loading
+33 −12
Original line number Diff line number Diff line
@@ -50,8 +50,12 @@ MODULE_LICENSE("GPL");
static DEFINE_SPINLOCK(kvm_lock);
static LIST_HEAD(vm_list);

static cpumask_t cpus_hardware_enabled;

struct kvm_arch_ops *kvm_arch_ops;

static void hardware_disable(void *ignored);

#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)

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.
		 */
		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;
}
@@ -2973,6 +2977,27 @@ static void decache_vcpus_on_cpu(int cpu)
	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,
			   void *v)
{
@@ -2985,16 +3010,13 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
	case CPU_UP_CANCELED_FROZEN:
		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
		       cpu);
		decache_vcpus_on_cpu(cpu);
		smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
					 NULL, 0, 1);
		smp_call_function_single(cpu, hardware_disable, NULL, 0, 1);
		break;
	case CPU_ONLINE:
	case CPU_ONLINE_FROZEN:
		printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
		       cpu);
		smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
					 NULL, 0, 1);
		smp_call_function_single(cpu, hardware_enable, NULL, 0, 1);
		break;
	}
	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)
{
	decache_vcpus_on_cpu(raw_smp_processor_id());
	on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
	on_each_cpu(hardware_disable, NULL, 0, 0);
	return 0;
}

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;
}

@@ -3136,7 +3157,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
	if (r < 0)
		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);
	if (r)
		goto out_free_1;
@@ -3168,7 +3189,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
	unregister_reboot_notifier(&kvm_reboot_notifier);
	unregister_cpu_notifier(&kvm_cpu_notifier);
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();
out:
	kvm_arch_ops = NULL;
@@ -3182,7 +3203,7 @@ void kvm_exit_arch(void)
	sysdev_class_unregister(&kvm_sysdev_class);
	unregister_reboot_notifier(&kvm_reboot_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 = NULL;
}