aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2011-02-09 17:36:19 +0100
committerKevin Wolf <kwolf@redhat.com>2011-02-10 13:24:29 +0100
commit16fde5f2c2788232b16c06d34d0459a5c1ec1f6c (patch)
treee92076b0f8ebc5a78a68a6ae347fc5744c06e9f0 /block
parenta9ae2bffea62ce5158be7475fe41e5fba6d026c1 (diff)
qcow2: Fix order in L2 table COW
When copying L2 tables (this happens only with internal snapshots), the order wasn't completely safe, so that after a crash you could end up with a L2 table that has too low refcount, possibly leading to corruption in the long run. This patch puts the operations in the right order: First allocate the new L2 table and replace the reference, and only then decrease the refcount of the old table. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/qcow2-cluster.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 437aaa8174..750abe37d4 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -515,13 +515,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return ret;
}
} else {
- /* FIXME Order */
- if (l2_offset)
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+ /* First allocate a new L2 table (and do COW if needed) */
ret = l2_allocate(bs, l1_index, &l2_table);
if (ret < 0) {
return ret;
}
+
+ /* Then decrease the refcount of the old table */
+ if (l2_offset) {
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+ }
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
}