aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block-qcow2.c162
1 files changed, 73 insertions, 89 deletions
diff --git a/block-qcow2.c b/block-qcow2.c
index a65a10d69b..98c66f192d 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -601,6 +601,34 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
return l2_table;
}
+static int size_to_clusters(BDRVQcowState *s, int64_t size)
+{
+ return (size + (s->cluster_size - 1)) >> s->cluster_bits;
+}
+
+static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
+ uint64_t *l2_table, uint64_t mask)
+{
+ int i;
+ uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+
+ for (i = 0; i < nb_clusters; i++)
+ if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+ break;
+
+ return i;
+}
+
+static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
+{
+ int i = 0;
+
+ while(nb_clusters-- && l2_table[i] == 0)
+ i++;
+
+ return i;
+}
+
/*
* get_cluster_offset
*
@@ -622,9 +650,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
int l1_index, l2_index;
- uint64_t l2_offset, *l2_table, cluster_offset, next;
- int l1_bits;
- int index_in_cluster, nb_available, nb_needed;
+ uint64_t l2_offset, *l2_table, cluster_offset;
+ int l1_bits, c;
+ int index_in_cluster, nb_available, nb_needed, nb_clusters;
index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
nb_needed = *num + index_in_cluster;
@@ -632,7 +660,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
l1_bits = s->l2_bits + s->cluster_bits;
/* compute how many bytes there are between the offset and
- * and the end of the l1 entry
+ * the end of the l1 entry
*/
nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
@@ -667,38 +695,25 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
cluster_offset = be64_to_cpu(l2_table[l2_index]);
- nb_available = s->cluster_sectors;
- l2_index++;
+ nb_clusters = size_to_clusters(s, nb_needed << 9);
if (!cluster_offset) {
-
- /* how many empty clusters ? */
-
- while (nb_available < nb_needed && !l2_table[l2_index]) {
- l2_index++;
- nb_available += s->cluster_sectors;
- }
+ /* how many empty clusters ? */
+ c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
} else {
+ /* how many allocated clusters ? */
+ c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], QCOW_OFLAG_COPIED);
+ }
- /* how many allocated clusters ? */
-
- cluster_offset &= ~QCOW_OFLAG_COPIED;
- while (nb_available < nb_needed) {
- next = be64_to_cpu(l2_table[l2_index]) & ~QCOW_OFLAG_COPIED;
- if (next != cluster_offset + (nb_available << 9))
- break;
- l2_index++;
- nb_available += s->cluster_sectors;
- }
- }
-
+ nb_available = (c * s->cluster_sectors);
out:
if (nb_available > nb_needed)
nb_available = nb_needed;
*num = nb_available - index_in_cluster;
- return cluster_offset;
+ return cluster_offset & ~QCOW_OFLAG_COPIED;
}
/*
@@ -862,15 +877,15 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs,
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
uint64_t l2_offset, *l2_table, cluster_offset;
- int nb_available, nb_clusters, i, j;
- uint64_t start_sect, current;
+ int nb_available, nb_clusters, i = 0;
+ uint64_t start_sect;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
if (ret == 0)
return 0;
- nb_clusters = ((n_end << 9) + s->cluster_size - 1) >>
- s->cluster_bits;
+ nb_clusters = size_to_clusters(s, n_end << 9);
+
if (nb_clusters > s->l2_size - l2_index)
nb_clusters = s->l2_size - l2_index;
@@ -879,13 +894,8 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs,
/* We keep all QCOW_OFLAG_COPIED clusters */
if (cluster_offset & QCOW_OFLAG_COPIED) {
-
- for (i = 1; i < nb_clusters; i++) {
- current = be64_to_cpu(l2_table[l2_index + i]);
- if (cluster_offset + (i << s->cluster_bits) != current)
- break;
- }
- nb_clusters = i;
+ nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], 0);
nb_available = nb_clusters << (s->cluster_bits - 9);
if (nb_available > n_end)
@@ -903,46 +913,27 @@ static uint64_t alloc_cluster_offset(BlockDriverState *bs,
/* how many available clusters ? */
- i = 0;
while (i < nb_clusters) {
+ int j;
+ i += count_contiguous_free_clusters(nb_clusters - i,
+ &l2_table[l2_index + i]);
- i++;
-
- if (!cluster_offset) {
-
- /* how many free clusters ? */
-
- while (i < nb_clusters) {
- cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
- if (cluster_offset != 0)
- break;
- i++;
- }
+ cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
- if ((cluster_offset & QCOW_OFLAG_COPIED) ||
+ if ((cluster_offset & QCOW_OFLAG_COPIED) ||
(cluster_offset & QCOW_OFLAG_COMPRESSED))
- break;
-
- } else {
+ break;
- /* how many contiguous clusters ? */
+ j = count_contiguous_clusters(nb_clusters - i, s->cluster_size,
+ &l2_table[l2_index + i], 0);
- j = 1;
- current = 0;
- while (i < nb_clusters) {
- current = be64_to_cpu(l2_table[l2_index + i]);
- if (cluster_offset + (j << s->cluster_bits) != current)
- break;
+ if (j)
+ free_any_clusters(bs, cluster_offset, j);
- i++;
- j++;
- }
+ i += j;
- free_any_clusters(bs, cluster_offset, j);
- if (current)
- break;
- cluster_offset = current;
- }
+ if(be64_to_cpu(l2_table[l2_index + i]))
+ break;
}
nb_clusters = i;
@@ -2194,26 +2185,19 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
BDRVQcowState *s = bs->opaque;
int i, nb_clusters;
- nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
- for(;;) {
- if (get_refcount(bs, s->free_cluster_index) == 0) {
- s->free_cluster_index++;
- for(i = 1; i < nb_clusters; i++) {
- if (get_refcount(bs, s->free_cluster_index) != 0)
- goto not_found;
- s->free_cluster_index++;
- }
+ nb_clusters = size_to_clusters(s, size);
+retry:
+ for(i = 0; i < nb_clusters; i++) {
+ int64_t i = s->free_cluster_index++;
+ if (get_refcount(bs, i) != 0)
+ goto retry;
+ }
#ifdef DEBUG_ALLOC2
- printf("alloc_clusters: size=%lld -> %lld\n",
- size,
- (s->free_cluster_index - nb_clusters) << s->cluster_bits);
+ printf("alloc_clusters: size=%lld -> %lld\n",
+ size,
+ (s->free_cluster_index - nb_clusters) << s->cluster_bits);
#endif
- return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
- } else {
- not_found:
- s->free_cluster_index++;
- }
- }
+ return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
}
static int64_t alloc_clusters(BlockDriverState *bs, int64_t size)
@@ -2548,7 +2532,7 @@ static void check_refcounts(BlockDriverState *bs)
uint16_t *refcount_table;
size = bdrv_getlength(s->hd);
- nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+ nb_clusters = size_to_clusters(s, size);
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
/* header */
@@ -2600,7 +2584,7 @@ static void dump_refcounts(BlockDriverState *bs)
int refcount;
size = bdrv_getlength(s->hd);
- nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+ nb_clusters = size_to_clusters(s, size);
for(k = 0; k < nb_clusters;) {
k1 = k;
refcount = get_refcount(bs, k);