aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-05 18:16:10 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-05 18:16:10 +0000
commit7cc73776e7f8f87c9b99e021a088e7de52d268ec (patch)
tree08b3de00f158ea91018a027bdbef9c9f1f0618fb
parent937e9a1c83cab9995778ed2037663948725b7079 (diff)
qcow2: fix image creation for large, > ~2TB, images (Chris Wright)
When creating large disk images w/ qcow2 format, qcow2_create is hard coded to creating a single refcount block. This is insufficient for large images, and will cause qemu-img to segfault as it walks off the end of the refcount block. Keep track of the space needed during image create and create proper number of refcount blocks accordingly. https://bugzilla.redhat.com/show_bug.cgi?id=491943 Signed-off-by: Chris Wright <chrisw@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/branches/stable_0_10@6988 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--block-qcow2.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/block-qcow2.c b/block-qcow2.c
index 894b05a30e..9e69ddf0a0 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -1462,6 +1462,7 @@ static int qcow_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
+ int ref_clusters;
QCowHeader header;
uint64_t tmp, offset;
QCowCreateState s1, *s = &s1;
@@ -1502,22 +1503,28 @@ static int qcow_create(const char *filename, int64_t total_size,
offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
s->refcount_table = qemu_mallocz(s->cluster_size);
- s->refcount_block = qemu_mallocz(s->cluster_size);
s->refcount_table_offset = offset;
header.refcount_table_offset = cpu_to_be64(offset);
header.refcount_table_clusters = cpu_to_be32(1);
offset += s->cluster_size;
-
- s->refcount_table[0] = cpu_to_be64(offset);
s->refcount_block_offset = offset;
- offset += s->cluster_size;
+
+ /* count how many refcount blocks needed */
+ tmp = offset >> s->cluster_bits;
+ ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
+ for (i=0; i < ref_clusters; i++) {
+ s->refcount_table[i] = cpu_to_be64(offset);
+ offset += s->cluster_size;
+ }
+
+ s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
/* update refcounts */
create_refcount_update(s, 0, header_size);
create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
- create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
+ create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size);
/* write all the data */
write(fd, &header, sizeof(header));
@@ -1533,7 +1540,7 @@ static int qcow_create(const char *filename, int64_t total_size,
write(fd, s->refcount_table, s->cluster_size);
lseek(fd, s->refcount_block_offset, SEEK_SET);
- write(fd, s->refcount_block, s->cluster_size);
+ write(fd, s->refcount_block, ref_clusters * s->cluster_size);
qemu_free(s->refcount_table);
qemu_free(s->refcount_block);