提交 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, ...@@ -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) ...@@ -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: ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册