Please note that there are a couple of errors (swapped parameters), which are
detailed below.
I will address these in the next iteration, along with any additional changes
based on your feedback.

Thank you
Marco

On Wednesday, October 01, 2025 18:18 CEST, Marco Cavenati 
<[email protected]> wrote:

> 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)) {

This should be
+         if (!handle_zero_mapped_ram(block, clear_bit_idx, set_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)) {

This should be
+    if (!handle_zero_mapped_ram(block, clear_bit_idx, num_pages, errp)) {

> +        return false;
> +    }
> +
>      return true;
>  
>  err:
> -- 
> 2.48.1
>


Reply via email to