With a bdrv_co_write_zeroes method on a target BDS zeroes will not be placed into the wire. Thus the target could be very efficiently zeroed out. This is should be done with the largest chunk possible.
This improves the performance of the live migration of the empty disk by 150 times if NBD supports write_zeroes. Signed-off-by: Denis V. Lunev <d...@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy<vsement...@virtuozzo.com> CC: Stefan Hajnoczi <stefa...@redhat.com> CC: Fam Zheng <f...@redhat.com> CC: Kevin Wolf <kw...@redhat.com> CC: Max Reitz <mre...@redhat.com> CC: Jeff Cody <jc...@redhat.com> CC: Eric Blake <ebl...@redhat.com> --- block/mirror.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/block/mirror.c b/block/mirror.c index c7b3639..c2f8773 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -21,6 +21,7 @@ #include "qemu/ratelimit.h" #include "qemu/bitmap.h" +#define MIRROR_ZERO_CHUNK (3u << (29 - BDRV_SECTOR_BITS)) /* 1.5 Gb */ #define SLICE_TIME 100000000ULL /* ns */ #define MAX_IN_FLIGHT 16 #define DEFAULT_MIRROR_BUF_SIZE (10 << 20) @@ -512,7 +513,8 @@ static int mirror_dirty_init(MirrorBlockJob *s) end = s->bdev_length / BDRV_SECTOR_SIZE; - if (base == NULL && !bdrv_has_zero_init(target_bs)) { + if (base == NULL && !bdrv_has_zero_init(target_bs) && + target_bs->drv->bdrv_co_write_zeroes == NULL) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, end); return 0; } @@ -546,6 +548,34 @@ static int mirror_dirty_init(MirrorBlockJob *s) } sector_num += n; } + + if (base != NULL || bdrv_has_zero_init(target_bs)) { + /* no need to zero out entire disk */ + return 0; + } + + for (sector_num = 0; sector_num < end; ) { + int nb_sectors = MIN(MIRROR_ZERO_CHUNK, end - sector_num); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + + if (now - last_pause_ns > SLICE_TIME) { + last_pause_ns = now; + block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, 0); + } + + if (block_job_is_cancelled(&s->common)) { + return -EINTR; + } + + if (s->in_flight == MAX_IN_FLIGHT) { + trace_mirror_yield(s, s->in_flight, s->buf_free_count, -1); + mirror_wait_for_io(s); + continue; + } + + mirror_do_zero_or_discard(s, sector_num, nb_sectors, false); + sector_num += nb_sectors; + } return 0; } -- 2.5.0