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 kvm_apic_map {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
u8 mode;
|
u8 mode;
|
||||||
struct kvm_lapic *phys_map[256];
|
u32 max_apic_id;
|
||||||
union {
|
union {
|
||||||
struct kvm_lapic *xapic_flat_map[8];
|
struct kvm_lapic *xapic_flat_map[8];
|
||||||
struct kvm_lapic *xapic_cluster_map[16][4];
|
struct kvm_lapic *xapic_cluster_map[16][4];
|
||||||
};
|
};
|
||||||
|
struct kvm_lapic *phys_map[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Hyper-V emulation context */
|
/* 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) {
|
switch (map->mode) {
|
||||||
case KVM_APIC_MODE_X2APIC: {
|
case KVM_APIC_MODE_X2APIC: {
|
||||||
u32 offset = (dest_id >> 16) * 16;
|
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) {
|
if (offset <= max_apic_id) {
|
||||||
u8 cluster_size = min(max_apic_id - offset + 1, 16U);
|
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_apic_map *new, *old = NULL;
|
||||||
struct kvm_vcpu *vcpu;
|
struct kvm_vcpu *vcpu;
|
||||||
int i;
|
int i;
|
||||||
|
u32 max_id = 255;
|
||||||
new = kzalloc(sizeof(struct kvm_apic_map), GFP_KERNEL);
|
|
||||||
|
|
||||||
mutex_lock(&kvm->arch.apic_map_lock);
|
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)
|
if (!new)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
new->max_apic_id = max_id;
|
||||||
|
|
||||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||||
struct kvm_lapic **cluster;
|
struct kvm_lapic **cluster;
|
||||||
@ -172,7 +180,7 @@ static void recalculate_apic_map(struct kvm *kvm)
|
|||||||
aid = kvm_apic_id(apic);
|
aid = kvm_apic_id(apic);
|
||||||
ldr = kvm_lapic_get_reg(apic, APIC_LDR);
|
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;
|
new->phys_map[aid] = apic;
|
||||||
|
|
||||||
if (apic_x2apic_mode(apic)) {
|
if (apic_x2apic_mode(apic)) {
|
||||||
@ -710,7 +718,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (irq->dest_mode == APIC_DEST_PHYSICAL) {
|
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;
|
*bitmap = 0;
|
||||||
} else {
|
} else {
|
||||||
*dst = &map->phys_map[irq->dest_id];
|
*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);
|
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;
|
return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user