Skip to content

Commit c5b0775

Browse files
Marc Zyngierbonzini
authored andcommitted
KVM: Convert the kvm->vcpus array to a xarray
At least on arm64 and x86, the vcpus array is pretty huge (up to 1024 entries on x86) and is mostly empty in the majority of the cases (running 1k vcpu VMs is not that common). This mean that we end-up with a 4kB block of unused memory in the middle of the kvm structure. Instead of wasting away this memory, let's use an xarray instead, which gives us almost the same flexibility as a normal array, but with a reduced memory usage with smaller VMs. Signed-off-by: Marc Zyngier <maz@kernel.org> Message-Id: <20211116160403.4074052-6-maz@kernel.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 113d10b commit c5b0775

File tree

2 files changed

+12
-8
lines changed

2 files changed

+12
-8
lines changed

include/linux/kvm_host.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/refcount.h>
3030
#include <linux/nospec.h>
3131
#include <linux/notifier.h>
32+
#include <linux/xarray.h>
3233
#include <asm/signal.h>
3334

3435
#include <linux/kvm.h>
@@ -552,7 +553,7 @@ struct kvm {
552553
struct mutex slots_arch_lock;
553554
struct mm_struct *mm; /* userspace tied to this vm */
554555
struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
555-
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
556+
struct xarray vcpu_array;
556557

557558
/* Used to wait for completion of MMU notifiers. */
558559
spinlock_t mn_invalidate_lock;
@@ -701,7 +702,7 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
701702

702703
/* Pairs with smp_wmb() in kvm_vm_ioctl_create_vcpu. */
703704
smp_rmb();
704-
return kvm->vcpus[i];
705+
return xa_load(&kvm->vcpu_array, i);
705706
}
706707

707708
#define kvm_for_each_vcpu(idx, vcpup, kvm) \

virt/kvm/kvm_main.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ void kvm_destroy_vcpus(struct kvm *kvm)
458458

459459
kvm_for_each_vcpu(i, vcpu, kvm) {
460460
kvm_vcpu_destroy(vcpu);
461-
kvm->vcpus[i] = NULL;
461+
xa_erase(&kvm->vcpu_array, i);
462462
}
463463

464464
atomic_set(&kvm->online_vcpus, 0);
@@ -1063,6 +1063,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
10631063
mutex_init(&kvm->slots_arch_lock);
10641064
spin_lock_init(&kvm->mn_invalidate_lock);
10651065
rcuwait_init(&kvm->mn_memslots_update_rcuwait);
1066+
xa_init(&kvm->vcpu_array);
10661067

10671068
INIT_LIST_HEAD(&kvm->devices);
10681069

@@ -3598,7 +3599,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
35983599
}
35993600

36003601
vcpu->vcpu_idx = atomic_read(&kvm->online_vcpus);
3601-
BUG_ON(kvm->vcpus[vcpu->vcpu_idx]);
3602+
r = xa_insert(&kvm->vcpu_array, vcpu->vcpu_idx, vcpu, GFP_KERNEL_ACCOUNT);
3603+
BUG_ON(r == -EBUSY);
3604+
if (r)
3605+
goto unlock_vcpu_destroy;
36023606

36033607
/* Fill the stats id string for the vcpu */
36043608
snprintf(vcpu->stats_id, sizeof(vcpu->stats_id), "kvm-%d/vcpu-%d",
@@ -3608,15 +3612,14 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
36083612
kvm_get_kvm(kvm);
36093613
r = create_vcpu_fd(vcpu);
36103614
if (r < 0) {
3615+
xa_erase(&kvm->vcpu_array, vcpu->vcpu_idx);
36113616
kvm_put_kvm_no_destroy(kvm);
36123617
goto unlock_vcpu_destroy;
36133618
}
36143619

3615-
kvm->vcpus[vcpu->vcpu_idx] = vcpu;
3616-
36173620
/*
3618-
* Pairs with smp_rmb() in kvm_get_vcpu. Write kvm->vcpus
3619-
* before kvm->online_vcpu's incremented value.
3621+
* Pairs with smp_rmb() in kvm_get_vcpu. Store the vcpu
3622+
* pointer before kvm->online_vcpu's incremented value.
36203623
*/
36213624
smp_wmb();
36223625
atomic_inc(&kvm->online_vcpus);

0 commit comments

Comments
 (0)