* [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 an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.