diff mbox

[1/2] acpi_piix4: fix migration of gpe fields

Message ID f8f0ebb7-0c79-8570-3210-dc45c3effda8@univention.de (mailing list archive)
State New, archived
Headers show

Commit Message

Philipp Hahn March 20, 2017, 12:02 p.m. UTC
Hello Marcelo, cc:qemu,

Sorry for re-using this old thread, but I have a problem loading some
saved state from qemu-kvm-1.1.2, which fails for piix4_pm.

You following patch was committed as
<http://git.qemu-project.org/?p=qemu.git;a=commitdiff;h=b0b873a07872f7ab7f66f259c73fb9dd42aa66a9>:

Am 15.11.2012 um 01:11 schrieb Marcelo Tosatti:
> Migrate 16 bytes for en/sts fields (which is the correct size),
> increase version to 3, and document how to support incoming
> migration from qemu-kvm 1.2.

I my case qemu-kvm-1.1.2/hw/acpi_piix4.c:284
| VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
only saves 4 bytes, not 16 bytes.

> Acked-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
> ---
>  hw/acpi_piix4.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++----
>  1 files changed, 46 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
> index 15275cf..519269a 100644
> --- a/hw/acpi_piix4.c
> +++ b/hw/acpi_piix4.c
> @@ -235,10 +235,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
>   {                                                                   \
>       .name       = (stringify(_field)),                              \
>       .version_id = 0,                                                \
> -     .num        = GPE_LEN,                                          \
>       .info       = &vmstate_info_uint16,                             \
>       .size       = sizeof(uint16_t),                                 \
> -     .flags      = VMS_ARRAY | VMS_POINTER,                          \
> +     .flags      = VMS_SINGLE | VMS_POINTER,                         \
>       .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
>   }
>  
> @@ -267,11 +266,54 @@ static const VMStateDescription vmstate_pci_status = {
>      }
>  };

On load qemu-2.8 uses this function

> +static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
> +{
> +    PIIX4PMState *s = opaque;
> +    int ret, i;
> +    uint16_t temp;
> +
> +    ret = pci_device_load(&s->dev, f);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +    qemu_get_be16s(f, &s->ar.pm1.evt.sts);
> +    qemu_get_be16s(f, &s->ar.pm1.evt.en);
> +    qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
> +
> +    ret = vmstate_load_state(f, &vmstate_apm, opaque, 1);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    qemu_get_timer(f, s->ar.tmr.timer);
> +    qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
> +
> +    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
> +    for (i = 0; i < 3; i++) {
> +        qemu_get_be16s(f, &temp);
> +    }

and the loop loads 6 extra bytes here

> +
> +    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
> +    for (i = 0; i < 3; i++) {
> +        qemu_get_be16s(f, &temp);
> +    }

and 6 here.
So in total 12 bytes are read too much and qemu_loadvm_state() ends
somewhere in the middle of the next device state section. (patch 0001
helped me to identify that offset)

If I apply the attached 0002 patch, I can load the old VM state.

> +
> +    ret = vmstate_load_state(f, &vmstate_pci_status, opaque, 1);
> +    return ret;
> +}
> +
> +/* 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
> + * qemu 1.2).
> + *
> + */
>  static const VMStateDescription vmstate_acpi = {
>      .name = "piix4_pm",
> -    .version_id = 2,
> -    .minimum_version_id = 1,
> +    .version_id = 3,
> +    .minimum_version_id = 3,
>      .minimum_version_id_old = 1,
> +    .load_state_old = acpi_load_old,
>      .post_load = vmstate_acpi_post_load,
>      .fields      = (VMStateField []) {
>          VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
> 

Do you remember why 16 bytes were saved in your case?

Thank you in advance.

Philipp

Comments

Marcelo Tosatti March 20, 2017, 11:20 p.m. UTC | #1
On Mon, Mar 20, 2017 at 01:02:10PM +0100, Philipp Hahn wrote:
> Hello Marcelo, cc:qemu,
> 
> Sorry for re-using this old thread, but I have a problem loading some
> saved state from qemu-kvm-1.1.2, which fails for piix4_pm.
> 
> You following patch was committed as
> <http://git.qemu-project.org/?p=qemu.git;a=commitdiff;h=b0b873a07872f7ab7f66f259c73fb9dd42aa66a9>:
> 
> Am 15.11.2012 um 01:11 schrieb Marcelo Tosatti:
> > Migrate 16 bytes for en/sts fields (which is the correct size),
> > increase version to 3, and document how to support incoming
> > migration from qemu-kvm 1.2.
> 
> I my case qemu-kvm-1.1.2/hw/acpi_piix4.c:284
> | VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
> only saves 4 bytes, not 16 bytes.

Hi Philipp,

IIRC qemu-1.1.2 saved 16 bytes, which is the correct size, not 4 bytes.

So while merging from qemu-kvm -> qemu, it was decided to maintain
backwards compability with qemu, and not qemu-kvm.

Is there any way to differentiate between the two (qemu vs qemu-kvm, 
perhaps via some other field not in the VMState of ACPI PIIX4), so
your patch can be integrated upstream?
Philipp Hahn March 21, 2017, 9:03 a.m. UTC | #2
Hello Marcelo,

Am 21.03.2017 um 00:20 schrieb Marcelo Tosatti:
> On Mon, Mar 20, 2017 at 01:02:10PM +0100, Philipp Hahn wrote:
>> Hello Marcelo, cc:qemu,
>>
>> Sorry for re-using this old thread, but I have a problem loading some
>> saved state from qemu-kvm-1.1.2, which fails for piix4_pm.
>>
>> You following patch was committed as
>> <http://git.qemu-project.org/?p=qemu.git;a=commitdiff;h=b0b873a07872f7ab7f66f259c73fb9dd42aa66a9>:
>>
>> Am 15.11.2012 um 01:11 schrieb Marcelo Tosatti:
>>> Migrate 16 bytes for en/sts fields (which is the correct size),
>>> increase version to 3, and document how to support incoming
>>> migration from qemu-kvm 1.2.
>>
>> I my case qemu-kvm-1.1.2/hw/acpi_piix4.c:284
>> | VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
>> only saves 4 bytes, not 16 bytes.
> 
> IIRC qemu-1.1.2 saved 16 bytes, which is the correct size, not 4 bytes.

I found 23910d3f669d46073b403876e30a7314599633af in qemu, which changed
"gpe" to be an array[4] instead of single "struct gpe_regs" without
changing the version number. So the incompatibility was introduced there.

> So while merging from qemu-kvm -> qemu, it was decided to maintain
> backwards compability with qemu, and not qemu-kvm.
> 
> Is there any way to differentiate between the two (qemu vs qemu-kvm, 
> perhaps via some other field not in the VMState of ACPI PIIX4), so
> your patch can be integrated upstream?

I had a look and haven't found any reliable indicator to distinguish
between "qemu" and "qemu-kvm" yet. I'll have another look if my time
permits, but as I know "qemu-kvm" was used in my case, I will hard code
that knowledge for now in my private build.

Thank you four sharing your knowledge.

Philipp
diff mbox

Patch

From 1313efdc0ac664169c5c271f832264efe6659743 Mon Sep 17 00:00:00 2001
Message-Id: <1313efdc0ac664169c5c271f832264efe6659743.1490011194.git.hahn@univention.de>
From: Philipp Hahn <hahn@univention.de>
Date: Fri, 17 Mar 2017 12:51:01 +0100
Subject: [PATCH 1/2] 0006-Bug-38877-debug-loadvm-offset
Organization: Univention GmbH, Bremen, Germany
To: qemu-devel@nongnu.org

debug: Print offset on section error:

30143@1489751176.344102:qemu_loadvm_state_section 48@0x364da2

Gbp: Topic debug
Signed-off-by: Philipp Hahn <hahn@univention.de>
---
 include/migration/qemu-file.h | 1 +
 migration/qemu-file.c         | 5 +++++
 migration/savevm.c            | 2 +-
 migration/trace-events        | 2 +-
 4 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index abedd46..a570836 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -126,6 +126,7 @@  int qemu_get_fd(QEMUFile *f);
 int qemu_fclose(QEMUFile *f);
 int64_t qemu_ftell(QEMUFile *f);
 int64_t qemu_ftell_fast(QEMUFile *f);
+int64_t qemu_ftell_internal(QEMUFile *f);
 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size);
 void qemu_put_byte(QEMUFile *f, int v);
 /*
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index e9fae31..862b8c7 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -543,6 +543,11 @@  int64_t qemu_ftell(QEMUFile *f)
     return f->pos;
 }
 
+int64_t qemu_ftell_internal(QEMUFile *f)
+{
+    return f->pos - f->buf_size + f->buf_index;
+}
+
 int qemu_file_rate_limit(QEMUFile *f)
 {
     if (qemu_file_get_error(f)) {
diff --git a/migration/savevm.c b/migration/savevm.c
index 0363372..da2a98b 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1882,7 +1882,7 @@  static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
 
     while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
         ret = 0;
-        trace_qemu_loadvm_state_section(section_type);
+        trace_qemu_loadvm_state_section(section_type, qemu_ftell_internal(f) - 1);
         switch (section_type) {
         case QEMU_VM_SECTION_START:
         case QEMU_VM_SECTION_FULL:
diff --git a/migration/trace-events b/migration/trace-events
index 94134f7..49f8458 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -1,7 +1,7 @@ 
 # See docs/tracing.txt for syntax documentation.
 
 # migration/savevm.c
-qemu_loadvm_state_section(unsigned int section_type) "%d"
+qemu_loadvm_state_section(unsigned int section_type, uint64_t offset) "%d@0x%" PRIx64
 qemu_loadvm_state_section_command(int ret) "%d"
 qemu_loadvm_state_section_partend(uint32_t section_id) "%u"
 qemu_loadvm_state_main(void) ""
-- 
2.1.4