From e4fe05f92fb86c2eddfbd84b75a4328aa3d6d8c9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost <ehabkost@redhat.com> Date: Wed, 9 Sep 2009 15:57:34 -0300 Subject: [PATCH 2/5] qcow2: Update multiple refcounts at once Message-id: <1250675987-18401-3-git-send-email-kwolf@redhat.com> RH-Author: Kevin Wolf <kwolf@redhat.com> Patchwork-id: 3272 O-Subject: [RHEL 5.5 PATCH 2/5] qcow2: Update multiple refcounts at once Bugzilla: 518169 RH-Acked-by: Juan Quintela <quintela@redhat.com> RH-Acked-by: Andrea Arcangeli <aarcange@redhat.com> RH-Acked-by: Gleb Natapov <gleb@redhat.com> 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> --- qemu/block-qcow2.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 files changed, 36 insertions(+), 4 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/block-qcow2.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 files changed, 36 insertions(+), 4 deletions(-) diff --git a/qemu/block-qcow2.c b/qemu/block-qcow2.c index 466de8a..171eb83 100644 --- a/qemu/block-qcow2.c +++ b/qemu/block-qcow2.c @@ -2588,6 +2588,9 @@ static int update_refcount(BlockDriverState *bs, { BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; + int64_t refcount_block_offset = 0; + int64_t table_index = -1, old_table_index; + int first_index = -1, last_index = -1; #ifdef DEBUG_ALLOC2 printf("update_refcount: offset=%lld size=%lld addend=%d\n", @@ -2600,10 +2603,25 @@ static int update_refcount(BlockDriverState *bs, for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size) { - int64_t refcount_block_offset; int block_index, refcount; int64_t cluster_index = cluster_offset >> s->cluster_bits; + /* Only write refcount block to disk when we are done with it */ + old_table_index = table_index; + table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); + if ((old_table_index >= 0) && (table_index != old_table_index)) { + size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT; + if (bdrv_pwrite(s->hd, + refcount_block_offset + (first_index << REFCOUNT_SHIFT), + &s->refcount_block_cache[first_index], size) != size) + { + return -EIO; + } + + first_index = -1; + last_index = -1; + } + /* Load the refcount block and allocate it if needed */ refcount_block_offset = alloc_refcount_block(bs, cluster_index); if (refcount_block_offset < 0) { @@ -2613,6 +2631,13 @@ static int update_refcount(BlockDriverState *bs, /* we can update the count and save it */ block_index = cluster_index & ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); + if (first_index == -1 || block_index < first_index) { + first_index = block_index; + } + if (block_index > last_index) { + last_index = block_index; + } + refcount = be16_to_cpu(s->refcount_block_cache[block_index]); refcount += addend; if (refcount < 0 || refcount > 0xffff) @@ -2621,12 +2646,19 @@ static int update_refcount(BlockDriverState *bs, s->free_cluster_index = cluster_index; } s->refcount_block_cache[block_index] = cpu_to_be16(refcount); + } + + /* Write last changed block to disk */ + if (refcount_block_offset != 0) { + size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT; if (bdrv_pwrite(s->hd, - refcount_block_offset + (block_index << REFCOUNT_SHIFT), - &s->refcount_block_cache[block_index], 2) != 2) + refcount_block_offset + (first_index << REFCOUNT_SHIFT), + &s->refcount_block_cache[first_index], size) != size) + { return -EIO; - + } } + return 0; } -- 1.6.3.rc4.29.g8146