Now this function follows the backing chain until seeing BDRV_BLOCK_ALLOCATED. Base is not included, and it can be NULL just like bdrv_is_allocated_above().
Existing callers pass in bs->backing_hd to keep the old behavior. Signed-off-by: Fam Zheng <f...@redhat.com> --- block/io.c | 39 ++++++++++++++++++++++++++++++++------- include/block/block.h | 3 ++- qemu-img.c | 6 ++++-- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/block/io.c b/block/io.c index 1ce62c4..36a4007 100644 --- a/block/io.c +++ b/block/io.c @@ -673,7 +673,8 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags) if (nb_sectors <= 0) { return 0; } - ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n); + ret = bdrv_get_block_status(bs, bs->backing_hd, sector_num, + nb_sectors, &n); if (ret < 0) { error_report("error getting block status at sector %" PRId64 ": %s", sector_num, strerror(-ret)); @@ -1450,7 +1451,8 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, if (ret & BDRV_BLOCK_RAW) { assert(ret & BDRV_BLOCK_OFFSET_VALID); - return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS, + return bdrv_get_block_status(bs->file, bs->file->backing_hd, + ret >> BDRV_SECTOR_BITS, *pnum, pnum); } @@ -1497,14 +1499,34 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, return ret; } +static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs, + BlockDriverState *base, + int64_t sector_num, + int nb_sectors, + int *pnum) +{ + BlockDriverState *p; + int64_t ret; + + assert(bs != base); + for (p = bs; p != base; p = p->backing_hd) { + ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum); + if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) { + break; + } + } + return ret; +} + /* Coroutine wrapper for bdrv_get_block_status() */ static void coroutine_fn bdrv_get_block_status_co_entry(void *opaque) { BdrvCoGetBlockStatusData *data = opaque; - BlockDriverState *bs = data->bs; - data->ret = bdrv_co_get_block_status(bs, data->sector_num, data->nb_sectors, - data->pnum); + data->ret = bdrv_co_get_block_status_above(data->bs, data->base, + data->sector_num, + data->nb_sectors, + data->pnum); data->done = true; } @@ -1513,12 +1535,14 @@ static void coroutine_fn bdrv_get_block_status_co_entry(void *opaque) * * See bdrv_co_get_block_status() for details. */ -int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, +int64_t bdrv_get_block_status(BlockDriverState *bs, BlockDriverState *base, + int64_t sector_num, int nb_sectors, int *pnum) { Coroutine *co; BdrvCoGetBlockStatusData data = { .bs = bs, + .base = base, .sector_num = sector_num, .nb_sectors = nb_sectors, .pnum = pnum, @@ -1543,7 +1567,8 @@ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { - int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum); + int64_t ret = bdrv_get_block_status(bs, bs->backing_hd, + sector_num, nb_sectors, pnum); if (ret < 0) { return ret; } diff --git a/include/block/block.h b/include/block/block.h index 7d1a717..e1d408c 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -359,7 +359,8 @@ int bdrv_has_zero_init_1(BlockDriverState *bs); int bdrv_has_zero_init(BlockDriverState *bs); bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); -int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num, +int64_t bdrv_get_block_status(BlockDriverState *bs, BlockDriverState *base, + int64_t sector_num, int nb_sectors, int *pnum); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); diff --git a/qemu-img.c b/qemu-img.c index 8d30e43..723d8a6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1350,7 +1350,8 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS); if (s->sector_next_status <= sector_num) { - ret = bdrv_get_block_status(blk_bs(s->src[s->src_cur]), + BlockDriverState *bs = blk_bs(s->src[s->src_cur]); + ret = bdrv_get_block_status(bs, bs->backing_hd, sector_num - s->src_cur_offset, n, &n); if (ret < 0) { @@ -2287,7 +2288,8 @@ static int get_block_status(BlockDriverState *bs, int64_t sector_num, depth = 0; for (;;) { - ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors); + ret = bdrv_get_block_status(bs, bs->backing_hd, sector_num, + nb_sectors, &nb_sectors); if (ret < 0) { return ret; } -- 2.4.1