Commit ee5306d0 authored by Fam Zheng's avatar Fam Zheng Committed by Stefan Hajnoczi
Browse files

qemu-img: Convert with copy offloading



The new blk_co_copy_range interface offers a more efficient way in the
case of network based storage. Make use of it to allow faster convert
operation.

Since copy offloading cannot do zero detection ('-S') and compression
(-c), only try it when these options are not used.

Signed-off-by: default avatarFam Zheng <famz@redhat.com>
Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Message-id: 20180601092648.24614-11-famz@redhat.com
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
parent b5679fa4
Loading
Loading
Loading
Loading
+48 −2
Original line number Diff line number Diff line
@@ -1547,6 +1547,7 @@ typedef struct ImgConvertState {
    bool compressed;
    bool target_has_backing;
    bool wr_in_order;
    bool copy_range;
    int min_sparse;
    size_t cluster_sectors;
    size_t buf_sectors;
@@ -1740,6 +1741,37 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
    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;
@@ -1762,6 +1794,7 @@ static void coroutine_fn convert_co_do_copy(void *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) {
@@ -1791,7 +1824,9 @@ static void coroutine_fn convert_co_do_copy(void *opaque)
                                        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
@@ -1813,7 +1848,15 @@ static void coroutine_fn convert_co_do_copy(void *opaque)
        }

        if (s->ret == -EINPROGRESS) {
            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));
@@ -1936,6 +1979,7 @@ static int img_convert(int argc, char **argv)
    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,
@@ -1976,6 +2020,7 @@ static int img_convert(int argc, char **argv)
            break;
        case 'c':
            s.compressed = true;
            s.copy_range = false;
            break;
        case 'o':
            if (!is_valid_option_list(optarg)) {
@@ -2017,6 +2062,7 @@ static int img_convert(int argc, char **argv)
            }

            s.min_sparse = sval / BDRV_SECTOR_SIZE;
            s.copy_range = false;
            break;
        }
        case 'p':