block/vpc: Fix conversion from size to disk geometry

The VHD algorithm calculates a disk geometry
which is usually smaller than the requested size.

QEMU tried to round up but failed for certain sizes:

qemu-img create -f vpc disk.vpc 9437184
would create an image with 9435136 bytes
(which is too small for qemu-img convert).

Instead of hacking the geometry algorithm, the patch
increases the number of sectors until we get enough
sectors.

Cc: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Stefan Weil 2010-05-10 21:46:26 +02:00 committed by Kevin Wolf
parent 1dec5a7097
commit dede4188cc

View File

@ -463,9 +463,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
} }
} }
// Note: Rounding up deviates from the Virtual PC behaviour *cyls = cyls_times_heads / *heads;
// However, we need this to avoid truncating images in qemu-img convert
*cyls = (cyls_times_heads + *heads - 1) / *heads;
return 0; return 0;
} }
@ -477,9 +475,9 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
struct vhd_dyndisk_header* dyndisk_header = struct vhd_dyndisk_header* dyndisk_header =
(struct vhd_dyndisk_header*) buf; (struct vhd_dyndisk_header*) buf;
int fd, i; int fd, i;
uint16_t cyls; uint16_t cyls = 0;
uint8_t heads; uint8_t heads = 0;
uint8_t secs_per_cyl; uint8_t secs_per_cyl = 0;
size_t block_size, num_bat_entries; size_t block_size, num_bat_entries;
int64_t total_sectors = 0; int64_t total_sectors = 0;
@ -496,9 +494,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
if (fd < 0) if (fd < 0)
return -EIO; return -EIO;
// Calculate matching total_size and geometry /* Calculate matching total_size and geometry. Increase the number of
if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl)) sectors requested until we get enough (or fail). */
return -EFBIG; for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
if (calculate_geometry(total_sectors + i,
&cyls, &heads, &secs_per_cyl)) {
return -EFBIG;
}
}
total_sectors = (int64_t) cyls * heads * secs_per_cyl; total_sectors = (int64_t) cyls * heads * secs_per_cyl;
// Prepare the Hard Disk Footer // Prepare the Hard Disk Footer