> Let's factor out the core logic, to be reused soon. > > Cc: Paolo Bonzini <pbonz...@redhat.com> > Cc: "Michael S. Tsirkin" <m...@redhat.com> > Cc: Alex Williamson <alex.william...@redhat.com> > Cc: Dr. David Alan Gilbert <dgilb...@redhat.com> > Cc: Igor Mammedov <imamm...@redhat.com> > Cc: Pankaj Gupta <pankaj.gupta.li...@gmail.com> > Cc: Peter Xu <pet...@redhat.com> > Cc: Auger Eric <eric.au...@redhat.com> > Cc: Wei Yang <richard.weiy...@linux.alibaba.com> > Cc: teawater <teawat...@linux.alibaba.com> > Cc: Marek Kedzierski <mkedz...@redhat.com> > Signed-off-by: David Hildenbrand <da...@redhat.com> > --- > hw/virtio/virtio-mem.c | 86 ++++++++++++++++++++++++------------------ > 1 file changed, 49 insertions(+), 37 deletions(-) > > diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c > index 655824ff81..471e464171 100644 > --- a/hw/virtio/virtio-mem.c > +++ b/hw/virtio/virtio-mem.c > @@ -145,6 +145,33 @@ static bool virtio_mem_is_busy(void) > return migration_in_incoming_postcopy() || !migration_is_idle(); > } > > +typedef int (*virtio_mem_range_cb)(const VirtIOMEM *vmem, void *arg, > + uint64_t offset, uint64_t size); > + > +static int virtio_mem_for_each_unplugged_range(const VirtIOMEM *vmem, void > *arg, > + virtio_mem_range_cb cb) > +{ > + unsigned long first_zero_bit, last_zero_bit; > + uint64_t offset, size; > + int ret = 0; > + > + first_zero_bit = find_first_zero_bit(vmem->bitmap, vmem->bitmap_size); > + while (first_zero_bit < vmem->bitmap_size) { > + offset = first_zero_bit * vmem->block_size; > + last_zero_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, > + first_zero_bit + 1) - 1; > + size = (last_zero_bit - first_zero_bit + 1) * vmem->block_size; > + > + ret = cb(vmem, arg, offset, size); > + if (ret) { > + break; > + } > + first_zero_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, > + last_zero_bit + 2); > + } > + return ret; > +} > + > static bool virtio_mem_test_bitmap(VirtIOMEM *vmem, uint64_t start_gpa, > uint64_t size, bool plugged) > { > @@ -594,33 +621,27 @@ static void virtio_mem_device_unrealize(DeviceState > *dev) > ram_block_discard_require(false); > } > > -static int virtio_mem_restore_unplugged(VirtIOMEM *vmem) > +static int virtio_mem_discard_range_cb(const VirtIOMEM *vmem, void *arg, > + uint64_t offset, uint64_t size) > { > RAMBlock *rb = vmem->memdev->mr.ram_block; > - unsigned long first_zero_bit, last_zero_bit; > - uint64_t offset, length; > int ret; > > - /* Find consecutive unplugged blocks and discard the consecutive range. > */ > - first_zero_bit = find_first_zero_bit(vmem->bitmap, vmem->bitmap_size); > - while (first_zero_bit < vmem->bitmap_size) { > - offset = first_zero_bit * vmem->block_size; > - last_zero_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, > - first_zero_bit + 1) - 1; > - length = (last_zero_bit - first_zero_bit + 1) * vmem->block_size; > - > - ret = ram_block_discard_range(rb, offset, length); > - if (ret) { > - error_report("Unexpected error discarding RAM: %s", > - strerror(-ret)); > - return -EINVAL; > - } > - first_zero_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, > - last_zero_bit + 2); > + ret = ram_block_discard_range(rb, offset, size); > + if (ret) { > + error_report("Unexpected error discarding RAM: %s", strerror(-ret)); > + return -EINVAL; > } > return 0; > } > > +static int virtio_mem_restore_unplugged(VirtIOMEM *vmem) > +{ > + /* Make sure all memory is really discarded after migration. */ > + return virtio_mem_for_each_unplugged_range(vmem, NULL, > + virtio_mem_discard_range_cb); > +} > + > static int virtio_mem_post_load(void *opaque, int version_id) > { > if (migration_in_incoming_postcopy()) { > @@ -872,28 +893,19 @@ static void virtio_mem_set_block_size(Object *obj, > Visitor *v, const char *name, > vmem->block_size = value; > } > > -static void virtio_mem_precopy_exclude_unplugged(VirtIOMEM *vmem) > +static int virtio_mem_precopy_exclude_range_cb(const VirtIOMEM *vmem, void > *arg, > + uint64_t offset, uint64_t > size) > { > void * const host = qemu_ram_get_host_addr(vmem->memdev->mr.ram_block); > - unsigned long first_zero_bit, last_zero_bit; > - uint64_t offset, length; > > - /* > - * Find consecutive unplugged blocks and exclude them from migration. > - * > - * Note: Blocks cannot get (un)plugged during precopy, no locking needed. > - */ > - first_zero_bit = find_first_zero_bit(vmem->bitmap, vmem->bitmap_size); > - while (first_zero_bit < vmem->bitmap_size) { > - offset = first_zero_bit * vmem->block_size; > - last_zero_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, > - first_zero_bit + 1) - 1; > - length = (last_zero_bit - first_zero_bit + 1) * vmem->block_size; > + qemu_guest_free_page_hint(host + offset, size); > + return 0; > +} > > - qemu_guest_free_page_hint(host + offset, length); > - first_zero_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, > - last_zero_bit + 2); > - } > +static void virtio_mem_precopy_exclude_unplugged(VirtIOMEM *vmem) > +{ > + virtio_mem_for_each_unplugged_range(vmem, NULL, > + virtio_mem_precopy_exclude_range_cb); > } > > static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data)
Reviewed-by: Pankaj Gupta <pankaj.gu...@cloud.ionos.com>