diff options
-rw-r--r-- | qemu-img.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/qemu-img.c b/qemu-img.c index ebe1b866da..ae4acb655b 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1556,7 +1556,9 @@ typedef struct ImgConvertState { BlockBackend *target; bool has_zero_init; bool compressed; + bool unallocated_blocks_are_zero; bool target_has_backing; + int64_t target_backing_sectors; /* negative if unknown */ bool wr_in_order; bool copy_range; int min_sparse; @@ -1586,12 +1588,23 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) { int64_t src_cur_offset; int ret, n, src_cur; + bool post_backing_zero = false; convert_select_part(s, sector_num, &src_cur, &src_cur_offset); assert(s->total_sectors > sector_num); n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS); + if (s->target_backing_sectors >= 0) { + if (sector_num >= s->target_backing_sectors) { + post_backing_zero = s->unallocated_blocks_are_zero; + } else if (sector_num + n > s->target_backing_sectors) { + /* Split requests around target_backing_sectors (because + * starting from there, zeros are handled differently) */ + n = s->target_backing_sectors - sector_num; + } + } + if (s->sector_next_status <= sector_num) { int64_t count = n * BDRV_SECTOR_SIZE; @@ -1613,7 +1626,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE); if (ret & BDRV_BLOCK_ZERO) { - s->status = BLK_ZERO; + s->status = post_backing_zero ? BLK_BACKING_FILE : BLK_ZERO; } else if (ret & BDRV_BLOCK_DATA) { s->status = BLK_DATA; } else { @@ -2379,6 +2392,16 @@ static int img_convert(int argc, char **argv) } } + if (s.target_has_backing) { + /* Errors are treated as "backing length unknown" (which means + * s.target_backing_sectors has to be negative, which it will + * be automatically). The backing file length is used only + * for optimizations, so such a case is not fatal. */ + s.target_backing_sectors = bdrv_nb_sectors(out_bs->backing->bs); + } else { + s.target_backing_sectors = -1; + } + ret = bdrv_get_info(out_bs, &bdi); if (ret < 0) { if (s.compressed) { @@ -2388,6 +2411,7 @@ static int img_convert(int argc, char **argv) } else { s.compressed = s.compressed || bdi.needs_compressed_writes; s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; + s.unallocated_blocks_are_zero = bdi.unallocated_blocks_are_zero; } ret = convert_do_copy(&s); |