int ret = 0;
aio_context_acquire(aio_context);
- block_job_ref(job);
+ job_ref(&job->job);
do {
+ float progress = 0.0f;
aio_poll(aio_context, true);
- qemu_progress_print(job->len ?
- ((float)job->offset / job->len * 100.f) : 0.0f, 0);
- } while (!job->ready && !job->completed);
+ if (job->job.progress_total) {
+ progress = (float)job->job.progress_current /
+ job->job.progress_total * 100.f;
+ }
+ qemu_progress_print(progress, 0);
+ } while (!job_is_ready(&job->job) && !job_is_completed(&job->job));
- if (!job->completed) {
- ret = block_job_complete_sync(job, errp);
+ if (!job_is_completed(&job->job)) {
+ ret = job_complete_sync(&job->job, errp);
} else {
- ret = job->ret;
+ ret = job->job.ret;
}
- block_job_unref(job);
+ job_unref(&job->job);
aio_context_release(aio_context);
/* publish completion progress only when success */
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0,
+ commit_active_start("commit", bs, base_bs, JOB_DEFAULT, 0,
BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb,
&cbi, false, &local_err);
aio_context_release(aio_context);
bool compressed;
bool target_has_backing;
bool wr_in_order;
+ bool copy_range;
int min_sparse;
size_t cluster_sectors;
size_t buf_sectors;
return 0;
}
+static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector_num,
+ int nb_sectors)
+{
+ int n, ret;
+
+ while (nb_sectors > 0) {
+ BlockBackend *blk;
+ int src_cur;
+ int64_t bs_sectors, src_cur_offset;
+ int64_t offset;
+
+ convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
+ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
+ blk = s->src[src_cur];
+ bs_sectors = s->src_sectors[src_cur];
+
+ n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
+
+ ret = blk_co_copy_range(blk, offset, s->target,
+ sector_num << BDRV_SECTOR_BITS,
+ n << BDRV_SECTOR_BITS, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ sector_num += n;
+ nb_sectors -= n;
+ }
+ return 0;
+}
+
static void coroutine_fn convert_co_do_copy(void *opaque)
{
ImgConvertState *s = opaque;
int n;
int64_t sector_num;
enum ImgConvertBlockStatus status;
+ bool copy_range;
qemu_co_mutex_lock(&s->lock);
if (s->ret != -EINPROGRESS || s->sector_num >= s->total_sectors) {
s->allocated_sectors, 0);
}
- if (status == BLK_DATA) {
+retry:
+ copy_range = s->copy_range && s->status == BLK_DATA;
+ if (status == BLK_DATA && !copy_range) {
ret = convert_co_read(s, sector_num, n, buf);
if (ret < 0) {
error_report("error while reading sector %" PRId64
}
if (s->ret == -EINPROGRESS) {
- ret = convert_co_write(s, sector_num, n, buf, status);
+ if (copy_range) {
+ ret = convert_co_copy_range(s, sector_num, n);
+ if (ret) {
+ s->copy_range = false;
+ goto retry;
+ }
+ } else {
+ ret = convert_co_write(s, sector_num, n, buf, status);
+ }
if (ret < 0) {
error_report("error while writing sector %" PRId64
": %s", sector_num, strerror(-ret));
ImgConvertState s = (ImgConvertState) {
/* Need at least 4k of zeros for sparse detection */
.min_sparse = 8,
+ .copy_range = true,
.buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
.wr_in_order = true,
.num_coroutines = 8,
break;
case 'c':
s.compressed = true;
+ s.copy_range = false;
break;
case 'o':
if (!is_valid_option_list(optarg)) {
}
s.min_sparse = sval / BDRV_SECTOR_SIZE;
+ s.copy_range = false;
break;
}
case 'p':