Commit d4d698f020e50333d6eae48ce323752613b5c3ea
Committed by
Anthony Liguori
1 parent
a6d65524
Fix cluster freeing in qcow2
Need to drop QCOW_OFLAG_COPIED from a cluster pointer before freeing it. Add an explanation how thing meant to work. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
1 changed file
with
8 additions
and
1 deletions
block-qcow2.c
@@ -992,6 +992,12 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, | @@ -992,6 +992,12 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, | ||
992 | goto err; | 992 | goto err; |
993 | 993 | ||
994 | for (i = 0; i < m->nb_clusters; i++) { | 994 | for (i = 0; i < m->nb_clusters; i++) { |
995 | + /* if two concurrent writes happen to the same unallocated cluster | ||
996 | + * each write allocates separate cluster and writes data concurrently. | ||
997 | + * The first one to complete updates l2 table with pointer to its | ||
998 | + * cluster the second one has to do RMW (which is done above by | ||
999 | + * copy_sectors()), update l2 table with its cluster pointer and free | ||
1000 | + * old cluster. This is what this loop does */ | ||
995 | if(l2_table[l2_index + i] != 0) | 1001 | if(l2_table[l2_index + i] != 0) |
996 | old_cluster[j++] = l2_table[l2_index + i]; | 1002 | old_cluster[j++] = l2_table[l2_index + i]; |
997 | 1003 | ||
@@ -1005,7 +1011,8 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, | @@ -1005,7 +1011,8 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, | ||
1005 | goto err; | 1011 | goto err; |
1006 | 1012 | ||
1007 | for (i = 0; i < j; i++) | 1013 | for (i = 0; i < j; i++) |
1008 | - free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1); | 1014 | + free_any_clusters(bs, be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, |
1015 | + 1); | ||
1009 | 1016 | ||
1010 | ret = 0; | 1017 | ret = 0; |
1011 | err: | 1018 | err: |