Commit a980c98cf1acb3e813428d4f783a8ebd153ef036

Authored by Kevin Wolf
Committed by Anthony Liguori
1 parent 44ff42de

qcow2: Update multiple refcounts at once

Don't write each single changed refcount block entry to the disk after it is
written, but update all entries of the block and write all of them at once.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 1 changed file with 36 additions and 4 deletions
block/qcow2.c
@@ -2578,6 +2578,9 @@ static int update_refcount(BlockDriverState *bs, @@ -2578,6 +2578,9 @@ static int update_refcount(BlockDriverState *bs,
2578 { 2578 {
2579 BDRVQcowState *s = bs->opaque; 2579 BDRVQcowState *s = bs->opaque;
2580 int64_t start, last, cluster_offset; 2580 int64_t start, last, cluster_offset;
  2581 + int64_t refcount_block_offset = 0;
  2582 + int64_t table_index = -1, old_table_index;
  2583 + int first_index = -1, last_index = -1;
2581 2584
2582 #ifdef DEBUG_ALLOC2 2585 #ifdef DEBUG_ALLOC2
2583 printf("update_refcount: offset=%lld size=%lld addend=%d\n", 2586 printf("update_refcount: offset=%lld size=%lld addend=%d\n",
@@ -2590,10 +2593,25 @@ static int update_refcount(BlockDriverState *bs, @@ -2590,10 +2593,25 @@ static int update_refcount(BlockDriverState *bs,
2590 for(cluster_offset = start; cluster_offset <= last; 2593 for(cluster_offset = start; cluster_offset <= last;
2591 cluster_offset += s->cluster_size) 2594 cluster_offset += s->cluster_size)
2592 { 2595 {
2593 - int64_t refcount_block_offset;  
2594 int block_index, refcount; 2596 int block_index, refcount;
2595 int64_t cluster_index = cluster_offset >> s->cluster_bits; 2597 int64_t cluster_index = cluster_offset >> s->cluster_bits;
2596 2598
  2599 + /* Only write refcount block to disk when we are done with it */
  2600 + old_table_index = table_index;
  2601 + table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
  2602 + if ((old_table_index >= 0) && (table_index != old_table_index)) {
  2603 + size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
  2604 + if (bdrv_pwrite(s->hd,
  2605 + refcount_block_offset + (first_index << REFCOUNT_SHIFT),
  2606 + &s->refcount_block_cache[first_index], size) != size)
  2607 + {
  2608 + return -EIO;
  2609 + }
  2610 +
  2611 + first_index = -1;
  2612 + last_index = -1;
  2613 + }
  2614 +
2597 /* Load the refcount block and allocate it if needed */ 2615 /* Load the refcount block and allocate it if needed */
2598 refcount_block_offset = alloc_refcount_block(bs, cluster_index); 2616 refcount_block_offset = alloc_refcount_block(bs, cluster_index);
2599 if (refcount_block_offset < 0) { 2617 if (refcount_block_offset < 0) {
@@ -2603,6 +2621,13 @@ static int update_refcount(BlockDriverState *bs, @@ -2603,6 +2621,13 @@ static int update_refcount(BlockDriverState *bs,
2603 /* we can update the count and save it */ 2621 /* we can update the count and save it */
2604 block_index = cluster_index & 2622 block_index = cluster_index &
2605 ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); 2623 ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
  2624 + if (first_index == -1 || block_index < first_index) {
  2625 + first_index = block_index;
  2626 + }
  2627 + if (block_index > last_index) {
  2628 + last_index = block_index;
  2629 + }
  2630 +
2606 refcount = be16_to_cpu(s->refcount_block_cache[block_index]); 2631 refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
2607 refcount += addend; 2632 refcount += addend;
2608 if (refcount < 0 || refcount > 0xffff) 2633 if (refcount < 0 || refcount > 0xffff)
@@ -2611,12 +2636,19 @@ static int update_refcount(BlockDriverState *bs, @@ -2611,12 +2636,19 @@ static int update_refcount(BlockDriverState *bs,
2611 s->free_cluster_index = cluster_index; 2636 s->free_cluster_index = cluster_index;
2612 } 2637 }
2613 s->refcount_block_cache[block_index] = cpu_to_be16(refcount); 2638 s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
  2639 + }
  2640 +
  2641 + /* Write last changed block to disk */
  2642 + if (refcount_block_offset != 0) {
  2643 + size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT;
2614 if (bdrv_pwrite(s->hd, 2644 if (bdrv_pwrite(s->hd,
2615 - refcount_block_offset + (block_index << REFCOUNT_SHIFT),  
2616 - &s->refcount_block_cache[block_index], 2) != 2) 2645 + refcount_block_offset + (first_index << REFCOUNT_SHIFT),
  2646 + &s->refcount_block_cache[first_index], size) != size)
  2647 + {
2617 return -EIO; 2648 return -EIO;
2618 - 2649 + }
2619 } 2650 }
  2651 +
2620 return 0; 2652 return 0;
2621 } 2653 }
2622 2654