static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) { int64_t sector_num, end; BlockDriverState *base = s->base; BlockDriverState *bs = s->source; BlockDriverState *target_bs = blk_bs(s->target); int ret, n; end = s->bdev_length / BDRV_SECTOR_SIZE; if (base == NULL && !bdrv_has_zero_init(target_bs)) { if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, end); return 0; } s->initial_zeroing_ongoing = true; for (sector_num = 0; sector_num < end; ) { int nb_sectors = MIN(end - sector_num, QEMU_ALIGN_DOWN(INT_MAX, s->granularity) >> BDRV_SECTOR_BITS); mirror_throttle(s); if (block_job_is_cancelled(&s->common)) { s->initial_zeroing_ongoing = false; return 0; } 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; } mirror_wait_for_all_io(s); s->initial_zeroing_ongoing = false; } /* First part, loop on the sectors and initialize the dirty bitmap. */ for (sector_num = 0; sector_num < end; ) { /* Just to make sure we are not exceeding int limit. */ int nb_sectors = MIN(INT_MAX >> BDRV_SECTOR_BITS, end - sector_num); mirror_throttle(s); if (block_job_is_cancelled(&s->common)) { return 0; } ret = bdrv_is_allocated_above(bs, base, sector_num, nb_sectors, &n); if (ret < 0) { return ret; } assert(n > 0); if (ret == 1) { bdrv_set_dirty_bitmap(s->dirty_bitmap, sector_num, n); } sector_num += n; } return 0; }