aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Reitz <mreitz@redhat.com>2013-09-25 12:07:22 +0200
committerKevin Wolf <kwolf@redhat.com>2013-09-27 11:16:35 +0200
commite390cf5a9722d3f3cc54efb505f6ff37fa554b11 (patch)
tree27e3c5dfadbfe70735c3a556ab8bda85386a9b3b
parentfef9c19139f4d69a080d99b8cbade163d0bbf0fc (diff)
qcow2: Correct bitmap size in zero expansion
Since the expanded_clusters bitmap is addressed using host offsets in the underlying image file, the correct size to use for allocating the bitmap is not determined by the guest disk image but by the underlying host image file. Furthermore, this size may change during the expansion due to cluster allocations on growable image files. In this case, the bitmap needs to be resized as well to reflect the growth. Signed-off-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
-rw-r--r--block/qcow2-cluster.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index cab5f2e6b5..ffa89411d8 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1510,8 +1510,8 @@ fail:
* i.e., the number of bits in expanded_clusters.
*/
static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
- int l1_size, uint8_t *expanded_clusters,
- uint64_t nb_clusters)
+ int l1_size, uint8_t **expanded_clusters,
+ uint64_t *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table);
@@ -1554,8 +1554,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
if (cluster_type == QCOW2_CLUSTER_NORMAL) {
cluster_index = offset >> s->cluster_bits;
- assert((cluster_index >= 0) && (cluster_index < nb_clusters));
- if (expanded_clusters[cluster_index / 8] &
+ assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
+ if ((*expanded_clusters)[cluster_index / 8] &
(1 << (cluster_index % 8))) {
/* Probably a shared L2 table; this cluster was a zero
* cluster which has been expanded, its refcount
@@ -1613,8 +1613,25 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
l2_dirty = true;
cluster_index = offset >> s->cluster_bits;
- assert((cluster_index >= 0) && (cluster_index < nb_clusters));
- expanded_clusters[cluster_index / 8] |= 1 << (cluster_index % 8);
+
+ if (cluster_index >= *nb_clusters) {
+ uint64_t old_bitmap_size = (*nb_clusters + 7) / 8;
+ uint64_t new_bitmap_size;
+ /* The offset may lie beyond the old end of the underlying image
+ * file for growable files only */
+ assert(bs->file->growable);
+ *nb_clusters = size_to_clusters(s, bs->file->total_sectors *
+ BDRV_SECTOR_SIZE);
+ new_bitmap_size = (*nb_clusters + 7) / 8;
+ *expanded_clusters = g_realloc(*expanded_clusters,
+ new_bitmap_size);
+ /* clear the newly allocated space */
+ memset(&(*expanded_clusters)[old_bitmap_size], 0,
+ new_bitmap_size - old_bitmap_size);
+ }
+
+ assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
+ (*expanded_clusters)[cluster_index / 8] |= 1 << (cluster_index % 8);
}
if (is_active_l1) {
@@ -1673,18 +1690,17 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table = NULL;
- int cluster_to_sector_bits = s->cluster_bits - BDRV_SECTOR_BITS;
uint64_t nb_clusters;
uint8_t *expanded_clusters;
int ret;
int i, j;
- nb_clusters = (bs->total_sectors + (1 << cluster_to_sector_bits) - 1)
- >> cluster_to_sector_bits;
+ nb_clusters = size_to_clusters(s, bs->file->total_sectors *
+ BDRV_SECTOR_SIZE);
expanded_clusters = g_malloc0((nb_clusters + 7) / 8);
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
- expanded_clusters, nb_clusters);
+ &expanded_clusters, &nb_clusters);
if (ret < 0) {
goto fail;
}
@@ -1718,7 +1734,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
}
ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size,
- expanded_clusters, nb_clusters);
+ &expanded_clusters, &nb_clusters);
if (ret < 0) {
goto fail;
}