Make mapped-ram compatible with loadvm snapshot restoring by explicitly zeroing memory pages in this case. Skip zeroing for -incoming and -loadvm migrations to preserve performance.
Signed-off-by: Marco Cavenati <[email protected]> --- migration/ram.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index e238c9233f..597d5ffe9e 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3958,12 +3958,55 @@ static size_t ram_load_multifd_pages(void *host_addr, size_t size, return size; } +/** + * handle_zero_mapped_ram: Zero out a range of RAM pages if required during + * mapped-ram load + * + * Zeroing is only performed when restoring from a snapshot (HMP loadvm). + * During incoming migration or -loadvm cli snapshot load, the function is a + * no-op and returns true as in those cases the pages are already guaranteed to + * be zeroed. + * + * Returns: true on success, false on error (with @errp set). + * @from_bit_idx: Starting index relative to the map of the page (inclusive) + * @to_bit_idx: Ending index relative to the map of the page (exclusive) + */ +static bool handle_zero_mapped_ram(RAMBlock *block, unsigned long from_bit_idx, + unsigned long to_bit_idx, Error **errp) +{ + ERRP_GUARD(); + ram_addr_t offset; + size_t size; + void *host; + + if (runstate_check(RUN_STATE_INMIGRATE) || + runstate_check(RUN_STATE_PRELAUNCH)) { + return true; + } + + if (from_bit_idx == to_bit_idx) { + return true; + } + + size = TARGET_PAGE_SIZE * (to_bit_idx - from_bit_idx); + offset = from_bit_idx << TARGET_PAGE_BITS; + host = host_from_ram_block_offset(block, offset); + if (!host) { + error_setg(errp, "zero page outside of ramblock %s range", + block->idstr); + return false; + } + ram_handle_zero(host, size); + + return true; +} + static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block, long num_pages, unsigned long *bitmap, Error **errp) { ERRP_GUARD(); - unsigned long set_bit_idx, clear_bit_idx; + unsigned long set_bit_idx, clear_bit_idx = 0; ram_addr_t offset; void *host; size_t read, unread, size; @@ -3972,6 +4015,12 @@ static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block, set_bit_idx < num_pages; set_bit_idx = find_next_bit(bitmap, num_pages, clear_bit_idx + 1)) { + /* Zero pages */ + if (!handle_zero_mapped_ram(block, set_bit_idx, clear_bit_idx, errp)) { + return false; + } + + /* Non-zero pages */ clear_bit_idx = find_next_zero_bit(bitmap, num_pages, set_bit_idx + 1); unread = TARGET_PAGE_SIZE * (clear_bit_idx - set_bit_idx); @@ -4003,6 +4052,11 @@ static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block, } } + /* Handle trailing 0 pages */ + if (!handle_zero_mapped_ram(block, num_pages, clear_bit_idx, errp)) { + return false; + } + return true; err: -- 2.48.1
