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 1555 {
1556 1556  
1557 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 1559 QCowHeader header;
1560 1560 uint64_t tmp, offset;
1561 1561 QCowCreateState s1, *s = &s1;
... ... @@ -1604,22 +1604,28 @@ static int qcow_create2(const char *filename, int64_t total_size,
1604 1604 offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
1605 1605  
1606 1606 s->refcount_table = qemu_mallocz(s->cluster_size);
1607   - s->refcount_block = qemu_mallocz(s->cluster_size);
1608 1607  
1609 1608 s->refcount_table_offset = offset;
1610 1609 header.refcount_table_offset = cpu_to_be64(offset);
1611 1610 header.refcount_table_clusters = cpu_to_be32(1);
1612 1611 offset += s->cluster_size;
1613   -
1614   - s->refcount_table[0] = cpu_to_be64(offset);
1615 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 1624 /* update refcounts */
1619 1625 create_refcount_update(s, 0, header_size);
1620 1626 create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
1621 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 1630 /* write all the data */
1625 1631 write(fd, &header, sizeof(header));
... ... @@ -1648,7 +1654,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
1648 1654 write(fd, s->refcount_table, s->cluster_size);
1649 1655  
1650 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 1659 qemu_free(s->refcount_table);
1654 1660 qemu_free(s->refcount_block);
... ...