qemu-img check: Distinguish different kinds of errors

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>
This commit is contained in:
Kevin Wolf 2010-06-29 11:43:13 +02:00
parent 734003e615
commit e076f3383b
3 changed files with 64 additions and 19 deletions

10
block.c
View File

@ -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 */

10
block.h
View File

@ -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);

View File

@ -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)