Commit f06f6b66 authored by Eric Blake's avatar Eric Blake Committed by Kevin Wolf
Browse files

qcow2: Switch is_zero_sectors() to byte-based



We are gradually converting to byte-based interfaces, as they are
easier to reason about than sector-based.  Convert another internal
function (no semantic change), and rename it to is_zero() in the
process.

Signed-off-by: default avatarEric Blake <eblake@redhat.com>
Reviewed-by: default avatarFam Zheng <famz@redhat.com>
Reviewed-by: default avatarJohn Snow <jsnow@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 7cfd5275
Loading
Loading
Loading
Loading
+19 −14
Original line number Diff line number Diff line
@@ -2972,21 +2972,29 @@ finish:
}


static bool is_zero_sectors(BlockDriverState *bs, int64_t start,
                            uint32_t count)
static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
{
    int nr;
    int64_t res;
    int64_t start;

    if (start + count > bs->total_sectors) {
        count = bs->total_sectors - start;
    /* TODO: Widening to sector boundaries should only be needed as
     * long as we can't query finer granularity. */
    start = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
    bytes = QEMU_ALIGN_UP(offset + bytes, BDRV_SECTOR_SIZE) - start;

    /* Clamp to image length, before checking status of underlying sectors */
    if (start + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
        bytes = bs->total_sectors * BDRV_SECTOR_SIZE - start;
    }

    if (!count) {
    if (!bytes) {
        return true;
    }
    res = bdrv_get_block_status_above(bs, NULL, start, count, &nr, NULL);
    return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == count;
    res = bdrv_get_block_status_above(bs, NULL, start >> BDRV_SECTOR_BITS,
                                      bytes >> BDRV_SECTOR_BITS, &nr, NULL);
    return res >= 0 && (res & BDRV_BLOCK_ZERO) &&
        nr * BDRV_SECTOR_SIZE == bytes;
}

static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
@@ -3004,24 +3012,21 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
    }

    if (head || tail) {
        int64_t cl_start = (offset - head) >> BDRV_SECTOR_BITS;
        uint64_t off;
        unsigned int nr;

        assert(head + bytes <= s->cluster_size);

        /* check whether remainder of cluster already reads as zero */
        if (!(is_zero_sectors(bs, cl_start,
                              DIV_ROUND_UP(head, BDRV_SECTOR_SIZE)) &&
              is_zero_sectors(bs, (offset + bytes) >> BDRV_SECTOR_BITS,
                              DIV_ROUND_UP(-tail & (s->cluster_size - 1),
                                           BDRV_SECTOR_SIZE)))) {
        if (!(is_zero(bs, offset - head, head) &&
              is_zero(bs, offset + bytes,
                      tail ? s->cluster_size - tail : 0))) {
            return -ENOTSUP;
        }

        qemu_co_mutex_lock(&s->lock);
        /* We can have new write after previous check */
        offset = cl_start << BDRV_SECTOR_BITS;
        offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
        bytes = s->cluster_size;
        nr = s->cluster_size;
        ret = qcow2_get_cluster_offset(bs, offset, &nr, &off);