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: |