qcow2: Split qcow2_check_refcounts()
Put the code for calculating the reference counts and comparing them during qemu-img check into own functions. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Benoît Canet <benoit.canet@nodalink.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
5b84106bd9
commit
6ca56bf5e9
@ -1535,71 +1535,70 @@ done:
|
|||||||
return new_offset;
|
return new_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
BdrvCheckMode fix, uint16_t **refcount_table,
|
||||||
|
int64_t *nb_clusters);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks an image for refcount consistency.
|
* Calculates an in-memory refcount table.
|
||||||
*
|
|
||||||
* 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 occurred.
|
|
||||||
*/
|
*/
|
||||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
BdrvCheckMode fix)
|
BdrvCheckMode fix, uint16_t **refcount_table,
|
||||||
|
int64_t *nb_clusters)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int64_t size, i, highest_cluster, nb_clusters;
|
int64_t i;
|
||||||
int refcount1, refcount2;
|
|
||||||
QCowSnapshot *sn;
|
QCowSnapshot *sn;
|
||||||
uint16_t *refcount_table;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(bs->file);
|
*refcount_table = g_try_new0(uint16_t, *nb_clusters);
|
||||||
if (size < 0) {
|
if (*nb_clusters && *refcount_table == NULL) {
|
||||||
res->check_errors++;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
|
||||||
if (nb_clusters > INT_MAX) {
|
|
||||||
res->check_errors++;
|
|
||||||
return -EFBIG;
|
|
||||||
}
|
|
||||||
|
|
||||||
refcount_table = g_try_new0(uint16_t, nb_clusters);
|
|
||||||
if (nb_clusters && refcount_table == NULL) {
|
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
res->bfi.total_clusters =
|
|
||||||
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
|
|
||||||
|
|
||||||
/* header */
|
/* header */
|
||||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
inc_refcounts(bs, res, *refcount_table, *nb_clusters,
|
||||||
0, s->cluster_size);
|
0, s->cluster_size);
|
||||||
|
|
||||||
/* current L1 table */
|
/* current L1 table */
|
||||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
ret = check_refcounts_l1(bs, res, *refcount_table, *nb_clusters,
|
||||||
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
|
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* snapshots */
|
/* snapshots */
|
||||||
for (i = 0; i < s->nb_snapshots; i++) {
|
for (i = 0; i < s->nb_snapshots; i++) {
|
||||||
sn = s->snapshots + i;
|
sn = s->snapshots + i;
|
||||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
ret = check_refcounts_l1(bs, res, *refcount_table, *nb_clusters,
|
||||||
sn->l1_table_offset, sn->l1_size, 0);
|
sn->l1_table_offset, sn->l1_size, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
inc_refcounts(bs, res, *refcount_table, *nb_clusters,
|
||||||
s->snapshots_offset, s->snapshots_size);
|
s->snapshots_offset, s->snapshots_size);
|
||||||
|
|
||||||
/* refcount data */
|
/* refcount data */
|
||||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
inc_refcounts(bs, res, *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));
|
||||||
|
|
||||||
|
return check_refblocks(bs, res, fix, refcount_table, nb_clusters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks consistency of refblocks and accounts for each refblock in
|
||||||
|
* *refcount_table.
|
||||||
|
*/
|
||||||
|
static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
BdrvCheckMode fix, uint16_t **refcount_table,
|
||||||
|
int64_t *nb_clusters)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
int64_t i;
|
||||||
|
|
||||||
for(i = 0; i < s->refcount_table_size; i++) {
|
for(i = 0; i < s->refcount_table_size; i++) {
|
||||||
uint64_t offset, cluster;
|
uint64_t offset, cluster;
|
||||||
offset = s->refcount_table[i];
|
offset = s->refcount_table[i];
|
||||||
@ -1613,7 +1612,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cluster >= nb_clusters) {
|
if (cluster >= *nb_clusters) {
|
||||||
fprintf(stderr, "ERROR refcount block %" PRId64
|
fprintf(stderr, "ERROR refcount block %" PRId64
|
||||||
" is outside image\n", i);
|
" is outside image\n", i);
|
||||||
res->corruptions++;
|
res->corruptions++;
|
||||||
@ -1621,14 +1620,14 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (offset != 0) {
|
if (offset != 0) {
|
||||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
inc_refcounts(bs, res, *refcount_table, *nb_clusters,
|
||||||
offset, s->cluster_size);
|
offset, s->cluster_size);
|
||||||
if (refcount_table[cluster] != 1) {
|
if ((*refcount_table)[cluster] != 1) {
|
||||||
fprintf(stderr, "%s refcount block %" PRId64
|
fprintf(stderr, "%s refcount block %" PRId64
|
||||||
" refcount=%d\n",
|
" refcount=%d\n",
|
||||||
fix & BDRV_FIX_ERRORS ? "Repairing" :
|
fix & BDRV_FIX_ERRORS ? "Repairing" :
|
||||||
"ERROR",
|
"ERROR",
|
||||||
i, refcount_table[cluster]);
|
i, (*refcount_table)[cluster]);
|
||||||
|
|
||||||
if (fix & BDRV_FIX_ERRORS) {
|
if (fix & BDRV_FIX_ERRORS) {
|
||||||
int64_t new_offset;
|
int64_t new_offset;
|
||||||
@ -1640,17 +1639,18 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* update refcounts */
|
/* update refcounts */
|
||||||
if ((new_offset >> s->cluster_bits) >= nb_clusters) {
|
if ((new_offset >> s->cluster_bits) >= *nb_clusters) {
|
||||||
/* increase refcount_table size if necessary */
|
/* increase refcount_table size if necessary */
|
||||||
int old_nb_clusters = nb_clusters;
|
int old_nb_clusters = *nb_clusters;
|
||||||
nb_clusters = (new_offset >> s->cluster_bits) + 1;
|
*nb_clusters = (new_offset >> s->cluster_bits) + 1;
|
||||||
refcount_table = g_renew(uint16_t, refcount_table,
|
*refcount_table = g_renew(uint16_t, *refcount_table,
|
||||||
nb_clusters);
|
*nb_clusters);
|
||||||
memset(&refcount_table[old_nb_clusters], 0, (nb_clusters
|
memset(&(*refcount_table)[old_nb_clusters], 0,
|
||||||
- old_nb_clusters) * sizeof(uint16_t));
|
(*nb_clusters - old_nb_clusters) *
|
||||||
|
sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
refcount_table[cluster]--;
|
(*refcount_table)[cluster]--;
|
||||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
inc_refcounts(bs, res, *refcount_table, *nb_clusters,
|
||||||
new_offset, s->cluster_size);
|
new_offset, s->cluster_size);
|
||||||
|
|
||||||
res->corruptions_fixed++;
|
res->corruptions_fixed++;
|
||||||
@ -1661,8 +1661,22 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compare ref counts */
|
return 0;
|
||||||
for (i = 0, highest_cluster = 0; i < nb_clusters; i++) {
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compares the actual reference count for each cluster in the image against the
|
||||||
|
* refcount as reported by the refcount structures on-disk.
|
||||||
|
*/
|
||||||
|
static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
BdrvCheckMode fix, int64_t *highest_cluster,
|
||||||
|
uint16_t *refcount_table, int64_t nb_clusters)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
int64_t i;
|
||||||
|
int refcount1, refcount2, ret;
|
||||||
|
|
||||||
|
for (i = 0, *highest_cluster = 0; i < nb_clusters; i++) {
|
||||||
refcount1 = get_refcount(bs, i);
|
refcount1 = get_refcount(bs, i);
|
||||||
if (refcount1 < 0) {
|
if (refcount1 < 0) {
|
||||||
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
|
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
|
||||||
@ -1674,11 +1688,10 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
refcount2 = refcount_table[i];
|
refcount2 = refcount_table[i];
|
||||||
|
|
||||||
if (refcount1 > 0 || refcount2 > 0) {
|
if (refcount1 > 0 || refcount2 > 0) {
|
||||||
highest_cluster = i;
|
*highest_cluster = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refcount1 != refcount2) {
|
if (refcount1 != refcount2) {
|
||||||
|
|
||||||
/* Check if we're allowed to fix the mismatch */
|
/* Check if we're allowed to fix the mismatch */
|
||||||
int *num_fixed = NULL;
|
int *num_fixed = NULL;
|
||||||
if (refcount1 > refcount2 && (fix & BDRV_FIX_LEAKS)) {
|
if (refcount1 > refcount2 && (fix & BDRV_FIX_LEAKS)) {
|
||||||
@ -1711,6 +1724,44 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 occurred.
|
||||||
|
*/
|
||||||
|
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
BdrvCheckMode fix)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
int64_t size, highest_cluster, nb_clusters;
|
||||||
|
uint16_t *refcount_table;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
size = bdrv_getlength(bs->file);
|
||||||
|
if (size < 0) {
|
||||||
|
res->check_errors++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_clusters = size_to_clusters(s, size);
|
||||||
|
if (nb_clusters > INT_MAX) {
|
||||||
|
res->check_errors++;
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->bfi.total_clusters =
|
||||||
|
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
|
ret = calculate_refcounts(bs, res, fix, &refcount_table, &nb_clusters);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
compare_refcounts(bs, res, fix, &highest_cluster, refcount_table,
|
||||||
|
nb_clusters);
|
||||||
|
|
||||||
/* check OFLAG_COPIED */
|
/* check OFLAG_COPIED */
|
||||||
ret = check_oflag_copied(bs, res, fix);
|
ret = check_oflag_copied(bs, res, fix);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user