Skip to content

Commit

Permalink
apic: Use apic_id as apic's migration instance_id
Browse files Browse the repository at this point in the history
instance_id is generated by last_used_id + 1 for a given device type
so for QEMU with 3 CPUs instance_id for APICs is a seti of [0, 1, 2]
When CPU in the middle is hot-removed and migration started
APICs with instance_ids 0 and 2 are transferred in migration stream.
However target starts with 2 CPUs and APICs' instance_ids are
generated from scratch [0, 1] hence migration fails with error
  Unknown savevm section or instance 'apic' 2

Fix issue by manually registering APIC's vmsd with apic_id as
instance_id, in this case instance_id on target will always
match instance_id on source as apic_id is the same for a given
cpu instance.

Reported-by: Bharata B Rao <bharata@linux.vnet.ibm.com>
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
  • Loading branch information
Igor Mammedov authored and ehabkost committed Jul 20, 2016
1 parent 9c156f9 commit f6e9844
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 1 deletion.
12 changes: 11 additions & 1 deletion hw/intc/apic_common.c
Expand Up @@ -294,11 +294,14 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
return 0;
}

static const VMStateDescription vmstate_apic_common;

static void apic_common_realize(DeviceState *dev, Error **errp)
{
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info;
static DeviceState *vapic;
int instance_id = s->id;

info = APIC_COMMON_GET_CLASS(s);
info->realize(dev, errp);
Expand All @@ -313,13 +316,19 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
info->enable_tpr_reporting(s, true);
}

if (s->legacy_instance_id) {
instance_id = -1;
}
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
s, -1, 0);
}

static void apic_common_unrealize(DeviceState *dev, Error **errp)
{
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);

vmstate_unregister(NULL, &vmstate_apic_common, s);
info->unrealize(dev, errp);

if (apic_report_tpr_access && info->enable_tpr_reporting) {
Expand Down Expand Up @@ -422,14 +431,15 @@ static Property apic_properties_common[] = {
DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
true),
DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
false),
DEFINE_PROP_END_OF_LIST(),
};

static void apic_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);

dc->vmsd = &vmstate_apic_common;
dc->reset = apic_reset_common;
dc->props = apic_properties_common;
dc->realize = apic_common_realize;
Expand Down
1 change: 1 addition & 0 deletions include/hw/i386/apic_internal.h
Expand Up @@ -183,6 +183,7 @@ struct APICCommonState {
uint32_t vapic_control;
DeviceState *vapic;
hwaddr vapic_paddr; /* note: persistence via kvmvapic */
bool legacy_instance_id;
};

typedef struct VAPICState {
Expand Down
5 changes: 5 additions & 0 deletions include/hw/i386/pc.h
Expand Up @@ -382,6 +382,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = TYPE_X86_CPU,\
.property = "fill-mtrr-mask",\
.value = "off",\
},\
{\
.driver = "apic",\
.property = "legacy-instance-id",\
.value = "on",\
},

#define PC_COMPAT_2_5 \
Expand Down

0 comments on commit f6e9844

Please sign in to comment.