9ae3a8
From 4d45b1791fb8bc24c17045a91b39c1d62e9e47c3 Mon Sep 17 00:00:00 2001
9ae3a8
From: Max Reitz <mreitz@redhat.com>
9ae3a8
Date: Tue, 7 Jan 2014 21:57:07 +0100
9ae3a8
Subject: [PATCH 02/14] qcow2-refcount: Snapshot update for zero clusters
9ae3a8
9ae3a8
RH-Author: Max Reitz <mreitz@redhat.com>
9ae3a8
Message-id: <1389131839-12920-3-git-send-email-mreitz@redhat.com>
9ae3a8
Patchwork-id: 56538
9ae3a8
O-Subject: [RHEL-7.0 qemu-kvm PATCH v2 02/14] qcow2-refcount: Snapshot update for zero clusters
9ae3a8
Bugzilla: 1033490
9ae3a8
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
RH-Acked-by: Fam Zheng <famz@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
BZ: 1033490
9ae3a8
9ae3a8
Account for all cluster types in qcow2_update_snapshot_refcounts;
9ae3a8
this prevents this function from updating the refcount of unallocated
9ae3a8
zero clusters which effectively led to wrong adjustments of the refcount
9ae3a8
of cluster 0 (the main qcow2 header). This in turn resulted in images
9ae3a8
with (unallocated) zero clusters having a cluster 0 refcount greater
9ae3a8
than one after creating a snapshot.
9ae3a8
9ae3a8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
(cherry picked from commit 8b81a7b6ba8686f35f9cb0acdd54004d63206f03)
9ae3a8
9ae3a8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow2-refcount.c | 52 +++++++++++++++++++++++++++++++++-----------------
9ae3a8
 1 file changed, 35 insertions(+), 17 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow2-refcount.c |   52 ++++++++++++++++++++++++++++++++---------------
9ae3a8
 1 files changed, 35 insertions(+), 17 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
9ae3a8
index 3787314..2b72d5e 100644
9ae3a8
--- a/block/qcow2-refcount.c
9ae3a8
+++ b/block/qcow2-refcount.c
9ae3a8
@@ -863,11 +863,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
             }
9ae3a8
 
9ae3a8
             for(j = 0; j < s->l2_size; j++) {
9ae3a8
+                uint64_t cluster_index;
9ae3a8
+
9ae3a8
                 offset = be64_to_cpu(l2_table[j]);
9ae3a8
-                if (offset != 0) {
9ae3a8
-                    old_offset = offset;
9ae3a8
-                    offset &= ~QCOW_OFLAG_COPIED;
9ae3a8
-                    if (offset & QCOW_OFLAG_COMPRESSED) {
9ae3a8
+                old_offset = offset;
9ae3a8
+                offset &= ~QCOW_OFLAG_COPIED;
9ae3a8
+
9ae3a8
+                switch (qcow2_get_cluster_type(offset)) {
9ae3a8
+                    case QCOW2_CLUSTER_COMPRESSED:
9ae3a8
                         nb_csectors = ((offset >> s->csize_shift) &
9ae3a8
                                        s->csize_mask) + 1;
9ae3a8
                         if (addend != 0) {
9ae3a8
@@ -882,8 +885,16 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
                         }
9ae3a8
                         /* compressed clusters are never modified */
9ae3a8
                         refcount = 2;
9ae3a8
-                    } else {
9ae3a8
-                        uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
9ae3a8
+                        break;
9ae3a8
+
9ae3a8
+                    case QCOW2_CLUSTER_NORMAL:
9ae3a8
+                    case QCOW2_CLUSTER_ZERO:
9ae3a8
+                        cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
9ae3a8
+                        if (!cluster_index) {
9ae3a8
+                            /* unallocated */
9ae3a8
+                            refcount = 0;
9ae3a8
+                            break;
9ae3a8
+                        }
9ae3a8
                         if (addend != 0) {
9ae3a8
                             refcount = update_cluster_refcount(bs, cluster_index, addend,
9ae3a8
                                                                QCOW2_DISCARD_SNAPSHOT);
9ae3a8
@@ -895,19 +906,26 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
9ae3a8
                             ret = refcount;
9ae3a8
                             goto fail;
9ae3a8
                         }
9ae3a8
-                    }
9ae3a8
+                        break;
9ae3a8
 
9ae3a8
-                    if (refcount == 1) {
9ae3a8
-                        offset |= QCOW_OFLAG_COPIED;
9ae3a8
-                    }
9ae3a8
-                    if (offset != old_offset) {
9ae3a8
-                        if (addend > 0) {
9ae3a8
-                            qcow2_cache_set_dependency(bs, s->l2_table_cache,
9ae3a8
-                                s->refcount_block_cache);
9ae3a8
-                        }
9ae3a8
-                        l2_table[j] = cpu_to_be64(offset);
9ae3a8
-                        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
9ae3a8
+                    case QCOW2_CLUSTER_UNALLOCATED:
9ae3a8
+                        refcount = 0;
9ae3a8
+                        break;
9ae3a8
+
9ae3a8
+                    default:
9ae3a8
+                        abort();
9ae3a8
+                }
9ae3a8
+
9ae3a8
+                if (refcount == 1) {
9ae3a8
+                    offset |= QCOW_OFLAG_COPIED;
9ae3a8
+                }
9ae3a8
+                if (offset != old_offset) {
9ae3a8
+                    if (addend > 0) {
9ae3a8
+                        qcow2_cache_set_dependency(bs, s->l2_table_cache,
9ae3a8
+                            s->refcount_block_cache);
9ae3a8
                     }
9ae3a8
+                    l2_table[j] = cpu_to_be64(offset);
9ae3a8
+                    qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
9ae3a8
                 }
9ae3a8
             }
9ae3a8
 
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8