[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PULL 15/17] block/vpc: make calculate_geometry spec confor
From: |
Kevin Wolf |
Subject: |
[Qemu-block] [PULL 15/17] block/vpc: make calculate_geometry spec conform |
Date: |
Mon, 16 Mar 2015 17:57:19 +0100 |
From: Peter Lieven <address@hidden>
The VHD spec [1] allows for total_sectors of 65535 x 16 x 255 (~127GB)
represented by a CHS geometry. If total_sectors is greater
than 65535 x 16 x 255 this geometry is set as a maximum.
Qemu, Hyper-V and disk2vhd use this special geometry as an indicator
to use the image current size from the footer as disk size.
This patch changes vpc_create to effectively calculate a CxHxS geometry
for the given image size if possible while rounding up if necessary.
If the image size is too big to be represented in CHS we set the maximum
and write the exact requested image size into the footer.
This partly reverts commit 258d2edb, but leaves support for >127G disks
intact.
[1]
http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
Signed-off-by: Peter Lieven <address@hidden>
Message-id: address@hidden
Reviewed-by: Max Reitz <address@hidden>
Signed-off-by: Max Reitz <address@hidden>
---
block/vpc.c | 41 ++++++++++++++++++++++-------------------
1 file changed, 22 insertions(+), 19 deletions(-)
diff --git a/block/vpc.c b/block/vpc.c
index 1c9592c..7e99a69 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -46,6 +46,7 @@ enum vhd_type {
#define VHD_TIMESTAMP_BASE 946684800
#define VHD_MAX_SECTORS (65535LL * 255 * 255)
+#define VHD_MAX_GEOMETRY (65535LL * 16 * 255)
// always big-endian
typedef struct vhd_footer {
@@ -218,7 +219,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options,
int flags,
/* Images that have exactly the maximum geometry are probably bigger and
* would be truncated if we adhered to the geometry for them. Rely on
* footer->size for them. */
- if (bs->total_sectors == 65535ULL * 16 * 255) {
+ if (bs->total_sectors == VHD_MAX_GEOMETRY) {
bs->total_sectors = be64_to_cpu(footer->size) / BDRV_SECTOR_SIZE;
}
@@ -655,26 +656,20 @@ static int calculate_geometry(int64_t total_sectors,
uint16_t* cyls,
{
uint32_t cyls_times_heads;
- /* Allow a maximum disk size of approximately 2 TB */
- if (total_sectors > 65535LL * 255 * 255) {
- return -EFBIG;
- }
+ total_sectors = MIN(total_sectors, VHD_MAX_GEOMETRY);
- if (total_sectors > 65535 * 16 * 63) {
+ if (total_sectors >= 65535LL * 16 * 63) {
*secs_per_cyl = 255;
- if (total_sectors > 65535 * 16 * 255) {
- *heads = 255;
- } else {
- *heads = 16;
- }
+ *heads = 16;
cyls_times_heads = total_sectors / *secs_per_cyl;
} else {
*secs_per_cyl = 17;
cyls_times_heads = total_sectors / *secs_per_cyl;
*heads = (cyls_times_heads + 1023) / 1024;
- if (*heads < 4)
+ if (*heads < 4) {
*heads = 4;
+ }
if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
*secs_per_cyl = 31;
@@ -830,20 +825,28 @@ static int vpc_create(const char *filename, QemuOpts
*opts, Error **errp)
* Calculate matching total_size and geometry. Increase the number of
* sectors requested until we get enough (or fail). This ensures that
* qemu-img convert doesn't truncate images, but rather rounds up.
+ *
+ * If the image size can't be represented by a spec conform CHS geometry,
+ * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
+ * the image size from the VHD footer to calculate total_sectors.
*/
- total_sectors = total_size / BDRV_SECTOR_SIZE;
+ total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
- if (calculate_geometry(total_sectors + i, &cyls, &heads,
- &secs_per_cyl))
- {
+ calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
+ }
+
+ if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
+ total_sectors = total_size / BDRV_SECTOR_SIZE;
+ /* Allow a maximum disk size of approximately 2 TB */
+ if (total_sectors > VHD_MAX_SECTORS) {
ret = -EFBIG;
goto out;
}
+ } else {
+ total_sectors = (int64_t)cyls * heads * secs_per_cyl;
+ total_size = total_sectors * BDRV_SECTOR_SIZE;
}
- total_sectors = (int64_t) cyls * heads * secs_per_cyl;
- total_size = total_sectors * BDRV_SECTOR_SIZE;
-
/* Prepare the Hard Disk Footer */
memset(buf, 0, 1024);
--
1.8.3.1
- [Qemu-block] [PULL 09/17] monitor: Convert bdrv_find to blk_by_name, (continued)
- [Qemu-block] [PULL 09/17] monitor: Convert bdrv_find to blk_by_name, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 10/17] migration: Convert bdrv_find to blk_by_name, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 07/17] iotests: Add tests for refcount table growth, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 08/17] iotests: Test non-self-referential qcow2 refblocks, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 11/17] blockdev: Convert bdrv_find to blk_by_name, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 13/17] block/vpc: optimize vpc_co_get_block_status, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 16/17] block/vpc: rename footer->size -> footer->current_size, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 12/17] block: Drop bdrv_find, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 14/17] vpc: Ignore geometry for large images, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 17/17] block/vpc: remove disabled code from get_sector_offset, Kevin Wolf, 2015/03/16
- [Qemu-block] [PULL 15/17] block/vpc: make calculate_geometry spec conform,
Kevin Wolf <=
- Re: [Qemu-block] [Qemu-devel] [PULL 00/17] Block patches for 2.3.0-rc0, Peter Maydell, 2015/03/17