Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 646

kvm-83-270.el5_11.src.rpm

From d616e83b49c629cb8c7f88b63b542a6ab061bd26 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Tue, 1 Jun 2010 13:52:44 -0300
Subject: [PATCH] qcow2: Fix corruption after refblock allocation

RH-Author: Kevin Wolf <kwolf@redhat.com>
Message-id: <1275400364-20450-1-git-send-email-kwolf@redhat.com>
Patchwork-id: 9645
O-Subject: [RHEL-5.6/5.5.z KVM PATCH] qcow2: Fix corruption after refblock
	allocation
Bugzilla: 598488
RH-Acked-by: Christoph Hellwig <chellwig@redhat.com>
RH-Acked-by: Juan Quintela <quintela@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>

Bugzilla: 598488
Upstream status: Submitted

Refblock allocation code needs to take into consideration that update_refcount
will load a different refcount block into the cache, so it must initialize the
cache for a new refcount block only afterwards. Not doing this means that not
only the refcount in the wrong block is updated, but also that the caller will
work on the wrong block.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu/block-qcow2.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 qemu/block-qcow2.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/qemu/block-qcow2.c b/qemu/block-qcow2.c
index 4885a6e..7276959 100644
--- a/qemu/block-qcow2.c
+++ b/qemu/block-qcow2.c
@@ -2759,8 +2759,6 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
 
     /* Allocate the refcount block itself and mark it as used */
     uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
-    memset(s->refcount_block_cache, 0, s->cluster_size);
-    s->refcount_block_cache_offset = new_block;
 
 #ifdef DEBUG_ALLOC2
     fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
@@ -2769,6 +2767,10 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
 #endif
 
     if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
+        /* Zero the new refcount block before updating it */
+        memset(s->refcount_block_cache, 0, s->cluster_size);
+        s->refcount_block_cache_offset = new_block;
+
         /* The block describes itself, need to update the cache */
         int block_index = (new_block >> s->cluster_bits) &
             ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
@@ -2780,6 +2782,11 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
         if (ret < 0) {
             goto fail_block;
         }
+
+        /* Initialize the new refcount block only after updating its refcount,
+         * update_refcount uses the refcount cache itself */
+        memset(s->refcount_block_cache, 0, s->cluster_size);
+        s->refcount_block_cache_offset = new_block;
     }
 
     /* Now the new refcount block needs to be written to disk */
-- 
1.7.0.3