diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 4b47f7495d..1c93e6d185 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -44,9 +44,9 @@ STEXI ETEXI DEF("convert", img_convert, - "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") + "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") STEXI -@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] [--salvage] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("create", img_create, diff --git a/qemu-img.c b/qemu-img.c index e15e617256..158b3a505f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -69,6 +69,7 @@ enum { OPTION_SIZE = 264, OPTION_PREALLOCATION = 265, OPTION_SHRINK = 266, + OPTION_SALVAGE = 267, }; typedef enum OutputFormat { @@ -1581,6 +1582,7 @@ typedef struct ImgConvertState { int64_t target_backing_sectors; /* negative if unknown */ bool wr_in_order; bool copy_range; + bool salvage; bool quiet; int min_sparse; int alignment; @@ -1628,25 +1630,44 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) } if (s->sector_next_status <= sector_num) { - int64_t count = n * BDRV_SECTOR_SIZE; + uint64_t offset = (sector_num - src_cur_offset) * BDRV_SECTOR_SIZE; + int64_t count; - if (s->target_has_backing) { + do { + count = n * BDRV_SECTOR_SIZE; + + if (s->target_has_backing) { + ret = bdrv_block_status(blk_bs(s->src[src_cur]), offset, + count, &count, NULL, NULL); + } else { + ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL, + offset, count, &count, NULL, + NULL); + } + + if (ret < 0) { + if (s->salvage) { + if (n == 1) { + if (!s->quiet) { + warn_report("error while reading block status at " + "offset %" PRIu64 ": %s", offset, + strerror(-ret)); + } + /* Just try to read the data, then */ + ret = BDRV_BLOCK_DATA; + count = BDRV_SECTOR_SIZE; + } else { + /* Retry on a shorter range */ + n = DIV_ROUND_UP(n, 4); + } + } else { + error_report("error while reading block status at offset " + "%" PRIu64 ": %s", offset, strerror(-ret)); + return ret; + } + } + } while (ret < 0); - ret = bdrv_block_status(blk_bs(s->src[src_cur]), - (sector_num - src_cur_offset) * - BDRV_SECTOR_SIZE, - count, &count, NULL, NULL); - } else { - ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL, - (sector_num - src_cur_offset) * - BDRV_SECTOR_SIZE, - count, &count, NULL, NULL); - } - if (ret < 0) { - error_report("error while reading block status of sector %" PRId64 - ": %s", sector_num, strerror(-ret)); - return ret; - } n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE); if (ret & BDRV_BLOCK_ZERO) { @@ -1683,6 +1704,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, int nb_sectors, uint8_t *buf) { + uint64_t single_read_until = 0; int n, ret; assert(nb_sectors <= s->buf_sectors); @@ -1690,6 +1712,7 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, BlockBackend *blk; int src_cur; int64_t bs_sectors, src_cur_offset; + uint64_t offset; /* In the case of compression with multiple source files, we can get a * nb_sectors that spreads into the next part. So we must be able to @@ -1698,13 +1721,29 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, blk = s->src[src_cur]; bs_sectors = s->src_sectors[src_cur]; - n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset)); + offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS; - ret = blk_co_pread( - blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS, - n << BDRV_SECTOR_BITS, buf, 0); + n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset)); + if (single_read_until > offset) { + n = 1; + } + + ret = blk_co_pread(blk, offset, n << BDRV_SECTOR_BITS, buf, 0); if (ret < 0) { - return ret; + if (s->salvage) { + if (n > 1) { + single_read_until = offset + (n << BDRV_SECTOR_BITS); + continue; + } else { + if (!s->quiet) { + warn_report("error while reading offset %" PRIu64 + ": %s", offset, strerror(-ret)); + } + memset(buf, 0, BDRV_SECTOR_SIZE); + } + } else { + return ret; + } } sector_num += n; @@ -2035,6 +2074,7 @@ static int img_convert(int argc, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {"force-share", no_argument, 0, 'U'}, {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, + {"salvage", no_argument, 0, OPTION_SALVAGE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU", @@ -2152,6 +2192,9 @@ static int img_convert(int argc, char **argv) case OPTION_IMAGE_OPTS: image_opts = true; break; + case OPTION_SALVAGE: + s.salvage = true; + break; case OPTION_TARGET_IMAGE_OPTS: tgt_image_opts = true; break; @@ -2178,6 +2221,11 @@ static int img_convert(int argc, char **argv) goto fail_getopt; } + if (s.copy_range && s.salvage) { + error_report("Cannot use copy offloading in salvaging mode"); + goto fail_getopt; + } + if (tgt_image_opts && !skip_create) { error_report("--target-image-opts requires use of -n flag"); goto fail_getopt; diff --git a/qemu-img.texi b/qemu-img.texi index e8bc0fd7a2..c8e9bba515 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -175,6 +175,10 @@ improve performance if the data is remote, such as with NFS or iSCSI backends, but will not automatically sparsify zero sectors, and may result in a fully allocated target image depending on the host support for getting allocation information. +@item --salvage +Try to ignore I/O errors when reading. Unless in quiet mode (@code{-q}), errors +will still be printed. Areas that cannot be read from the source will be +treated as containing only zeroes. @end table Parameters to dd subcommand: