Commit d4d698f020e50333d6eae48ce323752613b5c3ea

Authored by Gleb Natapov
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:
... ...