[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 15/20] qemu-img: Add salvaging mode to convert
From: |
Max Reitz |
Subject: |
[Qemu-devel] [PULL 15/20] qemu-img: Add salvaging mode to convert |
Date: |
Fri, 14 Jun 2019 15:40:16 +0200 |
This adds a salvaging mode (--salvage) to qemu-img convert which ignores
read errors and treats the respective areas as containing only zeroes.
This can be used for instance to at least partially recover the data
from terminally corrupted qcow2 images.
Signed-off-by: Max Reitz <address@hidden>
Reviewed-by: Vladimir Sementsov-Ogievskiy <address@hidden>
Message-id: address@hidden
Signed-off-by: Max Reitz <address@hidden>
---
qemu-img.c | 90 +++++++++++++++++++++++++++++++++++++-----------
qemu-img-cmds.hx | 4 +--
qemu-img.texi | 4 +++
3 files changed, 75 insertions(+), 23 deletions(-)
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];
+ 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;
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.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:
--
2.21.0
- [Qemu-devel] [PULL 03/20] QEMUMachine: add events_wait method, (continued)
- [Qemu-devel] [PULL 03/20] QEMUMachine: add events_wait method, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 09/20] hw/block/fdc: floppy command FIFO memory initialization, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 08/20] iotests: Fix intermittent failure in 219, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 05/20] iotests: add iotest 256 for testing blockdev-backup across iothread contexts, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 07/20] iotests: Filter 175's allocation information, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 10/20] iotests: restrict 254 to support only qcow2, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 11/20] qemu-img: Fix options leakage in img_rebase(), Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 12/20] qapi/block-core: Overlays are not snapshots, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 13/20] blockdev: Overlays are not snapshots, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 14/20] qemu-img: Move quiet into ImgConvertState, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 15/20] qemu-img: Add salvaging mode to convert,
Max Reitz <=
- [Qemu-devel] [PULL 16/20] blkdebug: Add @iotype error option, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 18/20] blkdebug: Inject errors on .bdrv_co_block_status(), Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 19/20] iotests: Test qemu-img convert --salvage, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 17/20] blkdebug: Add "none" event, Max Reitz, 2019/06/14
- [Qemu-devel] [PULL 20/20] iotests: Test qemu-img convert -C --salvage, Max Reitz, 2019/06/14
- Re: [Qemu-devel] [PULL 00/20] Block patches, Peter Maydell, 2019/06/14