Commit 46f63e5b authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging



Block layer patches

# gpg: Signature made Thu 26 Oct 2017 14:02:54 BST
# gpg:                using RSA key 0x7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream: (35 commits)
  iotests: Add cluster_size=64k to 125
  qcow2: Always execute preallocate() in a coroutine
  qcow2: Fix unaligned preallocated truncation
  qcow2: Emit errp when truncating the image tail
  iotests: Filter actual image size in 184 and 191
  iotests: Pull _filter_actual_image_size from 67/87
  iotests: Add test for dataplane mirroring
  qcow2: Use BDRV_SECTOR_BITS instead of its literal value
  qemu-img.1: Image invalidation on qemu-img commit
  qemu-io: Relax 'alloc' now that block-status doesn't assert
  qcow2: Reduce is_zero() rounding
  block: Reduce bdrv_aligned_preadv() rounding
  block: Align block status requests
  qemu-img: Change img_compare() to be byte-based
  qemu-img: Change img_rebase() to be byte-based
  qemu-img: Change compare_sectors() to be byte-based
  qemu-img: Change check_empty_sectors() to byte-based
  qemu-img: Drop redundant error message in compare
  qemu-img: Add find_nonzero()
  qemu-img: Speed up compare on pre-allocated larger file
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 6e6430a8 4254d01c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -2245,7 +2245,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
        goto free_exit;
    }

    if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
    if (!reference &&
        bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
        qdict_put_str(options, "driver", bs->backing_format);
    }

+12 −1
Original line number Diff line number Diff line
@@ -627,6 +627,17 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
    return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
}

static int64_t coroutine_fn blkdebug_co_get_block_status(
    BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
    BlockDriverState **file)
{
    assert(QEMU_IS_ALIGNED(sector_num | nb_sectors,
                           DIV_ROUND_UP(bs->bl.request_alignment,
                                        BDRV_SECTOR_SIZE)));
    return bdrv_co_get_block_status_from_file(bs, sector_num, nb_sectors,
                                              pnum, file);
}

static void blkdebug_close(BlockDriverState *bs)
{
    BDRVBlkdebugState *s = bs->opaque;
@@ -896,7 +907,7 @@ static BlockDriver bdrv_blkdebug = {
    .bdrv_co_flush_to_disk  = blkdebug_co_flush,
    .bdrv_co_pwrite_zeroes  = blkdebug_co_pwrite_zeroes,
    .bdrv_co_pdiscard       = blkdebug_co_pdiscard,
    .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
    .bdrv_co_get_block_status = blkdebug_co_get_block_status,

    .bdrv_debug_event           = blkdebug_debug_event,
    .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
+199 −135
Original line number Diff line number Diff line
@@ -469,9 +469,9 @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
 * Round a region to cluster boundaries
 */
void bdrv_round_to_clusters(BlockDriverState *bs,
                            int64_t offset, unsigned int bytes,
                            int64_t offset, int64_t bytes,
                            int64_t *cluster_offset,
                            unsigned int *cluster_bytes)
                            int64_t *cluster_bytes)
{
    BlockDriverInfo bdi;

@@ -716,39 +716,37 @@ int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
 */
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
{
    int64_t target_sectors, ret, nb_sectors, sector_num = 0;
    int ret;
    int64_t target_size, bytes, offset = 0;
    BlockDriverState *bs = child->bs;
    BlockDriverState *file;
    int n;

    target_sectors = bdrv_nb_sectors(bs);
    if (target_sectors < 0) {
        return target_sectors;
    target_size = bdrv_getlength(bs);
    if (target_size < 0) {
        return target_size;
    }

    for (;;) {
        nb_sectors = MIN(target_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
        if (nb_sectors <= 0) {
        bytes = MIN(target_size - offset, BDRV_REQUEST_MAX_BYTES);
        if (bytes <= 0) {
            return 0;
        }
        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
        ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
        if (ret < 0) {
            error_report("error getting block status at sector %" PRId64 ": %s",
                         sector_num, strerror(-ret));
            error_report("error getting block status at offset %" PRId64 ": %s",
                         offset, strerror(-ret));
            return ret;
        }
        if (ret & BDRV_BLOCK_ZERO) {
            sector_num += n;
            offset += bytes;
            continue;
        }
        ret = bdrv_pwrite_zeroes(child, sector_num << BDRV_SECTOR_BITS,
                                 n << BDRV_SECTOR_BITS, flags);
        ret = bdrv_pwrite_zeroes(child, offset, bytes, flags);
        if (ret < 0) {
            error_report("error writing zeroes at sector %" PRId64 ": %s",
                         sector_num, strerror(-ret));
            error_report("error writing zeroes at offset %" PRId64 ": %s",
                         offset, strerror(-ret));
            return ret;
        }
        sector_num += n;
        offset += bytes;
    }
}

@@ -970,7 +968,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
    struct iovec iov;
    QEMUIOVector local_qiov;
    int64_t cluster_offset;
    unsigned int cluster_bytes;
    int64_t cluster_bytes;
    size_t skip_bytes;
    int ret;
    int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
@@ -1126,18 +1124,14 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
    }

    if (flags & BDRV_REQ_COPY_ON_READ) {
        /* TODO: Simplify further once bdrv_is_allocated no longer
         * requires sector alignment */
        int64_t start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
        int64_t end = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE);
        int64_t pnum;

        ret = bdrv_is_allocated(bs, start, end - start, &pnum);
        ret = bdrv_is_allocated(bs, offset, bytes, &pnum);
        if (ret < 0) {
            goto out;
        }

        if (!ret || pnum != end - start) {
        if (!ret || pnum != bytes) {
            ret = bdrv_co_do_copy_on_readv(child, offset, bytes, qiov);
            goto out;
        }
@@ -1767,16 +1761,18 @@ int bdrv_flush_all(void)
}


typedef struct BdrvCoGetBlockStatusData {
typedef struct BdrvCoBlockStatusData {
    BlockDriverState *bs;
    BlockDriverState *base;
    bool want_zero;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
    int64_t *map;
    BlockDriverState **file;
    int64_t sector_num;
    int nb_sectors;
    int *pnum;
    int64_t ret;
    int ret;
    bool done;
} BdrvCoGetBlockStatusData;
} BdrvCoBlockStatusData;

int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
                                                        int64_t sector_num,
@@ -1809,99 +1805,157 @@ int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
 * Drivers not implementing the functionality are assumed to not support
 * backing files, hence all their sectors are reported as allocated.
 *
 * If 'sector_num' is beyond the end of the disk image the return value is
 * BDRV_BLOCK_EOF and 'pnum' is set to 0.
 * If 'want_zero' is true, the caller is querying for mapping purposes,
 * and the result should include BDRV_BLOCK_OFFSET_VALID and
 * BDRV_BLOCK_ZERO where possible; otherwise, the result may omit those
 * bits particularly if it allows for a larger value in 'pnum'.
 *
 * 'pnum' is set to the number of sectors (including and immediately following
 * the specified sector) that are known to be in the same
 * allocated/unallocated state.
 * If 'offset' is beyond the end of the disk image the return value is
 * BDRV_BLOCK_EOF and 'pnum' is set to 0.
 *
 * 'nb_sectors' is the max value 'pnum' should be set to.  If nb_sectors goes
 * 'bytes' is the max value 'pnum' should be set to.  If bytes goes
 * beyond the end of the disk image it will be clamped; if 'pnum' is set to
 * the end of the image, then the returned value will include BDRV_BLOCK_EOF.
 *
 * If returned value is positive and BDRV_BLOCK_OFFSET_VALID bit is set, 'file'
 * points to the BDS which the sector range is allocated in.
 * 'pnum' is set to the number of bytes (including and immediately
 * following the specified offset) that are easily known to be in the
 * same allocated/unallocated state.  Note that a second call starting
 * at the original offset plus returned pnum may have the same status.
 * The returned value is non-zero on success except at end-of-file.
 *
 * Returns negative errno on failure.  Otherwise, if the
 * BDRV_BLOCK_OFFSET_VALID bit is set, 'map' and 'file' (if non-NULL) are
 * set to the host mapping and BDS corresponding to the guest offset.
 */
static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
                                                     int64_t sector_num,
                                                     int nb_sectors, int *pnum,
static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
                                             bool want_zero,
                                             int64_t offset, int64_t bytes,
                                             int64_t *pnum, int64_t *map,
                                             BlockDriverState **file)
{
    int64_t total_sectors;
    int64_t n;
    int64_t ret, ret2;
    int64_t total_size;
    int64_t n; /* bytes */
    int ret;
    int64_t local_map = 0;
    BlockDriverState *local_file = NULL;
    int64_t aligned_offset, aligned_bytes;
    uint32_t align;

    *file = NULL;
    total_sectors = bdrv_nb_sectors(bs);
    if (total_sectors < 0) {
        return total_sectors;
    assert(pnum);
    *pnum = 0;
    total_size = bdrv_getlength(bs);
    if (total_size < 0) {
        ret = total_size;
        goto early_out;
    }

    if (sector_num >= total_sectors) {
        *pnum = 0;
        return BDRV_BLOCK_EOF;
    if (offset >= total_size) {
        ret = BDRV_BLOCK_EOF;
        goto early_out;
    }
    if (!nb_sectors) {
        *pnum = 0;
        return 0;
    if (!bytes) {
        ret = 0;
        goto early_out;
    }

    n = total_sectors - sector_num;
    if (n < nb_sectors) {
        nb_sectors = n;
    n = total_size - offset;
    if (n < bytes) {
        bytes = n;
    }

    if (!bs->drv->bdrv_co_get_block_status) {
        *pnum = nb_sectors;
        *pnum = bytes;
        ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
        if (sector_num + nb_sectors == total_sectors) {
        if (offset + bytes == total_size) {
            ret |= BDRV_BLOCK_EOF;
        }
        if (bs->drv->protocol_name) {
            ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
            *file = bs;
            ret |= BDRV_BLOCK_OFFSET_VALID;
            local_map = offset;
            local_file = bs;
        }
        return ret;
        goto early_out;
    }

    bdrv_inc_in_flight(bs);
    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
                                            file);
    if (ret < 0) {
        *pnum = 0;

    /* Round out to request_alignment boundaries */
    /* TODO: until we have a byte-based driver callback, we also have to
     * round out to sectors, even if that is bigger than request_alignment */
    align = MAX(bs->bl.request_alignment, BDRV_SECTOR_SIZE);
    aligned_offset = QEMU_ALIGN_DOWN(offset, align);
    aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;

    {
        int count; /* sectors */
        int64_t longret;

        assert(QEMU_IS_ALIGNED(aligned_offset | aligned_bytes,
                               BDRV_SECTOR_SIZE));
        /*
         * The contract allows us to return pnum smaller than bytes, even
         * if the next query would see the same status; we truncate the
         * request to avoid overflowing the driver's 32-bit interface.
         */
        longret = bs->drv->bdrv_co_get_block_status(
            bs, aligned_offset >> BDRV_SECTOR_BITS,
            MIN(INT_MAX, aligned_bytes) >> BDRV_SECTOR_BITS, &count,
            &local_file);
        if (longret < 0) {
            assert(INT_MIN <= longret);
            ret = longret;
            goto out;
        }
        if (longret & BDRV_BLOCK_OFFSET_VALID) {
            local_map = longret & BDRV_BLOCK_OFFSET_MASK;
        }
        ret = longret & ~BDRV_BLOCK_OFFSET_MASK;
        *pnum = count * BDRV_SECTOR_SIZE;
    }

    /*
     * The driver's result must be a multiple of request_alignment.
     * Clamp pnum and adjust map to original request.
     */
    assert(QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset);
    *pnum -= offset - aligned_offset;
    if (*pnum > bytes) {
        *pnum = bytes;
    }
    if (ret & BDRV_BLOCK_OFFSET_VALID) {
        local_map += offset - aligned_offset;
    }

    if (ret & BDRV_BLOCK_RAW) {
        assert(ret & BDRV_BLOCK_OFFSET_VALID && *file);
        ret = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
                                       *pnum, pnum, file);
        assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
        ret = bdrv_co_block_status(local_file, want_zero, local_map,
                                   *pnum, pnum, &local_map, &local_file);
        goto out;
    }

    if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
        ret |= BDRV_BLOCK_ALLOCATED;
    } else {
    } else if (want_zero) {
        if (bdrv_unallocated_blocks_are_zero(bs)) {
            ret |= BDRV_BLOCK_ZERO;
        } else if (bs->backing) {
            BlockDriverState *bs2 = bs->backing->bs;
            int64_t nb_sectors2 = bdrv_nb_sectors(bs2);
            if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) {
            int64_t size2 = bdrv_getlength(bs2);

            if (size2 >= 0 && offset >= size2) {
                ret |= BDRV_BLOCK_ZERO;
            }
        }
    }

    if (*file && *file != bs &&
    if (want_zero && local_file && local_file != bs &&
        (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
        (ret & BDRV_BLOCK_OFFSET_VALID)) {
        BlockDriverState *file2;
        int file_pnum;
        int64_t file_pnum;
        int ret2;

        ret2 = bdrv_co_get_block_status(*file, ret >> BDRV_SECTOR_BITS,
                                        *pnum, &file_pnum, &file2);
        ret2 = bdrv_co_block_status(local_file, want_zero, local_map,
                                    *pnum, &file_pnum, NULL, NULL);
        if (ret2 >= 0) {
            /* Ignore errors.  This is just providing extra information, it
             * is useful but not necessary.
@@ -1924,26 +1978,36 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,

out:
    bdrv_dec_in_flight(bs);
    if (ret >= 0 && sector_num + *pnum == total_sectors) {
    if (ret >= 0 && offset + *pnum == total_size) {
        ret |= BDRV_BLOCK_EOF;
    }
early_out:
    if (file) {
        *file = local_file;
    }
    if (map) {
        *map = local_map;
    }
    return ret;
}

static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
                                                   BlockDriverState *base,
        int64_t sector_num,
        int nb_sectors,
        int *pnum,
                                                   bool want_zero,
                                                   int64_t offset,
                                                   int64_t bytes,
                                                   int64_t *pnum,
                                                   int64_t *map,
                                                   BlockDriverState **file)
{
    BlockDriverState *p;
    int64_t ret = 0;
    int ret = 0;
    bool first = true;

    assert(bs != base);
    for (p = bs; p != base; p = backing_bs(p)) {
        ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
        ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
                                   file);
        if (ret < 0) {
            break;
        }
@@ -1954,94 +2018,94 @@ static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
             * unallocated length we learned from an earlier
             * iteration.
             */
            *pnum = nb_sectors;
            *pnum = bytes;
        }
        if (ret & (BDRV_BLOCK_ZERO | BDRV_BLOCK_DATA)) {
            break;
        }
        /* [sector_num, pnum] unallocated on this layer, which could be only
         * the first part of [sector_num, nb_sectors].  */
        nb_sectors = MIN(nb_sectors, *pnum);
        /* [offset, pnum] unallocated on this layer, which could be only
         * the first part of [offset, bytes].  */
        bytes = MIN(bytes, *pnum);
        first = false;
    }
    return ret;
}

/* Coroutine wrapper for bdrv_get_block_status_above() */
static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
/* Coroutine wrapper for bdrv_block_status_above() */
static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque)
{
    BdrvCoGetBlockStatusData *data = opaque;
    BdrvCoBlockStatusData *data = opaque;

    data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
                                               data->sector_num,
                                               data->nb_sectors,
                                               data->pnum,
                                               data->file);
    data->ret = bdrv_co_block_status_above(data->bs, data->base,
                                           data->want_zero,
                                           data->offset, data->bytes,
                                           data->pnum, data->map, data->file);
    data->done = true;
}

/*
 * Synchronous wrapper around bdrv_co_get_block_status_above().
 * Synchronous wrapper around bdrv_co_block_status_above().
 *
 * See bdrv_co_get_block_status_above() for details.
 * See bdrv_co_block_status_above() for details.
 */
int64_t bdrv_get_block_status_above(BlockDriverState *bs,
static int bdrv_common_block_status_above(BlockDriverState *bs,
                                          BlockDriverState *base,
                                    int64_t sector_num,
                                    int nb_sectors, int *pnum,
                                          bool want_zero, int64_t offset,
                                          int64_t bytes, int64_t *pnum,
                                          int64_t *map,
                                          BlockDriverState **file)
{
    Coroutine *co;
    BdrvCoGetBlockStatusData data = {
    BdrvCoBlockStatusData data = {
        .bs = bs,
        .base = base,
        .file = file,
        .sector_num = sector_num,
        .nb_sectors = nb_sectors,
        .want_zero = want_zero,
        .offset = offset,
        .bytes = bytes,
        .pnum = pnum,
        .map = map,
        .file = file,
        .done = false,
    };

    if (qemu_in_coroutine()) {
        /* Fast-path if already in coroutine context */
        bdrv_get_block_status_above_co_entry(&data);
        bdrv_block_status_above_co_entry(&data);
    } else {
        co = qemu_coroutine_create(bdrv_get_block_status_above_co_entry,
                                   &data);
        co = qemu_coroutine_create(bdrv_block_status_above_co_entry, &data);
        bdrv_coroutine_enter(bs, co);
        BDRV_POLL_WHILE(bs, !data.done);
    }
    return data.ret;
}

int64_t bdrv_get_block_status(BlockDriverState *bs,
                              int64_t sector_num,
                              int nb_sectors, int *pnum,
                              BlockDriverState **file)
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
                            int64_t offset, int64_t bytes, int64_t *pnum,
                            int64_t *map, BlockDriverState **file)
{
    return bdrv_get_block_status_above(bs, backing_bs(bs),
                                       sector_num, nb_sectors, pnum, file);
    return bdrv_common_block_status_above(bs, base, true, offset, bytes,
                                          pnum, map, file);
}

int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
                      int64_t *pnum, int64_t *map, BlockDriverState **file)
{
    return bdrv_block_status_above(bs, backing_bs(bs),
                                   offset, bytes, pnum, map, file);
}

int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
                                   int64_t bytes, int64_t *pnum)
{
    BlockDriverState *file;
    int64_t sector_num = offset >> BDRV_SECTOR_BITS;
    int nb_sectors = bytes >> BDRV_SECTOR_BITS;
    int64_t ret;
    int psectors;
    int ret;
    int64_t dummy;

    assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
    assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE) && bytes < INT_MAX);
    ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &psectors,
                                &file);
    ret = bdrv_common_block_status_above(bs, backing_bs(bs), false, offset,
                                         bytes, pnum ? pnum : &dummy, NULL,
                                         NULL);
    if (ret < 0) {
        return ret;
    }
    if (pnum) {
        *pnum = psectors * BDRV_SECTOR_SIZE;
    }
    return !!(ret & BDRV_BLOCK_ALLOCATED);
}

+9 −17
Original line number Diff line number Diff line
@@ -190,10 +190,9 @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
    bool need_cow;
    int ret = 0;
    int64_t align_offset = *offset;
    unsigned int align_bytes = *bytes;
    int64_t align_bytes = *bytes;
    int max_bytes = s->granularity * s->max_iov;

    assert(*bytes < INT_MAX);
    need_cow = !test_bit(*offset / s->granularity, s->cow_bitmap);
    need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity,
                          s->cow_bitmap);
@@ -329,7 +328,6 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
    uint64_t delay_ns = 0;
    /* At least the first dirty chunk is mirrored in one iteration. */
    int nb_chunks = 1;
    int sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
    bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
    int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);

@@ -377,7 +375,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
    }

    /* Clear dirty bits before querying the block status, because
     * calling bdrv_get_block_status_above could yield - if some blocks are
     * calling bdrv_block_status_above could yield - if some blocks are
     * marked dirty in this window, we need to know.
     */
    bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
@@ -386,11 +384,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)

    bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
    while (nb_chunks > 0 && offset < s->bdev_length) {
        int64_t ret;
        int io_sectors;
        unsigned int io_bytes;
        int ret;
        int64_t io_bytes;
        int64_t io_bytes_acct;
        BlockDriverState *file;
        enum MirrorMethod {
            MIRROR_METHOD_COPY,
            MIRROR_METHOD_ZERO,
@@ -398,11 +394,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
        } mirror_method = MIRROR_METHOD_COPY;

        assert(!(offset % s->granularity));
        ret = bdrv_get_block_status_above(source, NULL,
                                          offset >> BDRV_SECTOR_BITS,
                                          nb_chunks * sectors_per_chunk,
                                          &io_sectors, &file);
        io_bytes = io_sectors * BDRV_SECTOR_SIZE;
        ret = bdrv_block_status_above(source, NULL, offset,
                                      nb_chunks * s->granularity,
                                      &io_bytes, NULL, NULL);
        if (ret < 0) {
            io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
        } else if (ret & BDRV_BLOCK_DATA) {
@@ -414,7 +408,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
            io_bytes = s->granularity;
        } else if (ret >= 0 && !(ret & BDRV_BLOCK_DATA)) {
            int64_t target_offset;
            unsigned int target_bytes;
            int64_t target_bytes;
            bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes,
                                   &target_offset, &target_bytes);
            if (target_offset == offset &&
@@ -1133,9 +1127,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
        granularity = bdrv_get_default_bitmap_granularity(target);
    }

    assert ((granularity & (granularity - 1)) == 0);
    /* Granularity must be large enough for sector-based dirty bitmap */
    assert(granularity >= BDRV_SECTOR_SIZE);
    assert(is_power_of_2(granularity));

    if (buf_size < 0) {
        error_setg(errp, "Invalid parameter 'buf-size'");
+1 −1
Original line number Diff line number Diff line
@@ -1632,7 +1632,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
         * cluster is already marked as zero, or if it's unallocated and we
         * don't have a backing file.
         *
         * TODO We might want to use bdrv_get_block_status(bs) here, but we're
         * TODO We might want to use bdrv_block_status(bs) here, but we're
         * holding s->lock, so that doesn't work today.
         *
         * If full_discard is true, the sector should not read back as zeroes,
Loading