qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] [RFC] Add machine type pc-1.0-qemu-kvm for live mig


From: Alex Bligh
Subject: [Qemu-devel] [PATCH] [RFC] Add machine type pc-1.0-qemu-kvm for live migrate compatibility with qemu-kvm
Date: Tue, 22 Jul 2014 19:43:00 +0100

Add a machine type pc-1.0-qemu-kvm for live migrate compatibility
with qemu-kvm version 1.0.

Signed-off-by: Alex Bligh <address@hidden>
---
 hw/acpi/piix4.c          |   49 ++++++++++++++++++++++++++++++++++++++++++++--
 hw/i386/pc_piix.c        |   31 +++++++++++++++++++++++++++++
 hw/timer/i8254_common.c  |   41 ++++++++++++++++++++++++++++++++++++++
 include/hw/acpi/piix4.h  |    1 +
 include/hw/timer/i8254.h |    2 ++
 5 files changed, 122 insertions(+), 2 deletions(-)

This RFC patch adds inbound migrate capability from qemu-kvm version
1.0. The main ideas are those set out in Cole Robinson's patch here:
http://pkgs.fedoraproject.org/cgit/qemu.git/tree/0001-Fix-migration-from-qemu-kvm.patch?h=f20
however, rather than patching statically (and breaking inbound
migration on existing machine types), I have added a new machine
type (pc-1.0-qemu-kvm) without affecting any other machine types.

This requires 'hot patching' the VMStateDescription in a couple of
places, which in turn is less than obvious as there may be (indeed
are for i8259) derived classes. Whilst pretty nausea-inducing, this
approach has the benefit of being entirely self-contained.

I developed this on qemu 2.0 but have forward ported it (trivially)
to master. My testing has been on a VM live-migrated-to-file from
Ubuntu Precise qemu-kvm 1.0. Testing has been light to date (i.e.
can I migrate it inbound with -S without anything complaining).

I have not (yet) brought forward the qxl rom size (and possibly
video ram) changes in Cole's patches as I'd prefer an assessment
of whether this is the right approach first.

diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index b72b34e..708db79 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -267,8 +267,9 @@ static const VMStateDescription vmstate_memhp_state = {
 };
 
 /* qemu-kvm 1.2 uses version 3 but advertised as 2
- * To support incoming qemu-kvm 1.2 migration, change version_id
- * and minimum_version_id to 2 below (which breaks migration from
+ * To support incoming qemu-kvm 1.2 migration, we support
+ * via a command line option a change to minimum_version_id
+ * of 2 in a _compat structure (which breaks migration from
  * qemu 1.2).
  *
  */
@@ -307,6 +308,34 @@ static const VMStateDescription vmstate_acpi = {
     }
 };
 
+static const VMStateDescription vmstate_acpi_compat = {
+    .name = "piix4_pm",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = acpi_load_old,
+    .post_load = vmstate_acpi_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
+        VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+        VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
+        VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
+        VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
+        VMSTATE_STRUCT_TEST(
+            acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
+            PIIX4PMState,
+            vmstate_test_no_use_acpi_pci_hotplug,
+            2, vmstate_pci_status,
+            struct AcpiPciHpPciStatus),
+        VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
+                            vmstate_test_use_acpi_pci_hotplug),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static void piix4_reset(void *opaque)
 {
     PIIX4PMState *s = opaque;
@@ -619,6 +648,22 @@ static void piix4_pm_class_init(ObjectClass *klass, void 
*data)
     adevc->ospm_status = piix4_ospm_status;
 }
 
+void piix4_pm_class_fix_compat(void)
+{
+    GSList *el, *devices = object_class_get_list(TYPE_DEVICE, false);
+    /*
+     * Change the vmstate field in this class and any derived classes
+     * if not overriden. As no other classes should be using this
+     * vmstate, we can simply iterate the class list
+     */
+    for (el = devices; el; el = el->next) {
+        DeviceClass *dc = el->data;
+        if (dc->vmsd == &vmstate_acpi) {
+            dc->vmsd = &vmstate_acpi_compat;
+        }
+    }
+}
+
 static const TypeInfo piix4_pm_info = {
     .name          = TYPE_PIIX4_PM,
     .parent        = TYPE_PCI_DEVICE,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7081c08..e400ea6 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -49,6 +49,8 @@
 #include "hw/acpi/acpi.h"
 #include "cpu.h"
 #include "qemu/error-report.h"
+#include "hw/acpi/piix4.h"
+#include "hw/timer/i8254.h"
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
 #endif
@@ -386,6 +388,15 @@ static void pc_init_pci_1_2(MachineState *machine)
     pc_init_pci(machine);
 }
 
+/* PC machine init function for qemu-kvm 1.0 */
+static void pc_init_pci_1_2_qemu_kvm(MachineState *machine)
+{
+    piix4_pm_class_fix_compat();
+    pit_common_class_fix_compat();
+    pc_compat_1_2(machine);
+    pc_init_pci(machine);
+}
+
 /* PC init function for pc-0.10 to pc-0.13 */
 static void pc_init_pci_no_kvmclock(MachineState *machine)
 {
@@ -644,6 +655,25 @@ static QEMUMachine pc_machine_v1_0 = {
     .hw_version = "1.0",
 };
 
+#define PC_COMPAT_1_0_QEMU_KVM \
+        PC_COMPAT_1_0,\
+        {\
+            .driver   = "cirrus-vga",\
+            .property = "vgamem_mb",\
+            .value    = stringify(16),\
+        }
+
+static QEMUMachine pc_machine_v1_0_qemu_kvm = {
+    PC_I440FX_1_2_MACHINE_OPTIONS,
+    .name = "pc-1.0-qemu-kvm",
+    .init = pc_init_pci_1_2_qemu_kvm,
+    .compat_props = (GlobalProperty[]) {
+        PC_COMPAT_1_0_QEMU_KVM,
+        { /* end of list */ }
+    },
+    .hw_version = "1.0",
+};
+
 #define PC_COMPAT_0_15 \
         PC_COMPAT_1_0
 
@@ -886,6 +916,7 @@ static void pc_machine_init(void)
     qemu_register_pc_machine(&pc_machine_v1_2);
     qemu_register_pc_machine(&pc_machine_v1_1);
     qemu_register_pc_machine(&pc_machine_v1_0);
+    qemu_register_pc_machine(&pc_machine_v1_0_qemu_kvm);
     qemu_register_pc_machine(&pc_machine_v0_15);
     qemu_register_pc_machine(&pc_machine_v0_14);
     qemu_register_pc_machine(&pc_machine_v0_13);
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
index 07345f6..511ea05 100644
--- a/hw/timer/i8254_common.c
+++ b/hw/timer/i8254_common.c
@@ -275,6 +275,29 @@ static const VMStateDescription vmstate_pit_common = {
     }
 };
 
+static const VMStateDescription vmstate_pit_common_compat = {
+    .name = "i8254",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = pit_load_old,
+    .pre_save = pit_dispatch_pre_save,
+    .post_load = pit_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        /* qemu-kvm version_id=2 had 'flags' here which is equivalent
+         * This fixes incoming migration from qemu-kvm 1.0, but breaks
+         * incoming migration from qemu < 1.1
+         */
+        /* VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3), */
+        VMSTATE_UINT32(channels[0].irq_disabled, PITCommonState),
+        VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
+                             vmstate_pit_channel, PITChannelState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static void pit_common_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -289,6 +312,24 @@ static void pit_common_class_init(ObjectClass *klass, void 
*data)
     dc->cannot_instantiate_with_device_add_yet = true;
 }
 
+void pit_common_class_fix_compat(void)
+{
+    GSList *el, *devices = object_class_get_list(TYPE_DEVICE, false);
+    /*
+     * Change the vmstate field in this class and any derived classes
+     * if not overriden. As no other classes should be using this
+     * vmstate, we can simply iterate the class list
+     */
+    for (el = devices; el; el = el->next) {
+        DeviceClass *dc = el->data;
+        if (dc->vmsd == &vmstate_pit_common) {
+            dc->vmsd = &vmstate_pit_common_compat;
+        }
+    }
+
+    g_slist_free(devices);
+}
+
 static const TypeInfo pit_common_type = {
     .name          = TYPE_PIT_COMMON,
     .parent        = TYPE_ISA_DEVICE,
diff --git a/include/hw/acpi/piix4.h b/include/hw/acpi/piix4.h
index 65e6fd7..811d88f 100644
--- a/include/hw/acpi/piix4.h
+++ b/include/hw/acpi/piix4.h
@@ -4,5 +4,6 @@
 #include "qemu/typedefs.h"
 
 Object *piix4_pm_find(void);
+void piix4_pm_class_fix_compat(void);
 
 #endif
diff --git a/include/hw/timer/i8254.h b/include/hw/timer/i8254.h
index 4349033..0126424 100644
--- a/include/hw/timer/i8254.h
+++ b/include/hw/timer/i8254.h
@@ -72,4 +72,6 @@ static inline ISADevice *kvm_pit_init(ISABus *bus, int base)
 void pit_set_gate(ISADevice *dev, int channel, int val);
 void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
 
+void pit_common_class_fix_compat(void);
+
 #endif /* !HW_I8254_H */
-- 
1.7.9.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]