Skip to content

Commit 0ca52e7

Browse files
rkrcmarbonzini
authored andcommitted
KVM: x86: dynamic kvm_apic_map
x2APIC supports up to 2^32-1 LAPICs, but most guest in coming years will probably has fewer VCPUs. Dynamic size saves memory at the cost of turning one constant into a variable. apic_map mutex had to be moved before allocation to avoid races with cpu hotplug. Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent e45115b commit 0ca52e7

File tree

3 files changed

+16
-7
lines changed

3 files changed

+16
-7
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,11 +682,12 @@ struct kvm_arch_memory_slot {
682682
struct kvm_apic_map {
683683
struct rcu_head rcu;
684684
u8 mode;
685-
struct kvm_lapic *phys_map[256];
685+
u32 max_apic_id;
686686
union {
687687
struct kvm_lapic *xapic_flat_map[8];
688688
struct kvm_lapic *xapic_cluster_map[16][4];
689689
};
690+
struct kvm_lapic *phys_map[];
690691
};
691692

692693
/* Hyper-V emulation context */

arch/x86/kvm/lapic.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
120120
switch (map->mode) {
121121
case KVM_APIC_MODE_X2APIC: {
122122
u32 offset = (dest_id >> 16) * 16;
123-
u32 max_apic_id = ARRAY_SIZE(map->phys_map) - 1;
123+
u32 max_apic_id = map->max_apic_id;
124124

125125
if (offset <= max_apic_id) {
126126
u8 cluster_size = min(max_apic_id - offset + 1, 16U);
@@ -152,14 +152,22 @@ static void recalculate_apic_map(struct kvm *kvm)
152152
struct kvm_apic_map *new, *old = NULL;
153153
struct kvm_vcpu *vcpu;
154154
int i;
155-
156-
new = kzalloc(sizeof(struct kvm_apic_map), GFP_KERNEL);
155+
u32 max_id = 255;
157156

158157
mutex_lock(&kvm->arch.apic_map_lock);
159158

159+
kvm_for_each_vcpu(i, vcpu, kvm)
160+
if (kvm_apic_present(vcpu))
161+
max_id = max(max_id, kvm_apic_id(vcpu->arch.apic));
162+
163+
new = kzalloc(sizeof(struct kvm_apic_map) +
164+
sizeof(struct kvm_lapic *) * (max_id + 1), GFP_KERNEL);
165+
160166
if (!new)
161167
goto out;
162168

169+
new->max_apic_id = max_id;
170+
163171
kvm_for_each_vcpu(i, vcpu, kvm) {
164172
struct kvm_lapic *apic = vcpu->arch.apic;
165173
struct kvm_lapic **cluster;
@@ -172,7 +180,7 @@ static void recalculate_apic_map(struct kvm *kvm)
172180
aid = kvm_apic_id(apic);
173181
ldr = kvm_lapic_get_reg(apic, APIC_LDR);
174182

175-
if (aid < ARRAY_SIZE(new->phys_map))
183+
if (aid <= new->max_apic_id)
176184
new->phys_map[aid] = apic;
177185

178186
if (apic_x2apic_mode(apic)) {
@@ -710,7 +718,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
710718
return false;
711719

712720
if (irq->dest_mode == APIC_DEST_PHYSICAL) {
713-
if (irq->dest_id >= ARRAY_SIZE(map->phys_map)) {
721+
if (irq->dest_id > map->max_apic_id) {
714722
*bitmap = 0;
715723
} else {
716724
*dst = &map->phys_map[irq->dest_id];

arch/x86/kvm/lapic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
200200
return lapic_in_kernel(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
201201
}
202202

203-
static inline int kvm_apic_id(struct kvm_lapic *apic)
203+
static inline u32 kvm_apic_id(struct kvm_lapic *apic)
204204
{
205205
return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff;
206206
}

0 commit comments

Comments
 (0)