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 | 992 | goto err; |
993 | 993 | |
994 | 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 | 1001 | if(l2_table[l2_index + i] != 0) |
996 | 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 | 1011 | goto err; |
1006 | 1012 | |
1007 | 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 | 1017 | ret = 0; |
1011 | 1018 | err: | ... | ... |