mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
qcow2: Allow get_refcount to return errors
get_refcount might need to load a refcount block from disk, so errors may happen. Return the error code instead of assuming a refcount of 1 and change the callers to respect error return values. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
6c6ea921ff
commit
018faafdbd
1 changed files with 37 additions and 4 deletions
|
@ -105,11 +105,17 @@ static int load_refcount_block(BlockDriverState *bs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the refcount of the cluster given by its index. Any non-negative
|
||||||
|
* return value is the refcount of the cluster, negative values are -errno
|
||||||
|
* and indicate an error.
|
||||||
|
*/
|
||||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int refcount_table_index, block_index;
|
int refcount_table_index, block_index;
|
||||||
int64_t refcount_block_offset;
|
int64_t refcount_block_offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||||
if (refcount_table_index >= s->refcount_table_size)
|
if (refcount_table_index >= s->refcount_table_size)
|
||||||
|
@ -119,8 +125,10 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||||
return 0;
|
return 0;
|
||||||
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
||||||
/* better than nothing: return allocated if read error */
|
/* better than nothing: return allocated if read error */
|
||||||
if (load_refcount_block(bs, refcount_block_offset) < 0)
|
ret = load_refcount_block(bs, refcount_block_offset);
|
||||||
return 1;
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
block_index = cluster_index &
|
block_index = cluster_index &
|
||||||
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
|
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
|
||||||
|
@ -538,7 +546,13 @@ fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* addend must be 1 or -1 */
|
/*
|
||||||
|
* Increases or decreases the refcount of a given cluster by one.
|
||||||
|
* addend must be 1 or -1.
|
||||||
|
*
|
||||||
|
* If the return value is non-negative, it is the new refcount of the cluster.
|
||||||
|
* If it is negative, it is -errno and indicates an error.
|
||||||
|
*/
|
||||||
static int update_cluster_refcount(BlockDriverState *bs,
|
static int update_cluster_refcount(BlockDriverState *bs,
|
||||||
int64_t cluster_index,
|
int64_t cluster_index,
|
||||||
int addend)
|
int addend)
|
||||||
|
@ -779,6 +793,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||||
} else {
|
} else {
|
||||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (refcount < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refcount == 1) {
|
if (refcount == 1) {
|
||||||
|
@ -801,7 +819,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||||
} else {
|
} else {
|
||||||
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
|
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
|
||||||
}
|
}
|
||||||
if (refcount == 1) {
|
if (refcount < 0) {
|
||||||
|
goto fail;
|
||||||
|
} else if (refcount == 1) {
|
||||||
l2_offset |= QCOW_OFLAG_COPIED;
|
l2_offset |= QCOW_OFLAG_COPIED;
|
||||||
}
|
}
|
||||||
if (l2_offset != old_l2_offset) {
|
if (l2_offset != old_l2_offset) {
|
||||||
|
@ -934,6 +954,10 @@ static int check_refcounts_l2(BlockDriverState *bs,
|
||||||
uint64_t entry = offset;
|
uint64_t entry = offset;
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
offset &= ~QCOW_OFLAG_COPIED;
|
||||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
||||||
|
if (refcount < 0) {
|
||||||
|
fprintf(stderr, "Can't get refcount for offset %"
|
||||||
|
PRIx64 ": %s\n", entry, strerror(-refcount));
|
||||||
|
}
|
||||||
if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
|
if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
|
||||||
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
||||||
PRIx64 " refcount=%d\n", entry, refcount);
|
PRIx64 " refcount=%d\n", entry, refcount);
|
||||||
|
@ -1011,6 +1035,10 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||||
if (check_copied) {
|
if (check_copied) {
|
||||||
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
|
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
|
||||||
>> s->cluster_bits);
|
>> s->cluster_bits);
|
||||||
|
if (refcount < 0) {
|
||||||
|
fprintf(stderr, "Can't get refcount for l2_offset %"
|
||||||
|
PRIx64 ": %s\n", l2_offset, strerror(-refcount));
|
||||||
|
}
|
||||||
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);
|
||||||
|
@ -1118,6 +1146,11 @@ int qcow2_check_refcounts(BlockDriverState *bs)
|
||||||
/* compare ref counts */
|
/* compare ref counts */
|
||||||
for(i = 0; i < nb_clusters; i++) {
|
for(i = 0; i < nb_clusters; i++) {
|
||||||
refcount1 = get_refcount(bs, i);
|
refcount1 = get_refcount(bs, i);
|
||||||
|
if (refcount1 < 0) {
|
||||||
|
fprintf(stderr, "Can't get refcount for cluster %d: %s\n",
|
||||||
|
i, strerror(-refcount1));
|
||||||
|
}
|
||||||
|
|
||||||
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",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue