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