From: Joerg Roedel <[email protected]>

Do the accounting of created vcpus and the sanity checks only once per
plane.

Co-developed-by: Carlos López <[email protected]>
Signed-off-by: Joerg Roedel <[email protected]>
---
 include/linux/kvm_host.h |   2 +
 virt/kvm/kvm_main.c      | 108 ++++++++++++++++++++++++---------------
 2 files changed, 68 insertions(+), 42 deletions(-)

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c4c4922df965..47144a83f9c5 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -325,6 +325,8 @@ struct kvm_mmio_fragment {
 struct kvm_vcpu_common {
        struct kvm *kvm;
 
+       int vcpu_idx; /* index into kvm->planes[]->vcpu_array */
+
        /* Currently active VCPU */
        struct kvm_vcpu *current_vcpu;
 };
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index fb840d029c56..14e74cdc4709 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -438,18 +438,58 @@ void *kvm_mmu_memory_cache_alloc(struct 
kvm_mmu_memory_cache *mc)
 }
 #endif
 
-static int kvm_vcpu_init_common(struct kvm_vcpu *vcpu, struct kvm *kvm)
+static int kvm_vcpu_init_common(struct kvm_vcpu *vcpu, struct kvm *kvm, 
unsigned long id)
 {
-       struct kvm_vcpu_common *common = kzalloc(sizeof(*common), 
GFP_KERNEL_ACCOUNT);
+       struct kvm_vcpu_common *common __free(kfree) = kzalloc(sizeof(*common), 
GFP_KERNEL_ACCOUNT);
+       int r;
 
-       if (common == NULL)
-               return -ENOMEM;
+       /*
+        * KVM tracks vCPU IDs as 'int', be kind to userspace and reject
+        * too-large values instead of silently truncating.
+        *
+        * Ensure KVM_MAX_VCPU_IDS isn't pushed above INT_MAX without first
+        * changing the storage type (at the very least, IDs should be tracked
+        * as unsigned ints).
+        */
+       BUILD_BUG_ON(KVM_MAX_VCPU_IDS > INT_MAX);
+       if (id >= KVM_MAX_VCPU_IDS)
+               return -EINVAL;
+
+       mutex_lock(&kvm->lock);
+       kvm->created_vcpus++;
+       mutex_unlock(&kvm->lock);
+
+       if (common == NULL) {
+               r = -ENOMEM;
+               goto out_drop_counter;
+       }
+
+       common->vcpu_idx = atomic_read(&kvm->online_vcpus);
 
        common->kvm = kvm;
        common->current_vcpu = vcpu;
-       vcpu->common = common;
+       vcpu->common = no_free_ptr(common);
 
        return 0;
+
+out_drop_counter:
+       mutex_lock(&kvm->lock);
+       kvm->created_vcpus--;
+       mutex_unlock(&kvm->lock);
+
+       return r;
+}
+
+static void kvm_vcpu_finish_common(struct kvm_vcpu *vcpu)
+{
+       smp_wmb();
+       if (vcpu->plane_level == 0) {
+               /*
+                * Pairs with smp_rmb() in kvm_get_vcpu.  Store the vcpu
+                * pointer before kvm->online_vcpu's incremented value.
+                */
+               atomic_inc(&vcpu->kvm->online_vcpus);
+       }
 }
 
 static void kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
@@ -482,10 +522,19 @@ static void kvm_vcpu_init(struct kvm_vcpu *vcpu, struct 
kvm *kvm, unsigned id)
 
 static void kvm_vcpu_common_destroy(struct kvm_vcpu *vcpu)
 {
-       if (vcpu->plane_level == 0)
-               kfree(vcpu->common);
+       struct kvm_vcpu_common *common = vcpu->common;
+       struct kvm *kvm = common->kvm;
 
        vcpu->common = NULL;
+
+       if (vcpu->plane_level != 0)
+              return;
+
+       mutex_lock(&common->kvm->lock);
+       kvm->created_vcpus--;
+       mutex_unlock(&common->kvm->lock);
+
+       kfree(common);
 }
 
 static void kvm_vcpu_destroy(struct kvm_vcpu *vcpu)
@@ -4235,22 +4284,10 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu 
*vcpu)
  */
 static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
 {
-       int r;
+       int r = -EINVAL;
        struct kvm_vcpu *vcpu;
        struct page *page;
 
-       /*
-        * KVM tracks vCPU IDs as 'int', be kind to userspace and reject
-        * too-large values instead of silently truncating.
-        *
-        * Ensure KVM_MAX_VCPU_IDS isn't pushed above INT_MAX without first
-        * changing the storage type (at the very least, IDs should be tracked
-        * as unsigned ints).
-        */
-       BUILD_BUG_ON(KVM_MAX_VCPU_IDS > INT_MAX);
-       if (id >= KVM_MAX_VCPU_IDS)
-               return -EINVAL;
-
        mutex_lock(&kvm->lock);
        if (kvm->created_vcpus >= kvm->max_vcpus) {
                mutex_unlock(&kvm->lock);
@@ -4258,24 +4295,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, 
unsigned long id)
        }
 
        r = kvm_arch_vcpu_precreate(kvm, id);
-       if (r) {
-               mutex_unlock(&kvm->lock);
-               return r;
-       }
-
-       kvm->created_vcpus++;
        mutex_unlock(&kvm->lock);
+       if (r)
+               return r;
 
        vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT);
-       if (!vcpu) {
-               r = -ENOMEM;
-               goto vcpu_decrement;
-       }
+       if (!vcpu)
+               return -ENOMEM;
 
-       r = kvm_vcpu_init_common(vcpu, kvm);
+       r = kvm_vcpu_init_common(vcpu, kvm, id);
        if (r)
                goto vcpu_free;
 
+       vcpu->vcpu_idx = vcpu->common->vcpu_idx;
+
        BUILD_BUG_ON(sizeof(struct kvm_run) > PAGE_SIZE);
        page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
        if (!page) {
@@ -4304,7 +4337,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, 
unsigned long id)
                goto unlock_vcpu_destroy;
        }
 
-       vcpu->vcpu_idx = atomic_read(&kvm->online_vcpus);
        r = xa_insert(&kvm->planes[0]->vcpu_array, vcpu->vcpu_idx, vcpu, 
GFP_KERNEL_ACCOUNT);
        WARN_ON_ONCE(r == -EBUSY);
        if (r)
@@ -4324,12 +4356,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, 
unsigned long id)
        if (r < 0)
                goto kvm_put_xa_erase;
 
-       /*
-        * Pairs with smp_rmb() in kvm_get_vcpu.  Store the vcpu
-        * pointer before kvm->online_vcpu's incremented value.
-        */
-       smp_wmb();
-       atomic_inc(&kvm->online_vcpus);
+       kvm_vcpu_finish_common(vcpu);
        mutex_unlock(&vcpu->mutex);
 
        mutex_unlock(&kvm->lock);
@@ -4352,10 +4379,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, 
unsigned long id)
        kvm_vcpu_common_destroy(vcpu);
 vcpu_free:
        kmem_cache_free(kvm_vcpu_cache, vcpu);
-vcpu_decrement:
-       mutex_lock(&kvm->lock);
-       kvm->created_vcpus--;
-       mutex_unlock(&kvm->lock);
+
        return r;
 }
 
-- 
2.53.0


Reply via email to