aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/qcow2-cluster.c25
-rw-r--r--block/qcow2-snapshot.c2
-rw-r--r--block/qcow2.c2
-rw-r--r--block/qcow2.h2
4 files changed, 19 insertions, 12 deletions
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index fb4224a669..4f7dc59b76 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -28,7 +28,7 @@
#include "block_int.h"
#include "block/qcow2.h"
-int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
{
BDRVQcowState *s = bs->opaque;
int new_l1_size, new_l1_size2, ret, i;
@@ -36,15 +36,22 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
int64_t new_l1_table_offset;
uint8_t data[12];
- new_l1_size = s->l1_size;
- if (min_size <= new_l1_size)
+ if (min_size <= s->l1_size)
return 0;
- if (new_l1_size == 0) {
- new_l1_size = 1;
- }
- while (min_size > new_l1_size) {
- new_l1_size = (new_l1_size * 3 + 1) / 2;
+
+ if (exact_size) {
+ new_l1_size = min_size;
+ } else {
+ /* Bump size up to reduce the number of times we have to grow */
+ new_l1_size = s->l1_size;
+ if (new_l1_size == 0) {
+ new_l1_size = 1;
+ }
+ while (min_size > new_l1_size) {
+ new_l1_size = (new_l1_size * 3 + 1) / 2;
+ }
}
+
#ifdef DEBUG_ALLOC2
printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
#endif
@@ -550,7 +557,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
l1_index = offset >> (s->l2_bits + s->cluster_bits);
if (l1_index >= s->l1_size) {
- ret = qcow2_grow_l1_table(bs, l1_index + 1);
+ ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index bbfcaaae22..8dd5df0bcd 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -327,7 +327,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
goto fail;
- if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
+ if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
goto fail;
s->l1_size = sn->l1_size;
diff --git a/block/qcow2.c b/block/qcow2.c
index ee3481b786..345d2e4c3b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1154,7 +1154,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
}
new_l1_size = size_to_l1(s, offset);
- ret = qcow2_grow_l1_table(bs, new_l1_size);
+ ret = qcow2_grow_l1_table(bs, new_l1_size, true);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow2.h b/block/qcow2.h
index 356a34af43..add710ba76 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -188,7 +188,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
/* qcow2-cluster.c functions */
-int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
void qcow2_l2_cache_reset(BlockDriverState *bs);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,