summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Habkost <ehabkost@redhat.com>2009-09-09 17:29:05 -0300
committerEduardo Habkost <ehabkost@redhat.com>2009-09-09 18:02:08 -0300
commit41f29a5aa47004f244e842385915d002d0ddead0 (patch)
tree7f1a3701f44e7b24eefd32531cbbdf31f925fd88
parent84922c03f768ca4f83949fa9020b38e872b07616 (diff)
qcow2: Update multiple refcounts at once
Message-id: <1252527484-19604-3-git-send-email-ehabkost@redhat.com> RH-Author: Eduardo Habkost <ehabkost@redhat.com> Patchwork-id: 3386 O-Subject: [PATCH 2/5] qcow2: Update multiple refcounts at once Bugzilla: Author: Kevin Wolf <kwolf@redhat.com> Bugzilla: 520693 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(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
-rw-r--r--qemu/block-qcow2.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/qemu/block-qcow2.c b/qemu/block-qcow2.c
index 466de8ae..171eb83f 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;
}