qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH 2/2] pc: hack for migration compatibility from Q


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH 2/2] pc: hack for migration compatibility from QEMU 2.0
Date: Thu, 24 Jul 2014 16:28:45 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0

Il 24/07/2014 10:59, Igor Mammedov ha scritto:
> On Wed, 23 Jul 2014 18:37:46 +0200
> Paolo Bonzini <address@hidden> wrote:
> 
>> Changing the ACPI table size causes migration to break, and the memory
>> hotplug work opened our eyes on how horribly we were breaking things in
>> 2.0 already.
>>
>> The ACPI table size is rounded to the next 4k, which one would think
>> gives some headroom.  In practice this is not the case, because the user
>> can control the ACPI table size (each CPU adds 105 bytes) and so some
>> "-smp" values will break the 4k boundary and fail to migrate.  Similarly,
>> PCI bridges add ~1870 bytes to the SSDT.
>>
>> To fix this, hard-code 64k as the maximum ACPI table size, which
>> (despite being an order of magnitude smaller than 640k) should be enough
>> for everyone.
>>
>> To fix migration from QEMU 2.0, compute the payload size of QEMU 2.0
>> and always use that one.  The previous patch shrunk the ACPI tables
>> enough that the QEMU 2.0 size should always be enough.
>>
>> Non-AML tables can change depending on the configuration (especially
>> MADT, SRAT, HPET) but they remain the same between QEMU 2.0 and 2.1,
>> so we only compute our padding based on the sizes of the SSDT and DSDT.
>>
>> Migration from QEMU 1.7 should work for guests that have a number of CPUs
>> other than 12, 13, 14, 54, 55, 56, 97, 98, 139, 140, and that have no
>> PCI bridges.  It was already broken from QEMU 1.7 to QEMU 2.0 in the
>> same way, though.
>>
>> Signed-off-by: Paolo Bonzini <address@hidden>
>> ---
>>  hw/i386/acpi-build.c | 61 
>> ++++++++++++++++++++++++++++++++++++++++++++++++----
>>  hw/i386/pc_piix.c    | 20 +++++++++++++++++
>>  hw/i386/pc_q35.c     |  5 +++++
>>  include/hw/i386/pc.h |  1 +
>>  4 files changed, 83 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index ebc5f03..7373d93 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -25,7 +25,9 @@
>>  #include <glib.h>
>>  #include "qemu-common.h"
>>  #include "qemu/bitmap.h"
>> +#include "qemu/osdep.h"
>>  #include "qemu/range.h"
>> +#include "qemu/error-report.h"
>>  #include "hw/pci/pci.h"
>>  #include "qom/cpu.h"
>>  #include "hw/i386/pc.h"
>> @@ -87,6 +89,8 @@ typedef struct AcpiBuildPciBusHotplugState {
>>      struct AcpiBuildPciBusHotplugState *parent;
>>  } AcpiBuildPciBusHotplugState;
>>  
>> +unsigned bsel_alloc;
>> +
>>  static void acpi_get_dsdt(AcpiMiscInfo *info)
>>  {
>>      uint16_t *applesmc_sta;
>> @@ -759,8 +763,8 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque)
>>  static void acpi_set_pci_info(void)
>>  {
>>      PCIBus *bus = find_i440fx(); /* TODO: Q35 support */
>> -    unsigned bsel_alloc = 0;
>>  
>> +    assert(bsel_alloc == 0);
>>      if (bus) {
>>          /* Scan all PCI buses. Set property to enable acpi based hotplug. */
>>          pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
>> @@ -1440,13 +1444,14 @@ static
>>  void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
>>  {
>>      GArray *table_offsets;
>> -    unsigned facs, dsdt, rsdt;
>> +    unsigned facs, ssdt, dsdt, rsdt;
>>      AcpiCpuInfo cpu;
>>      AcpiPmInfo pm;
>>      AcpiMiscInfo misc;
>>      AcpiMcfgInfo mcfg;
>>      PcPciInfo pci;
>>      uint8_t *u;
>> +    size_t aml_len = 0;
>>  
>>      acpi_get_cpu_info(&cpu);
>>      acpi_get_pm_info(&pm);
>> @@ -1474,13 +1479,20 @@ void acpi_build(PcGuestInfo *guest_info, 
>> AcpiBuildTables *tables)
>>      dsdt = tables->table_data->len;
>>      build_dsdt(tables->table_data, tables->linker, &misc);
>>  
>> +    /* Count the size of the DSDT and SSDT, we will need it for legacy
>> +     * sizing of ACPI tables.
>> +     */
>> +    aml_len += tables->table_data->len - dsdt;
>> +
>>      /* ACPI tables pointed to by RSDT */
>>      acpi_add_table(table_offsets, tables->table_data);
>>      build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt);
>>  
>> +    ssdt = tables->table_data->len;
>>      acpi_add_table(table_offsets, tables->table_data);
>>      build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci,
>>                 guest_info);
>> +    aml_len += tables->table_data->len - ssdt;
>>  
>>      acpi_add_table(table_offsets, tables->table_data);
>>      build_madt(tables->table_data, tables->linker, &cpu, guest_info);
>> @@ -1513,12 +1525,53 @@ void acpi_build(PcGuestInfo *guest_info, 
>> AcpiBuildTables *tables)
>>      /* RSDP is in FSEG memory, so allocate it separately */
>>      build_rsdp(tables->rsdp, tables->linker, rsdt);
>>  
>> -    /* We'll expose it all to Guest so align size to reduce
>> +    /* We'll expose it all to Guest so we want to reduce
>>       * chance of size changes.
>>       * RSDP is small so it's easy to keep it immutable, no need to
>>       * bother with alignment.
>> +     *
>> +     * We used to align the tables to 4k, but of course this would
>> +     * too simple to be enough.  4k turned out to be too small an
>> +     * alignment very soon, and in fact it is almost impossible to
>> +     * keep the table size stable for all (max_cpus, max_memory_slots)
>> +     * combinations.  So the table size is always 64k for pc-2.1 and
>> +     * we give an error if the table grows beyond that limit.
>> +     *
>> +     * We still have the problem of migrating from "-M pc-2.0".  For that,
>> +     * we exploit the fact that QEMU 2.1 generates _smaller_ tables than 2.0
>> +     * and we can always pad the smaller tables with zeros.  We can then use
>> +     * the exact size of the 2.0 tables.
>> +     *
>> +     * All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration.
>>       */
>> -    acpi_align_size(tables->table_data, 0x1000);
>> +    if (guest_info->legacy_acpi_table_size) {
>> +        /* Subtracting aml_len gives the size of fixed tables.  Then add the
>> +         * size of the PIIX4 DSDT/SSDT in QEMU 2.0.
>> +         */
>> +        int legacy_aml_len =
>> +            guest_info->legacy_acpi_table_size +
>> +            97 * max_cpus +
> Commit message says it's 105 and not 97 so one of them should be fixed.
> Also please replace magic numbers (above and below) with defines so that
> it would be clear what they mean in the future.

Right, it's 97 in the SSDT and 8 in the MADT.

>> +            1875 * (MAX(bsel_alloc, 1) - 1);
>> +        int legacy_table_size =
>> +            ROUND_UP(tables->table_data->len - aml_len + legacy_aml_len, 
>> 0x1000);
> line over 80 characters
> 
>> +        if (tables->table_data->len > legacy_table_size) {
>> +            /* -M pc-2.0 doesn't support memory hotplug, so this should 
>> never
>> +             * happen.
> it supports hotplug on PCI bridges, which could lead to this branch,
> just dropping this comment is fine.

Hotplug on PCI bridges is accounted, see the 1875 above.

> Looking in future if we expand amount of supported VCPUs to 1024,
> SSDT table will quickly grow to 100K, perhaps 128K or 256K would be better?

This memory is allocated by the BIOS (including all the unused space at
the end), so I'd rather not have an exaggerate padding).

> 
>> +            /* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory 
>> slots.  */
> isn't for 2.1 VCPUs max 256, or even for 2.0?

Yeah, this is just an example.  The limit is really just what the kernel
reports.

> line over 80 characters
> 
>> +            error_report("Too many maximum CPUs, NUMA nodes or memory 
>> slots.");
> Add PCI bridges here since they affect size greatly, and even if user removes
> all CPUs and turns off memory hotplug, he still will get this error if bridge 
> devices
> at startup will exceed above limit.

Ok.

>> +            error_report("Please decrease one of these parameters.");
>> +            exit(1);
>> +        }
>> +        g_array_set_size(tables->table_data, 0x10000);
> Maybe define for size here and above?

Oops, of course. :)

Paolo



reply via email to

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