summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2011-02-09 17:36:19 +0100
committerKevin Wolf <kwolf@redhat.com>2011-02-11 14:34:06 +0100
commitc7e9df3bc6bf0cad74081c7492b5aab753bf9cc9 (patch)
treeaf1aaeba15d175ac54794dc13d21609f875dfac2
parent038a866f8153c45499b80162f8e1b7188620bd8a (diff)
downloadqemu-c7e9df3bc6bf0cad74081c7492b5aab753bf9cc9.tar.gz
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> (cherry picked from commit 16fde5f2c2788232b16c06d34d0459a5c1ec1f6c)
-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;
}