For cpr-exec mode, ramblock_is_ignored is always true, and the address of each migrated memory region must match the address of the statically initialized region on the target. However, for a PCI rom block, the region address is set when the guest writes to a BAR on the source, which does not occur on the target, causing a "Mismatched GPAs" error during cpr-exec migration.
To fix, unconditionally set the target's address to the source's address if the region does not have an address yet. Signed-off-by: Steve Sistare <steven.sist...@oracle.com> --- include/exec/memory.h | 12 ++++++++++++ migration/ram.c | 15 +++++++++------ system/memory.c | 10 ++++++++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index d337737..4f654b0 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -801,6 +801,7 @@ struct MemoryRegion { bool unmergeable; uint8_t dirty_log_mask; bool is_iommu; + bool has_addr; RAMBlock *ram_block; Object *owner; /* owner as TYPE_DEVICE. Used for re-entrancy checks in MR access hotpath */ @@ -2402,6 +2403,17 @@ void memory_region_set_enabled(MemoryRegion *mr, bool enabled); void memory_region_set_address(MemoryRegion *mr, hwaddr addr); /* + * memory_region_set_address_only: set the address of a region. + * + * Same as memory_region_set_address, but without causing transaction side + * effects. + * + * @mr: the region to be updated + * @addr: new address, relative to container region + */ +void memory_region_set_address_only(MemoryRegion *mr, hwaddr addr); + +/* * memory_region_set_size: dynamically update the size of a region. * * Dynamically updates the size of a region. diff --git a/migration/ram.c b/migration/ram.c index add285b..7b8d7f6 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4196,12 +4196,15 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) } if (migrate_ignore_shared()) { hwaddr addr = qemu_get_be64(f); - if (migrate_ram_is_ignored(block) && - block->mr->addr != addr) { - error_report("Mismatched GPAs for block %s " - "%" PRId64 "!= %" PRId64, block->idstr, - (uint64_t)addr, (uint64_t)block->mr->addr); - return -EINVAL; + if (migrate_ram_is_ignored(block)) { + if (!block->mr->has_addr) { + memory_region_set_address_only(block->mr, addr); + } else if (block->mr->addr != addr) { + error_report("Mismatched GPAs for block %s " + "%" PRId64 "!= %" PRId64, block->idstr, + (uint64_t)addr, (uint64_t)block->mr->addr); + return -EINVAL; + } } } ret = rdma_block_notification_handle(f, block->idstr); diff --git a/system/memory.c b/system/memory.c index ca04a0e..3c72504 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2665,7 +2665,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr, for (alias = subregion->alias; alias; alias = alias->alias) { alias->mapped_via_alias++; } - subregion->addr = offset; + memory_region_set_address_only(subregion, offset); memory_region_update_container_subregions(subregion); } @@ -2745,10 +2745,16 @@ static void memory_region_readd_subregion(MemoryRegion *mr) } } +void memory_region_set_address_only(MemoryRegion *mr, hwaddr addr) +{ + mr->addr = addr; + mr->has_addr = true; +} + void memory_region_set_address(MemoryRegion *mr, hwaddr addr) { if (addr != mr->addr) { - mr->addr = addr; + memory_region_set_address_only(mr, addr); memory_region_readd_subregion(mr); } } -- 1.8.3.1