aboutsummaryrefslogtreecommitdiff
path: root/qemu-img.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu-img.c')
-rw-r--r--qemu-img.c90
1 files changed, 69 insertions, 21 deletions
diff --git a/qemu-img.c b/qemu-img.c
index e15e617..158b3a5 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];
+ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
+
n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
+ if (single_read_until > offset) {
+ n = 1;
+ }
- ret = blk_co_pread(
- blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS,
- n << BDRV_SECTOR_BITS, buf, 0);
+ 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;