0a122b
From 6529ac40614e6b28a9c52de40defb6e2f455698b Mon Sep 17 00:00:00 2001
0a122b
From: Max Reitz <mreitz@redhat.com>
0a122b
Date: Tue, 7 Jan 2014 21:57:14 +0100
0a122b
Subject: [PATCH 09/14] qcow2: Correct bitmap size in zero expansion
0a122b
0a122b
RH-Author: Max Reitz <mreitz@redhat.com>
0a122b
Message-id: <1389131839-12920-10-git-send-email-mreitz@redhat.com>
0a122b
Patchwork-id: 56545
0a122b
O-Subject: [RHEL-7.0 qemu-kvm PATCH v2 09/14] qcow2: Correct bitmap size in zero expansion
0a122b
Bugzilla: 1033490
0a122b
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
0a122b
RH-Acked-by: Fam Zheng <famz@redhat.com>
0a122b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
0a122b
BZ: 1033490
0a122b
0a122b
Since the expanded_clusters bitmap is addressed using host offsets in
0a122b
the underlying image file, the correct size to use for allocating the
0a122b
bitmap is not determined by the guest disk image but by the underlying
0a122b
host image file.
0a122b
0a122b
Furthermore, this size may change during the expansion due to cluster
0a122b
allocations on growable image files. In this case, the bitmap needs to
0a122b
be resized as well to reflect the growth.
0a122b
0a122b
Signed-off-by: Max Reitz <mreitz@redhat.com>
0a122b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
0a122b
(cherry picked from commit e390cf5a9722d3f3cc54efb505f6ff37fa554b11)
0a122b
0a122b
Signed-off-by: Max Reitz <mreitz@redhat.com>
0a122b
---
0a122b
 block/qcow2-cluster.c | 38 +++++++++++++++++++++++++++-----------
0a122b
 1 file changed, 27 insertions(+), 11 deletions(-)
0a122b
0a122b
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
0a122b
---
0a122b
 block/qcow2-cluster.c |   38 +++++++++++++++++++++++++++-----------
0a122b
 1 files changed, 27 insertions(+), 11 deletions(-)
0a122b
0a122b
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
0a122b
index 796d7c5..bfdc83a 100644
0a122b
--- a/block/qcow2-cluster.c
0a122b
+++ b/block/qcow2-cluster.c
0a122b
@@ -1511,8 +1511,8 @@ fail:
0a122b
  * i.e., the number of bits in expanded_clusters.
0a122b
  */
0a122b
 static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
0a122b
-                                      int l1_size, uint8_t *expanded_clusters,
0a122b
-                                      uint64_t nb_clusters)
0a122b
+                                      int l1_size, uint8_t **expanded_clusters,
0a122b
+                                      uint64_t *nb_clusters)
0a122b
 {
0a122b
     BDRVQcowState *s = bs->opaque;
0a122b
     bool is_active_l1 = (l1_table == s->l1_table);
0a122b
@@ -1555,8 +1555,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
0a122b
 
0a122b
             if (cluster_type == QCOW2_CLUSTER_NORMAL) {
0a122b
                 cluster_index = offset >> s->cluster_bits;
0a122b
-                assert((cluster_index >= 0) && (cluster_index < nb_clusters));
0a122b
-                if (expanded_clusters[cluster_index / 8] &
0a122b
+                assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
0a122b
+                if ((*expanded_clusters)[cluster_index / 8] &
0a122b
                     (1 << (cluster_index % 8))) {
0a122b
                     /* Probably a shared L2 table; this cluster was a zero
0a122b
                      * cluster which has been expanded, its refcount
0a122b
@@ -1613,8 +1613,25 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
0a122b
             l2_dirty = true;
0a122b
 
0a122b
             cluster_index = offset >> s->cluster_bits;
0a122b
-            assert((cluster_index >= 0) && (cluster_index < nb_clusters));
0a122b
-            expanded_clusters[cluster_index / 8] |= 1 << (cluster_index % 8);
0a122b
+
0a122b
+            if (cluster_index >= *nb_clusters) {
0a122b
+                uint64_t old_bitmap_size = (*nb_clusters + 7) / 8;
0a122b
+                uint64_t new_bitmap_size;
0a122b
+                /* The offset may lie beyond the old end of the underlying image
0a122b
+                 * file for growable files only */
0a122b
+                assert(bs->file->growable);
0a122b
+                *nb_clusters = size_to_clusters(s, bs->file->total_sectors *
0a122b
+                                                BDRV_SECTOR_SIZE);
0a122b
+                new_bitmap_size = (*nb_clusters + 7) / 8;
0a122b
+                *expanded_clusters = g_realloc(*expanded_clusters,
0a122b
+                                               new_bitmap_size);
0a122b
+                /* clear the newly allocated space */
0a122b
+                memset(&(*expanded_clusters)[old_bitmap_size], 0,
0a122b
+                       new_bitmap_size - old_bitmap_size);
0a122b
+            }
0a122b
+
0a122b
+            assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
0a122b
+            (*expanded_clusters)[cluster_index / 8] |= 1 << (cluster_index % 8);
0a122b
         }
0a122b
 
0a122b
         if (is_active_l1) {
0a122b
@@ -1673,18 +1690,17 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
0a122b
 {
0a122b
     BDRVQcowState *s = bs->opaque;
0a122b
     uint64_t *l1_table = NULL;
0a122b
-    int cluster_to_sector_bits = s->cluster_bits - BDRV_SECTOR_BITS;
0a122b
     uint64_t nb_clusters;
0a122b
     uint8_t *expanded_clusters;
0a122b
     int ret;
0a122b
     int i, j;
0a122b
 
0a122b
-    nb_clusters = (bs->total_sectors + (1 << cluster_to_sector_bits) - 1)
0a122b
-            >> cluster_to_sector_bits;
0a122b
+    nb_clusters = size_to_clusters(s, bs->file->total_sectors *
0a122b
+                                   BDRV_SECTOR_SIZE);
0a122b
     expanded_clusters = g_malloc0((nb_clusters + 7) / 8);
0a122b
 
0a122b
     ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
0a122b
-                                     expanded_clusters, nb_clusters);
0a122b
+                                     &expanded_clusters, &nb_clusters);
0a122b
     if (ret < 0) {
0a122b
         goto fail;
0a122b
     }
0a122b
@@ -1718,7 +1734,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
0a122b
         }
0a122b
 
0a122b
         ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size,
0a122b
-                                         expanded_clusters, nb_clusters);
0a122b
+                                         &expanded_clusters, &nb_clusters);
0a122b
         if (ret < 0) {
0a122b
             goto fail;
0a122b
         }
0a122b
-- 
0a122b
1.7.1
0a122b