[PATCH] KVM: SVM: refactor avic VM ID allocation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2017-08-11 22:11+0200, Denys Vlasenko:
> 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@xxxxxxxxxx>
> Cc: Joerg Roedel <joro@xxxxxxxxxx>
> Cc: pbonzini@xxxxxxxxxx
> Cc: rkrcmar@xxxxxxxxxx
> Cc: tglx@xxxxxxxxxxxxx
> Cc: mingo@xxxxxxxxxx
> Cc: hpa@xxxxxxxxx
> Cc: x86@xxxxxxxxxx
> Cc: kvm@xxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> ---

Ah, I suspected my todo wasn't this short;  thanks for the patch!

> @@ -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 */

Suravee, did the reserved zero mean something?

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

Although hitting the case where all 2^24 ids are already used is
practically impossible, I don't like the loose end ...

What about applying something like the following on top?
---8<---
Subject: [PATCH] KVM: SVM: refactor avic VM ID allocation

We missed protection in case someone deserving a medal allocated 2^24
VMs and got a deadlock instead.  I think it is nicer without the goto
even if we droppped the error handling.

Signed-off-by: Radim Krčmář <rkrcmar@xxxxxxxxxx>
---
 arch/x86/kvm/svm.c | 58 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c21b49b5ee96..4d9ee8d76db3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -985,8 +985,6 @@ 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:
@@ -1385,6 +1383,38 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static bool avic_vm_id_is_used(u32 vm_id)
+{
+	struct kvm_arch *ka;
+
+	hash_for_each_possible(svm_vm_data_hash, ka, hnode, vm_id)
+		if (ka->avic_vm_id == vm_id)
+			return true;
+
+	return false;
+}
+
+static u32 avic_get_next_vm_id(void)
+{
+	static u32 next_vm_id = 0;
+	static bool next_vm_id_wrapped = false;
+	unsigned i;
+
+	for (i = 0; i < AVIC_VM_ID_NR; i++) {
+		next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
+
+		if (next_vm_id == 0) { /* id is 1-based, zero is not okay */
+			next_vm_id = 1;
+			next_vm_id_wrapped = true;
+		}
+
+		if (!next_vm_id_wrapped || !avic_vm_id_is_used(next_vm_id))
+			return next_vm_id;
+	}
+
+	return 0;
+}
+
 static void avic_vm_destroy(struct kvm *kvm)
 {
 	unsigned long flags;
@@ -1410,8 +1440,6 @@ static int avic_vm_init(struct kvm *kvm)
 	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;
@@ -1432,28 +1460,18 @@ static int avic_vm_init(struct kvm *kvm)
 	vm_data->avic_logical_id_table_page = l_page;
 	clear_page(page_address(l_page));
 
+	err = -EAGAIN;
 	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;
+	vm_data->avic_vm_id = avic_get_next_vm_id();
+	if (!vm_data->avic_vm_id)
+		goto unlock;
 	hash_add(svm_vm_data_hash, &vm_data->hnode, vm_data->avic_vm_id);
 	spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
 
 	return 0;
 
+unlock:
+	spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
 free_avic:
 	avic_vm_destroy(kvm);
 	return err;
-- 
2.13.3




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux