qcow2: Increase maximum cluster size to 2 MB
authorKevin Wolf <kwolf@redhat.com>
Tue, 15 Sep 2009 10:30:43 +0000 (12:30 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 5 Oct 2009 14:32:52 +0000 (09:32 -0500)
This patch increases the maximum qcow2 cluster size to 2 MB. Starting with 128k
clusters, L2 tables span 2 GB or more of virtual disk space, causing 32 bit
truncation and wraparound of signed integers. Therefore some variables need to
use a larger data type.

While being at reviewing data types, change some integers that are used for
array indices to unsigned. In some places they were checked against some upper
limit but not for negative values. This could avoid potential segfaults with
corrupted qcow2 images.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
block/qcow2-cluster.c
block/qcow2-refcount.c
block/qcow2.h
qemu-img.c

index 54e505cbed011b4e1a796fdb4c4bc2e72f5e2174..e444e53e136a5cb98ff99386686a397cd8632f6e 100644 (file)
@@ -264,7 +264,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
         return 0;
 
     for (i = start; i < start + nb_clusters; i++)
-        if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+        if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
             break;
 
        return (i - start);
@@ -395,10 +395,11 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
     int *num)
 {
     BDRVQcowState *s = bs->opaque;
-    int l1_index, l2_index;
+    unsigned int l1_index, l2_index;
     uint64_t l2_offset, *l2_table, cluster_offset;
     int l1_bits, c;
-    int index_in_cluster, nb_available, nb_needed, nb_clusters;
+    unsigned int index_in_cluster, nb_clusters;
+    uint64_t nb_available, nb_needed;
 
     index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
     nb_needed = *num + index_in_cluster;
@@ -409,7 +410,7 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
      * the end of the l1 entry
      */
 
-    nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
+    nb_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1));
 
     /* compute the number of available sectors */
 
@@ -483,8 +484,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
                              int *new_l2_index)
 {
     BDRVQcowState *s = bs->opaque;
-    int l1_index, l2_index, ret;
+    unsigned int l1_index, l2_index;
     uint64_t l2_offset, *l2_table;
+    int ret;
 
     /* seek the the l2 offset in the l1 table */
 
@@ -683,7 +685,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     int l2_index, ret;
     uint64_t l2_offset, *l2_table, cluster_offset;
-    int nb_clusters, i = 0;
+    unsigned int nb_clusters, i = 0;
     QCowL2Meta *old_alloc;
 
     ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
index 0aac2edee13f8c024aa5c744ab126a3732c0b426..609eee1891beefcb1f95b7059a8e371d77c7998f 100644 (file)
@@ -192,7 +192,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
 {
     BDRVQcowState *s = bs->opaque;
     int64_t offset, refcount_block_offset;
-    int ret, refcount_table_index;
+    unsigned int refcount_table_index;
+    int ret;
     uint64_t data64;
     int cache = cache_refcount_updates;
 
index ecc94cbfad6674326a0c3045eeeb166f76ffb598..26ab5d95233f0e23c3dcb21a3bf8fab0993bb085 100644 (file)
@@ -47,7 +47,7 @@
 #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
 
 #define MIN_CLUSTER_BITS 9
-#define MAX_CLUSTER_BITS 16
+#define MAX_CLUSTER_BITS 21
 
 #define L2_CACHE_SIZE 16
 
index 070fe2e229c8218b58d426f6aa26f96b3459bd1d..204f618c6e86820df5342f5a5398d5518ca0d2cc 100644 (file)
@@ -530,7 +530,7 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
     return v;
 }
 
-#define IO_BUF_SIZE 65536
+#define IO_BUF_SIZE (2 * 1024 * 1024)
 
 static int img_convert(int argc, char **argv)
 {