summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2009-05-26 14:36:03 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2009-05-27 09:45:20 -0500
commit95762a79aaaa0f7cea5a9a934bdf8466bf2fd614 (patch)
tree92e2b4bf3e581fa1c2b1cbe5eeb9d860f9ddd60b /block
parent31163aeb3fd9778d2c1813b863538caf0eb76a89 (diff)
downloadqemu-95762a79aaaa0f7cea5a9a934bdf8466bf2fd614.tar.gz
qemu-95762a79aaaa0f7cea5a9a934bdf8466bf2fd614.tar.bz2
qemu-95762a79aaaa0f7cea5a9a934bdf8466bf2fd614.zip
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>
Diffstat (limited to 'block')
-rw-r--r--block/qcow2.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index ba946e6cbc..619b923142 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2578,6 +2578,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",
@@ -2590,10 +2593,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) {
@@ -2603,6 +2621,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)
@@ -2611,12 +2636,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;
}