Commit 6c7caebc authored by Paolo Bonzini's avatar Paolo Bonzini

KVM: introduce kvm->created_vcpus

The race between creating the irqchip and the first VCPU is
currently fixed by checking the presence of an irqchip before
updating kvm->online_vcpus, and undoing the whole VCPU creation
if someone created the irqchip in the meanwhile.

Instead, introduce a new field in struct kvm that will count VCPUs
under a mutex, without the atomic access and memory ordering that we
need elsewhere to protect the vcpus array.  This also plugs the race
and is more easily applicable in all similar circumstances.
Reviewed-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 682a8108
...@@ -371,7 +371,15 @@ struct kvm { ...@@ -371,7 +371,15 @@ struct kvm {
struct srcu_struct srcu; struct srcu_struct srcu;
struct srcu_struct irq_srcu; struct srcu_struct irq_srcu;
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
/*
* created_vcpus is protected by kvm->lock, and is incremented
* at the beginning of KVM_CREATE_VCPU. online_vcpus is only
* incremented after storing the kvm_vcpu pointer in vcpus,
* and is accessed atomically.
*/
atomic_t online_vcpus; atomic_t online_vcpus;
int created_vcpus;
int last_boosted_vcpu; int last_boosted_vcpu;
struct list_head vm_list; struct list_head vm_list;
struct mutex lock; struct mutex lock;
......
...@@ -2346,9 +2346,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) ...@@ -2346,9 +2346,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
if (id >= KVM_MAX_VCPU_ID) if (id >= KVM_MAX_VCPU_ID)
return -EINVAL; return -EINVAL;
mutex_lock(&kvm->lock);
if (kvm->created_vcpus == KVM_MAX_VCPUS) {
mutex_unlock(&kvm->lock);
return -EINVAL;
}
kvm->created_vcpus++;
mutex_unlock(&kvm->lock);
vcpu = kvm_arch_vcpu_create(kvm, id); vcpu = kvm_arch_vcpu_create(kvm, id);
if (IS_ERR(vcpu)) if (IS_ERR(vcpu)) {
return PTR_ERR(vcpu); r = PTR_ERR(vcpu);
goto vcpu_decrement;
}
preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
...@@ -2361,10 +2372,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) ...@@ -2361,10 +2372,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
r = -EINVAL; r = -EINVAL;
goto unlock_vcpu_destroy; goto unlock_vcpu_destroy;
} }
if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
r = -EINVAL;
goto unlock_vcpu_destroy;
}
if (kvm_get_vcpu_by_id(kvm, id)) { if (kvm_get_vcpu_by_id(kvm, id)) {
r = -EEXIST; r = -EEXIST;
goto unlock_vcpu_destroy; goto unlock_vcpu_destroy;
...@@ -2397,6 +2404,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) ...@@ -2397,6 +2404,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
vcpu_destroy: vcpu_destroy:
kvm_arch_vcpu_destroy(vcpu); kvm_arch_vcpu_destroy(vcpu);
vcpu_decrement:
mutex_lock(&kvm->lock);
kvm->created_vcpus--;
mutex_unlock(&kvm->lock);
return r; return r;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment