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>
This commit is contained in:
parent
e45115b62f
commit
0ca52e7b81
|
@ -682,11 +682,12 @@ struct kvm_arch_memory_slot {
|
|||
struct kvm_apic_map {
|
||||
struct rcu_head rcu;
|
||||
u8 mode;
|
||||
struct kvm_lapic *phys_map[256];
|
||||
u32 max_apic_id;
|
||||
union {
|
||||
struct kvm_lapic *xapic_flat_map[8];
|
||||
struct kvm_lapic *xapic_cluster_map[16][4];
|
||||
};
|
||||
struct kvm_lapic *phys_map[];
|
||||
};
|
||||
|
||||
/* Hyper-V emulation context */
|
||||
|
|
|
@ -120,7 +120,7 @@ static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
|
|||
switch (map->mode) {
|
||||
case KVM_APIC_MODE_X2APIC: {
|
||||
u32 offset = (dest_id >> 16) * 16;
|
||||
u32 max_apic_id = ARRAY_SIZE(map->phys_map) - 1;
|
||||
u32 max_apic_id = map->max_apic_id;
|
||||
|
||||
if (offset <= max_apic_id) {
|
||||
u8 cluster_size = min(max_apic_id - offset + 1, 16U);
|
||||
|
@ -152,14 +152,22 @@ static void recalculate_apic_map(struct kvm *kvm)
|
|||
struct kvm_apic_map *new, *old = NULL;
|
||||
struct kvm_vcpu *vcpu;
|
||||
int i;
|
||||
|
||||
new = kzalloc(sizeof(struct kvm_apic_map), GFP_KERNEL);
|
||||
u32 max_id = 255;
|
||||
|
||||
mutex_lock(&kvm->arch.apic_map_lock);
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
if (kvm_apic_present(vcpu))
|
||||
max_id = max(max_id, kvm_apic_id(vcpu->arch.apic));
|
||||
|
||||
new = kzalloc(sizeof(struct kvm_apic_map) +
|
||||
sizeof(struct kvm_lapic *) * (max_id + 1), GFP_KERNEL);
|
||||
|
||||
if (!new)
|
||||
goto out;
|
||||
|
||||
new->max_apic_id = max_id;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
struct kvm_lapic **cluster;
|
||||
|
@ -172,7 +180,7 @@ static void recalculate_apic_map(struct kvm *kvm)
|
|||
aid = kvm_apic_id(apic);
|
||||
ldr = kvm_lapic_get_reg(apic, APIC_LDR);
|
||||
|
||||
if (aid < ARRAY_SIZE(new->phys_map))
|
||||
if (aid <= new->max_apic_id)
|
||||
new->phys_map[aid] = apic;
|
||||
|
||||
if (apic_x2apic_mode(apic)) {
|
||||
|
@ -710,7 +718,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
|
|||
return false;
|
||||
|
||||
if (irq->dest_mode == APIC_DEST_PHYSICAL) {
|
||||
if (irq->dest_id >= ARRAY_SIZE(map->phys_map)) {
|
||||
if (irq->dest_id > map->max_apic_id) {
|
||||
*bitmap = 0;
|
||||
} else {
|
||||
*dst = &map->phys_map[irq->dest_id];
|
||||
|
|
|
@ -200,7 +200,7 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
|
|||
return lapic_in_kernel(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
|
||||
}
|
||||
|
||||
static inline int kvm_apic_id(struct kvm_lapic *apic)
|
||||
static inline u32 kvm_apic_id(struct kvm_lapic *apic)
|
||||
{
|
||||
return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue