提交 018faafd 编写于 作者: K Kevin Wolf

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: NKevin Wolf <kwolf@redhat.com>
上级 6c6ea921
......@@ -105,11 +105,17 @@ static int load_refcount_block(BlockDriverState *bs,
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)
{
BDRVQcowState *s = bs->opaque;
int refcount_table_index, block_index;
int64_t refcount_block_offset;
int ret;
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size)
......@@ -119,8 +125,10 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
return 0;
if (refcount_block_offset != s->refcount_block_cache_offset) {
/* better than nothing: return allocated if read error */
if (load_refcount_block(bs, refcount_block_offset) < 0)
return 1;
ret = load_refcount_block(bs, refcount_block_offset);
if (ret < 0) {
return ret;
}
}
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
......@@ -538,7 +546,13 @@ fail:
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,
int64_t cluster_index,
int addend)
......@@ -779,6 +793,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} else {
refcount = get_refcount(bs, offset >> s->cluster_bits);
}
if (refcount < 0) {
goto fail;
}
}
if (refcount == 1) {
......@@ -801,7 +819,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} else {
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;
}
if (l2_offset != old_l2_offset) {
......@@ -934,6 +954,10 @@ static int check_refcounts_l2(BlockDriverState *bs,
uint64_t entry = offset;
offset &= ~QCOW_OFLAG_COPIED;
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)) {
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
PRIx64 " refcount=%d\n", entry, refcount);
......@@ -1011,6 +1035,10 @@ static int check_refcounts_l1(BlockDriverState *bs,
if (check_copied) {
refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
>> 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)) {
fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
" refcount=%d\n", l2_offset, refcount);
......@@ -1118,6 +1146,11 @@ int qcow2_check_refcounts(BlockDriverState *bs)
/* compare ref counts */
for(i = 0; i < nb_clusters; 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];
if (refcount1 != refcount2) {
fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册