From acb18fd7600f8433e082536bb5603860034c4128 Mon Sep 17 00:00:00 2001
From: Igor Mammedov <imammedo@redhat.com>
Date: Wed, 3 Aug 2016 07:39:37 +0200
Subject: [PATCH 73/99] apic: Use apic_id as apic's migration instance_id

RH-Author: Igor Mammedov <imammedo@redhat.com>
Message-id: <1470209977-112882-1-git-send-email-imammedo@redhat.com>
Patchwork-id: 71794
O-Subject: [RHEV-7.3 qemu-kvm-rhev v2 68/78] apic: Use apic_id as apic's migration instance_id
Bugzilla: 1087672
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
RH-Acked-by: Marcel Apfelbaum <marcel@redhat.com>
RH-Acked-by: David Gibson <dgibson@redhat.com>

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>
(cherry picked from commit f6e984443f1634eee8d6876a7cce039b976c95e0)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>

Conflicts:
	include/hw/i386/pc.h
	hw/i386/pc_piix.c
        hw/i386/pc_q35.c
            - due to missing PC_COMPAT_2_6 and need to ammend
              rhel-7.2 machine type

        include/hw/i386/pc.h
            - in rhel72 compat props due to commit
                910cf4a5 target-i386: Fill high bits of mtrr mask
v2:
  fix conflicti with 910cf4a5 in rhel72 compat props
---
 hw/intc/apic_common.c           | 12 +++++++++++-
 include/hw/i386/apic_internal.h |  1 +
 include/hw/i386/pc.h            |  5 +++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 2038f1c..a4f38a8 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -292,11 +292,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);
@@ -311,6 +314,11 @@ 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)
@@ -318,6 +326,7 @@ 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) {
@@ -420,6 +429,8 @@ 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(),
 };
 
@@ -427,7 +438,6 @@ 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;
diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h
index 52ca45d..a694322 100644
--- a/include/hw/i386/apic_internal.h
+++ b/include/hw/i386/apic_internal.h
@@ -182,6 +182,7 @@ struct APICCommonState {
     uint32_t vapic_control;
     DeviceState *vapic;
     hwaddr vapic_paddr; /* note: persistence via kvmvapic */
+    bool legacy_instance_id;
 };
 
 typedef struct VAPICState {
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 68bfa71..f28483c 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -958,6 +958,11 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id);
             .driver = TYPE_X86_CPU,\
             .property = "fill-mtrr-mask",\
             .value = "off",\
+        },\
+        { /* PC_RHEL7_2_COMPAT */ \
+            .driver   = "apic",\
+            .property = "legacy-instance-id",\
+            .value    = "on",\
         },
 
 
-- 
1.8.3.1

