qcow2-refcount: Snapshot update for zero clusters
Account for all cluster types in qcow2_update_snapshot_refcounts; this prevents this function from updating the refcount of unallocated zero clusters which effectively led to wrong adjustments of the refcount of cluster 0 (the main qcow2 header). This in turn resulted in images with (unallocated) zero clusters having a cluster 0 refcount greater than one after creating a snapshot. Signed-off-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
d4ca092a42
commit
8b81a7b6ba
@ -861,11 +861,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(j = 0; j < s->l2_size; j++) {
|
for(j = 0; j < s->l2_size; j++) {
|
||||||
|
uint64_t cluster_index;
|
||||||
|
|
||||||
offset = be64_to_cpu(l2_table[j]);
|
offset = be64_to_cpu(l2_table[j]);
|
||||||
if (offset != 0) {
|
|
||||||
old_offset = offset;
|
old_offset = offset;
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
offset &= ~QCOW_OFLAG_COPIED;
|
||||||
if (offset & QCOW_OFLAG_COMPRESSED) {
|
|
||||||
|
switch (qcow2_get_cluster_type(offset)) {
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
nb_csectors = ((offset >> s->csize_shift) &
|
nb_csectors = ((offset >> s->csize_shift) &
|
||||||
s->csize_mask) + 1;
|
s->csize_mask) + 1;
|
||||||
if (addend != 0) {
|
if (addend != 0) {
|
||||||
@ -880,8 +883,16 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
/* compressed clusters are never modified */
|
/* compressed clusters are never modified */
|
||||||
refcount = 2;
|
refcount = 2;
|
||||||
} else {
|
break;
|
||||||
uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
|
||||||
|
if (!cluster_index) {
|
||||||
|
/* unallocated */
|
||||||
|
refcount = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (addend != 0) {
|
if (addend != 0) {
|
||||||
refcount = update_cluster_refcount(bs, cluster_index, addend,
|
refcount = update_cluster_refcount(bs, cluster_index, addend,
|
||||||
QCOW2_DISCARD_SNAPSHOT);
|
QCOW2_DISCARD_SNAPSHOT);
|
||||||
@ -893,6 +904,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
ret = refcount;
|
ret = refcount;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
|
refcount = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refcount == 1) {
|
if (refcount == 1) {
|
||||||
@ -907,7 +926,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
|
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user