* [Qemu-devel] [PATCH 0/2] Improve qemu-img check output @ 2010-07-02 17:14 Kevin Wolf 2010-07-02 17:14 ` [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors Kevin Wolf 2010-07-02 17:15 ` [Qemu-devel] [PATCH 2/2] qcow2/vdi: Change check to distinguish error cases Kevin Wolf 0 siblings, 2 replies; 6+ messages in thread From: Kevin Wolf @ 2010-07-02 17:14 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf qemu-img check produces messages that are hard to understand. Even worse is that in the end it just says something like "42 errors" with no further explanation. Recently I got bug reports from people who though that their image was corrupted, when in fact there were only a few leaked clusters after a crash. This series tries to tell the user if it's real corruption, leaked clusters or something that went wrong during the check. Kevin Wolf (2): qemu-img check: Distinguish different kinds of errors qcow2/vdi: Change check to distinguish error cases block.c | 9 ++- block.h | 10 ++++- block/qcow2-refcount.c | 120 ++++++++++++++++++++++++++---------------------- block/qcow2.c | 4 +- block/qcow2.h | 2 +- block/vdi.c | 10 ++-- block_int.h | 7 ++- qemu-img.c | 62 +++++++++++++++++++------ 8 files changed, 140 insertions(+), 84 deletions(-) ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors 2010-07-02 17:14 [Qemu-devel] [PATCH 0/2] Improve qemu-img check output Kevin Wolf @ 2010-07-02 17:14 ` Kevin Wolf 2010-07-06 10:51 ` MORITA Kazutaka 2010-07-06 11:03 ` [Qemu-devel] [PATCH v2 " Kevin Wolf 2010-07-02 17:15 ` [Qemu-devel] [PATCH 2/2] qcow2/vdi: Change check to distinguish error cases Kevin Wolf 1 sibling, 2 replies; 6+ messages in thread From: Kevin Wolf @ 2010-07-02 17:14 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf People think that their images are corrupted when in fact there are just some leaked clusters. Differentiating several error cases should make the messages more comprehensible. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block.c | 10 ++++++-- block.h | 10 ++++++++- qemu-img.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index dd6dd76..b0ceef0 100644 --- a/block.c +++ b/block.c @@ -710,15 +710,19 @@ DeviceState *bdrv_get_attached(BlockDriverState *bs) /* * Run consistency checks on an image * - * Returns the number of errors or -errno when an internal error occurs + * Returns 0 if the check could be completed (it doesn't mean that the image is + * free of errors) or -errno when an internal error occured. The results of the + * check are stored in res. */ -int bdrv_check(BlockDriverState *bs) +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) { if (bs->drv->bdrv_check == NULL) { return -ENOTSUP; } - return bs->drv->bdrv_check(bs); + memset(res, 0, sizeof(*res)); + res->corruptions = bs->drv->bdrv_check(bs); + return res->corruptions < 0 ? res->corruptions : 0; } /* commit COW file into the raw image */ diff --git a/block.h b/block.h index 3d03b3e..c2a7e4c 100644 --- a/block.h +++ b/block.h @@ -74,7 +74,6 @@ void bdrv_close(BlockDriverState *bs); int bdrv_attach(BlockDriverState *bs, DeviceState *qdev); void bdrv_detach(BlockDriverState *bs, DeviceState *qdev); DeviceState *bdrv_get_attached(BlockDriverState *bs); -int bdrv_check(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, @@ -97,6 +96,15 @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt); void bdrv_register(BlockDriver *bdrv); + +typedef struct BdrvCheckResult { + int corruptions; + int leaks; + int check_errors; +} BdrvCheckResult; + +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res); + /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); diff --git a/qemu-img.c b/qemu-img.c index 700af21..1782ac9 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -425,11 +425,20 @@ out: return 0; } +/* + * Checks an image for consistency. Exit codes: + * + * 0 - Check completed, image is good + * 1 - Check not completed because of internal errors + * 2 - Check completed, image is corrupted + * 3 - Check completed, image has leaked clusters, but is good otherwise + */ static int img_check(int argc, char **argv) { int c, ret; const char *filename, *fmt; BlockDriverState *bs; + BdrvCheckResult result; fmt = NULL; for(;;) { @@ -453,28 +462,51 @@ static int img_check(int argc, char **argv) if (!bs) { return 1; } - ret = bdrv_check(bs); - switch(ret) { - case 0: - printf("No errors were found on the image.\n"); - break; - case -ENOTSUP: + ret = bdrv_check(bs, &result); + + if (ret == -ENOTSUP) { error("This image format does not support checks"); - break; - default: - if (ret < 0) { - error("An error occurred during the check"); - } else { - printf("%d errors were found on the image.\n", ret); + return 1; + } + + if (!(result.corruptions || result.leaks || result.check_errors)) { + printf("No errors were found on the image.\n"); + } else { + if (result.corruptions) { + printf("\n%d errors were found on the image.\n" + "Data may be corrupted, or further writes to the image " + "may corrupt it.\n", + result.corruptions); + } + + if (result.leaks) { + printf("\n%d leaked clusters were found on the image.\n" + "This means waste of disk space, but no harm to data.\n", + result.leaks); + } + + if (result.check_errors) { + printf("\n%d internal errors have occurred during the check.\n", + result.check_errors); } - break; } bdrv_delete(bs); - if (ret) { + + if (ret < 0 || result.check_errors) { + printf("\nAn error has occurred during the check: %s\n" + "The check is not complete and may have missed error.\n", + strerror(-ret)); return 1; } - return 0; + + if (result.corruptions) { + return 2; + } else if (result.leaks) { + return 3; + } else { + return 0; + } } static int img_commit(int argc, char **argv) -- 1.6.6.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors 2010-07-02 17:14 ` [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors Kevin Wolf @ 2010-07-06 10:51 ` MORITA Kazutaka 2010-07-06 11:01 ` Kevin Wolf 2010-07-06 11:03 ` [Qemu-devel] [PATCH v2 " Kevin Wolf 1 sibling, 1 reply; 6+ messages in thread From: MORITA Kazutaka @ 2010-07-06 10:51 UTC (permalink / raw) To: Kevin Wolf; +Cc: qemu-devel At Fri, 2 Jul 2010 19:14:59 +0200, Kevin Wolf wrote: > > People think that their images are corrupted when in fact there are just some > leaked clusters. Differentiating several error cases should make the messages > more comprehensible. > > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > --- > block.c | 10 ++++++-- > block.h | 10 ++++++++- > qemu-img.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-------------- > 3 files changed, 63 insertions(+), 19 deletions(-) > > diff --git a/block.c b/block.c > index dd6dd76..b0ceef0 100644 > --- a/block.c > +++ b/block.c > @@ -710,15 +710,19 @@ DeviceState *bdrv_get_attached(BlockDriverState *bs) > /* > * Run consistency checks on an image > * > - * Returns the number of errors or -errno when an internal error occurs > + * Returns 0 if the check could be completed (it doesn't mean that the image is > + * free of errors) or -errno when an internal error occured. The results of the > + * check are stored in res. > */ > -int bdrv_check(BlockDriverState *bs) > +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) > { > if (bs->drv->bdrv_check == NULL) { > return -ENOTSUP; > } > > - return bs->drv->bdrv_check(bs); > + memset(res, 0, sizeof(*res)); > + res->corruptions = bs->drv->bdrv_check(bs); > + return res->corruptions < 0 ? res->corruptions : 0; > } > > /* commit COW file into the raw image */ > diff --git a/block.h b/block.h > index 3d03b3e..c2a7e4c 100644 > --- a/block.h > +++ b/block.h > @@ -74,7 +74,6 @@ void bdrv_close(BlockDriverState *bs); > int bdrv_attach(BlockDriverState *bs, DeviceState *qdev); > void bdrv_detach(BlockDriverState *bs, DeviceState *qdev); > DeviceState *bdrv_get_attached(BlockDriverState *bs); > -int bdrv_check(BlockDriverState *bs); > int bdrv_read(BlockDriverState *bs, int64_t sector_num, > uint8_t *buf, int nb_sectors); > int bdrv_write(BlockDriverState *bs, int64_t sector_num, > @@ -97,6 +96,15 @@ int bdrv_change_backing_file(BlockDriverState *bs, > const char *backing_file, const char *backing_fmt); > void bdrv_register(BlockDriver *bdrv); > > + > +typedef struct BdrvCheckResult { > + int corruptions; > + int leaks; > + int check_errors; > +} BdrvCheckResult; > + > +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res); > + > /* async block I/O */ > typedef struct BlockDriverAIOCB BlockDriverAIOCB; > typedef void BlockDriverCompletionFunc(void *opaque, int ret); > diff --git a/qemu-img.c b/qemu-img.c > index 700af21..1782ac9 100644 > --- a/qemu-img.c > +++ b/qemu-img.c > @@ -425,11 +425,20 @@ out: > return 0; > } > > +/* > + * Checks an image for consistency. Exit codes: > + * > + * 0 - Check completed, image is good > + * 1 - Check not completed because of internal errors > + * 2 - Check completed, image is corrupted > + * 3 - Check completed, image has leaked clusters, but is good otherwise > + */ > static int img_check(int argc, char **argv) > { > int c, ret; > const char *filename, *fmt; > BlockDriverState *bs; > + BdrvCheckResult result; > > fmt = NULL; > for(;;) { > @@ -453,28 +462,51 @@ static int img_check(int argc, char **argv) > if (!bs) { > return 1; > } > - ret = bdrv_check(bs); > - switch(ret) { > - case 0: > - printf("No errors were found on the image.\n"); > - break; > - case -ENOTSUP: > + ret = bdrv_check(bs, &result); > + > + if (ret == -ENOTSUP) { > error("This image format does not support checks"); > - break; > - default: > - if (ret < 0) { > - error("An error occurred during the check"); > - } else { > - printf("%d errors were found on the image.\n", ret); > + return 1; Is it okay to call bdrv_delete(bs) before return? It is necessary for the sheepdog driver to pass qemu-iotests. Kazutaka --- a/qemu-img.c +++ b/qemu-img.c @@ -466,6 +466,7 @@ static int img_check(int argc, char **argv) if (ret == -ENOTSUP) { error("This image format does not support checks"); + bdrv_delete(bs); return 1; } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors 2010-07-06 10:51 ` MORITA Kazutaka @ 2010-07-06 11:01 ` Kevin Wolf 0 siblings, 0 replies; 6+ messages in thread From: Kevin Wolf @ 2010-07-06 11:01 UTC (permalink / raw) To: MORITA Kazutaka; +Cc: qemu-devel Am 06.07.2010 12:51, schrieb MORITA Kazutaka: > At Fri, 2 Jul 2010 19:14:59 +0200, > Kevin Wolf wrote: >> >> People think that their images are corrupted when in fact there are just some >> leaked clusters. Differentiating several error cases should make the messages >> more comprehensible. >> >> Signed-off-by: Kevin Wolf <kwolf@redhat.com> >> --- >> block.c | 10 ++++++-- >> block.h | 10 ++++++++- >> qemu-img.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-------------- >> 3 files changed, 63 insertions(+), 19 deletions(-) >> @@ -453,28 +462,51 @@ static int img_check(int argc, char **argv) >> if (!bs) { >> return 1; >> } >> - ret = bdrv_check(bs); >> - switch(ret) { >> - case 0: >> - printf("No errors were found on the image.\n"); >> - break; >> - case -ENOTSUP: >> + ret = bdrv_check(bs, &result); >> + >> + if (ret == -ENOTSUP) { >> error("This image format does not support checks"); >> - break; >> - default: >> - if (ret < 0) { >> - error("An error occurred during the check"); >> - } else { >> - printf("%d errors were found on the image.\n", ret); >> + return 1; > > Is it okay to call bdrv_delete(bs) before return? It is necessary for > the sheepdog driver to pass qemu-iotests. > > Kazutaka Yes, you're right. Thanks for catching this, I'll send a new version. Kevin ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v2 1/2] qemu-img check: Distinguish different kinds of errors 2010-07-02 17:14 ` [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors Kevin Wolf 2010-07-06 10:51 ` MORITA Kazutaka @ 2010-07-06 11:03 ` Kevin Wolf 1 sibling, 0 replies; 6+ messages in thread From: Kevin Wolf @ 2010-07-06 11:03 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf People think that their images are corrupted when in fact there are just some leaked clusters. Differentiating several error cases should make the messages more comprehensible. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- v2: - Call bdrv_delete in -ENOTSUP case, too block.c | 10 ++++++-- block.h | 10 ++++++++- qemu-img.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index dd6dd76..b0ceef0 100644 --- a/block.c +++ b/block.c @@ -710,15 +710,19 @@ DeviceState *bdrv_get_attached(BlockDriverState *bs) /* * Run consistency checks on an image * - * Returns the number of errors or -errno when an internal error occurs + * Returns 0 if the check could be completed (it doesn't mean that the image is + * free of errors) or -errno when an internal error occured. The results of the + * check are stored in res. */ -int bdrv_check(BlockDriverState *bs) +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) { if (bs->drv->bdrv_check == NULL) { return -ENOTSUP; } - return bs->drv->bdrv_check(bs); + memset(res, 0, sizeof(*res)); + res->corruptions = bs->drv->bdrv_check(bs); + return res->corruptions < 0 ? res->corruptions : 0; } /* commit COW file into the raw image */ diff --git a/block.h b/block.h index 3d03b3e..c2a7e4c 100644 --- a/block.h +++ b/block.h @@ -74,7 +74,6 @@ void bdrv_close(BlockDriverState *bs); int bdrv_attach(BlockDriverState *bs, DeviceState *qdev); void bdrv_detach(BlockDriverState *bs, DeviceState *qdev); DeviceState *bdrv_get_attached(BlockDriverState *bs); -int bdrv_check(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, @@ -97,6 +96,15 @@ int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt); void bdrv_register(BlockDriver *bdrv); + +typedef struct BdrvCheckResult { + int corruptions; + int leaks; + int check_errors; +} BdrvCheckResult; + +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res); + /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); diff --git a/qemu-img.c b/qemu-img.c index 700af21..e300f91 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -425,11 +425,20 @@ out: return 0; } +/* + * Checks an image for consistency. Exit codes: + * + * 0 - Check completed, image is good + * 1 - Check not completed because of internal errors + * 2 - Check completed, image is corrupted + * 3 - Check completed, image has leaked clusters, but is good otherwise + */ static int img_check(int argc, char **argv) { int c, ret; const char *filename, *fmt; BlockDriverState *bs; + BdrvCheckResult result; fmt = NULL; for(;;) { @@ -453,28 +462,52 @@ static int img_check(int argc, char **argv) if (!bs) { return 1; } - ret = bdrv_check(bs); - switch(ret) { - case 0: - printf("No errors were found on the image.\n"); - break; - case -ENOTSUP: + ret = bdrv_check(bs, &result); + + if (ret == -ENOTSUP) { error("This image format does not support checks"); - break; - default: - if (ret < 0) { - error("An error occurred during the check"); - } else { - printf("%d errors were found on the image.\n", ret); + bdrv_delete(bs); + return 1; + } + + if (!(result.corruptions || result.leaks || result.check_errors)) { + printf("No errors were found on the image.\n"); + } else { + if (result.corruptions) { + printf("\n%d errors were found on the image.\n" + "Data may be corrupted, or further writes to the image " + "may corrupt it.\n", + result.corruptions); + } + + if (result.leaks) { + printf("\n%d leaked clusters were found on the image.\n" + "This means waste of disk space, but no harm to data.\n", + result.leaks); + } + + if (result.check_errors) { + printf("\n%d internal errors have occurred during the check.\n", + result.check_errors); } - break; } bdrv_delete(bs); - if (ret) { + + if (ret < 0 || result.check_errors) { + printf("\nAn error has occurred during the check: %s\n" + "The check is not complete and may have missed error.\n", + strerror(-ret)); return 1; } - return 0; + + if (result.corruptions) { + return 2; + } else if (result.leaks) { + return 3; + } else { + return 0; + } } static int img_commit(int argc, char **argv) -- 1.6.6.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 2/2] qcow2/vdi: Change check to distinguish error cases 2010-07-02 17:14 [Qemu-devel] [PATCH 0/2] Improve qemu-img check output Kevin Wolf 2010-07-02 17:14 ` [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors Kevin Wolf @ 2010-07-02 17:15 ` Kevin Wolf 1 sibling, 0 replies; 6+ messages in thread From: Kevin Wolf @ 2010-07-02 17:15 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf This distinguishes between harmless leaks and real corruption. Hopefully users better understand what qemu-img check wants to tell them. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block.c | 3 +- block/qcow2-refcount.c | 120 ++++++++++++++++++++++++++---------------------- block/qcow2.c | 4 +- block/qcow2.h | 2 +- block/vdi.c | 10 ++-- block_int.h | 7 ++- 6 files changed, 79 insertions(+), 67 deletions(-) diff --git a/block.c b/block.c index b0ceef0..65cf4dc 100644 --- a/block.c +++ b/block.c @@ -721,8 +721,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) } memset(res, 0, sizeof(*res)); - res->corruptions = bs->drv->bdrv_check(bs); - return res->corruptions < 0 ? res->corruptions : 0; + return bs->drv->bdrv_check(bs, res); } /* commit COW file into the raw image */ diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4a96d98..4c19e7e 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -884,9 +884,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, * This is used to construct a temporary refcount table out of L1 and L2 tables * which can be compared the the refcount table saved in the image. * - * Returns the number of errors in the image that were found + * Modifies the number of errors in res. */ -static int inc_refcounts(BlockDriverState *bs, +static void inc_refcounts(BlockDriverState *bs, + BdrvCheckResult *res, uint16_t *refcount_table, int refcount_table_size, int64_t offset, int64_t size) @@ -894,30 +895,32 @@ static int inc_refcounts(BlockDriverState *bs, BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; int k; - int errors = 0; if (size <= 0) - return 0; + return; start = offset & ~(s->cluster_size - 1); last = (offset + size - 1) & ~(s->cluster_size - 1); for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size) { k = cluster_offset >> s->cluster_bits; - if (k < 0 || k >= refcount_table_size) { + if (k < 0) { fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n", cluster_offset); - errors++; + res->corruptions++; + } else if (k >= refcount_table_size) { + fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after " + "the end of the image file, can't properly check refcounts.\n", + cluster_offset); + res->check_errors++; } else { if (++refcount_table[k] == 0) { fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 "\n", cluster_offset); - errors++; + res->corruptions++; } } } - - return errors; } /* @@ -928,14 +931,13 @@ static int inc_refcounts(BlockDriverState *bs, * Returns the number of errors found by the checks or -errno if an internal * error occurred. */ -static int check_refcounts_l2(BlockDriverState *bs, +static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset, int check_copied) { BDRVQcowState *s = bs->opaque; uint64_t *l2_table, offset; int i, l2_size, nb_csectors, refcount; - int errors = 0; /* Read L2 table from disk */ l2_size = s->l2_size * sizeof(uint64_t); @@ -955,16 +957,15 @@ static int check_refcounts_l2(BlockDriverState *bs, "copied flag must never be set for compressed " "clusters\n", offset >> s->cluster_bits); offset &= ~QCOW_OFLAG_COPIED; - errors++; + res->corruptions++; } /* Mark cluster as used */ nb_csectors = ((offset >> s->csize_shift) & s->csize_mask) + 1; offset &= s->cluster_offset_mask; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - offset & ~511, nb_csectors * 512); + inc_refcounts(bs, res, refcount_table, refcount_table_size, + offset & ~511, nb_csectors * 512); } else { /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ if (check_copied) { @@ -974,35 +975,35 @@ static int check_refcounts_l2(BlockDriverState *bs, if (refcount < 0) { fprintf(stderr, "Can't get refcount for offset %" PRIx64 ": %s\n", entry, strerror(-refcount)); + goto fail; } if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" PRIx64 " refcount=%d\n", entry, refcount); - errors++; + res->corruptions++; } } /* Mark cluster as used */ offset &= ~QCOW_OFLAG_COPIED; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - offset, s->cluster_size); + inc_refcounts(bs, res, refcount_table,refcount_table_size, + offset, s->cluster_size); /* Correct offsets are cluster aligned */ if (offset & (s->cluster_size - 1)) { fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " "properly aligned; L2 entry corrupted.\n", offset); - errors++; + res->corruptions++; } } } } qemu_free(l2_table); - return errors; + return 0; fail: - fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); + fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n"); qemu_free(l2_table); return -EIO; } @@ -1016,6 +1017,7 @@ fail: * error occurred. */ static int check_refcounts_l1(BlockDriverState *bs, + BdrvCheckResult *res, uint16_t *refcount_table, int refcount_table_size, int64_t l1_table_offset, int l1_size, @@ -1024,13 +1026,12 @@ static int check_refcounts_l1(BlockDriverState *bs, BDRVQcowState *s = bs->opaque; uint64_t *l1_table, l2_offset, l1_size2; int i, refcount, ret; - int errors = 0; l1_size2 = l1_size * sizeof(uint64_t); /* Mark L1 table as used */ - errors += inc_refcounts(bs, refcount_table, refcount_table_size, - l1_table_offset, l1_size2); + inc_refcounts(bs, res, refcount_table, refcount_table_size, + l1_table_offset, l1_size2); /* Read L1 table entries from disk */ if (l1_size2 == 0) { @@ -1055,42 +1056,41 @@ static int check_refcounts_l1(BlockDriverState *bs, if (refcount < 0) { fprintf(stderr, "Can't get refcount for l2_offset %" PRIx64 ": %s\n", l2_offset, strerror(-refcount)); + goto fail; } if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 " refcount=%d\n", l2_offset, refcount); - errors++; + res->corruptions++; } } /* Mark L2 table as used */ l2_offset &= ~QCOW_OFLAG_COPIED; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - l2_offset, - s->cluster_size); + inc_refcounts(bs, res, refcount_table, refcount_table_size, + l2_offset, s->cluster_size); /* L2 tables are cluster aligned */ if (l2_offset & (s->cluster_size - 1)) { fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not " "cluster aligned; L1 entry corrupted\n", l2_offset); - errors++; + res->corruptions++; } /* Process and check L2 entries */ - ret = check_refcounts_l2(bs, refcount_table, refcount_table_size, - l2_offset, check_copied); + ret = check_refcounts_l2(bs, res, refcount_table, + refcount_table_size, l2_offset, check_copied); if (ret < 0) { goto fail; } - errors += ret; } } qemu_free(l1_table); - return errors; + return 0; fail: fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); + res->check_errors++; qemu_free(l1_table); return -EIO; } @@ -1101,44 +1101,47 @@ fail: * Returns 0 if no errors are found, the number of errors in case the image is * detected as corrupted, and -errno when an internal error occured. */ -int qcow2_check_refcounts(BlockDriverState *bs) +int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res) { BDRVQcowState *s = bs->opaque; int64_t size; int nb_clusters, refcount1, refcount2, i; QCowSnapshot *sn; uint16_t *refcount_table; - int ret, errors = 0; + int ret; size = bdrv_getlength(bs->file); nb_clusters = size_to_clusters(s, size); refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); /* header */ - errors += inc_refcounts(bs, refcount_table, nb_clusters, - 0, s->cluster_size); + inc_refcounts(bs, res, refcount_table, nb_clusters, + 0, s->cluster_size); /* current L1 table */ - ret = check_refcounts_l1(bs, refcount_table, nb_clusters, + ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters, s->l1_table_offset, s->l1_size, 1); if (ret < 0) { return ret; } - errors += ret; /* snapshots */ for(i = 0; i < s->nb_snapshots; i++) { sn = s->snapshots + i; - check_refcounts_l1(bs, refcount_table, nb_clusters, - sn->l1_table_offset, sn->l1_size, 0); + ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters, + sn->l1_table_offset, sn->l1_size, 0); + if (ret < 0) { + return ret; + } } - errors += inc_refcounts(bs, refcount_table, nb_clusters, - s->snapshots_offset, s->snapshots_size); + inc_refcounts(bs, res, refcount_table, nb_clusters, + s->snapshots_offset, s->snapshots_size); /* refcount data */ - errors += inc_refcounts(bs, refcount_table, nb_clusters, - s->refcount_table_offset, - s->refcount_table_size * sizeof(uint64_t)); + inc_refcounts(bs, res, refcount_table, nb_clusters, + s->refcount_table_offset, + s->refcount_table_size * sizeof(uint64_t)); + for(i = 0; i < s->refcount_table_size; i++) { uint64_t offset, cluster; offset = s->refcount_table[i]; @@ -1148,22 +1151,23 @@ int qcow2_check_refcounts(BlockDriverState *bs) if (offset & (s->cluster_size - 1)) { fprintf(stderr, "ERROR refcount block %d is not " "cluster aligned; refcount table entry corrupted\n", i); - errors++; + res->corruptions++; continue; } if (cluster >= nb_clusters) { fprintf(stderr, "ERROR refcount block %d is outside image\n", i); - errors++; + res->corruptions++; continue; } if (offset != 0) { - errors += inc_refcounts(bs, refcount_table, nb_clusters, - offset, s->cluster_size); + inc_refcounts(bs, res, refcount_table, nb_clusters, + offset, s->cluster_size); if (refcount_table[cluster] != 1) { fprintf(stderr, "ERROR refcount block %d refcount=%d\n", i, refcount_table[cluster]); + res->corruptions++; } } } @@ -1174,19 +1178,25 @@ int qcow2_check_refcounts(BlockDriverState *bs) if (refcount1 < 0) { fprintf(stderr, "Can't get refcount for cluster %d: %s\n", i, strerror(-refcount1)); + res->check_errors++; continue; } refcount2 = refcount_table[i]; if (refcount1 != refcount2) { - fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n", + fprintf(stderr, "%s cluster %d refcount=%d reference=%d\n", + refcount1 < refcount2 ? "ERROR" : "Leaked", i, refcount1, refcount2); - errors++; + if (refcount1 < refcount2) { + res->corruptions++; + } else { + res->leaks++; + } } } qemu_free(refcount_table); - return errors; + return 0; } diff --git a/block/qcow2.c b/block/qcow2.c index 24651fc..f2b1b1c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1146,9 +1146,9 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) } -static int qcow_check(BlockDriverState *bs) +static int qcow_check(BlockDriverState *bs, BdrvCheckResult *result) { - return qcow2_check_refcounts(bs); + return qcow2_check_refcounts(bs, result); } #if 0 diff --git a/block/qcow2.h b/block/qcow2.h index c59b827..3ff162e 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -185,7 +185,7 @@ void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset, int qcow2_update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset, int l1_size, int addend); -int qcow2_check_refcounts(BlockDriverState *bs); +int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res); /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size); diff --git a/block/vdi.c b/block/vdi.c index ee8cc7b..f72633c 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -291,11 +291,10 @@ static void vdi_header_print(VdiHeader *header) } #endif -static int vdi_check(BlockDriverState *bs) +static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res) { /* TODO: additional checks possible. */ BDRVVdiState *s = (BDRVVdiState *)bs->opaque; - int n_errors = 0; uint32_t blocks_allocated = 0; uint32_t block; uint32_t *bmap; @@ -315,11 +314,12 @@ static int vdi_check(BlockDriverState *bs) } else { fprintf(stderr, "ERROR: block index %" PRIu32 " also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry); + res->corruptions++; } } else { fprintf(stderr, "ERROR: block index %" PRIu32 " too large, is %" PRIu32 "\n", block, bmap_entry); - n_errors++; + res->corruptions++; } } } @@ -327,12 +327,12 @@ static int vdi_check(BlockDriverState *bs) fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32 ", should be %" PRIu32 "\n", blocks_allocated, s->header.blocks_allocated); - n_errors++; + res->corruptions++; } qemu_free(bmap); - return n_errors; + return 0; } static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) diff --git a/block_int.h b/block_int.h index a94b801..877e1e5 100644 --- a/block_int.h +++ b/block_int.h @@ -119,8 +119,11 @@ struct BlockDriver { QEMUOptionParameter *create_options; - /* Returns number of errors in image, -errno for internal errors */ - int (*bdrv_check)(BlockDriverState* bs); + /* + * Returns 0 for completed check, -errno for internal errors. + * The check results are stored in result. + */ + int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result); void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); -- 1.6.6.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-07-06 11:03 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-07-02 17:14 [Qemu-devel] [PATCH 0/2] Improve qemu-img check output Kevin Wolf 2010-07-02 17:14 ` [Qemu-devel] [PATCH 1/2] qemu-img check: Distinguish different kinds of errors Kevin Wolf 2010-07-06 10:51 ` MORITA Kazutaka 2010-07-06 11:01 ` Kevin Wolf 2010-07-06 11:03 ` [Qemu-devel] [PATCH v2 " Kevin Wolf 2010-07-02 17:15 ` [Qemu-devel] [PATCH 2/2] qcow2/vdi: Change check to distinguish error cases Kevin Wolf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).