From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33402) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XAhl4-0004QZ-0P for qemu-devel@nongnu.org; Fri, 25 Jul 2014 11:50:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XAhkq-0004P1-Mj for qemu-devel@nongnu.org; Fri, 25 Jul 2014 11:50:09 -0400 From: Igor Mammedov Date: Fri, 25 Jul 2014 15:48:57 +0000 Message-Id: <1406303338-13212-2-git-send-email-imammedo@redhat.com> In-Reply-To: <1406303338-13212-1-git-send-email-imammedo@redhat.com> References: <1406303338-13212-1-git-send-email-imammedo@redhat.com> Subject: [Qemu-devel] [PATCH for-2.1 1/2] migration: load smaller RAMBlock to a bigger one if permitted List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, mst@redhat.com, qemu-stable@nongnu.org, dgilbert@redhat.com, pbonzini@redhat.com, lersek@redhat.com Add API to mark memory region as extend-able on migration, to allow migration code to load smaller RAMBlock into a bigger one on destination QEMU instance. This will allow to fix broken migration from QEMU 1.7/2.0 to QEMU 2.1 due to ACPI tables size changes across 1.7/2.0/2.1 versions by marking ACPI tables ROM blob as extend-able. So that smaller tables from previos version could be always migrated to a bigger rom blob on new version. Credits-for-idea: Michael S. Tsirkin Signed-off-by: Igor Mammedov --- arch_init.c | 19 ++++++++++++++----- exec.c | 15 +++++++++------ include/exec/cpu-all.h | 15 ++++++++++++++- include/exec/memory.h | 10 ++++++++++ include/exec/ram_addr.h | 1 + memory.c | 5 +++++ 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/arch_init.c b/arch_init.c index 8ddaf35..812f8b5 100644 --- a/arch_init.c +++ b/arch_init.c @@ -1071,11 +1071,20 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (!strncmp(id, block->idstr, sizeof(id))) { - if (block->length != length) { - error_report("Length mismatch: %s: " RAM_ADDR_FMT - " in != " RAM_ADDR_FMT, id, length, - block->length); - ret = -EINVAL; + if (block->flags & RAM_EXTENDABLE_ON_MIGRATE) { + if (block->length < length) { + error_report("Length too big: %s: "RAM_ADDR_FMT + " > " RAM_ADDR_FMT, id, length, + block->length); + ret = -EINVAL; + } + } else { + if (block->length != length) { + error_report("Length mismatch: %s: "RAM_ADDR_FMT + " in != " RAM_ADDR_FMT, id, length, + block->length); + ret = -EINVAL; + } } break; } diff --git a/exec.c b/exec.c index 765bd94..755b1d3 100644 --- a/exec.c +++ b/exec.c @@ -69,12 +69,6 @@ AddressSpace address_space_memory; MemoryRegion io_mem_rom, io_mem_notdirty; static MemoryRegion io_mem_unassigned; -/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ -#define RAM_PREALLOC (1 << 0) - -/* RAM is mmap-ed with MAP_SHARED */ -#define RAM_SHARED (1 << 1) - #endif struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); @@ -1214,6 +1208,15 @@ void qemu_ram_unset_idstr(ram_addr_t addr) } } +void qemu_ram_set_extendable_on_migration(ram_addr_t addr) +{ + RAMBlock *block = find_ram_block(addr); + + if (block) { + block->flags |= RAM_EXTENDABLE_ON_MIGRATE; + } +} + static int memory_try_enable_merging(void *addr, size_t len) { if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) { diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f91581f..2b9aea3 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -296,13 +296,26 @@ CPUArchState *cpu_copy(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) /* memory API */ +typedef enum { + /* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ + RAM_PREALLOC = 1 << 0, + /* RAM is mmap-ed with MAP_SHARED */ + RAM_SHARED = 1 << 1, + /* + * Allow at migration time to load RAMBlock of smaller size than + * destination RAMBlock is + */ + RAM_EXTENDABLE_ON_MIGRATE = 1 << 2, + RAM_FLAGS_END = 1 << 31 +} RAMBlockFlags; + typedef struct RAMBlock { struct MemoryRegion *mr; uint8_t *host; ram_addr_t offset; ram_addr_t length; - uint32_t flags; + RAMBlockFlags flags; char idstr[256]; /* Reads can take either the iothread or the ramlist lock. * Writes must take both locks. diff --git a/include/exec/memory.h b/include/exec/memory.h index e2c8e3e..6c03f70 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -894,6 +894,16 @@ bool memory_region_present(MemoryRegion *container, hwaddr addr); bool memory_region_is_mapped(MemoryRegion *mr); /** + * memory_region_permit_extendable_migration: allows to mark + * #MemoryRegion as extendable on migrartion, which permits to + * load source memory block of smaller size than destination memory block + * at migration time + * + * @mr: a #MemoryRegion which should be marked as extendable on migration + */ +void memory_region_permit_extendable_migration(MemoryRegion *mr); + +/** * memory_region_find: translate an address/size relative to a * MemoryRegion into a #MemoryRegionSection. * diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 6593be1..248c075 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -33,6 +33,7 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr); void *qemu_get_ram_ptr(ram_addr_t addr); void qemu_ram_free(ram_addr_t addr); void qemu_ram_free_from_ptr(ram_addr_t addr); +void qemu_ram_set_extendable_on_migration(ram_addr_t addr); static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, ram_addr_t length, diff --git a/memory.c b/memory.c index 64d7176..744c746 100644 --- a/memory.c +++ b/memory.c @@ -1791,6 +1791,11 @@ bool memory_region_is_mapped(MemoryRegion *mr) return mr->container ? true : false; } +void memory_region_permit_extendable_migration(MemoryRegion *mr) +{ + qemu_ram_set_extendable_on_migration(mr->ram_addr); +} + MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size) { -- 1.8.3.1