The QED block driver already provides the functionality to not only detect inconsistencies in images, but also fix them. However, this functionality cannot be manually invoked with qemu-img, but the check happens only automatically during bdrv_open().
This adds a -r switch to qemu-img check that allows manual invocation of an image repair. Signed-off-by: Kevin Wolf <kw...@redhat.com> --- block.c | 4 ++-- block.h | 7 ++++++- block/qcow2.c | 7 ++++++- block/qed.c | 5 +++-- block/vdi.c | 7 ++++++- block_int.h | 3 ++- qemu-img-cmds.hx | 4 ++-- qemu-img.c | 25 ++++++++++++++++++++++--- qemu-img.texi | 7 ++++++- 9 files changed, 55 insertions(+), 14 deletions(-) diff --git a/block.c b/block.c index c07ff39..355ac86 100644 --- a/block.c +++ b/block.c @@ -1222,14 +1222,14 @@ bool bdrv_dev_is_medium_locked(BlockDriverState *bs) * free of errors) or -errno when an internal error occurred. The results of the * check are stored in res. */ -int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) { if (bs->drv->bdrv_check == NULL) { return -ENOTSUP; } memset(res, 0, sizeof(*res)); - return bs->drv->bdrv_check(bs, res); + return bs->drv->bdrv_check(bs, res, fix); } #define COMMIT_BUF_SECTORS 2048 diff --git a/block.h b/block.h index 799cf48..61b7e8e 100644 --- a/block.h +++ b/block.h @@ -190,7 +190,12 @@ typedef struct BdrvCheckResult { BlockFragInfo bfi; } BdrvCheckResult; -int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res); +typedef enum { + BDRV_FIX_LEAKS = 1, + BDRV_FIX_ERRORS = 2, +} BdrvCheckMode; + +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); /* async block I/O */ typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector, diff --git a/block/qcow2.c b/block/qcow2.c index c2e49cd..7797015 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1470,8 +1470,13 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) } -static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result) +static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result, + BdrvCheckMode fix) { + if (fix) { + return -ENOTSUP; + } + return qcow2_check_refcounts(bs, result); } diff --git a/block/qed.c b/block/qed.c index 30a31f9..ab59724 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1517,11 +1517,12 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs) bdrv_qed_open(bs, bs->open_flags); } -static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result) +static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result, + BdrvCheckMode fix) { BDRVQEDState *s = bs->opaque; - return qed_check(s, result, false); + return qed_check(s, result, !!fix); } static QEMUOptionParameter qed_create_options[] = { diff --git a/block/vdi.c b/block/vdi.c index 119d3c7..57325d6 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -277,7 +277,8 @@ static void vdi_header_print(VdiHeader *header) } #endif -static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res) +static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res, + BdrvCheckMode fix) { /* TODO: additional checks possible. */ BDRVVdiState *s = (BDRVVdiState *)bs->opaque; @@ -286,6 +287,10 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res) uint32_t *bmap; logout("\n"); + if (fix) { + return -ENOTSUP; + } + bmap = g_malloc(s->header.blocks_in_image * sizeof(uint32_t)); memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t)); diff --git a/block_int.h b/block_int.h index 3d4abc6..1fb5352 100644 --- a/block_int.h +++ b/block_int.h @@ -241,7 +241,8 @@ struct BlockDriver { * Returns 0 for completed check, -errno for internal errors. * The check results are stored in result. */ - int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result); + int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result, + BdrvCheckMode fix); void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 49dce7c..39419a0 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,9 +10,9 @@ STEXI ETEXI DEF("check", img_check, - "check [-f fmt] filename") + "check [-f fmt] [-r [leaks | all]] filename") STEXI -@item check [-f @var{fmt}] @var{filename} +@item check [-f @var{fmt}] [-r [leaks | all]] @var{filename} ETEXI DEF("create", img_create, diff --git a/qemu-img.c b/qemu-img.c index c8a70ff..c45ff62 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -85,6 +85,12 @@ static void help(void) " '-S' indicates the consecutive number of bytes that must contain only zeros\n" " for qemu-img to create a sparse image during conversion\n" "\n" + "Parameters to check subcommand:\n" + " '-r' tries to repair any inconsistencies that are found during the check.\n" + " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n" + " kinds of errors, with a higher risk of choosing the wrong fix or\n" + " hiding corruption that has already occured.\n" + "\n" "Parameters to snapshot subcommand:\n" " 'snapshot' is the name of the snapshot to create, apply or delete\n" " '-a' applies a snapshot (revert disk to saved state)\n" @@ -372,10 +378,12 @@ static int img_check(int argc, char **argv) const char *filename, *fmt; BlockDriverState *bs; BdrvCheckResult result; + int fix = 0; + int flags = BDRV_O_FLAGS; fmt = NULL; for(;;) { - c = getopt(argc, argv, "f:h"); + c = getopt(argc, argv, "f:hr:"); if (c == -1) { break; } @@ -387,6 +395,17 @@ static int img_check(int argc, char **argv) case 'f': fmt = optarg; break; + case 'r': + flags |= BDRV_O_RDWR; + + if (!strcmp(optarg, "leaks")) { + fix = BDRV_FIX_LEAKS; + } else if (!strcmp(optarg, "all")) { + fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS; + } else { + help(); + } + break; } } if (optind >= argc) { @@ -394,11 +413,11 @@ static int img_check(int argc, char **argv) } filename = argv[optind++]; - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS); + bs = bdrv_new_open(filename, fmt, flags); if (!bs) { return 1; } - ret = bdrv_check(bs, &result); + ret = bdrv_check(bs, &result, fix); if (ret == -ENOTSUP) { error_report("This image format does not support checks"); diff --git a/qemu-img.texi b/qemu-img.texi index 6fc3c28..5a7b2bb 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -70,10 +70,15 @@ lists all snapshots in the given image Command description: @table @option -@item check [-f @var{fmt}] @var{filename} +@item check [-f @var{fmt}] [-r [leaks | all]] @var{filename} Perform a consistency check on the disk image @var{filename}. +If @code{-r} is specified, qemu-img tries to repair any inconsistencies found +during the check. @code{-r leaks} repairs only cluster leaks, whereas +@code{-r all} fixes all kinds of errors, with a higher risk of choosing the +wrong fix or hiding corruption that has already occured. + Only the formats @code{qcow2}, @code{qed} and @code{vdi} support consistency checks. -- 1.7.6.5