Re: [Qemu-devel] [PATCH v2 8/8] vpc: Require aligned size in .bdrv_co_create

2018-03-13 Thread Max Reitz
On 2018-03-13 15:47, Kevin Wolf wrote:
> Perform the rounding to match a CHS geometry only in the legacy code
> path in .bdrv_co_create_opts. QMP now requires that the user already
> passes a CHS aligned image size, unless force-size=true is given.
> 
> CHS alignment is required to make the image compatible with Virtual PC,
> but not for use with newer Microsoft hypervisors.
> 
> Signed-off-by: Kevin Wolf 
> ---
>  block/vpc.c | 113 
> +++-
>  1 file changed, 82 insertions(+), 31 deletions(-)

Reviewed-by: Max Reitz 



signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH v2 8/8] vpc: Require aligned size in .bdrv_co_create

2018-03-13 Thread Kevin Wolf
Perform the rounding to match a CHS geometry only in the legacy code
path in .bdrv_co_create_opts. QMP now requires that the user already
passes a CHS aligned image size, unless force-size=true is given.

CHS alignment is required to make the image compatible with Virtual PC,
but not for use with newer Microsoft hypervisors.

Signed-off-by: Kevin Wolf 
---
 block/vpc.c | 113 +++-
 1 file changed, 82 insertions(+), 31 deletions(-)

diff --git a/block/vpc.c b/block/vpc.c
index 8824211713..28ffa0d2f8 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -902,6 +902,62 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t 
*buf,
 return ret;
 }
 
+static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
+uint16_t *out_cyls,
+uint8_t *out_heads,
+uint8_t *out_secs_per_cyl,
+int64_t *out_total_sectors,
+Error **errp)
+{
+int64_t total_size = vpc_opts->size;
+uint16_t cyls = 0;
+uint8_t heads = 0;
+uint8_t secs_per_cyl = 0;
+int64_t total_sectors;
+int i;
+
+/*
+ * 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 conformant 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.
+ */
+if (vpc_opts->force_size) {
+/* This will force the use of total_size for sector count, below */
+cyls = VHD_CHS_MAX_C;
+heads= VHD_CHS_MAX_H;
+secs_per_cyl = VHD_CHS_MAX_S;
+} else {
+total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
+for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) 
{
+calculate_geometry(total_sectors + i, , , 
_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 2040 GiB */
+if (total_sectors > VHD_MAX_SECTORS) {
+error_setg(errp, "Disk size is too large, max size is 2040 GiB");
+return -EFBIG;
+}
+} else {
+total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+}
+
+*out_total_sectors = total_sectors;
+if (out_cyls) {
+*out_cyls = cyls;
+*out_heads = heads;
+*out_secs_per_cyl = secs_per_cyl;
+}
+
+return 0;
+}
+
 static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
   Error **errp)
 {
@@ -911,7 +967,6 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions 
*opts,
 
 uint8_t buf[1024];
 VHDFooter *footer = (VHDFooter *) buf;
-int i;
 uint16_t cyls = 0;
 uint8_t heads = 0;
 uint8_t secs_per_cyl = 0;
@@ -953,38 +1008,22 @@ static int coroutine_fn 
vpc_co_create(BlockdevCreateOptions *opts,
 }
 blk_set_allow_write_beyond_eof(blk, true);
 
-/*
- * 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 conformant 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.
- */
-if (vpc_opts->force_size) {
-/* This will force the use of total_size for sector count, below */
-cyls = VHD_CHS_MAX_C;
-heads= VHD_CHS_MAX_H;
-secs_per_cyl = VHD_CHS_MAX_S;
-} else {
-total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
-for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) 
{
-calculate_geometry(total_sectors + i, , , 
_per_cyl);
-}
+/* Get geometry and check that it matches the image size*/
+ret = calculate_rounded_image_size(vpc_opts, , , _per_cyl,
+   _sectors, errp);
+if (ret < 0) {
+goto out;
 }
 
-if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
-total_sectors = total_size / BDRV_SECTOR_SIZE;
-/* Allow a maximum disk size of 2040 GiB */
-if (total_sectors > VHD_MAX_SECTORS) {
-error_setg(errp, "Disk size is too large, max size is 2040 GiB");
-ret = -EFBIG;
-goto out;
-}
-} else {
-total_sectors = (int64_t)cyls *