Commit 2d2431f03fc78b532f3a1c5f858cf78859d50fc3

Authored by aliguori
1 parent 8707ecca

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/trunk@6982 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 13 additions and 7 deletions
block-qcow2.c
@@ -1555,7 +1555,7 @@ static int qcow_create2(const char *filename, int64_t total_size, @@ -1555,7 +1555,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
1555 { 1555 {
1556 1556
1557 int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; 1557 int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
1558 - int backing_format_len = 0; 1558 + int ref_clusters, backing_format_len = 0;
1559 QCowHeader header; 1559 QCowHeader header;
1560 uint64_t tmp, offset; 1560 uint64_t tmp, offset;
1561 QCowCreateState s1, *s = &s1; 1561 QCowCreateState s1, *s = &s1;
@@ -1604,22 +1604,28 @@ static int qcow_create2(const char *filename, int64_t total_size, @@ -1604,22 +1604,28 @@ static int qcow_create2(const char *filename, int64_t total_size,
1604 offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); 1604 offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
1605 1605
1606 s->refcount_table = qemu_mallocz(s->cluster_size); 1606 s->refcount_table = qemu_mallocz(s->cluster_size);
1607 - s->refcount_block = qemu_mallocz(s->cluster_size);  
1608 1607
1609 s->refcount_table_offset = offset; 1608 s->refcount_table_offset = offset;
1610 header.refcount_table_offset = cpu_to_be64(offset); 1609 header.refcount_table_offset = cpu_to_be64(offset);
1611 header.refcount_table_clusters = cpu_to_be32(1); 1610 header.refcount_table_clusters = cpu_to_be32(1);
1612 offset += s->cluster_size; 1611 offset += s->cluster_size;
1613 -  
1614 - s->refcount_table[0] = cpu_to_be64(offset);  
1615 s->refcount_block_offset = offset; 1612 s->refcount_block_offset = offset;
1616 - offset += s->cluster_size; 1613 +
  1614 + /* count how many refcount blocks needed */
  1615 + tmp = offset >> s->cluster_bits;
  1616 + ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
  1617 + for (i=0; i < ref_clusters; i++) {
  1618 + s->refcount_table[i] = cpu_to_be64(offset);
  1619 + offset += s->cluster_size;
  1620 + }
  1621 +
  1622 + s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
1617 1623
1618 /* update refcounts */ 1624 /* update refcounts */
1619 create_refcount_update(s, 0, header_size); 1625 create_refcount_update(s, 0, header_size);
1620 create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t)); 1626 create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
1621 create_refcount_update(s, s->refcount_table_offset, s->cluster_size); 1627 create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
1622 - create_refcount_update(s, s->refcount_block_offset, s->cluster_size); 1628 + create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size);
1623 1629
1624 /* write all the data */ 1630 /* write all the data */
1625 write(fd, &header, sizeof(header)); 1631 write(fd, &header, sizeof(header));
@@ -1648,7 +1654,7 @@ static int qcow_create2(const char *filename, int64_t total_size, @@ -1648,7 +1654,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
1648 write(fd, s->refcount_table, s->cluster_size); 1654 write(fd, s->refcount_table, s->cluster_size);
1649 1655
1650 lseek(fd, s->refcount_block_offset, SEEK_SET); 1656 lseek(fd, s->refcount_block_offset, SEEK_SET);
1651 - write(fd, s->refcount_block, s->cluster_size); 1657 + write(fd, s->refcount_block, ref_clusters * s->cluster_size);
1652 1658
1653 qemu_free(s->refcount_table); 1659 qemu_free(s->refcount_table);
1654 qemu_free(s->refcount_block); 1660 qemu_free(s->refcount_block);