Introduce bdrv_check (Kevin Wolf)
From: Kevin Wolf <kwolf@redhat.com> Introduce a new bdrv_check function pointer for block drivers. Modify qcow2 to return an error status in check_refcounts(), so it can implement bdrv_check. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7214 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
8ddbc04f06
commit
e97fc193e1
@ -177,9 +177,7 @@ static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
|
|||||||
static int64_t alloc_bytes(BlockDriverState *bs, int size);
|
static int64_t alloc_bytes(BlockDriverState *bs, int size);
|
||||||
static void free_clusters(BlockDriverState *bs,
|
static void free_clusters(BlockDriverState *bs,
|
||||||
int64_t offset, int64_t size);
|
int64_t offset, int64_t size);
|
||||||
#ifdef DEBUG_ALLOC
|
static int check_refcounts(BlockDriverState *bs);
|
||||||
static void check_refcounts(BlockDriverState *bs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
@ -2564,8 +2562,14 @@ static void update_refcount(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
/*
|
||||||
static void inc_refcounts(BlockDriverState *bs,
|
* Increases the refcount for a range of clusters in a given refcount table.
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
static int inc_refcounts(BlockDriverState *bs,
|
||||||
uint16_t *refcount_table,
|
uint16_t *refcount_table,
|
||||||
int refcount_table_size,
|
int refcount_table_size,
|
||||||
int64_t offset, int64_t size)
|
int64_t offset, int64_t size)
|
||||||
@ -2573,9 +2577,10 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t start, last, cluster_offset;
|
int64_t start, last, cluster_offset;
|
||||||
int k;
|
int k;
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
start = offset & ~(s->cluster_size - 1);
|
start = offset & ~(s->cluster_size - 1);
|
||||||
last = (offset + size - 1) & ~(s->cluster_size - 1);
|
last = (offset + size - 1) & ~(s->cluster_size - 1);
|
||||||
@ -2585,13 +2590,17 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
if (k < 0 || k >= refcount_table_size) {
|
if (k < 0 || k >= refcount_table_size) {
|
||||||
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
||||||
cluster_offset);
|
cluster_offset);
|
||||||
|
errors++;
|
||||||
} else {
|
} else {
|
||||||
if (++refcount_table[k] == 0) {
|
if (++refcount_table[k] == 0) {
|
||||||
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
|
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
|
||||||
"\n", cluster_offset);
|
"\n", cluster_offset);
|
||||||
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_refcounts_l1(BlockDriverState *bs,
|
static int check_refcounts_l1(BlockDriverState *bs,
|
||||||
@ -2603,11 +2612,12 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
|
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
|
||||||
int l2_size, i, j, nb_csectors, refcount;
|
int l2_size, i, j, nb_csectors, refcount;
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
l2_table = NULL;
|
l2_table = NULL;
|
||||||
l1_size2 = l1_size * sizeof(uint64_t);
|
l1_size2 = l1_size * sizeof(uint64_t);
|
||||||
|
|
||||||
inc_refcounts(bs, refcount_table, refcount_table_size,
|
errors += inc_refcounts(bs, refcount_table, refcount_table_size,
|
||||||
l1_table_offset, l1_size2);
|
l1_table_offset, l1_size2);
|
||||||
|
|
||||||
l1_table = qemu_malloc(l1_size2);
|
l1_table = qemu_malloc(l1_size2);
|
||||||
@ -2627,6 +2637,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
|
if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
|
||||||
fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
|
fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
|
||||||
" refcount=%d\n", l2_offset, refcount);
|
" refcount=%d\n", l2_offset, refcount);
|
||||||
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||||
@ -2641,11 +2652,12 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
"copied flag must never be set for compressed "
|
"copied flag must never be set for compressed "
|
||||||
"clusters\n", offset >> s->cluster_bits);
|
"clusters\n", offset >> s->cluster_bits);
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
offset &= ~QCOW_OFLAG_COPIED;
|
||||||
|
errors++;
|
||||||
}
|
}
|
||||||
nb_csectors = ((offset >> s->csize_shift) &
|
nb_csectors = ((offset >> s->csize_shift) &
|
||||||
s->csize_mask) + 1;
|
s->csize_mask) + 1;
|
||||||
offset &= s->cluster_offset_mask;
|
offset &= s->cluster_offset_mask;
|
||||||
inc_refcounts(bs, refcount_table,
|
errors += inc_refcounts(bs, refcount_table,
|
||||||
refcount_table_size,
|
refcount_table_size,
|
||||||
offset & ~511, nb_csectors * 512);
|
offset & ~511, nb_csectors * 512);
|
||||||
} else {
|
} else {
|
||||||
@ -2654,16 +2666,17 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
|
if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
|
||||||
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
||||||
PRIx64 " refcount=%d\n", offset, refcount);
|
PRIx64 " refcount=%d\n", offset, refcount);
|
||||||
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
offset &= ~QCOW_OFLAG_COPIED;
|
||||||
inc_refcounts(bs, refcount_table,
|
errors += inc_refcounts(bs, refcount_table,
|
||||||
refcount_table_size,
|
refcount_table_size,
|
||||||
offset, s->cluster_size);
|
offset, s->cluster_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inc_refcounts(bs, refcount_table,
|
errors += inc_refcounts(bs, refcount_table,
|
||||||
refcount_table_size,
|
refcount_table_size,
|
||||||
l2_offset,
|
l2_offset,
|
||||||
s->cluster_size);
|
s->cluster_size);
|
||||||
@ -2671,7 +2684,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
qemu_free(l1_table);
|
qemu_free(l1_table);
|
||||||
qemu_free(l2_table);
|
qemu_free(l2_table);
|
||||||
return 0;
|
return errors;
|
||||||
fail:
|
fail:
|
||||||
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
|
||||||
qemu_free(l1_table);
|
qemu_free(l1_table);
|
||||||
@ -2679,24 +2692,35 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_refcounts(BlockDriverState *bs)
|
/*
|
||||||
|
* Checks an image for refcount consistency.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static int check_refcounts(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t size;
|
int64_t size;
|
||||||
int nb_clusters, refcount1, refcount2, i;
|
int nb_clusters, refcount1, refcount2, i;
|
||||||
QCowSnapshot *sn;
|
QCowSnapshot *sn;
|
||||||
uint16_t *refcount_table;
|
uint16_t *refcount_table;
|
||||||
|
int ret, errors = 0;
|
||||||
|
|
||||||
size = bdrv_getlength(s->hd);
|
size = bdrv_getlength(s->hd);
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
|
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
|
||||||
|
|
||||||
/* header */
|
/* header */
|
||||||
inc_refcounts(bs, refcount_table, nb_clusters,
|
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||||
0, s->cluster_size);
|
0, s->cluster_size);
|
||||||
|
|
||||||
check_refcounts_l1(bs, refcount_table, nb_clusters,
|
ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
|
||||||
s->l1_table_offset, s->l1_size, 1);
|
s->l1_table_offset, s->l1_size, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
errors += ret;
|
||||||
|
|
||||||
/* snapshots */
|
/* snapshots */
|
||||||
for(i = 0; i < s->nb_snapshots; i++) {
|
for(i = 0; i < s->nb_snapshots; i++) {
|
||||||
@ -2704,18 +2728,18 @@ static void check_refcounts(BlockDriverState *bs)
|
|||||||
check_refcounts_l1(bs, refcount_table, nb_clusters,
|
check_refcounts_l1(bs, refcount_table, nb_clusters,
|
||||||
sn->l1_table_offset, sn->l1_size, 0);
|
sn->l1_table_offset, sn->l1_size, 0);
|
||||||
}
|
}
|
||||||
inc_refcounts(bs, refcount_table, nb_clusters,
|
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||||
s->snapshots_offset, s->snapshots_size);
|
s->snapshots_offset, s->snapshots_size);
|
||||||
|
|
||||||
/* refcount data */
|
/* refcount data */
|
||||||
inc_refcounts(bs, refcount_table, nb_clusters,
|
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||||
s->refcount_table_offset,
|
s->refcount_table_offset,
|
||||||
s->refcount_table_size * sizeof(uint64_t));
|
s->refcount_table_size * sizeof(uint64_t));
|
||||||
for(i = 0; i < s->refcount_table_size; i++) {
|
for(i = 0; i < s->refcount_table_size; i++) {
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
offset = s->refcount_table[i];
|
offset = s->refcount_table[i];
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
inc_refcounts(bs, refcount_table, nb_clusters,
|
errors += inc_refcounts(bs, refcount_table, nb_clusters,
|
||||||
offset, s->cluster_size);
|
offset, s->cluster_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2724,12 +2748,21 @@ static void check_refcounts(BlockDriverState *bs)
|
|||||||
for(i = 0; i < nb_clusters; i++) {
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
refcount1 = get_refcount(bs, i);
|
refcount1 = get_refcount(bs, i);
|
||||||
refcount2 = refcount_table[i];
|
refcount2 = refcount_table[i];
|
||||||
if (refcount1 != refcount2)
|
if (refcount1 != refcount2) {
|
||||||
fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
|
fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
|
||||||
i, refcount1, refcount2);
|
i, refcount1, refcount2);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_free(refcount_table);
|
qemu_free(refcount_table);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcow_check(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return check_refcounts(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -2751,7 +2784,6 @@ static void dump_refcounts(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
|
static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
|
||||||
int64_t pos, int size)
|
int64_t pos, int size)
|
||||||
@ -2806,4 +2838,5 @@ BlockDriver bdrv_qcow2 = {
|
|||||||
.bdrv_get_buffer = qcow_get_buffer,
|
.bdrv_get_buffer = qcow_get_buffer,
|
||||||
|
|
||||||
.bdrv_create2 = qcow_create2,
|
.bdrv_create2 = qcow_create2,
|
||||||
|
.bdrv_check = qcow_check,
|
||||||
};
|
};
|
||||||
|
14
block.c
14
block.c
@ -506,6 +506,20 @@ void bdrv_delete(BlockDriverState *bs)
|
|||||||
qemu_free(bs);
|
qemu_free(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run consistency checks on an image
|
||||||
|
*
|
||||||
|
* Returns the number of errors or -errno when an internal error occurs
|
||||||
|
*/
|
||||||
|
int bdrv_check(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
if (bs->drv->bdrv_check == NULL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs->drv->bdrv_check(bs);
|
||||||
|
}
|
||||||
|
|
||||||
/* commit COW file into the raw image */
|
/* commit COW file into the raw image */
|
||||||
int bdrv_commit(BlockDriverState *bs)
|
int bdrv_commit(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
|
1
block.h
1
block.h
@ -73,6 +73,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
|
|||||||
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||||
BlockDriver *drv);
|
BlockDriver *drv);
|
||||||
void bdrv_close(BlockDriverState *bs);
|
void bdrv_close(BlockDriverState *bs);
|
||||||
|
int bdrv_check(BlockDriverState *bs);
|
||||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors);
|
uint8_t *buf, int nb_sectors);
|
||||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
@ -102,6 +102,9 @@ struct BlockDriver {
|
|||||||
const char *backing_file, const char *backing_format,
|
const char *backing_file, const char *backing_format,
|
||||||
int flags);
|
int flags);
|
||||||
|
|
||||||
|
/* Returns number of errors in image, -errno for internal errors */
|
||||||
|
int (*bdrv_check)(BlockDriverState* bs);
|
||||||
|
|
||||||
struct BlockDriver *next;
|
struct BlockDriver *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user