KVM: SVM: delete avic_vm_id_bitmap (2 megabyte static array)
authorDenys Vlasenko <dvlasenk@redhat.com>
Fri, 11 Aug 2017 20:11:58 +0000 (22:11 +0200)
committerRadim Krčmář <rkrcmar@redhat.com>
Fri, 18 Aug 2017 12:37:50 +0000 (14:37 +0200)
With lightly tweaked defconfig:

    text    data     bss      dec     hex filename
11259661 5109408 2981888 19350957 12745ad vmlinux.before
11259661 5109408  884736 17253805 10745ad vmlinux.after

Only compile-tested.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: pbonzini@redhat.com
Cc: rkrcmar@redhat.com
Cc: tglx@linutronix.de
Cc: mingo@redhat.com
Cc: hpa@zytor.com
Cc: x86@kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/svm.c

index a603d0c14a5a46b4396446d97f5746270670f049..36812876f371f0ff140793450241f153f23ae1e0 100644 (file)
@@ -280,10 +280,6 @@ module_param(avic, int, S_IRUGO);
 static int vls = true;
 module_param(vls, int, 0444);
 
-/* AVIC VM ID bit masks and lock */
-static DECLARE_BITMAP(avic_vm_id_bitmap, AVIC_VM_ID_NR);
-static DEFINE_SPINLOCK(avic_vm_id_lock);
-
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -989,6 +985,8 @@ static void disable_nmi_singlestep(struct vcpu_svm *svm)
  */
 #define SVM_VM_DATA_HASH_BITS  8
 static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS);
+static u32 next_vm_id = 0;
+static bool next_vm_id_wrapped = 0;
 static DEFINE_SPINLOCK(svm_vm_data_hash_lock);
 
 /* Note:
@@ -1387,34 +1385,6 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static inline int avic_get_next_vm_id(void)
-{
-       int id;
-
-       spin_lock(&avic_vm_id_lock);
-
-       /* AVIC VM ID is one-based. */
-       id = find_next_zero_bit(avic_vm_id_bitmap, AVIC_VM_ID_NR, 1);
-       if (id <= AVIC_VM_ID_MASK)
-               __set_bit(id, avic_vm_id_bitmap);
-       else
-               id = -EAGAIN;
-
-       spin_unlock(&avic_vm_id_lock);
-       return id;
-}
-
-static inline int avic_free_vm_id(int id)
-{
-       if (id <= 0 || id > AVIC_VM_ID_MASK)
-               return -EINVAL;
-
-       spin_lock(&avic_vm_id_lock);
-       __clear_bit(id, avic_vm_id_bitmap);
-       spin_unlock(&avic_vm_id_lock);
-       return 0;
-}
-
 static void avic_vm_destroy(struct kvm *kvm)
 {
        unsigned long flags;
@@ -1423,8 +1393,6 @@ static void avic_vm_destroy(struct kvm *kvm)
        if (!avic)
                return;
 
-       avic_free_vm_id(vm_data->avic_vm_id);
-
        if (vm_data->avic_logical_id_table_page)
                __free_page(vm_data->avic_logical_id_table_page);
        if (vm_data->avic_physical_id_table_page)
@@ -1438,19 +1406,16 @@ static void avic_vm_destroy(struct kvm *kvm)
 static int avic_vm_init(struct kvm *kvm)
 {
        unsigned long flags;
-       int vm_id, err = -ENOMEM;
+       int err = -ENOMEM;
        struct kvm_arch *vm_data = &kvm->arch;
        struct page *p_page;
        struct page *l_page;
+       struct kvm_arch *ka;
+       u32 vm_id;
 
        if (!avic)
                return 0;
 
-       vm_id = avic_get_next_vm_id();
-       if (vm_id < 0)
-               return vm_id;
-       vm_data->avic_vm_id = (u32)vm_id;
-
        /* Allocating physical APIC ID table (4KB) */
        p_page = alloc_page(GFP_KERNEL);
        if (!p_page)
@@ -1468,6 +1433,22 @@ static int avic_vm_init(struct kvm *kvm)
        clear_page(page_address(l_page));
 
        spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ again:
+       vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
+       if (vm_id == 0) { /* id is 1-based, zero is not okay */
+               next_vm_id_wrapped = 1;
+               goto again;
+       }
+       /* Is it still in use? Only possible if wrapped at least once */
+       if (next_vm_id_wrapped) {
+               hash_for_each_possible(svm_vm_data_hash, ka, hnode, vm_id) {
+                       struct kvm *k2 = container_of(ka, struct kvm, arch);
+                       struct kvm_arch *vd2 = &k2->arch;
+                       if (vd2->avic_vm_id == vm_id)
+                               goto again;
+               }
+       }
+       vm_data->avic_vm_id = vm_id;
        hash_add(svm_vm_data_hash, &vm_data->hnode, vm_data->avic_vm_id);
        spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);