From patchwork Mon Feb 23 14:27:40 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Lieven X-Patchwork-Id: 442552 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 7350E14017C for ; Tue, 24 Feb 2015 01:31:34 +1100 (AEDT) Received: from localhost ([::1]:43838 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YPu2m-0003A8-Fc for incoming@patchwork.ozlabs.org; Mon, 23 Feb 2015 09:31:32 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56722) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YPu1Z-0007MB-0j for qemu-devel@nongnu.org; Mon, 23 Feb 2015 09:30:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YPu1S-0003cS-W0 for qemu-devel@nongnu.org; Mon, 23 Feb 2015 09:30:16 -0500 Received: from mx-v6.kamp.de ([2a02:248:0:51::16]:54723 helo=mx01.kamp.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YPu1S-0003bU-LQ for qemu-devel@nongnu.org; Mon, 23 Feb 2015 09:30:10 -0500 Received: (qmail 30618 invoked by uid 89); 23 Feb 2015 14:30:08 -0000 Received: from [82.141.1.145] by client-16-kamp (envelope-from , uid 89) with qmail-scanner-2010/03/19-MF (clamdscan: 0.98.6/20096. hbedv: 8.3.28.26/7.11.212.36. spamassassin: 3.4.0. Clear:RC:1(82.141.1.145):SA:0(-1.2/5.0):. Processed in 1.576327 secs); 23 Feb 2015 14:30:08 -0000 Received: from ns.kamp-intra.net (HELO dns.kamp-intra.net) ([82.141.1.145]) by mx01.kamp.de with SMTP; 23 Feb 2015 14:30:06 -0000 X-GL_Whitelist: yes Received: from lieven-vm-neu (lieven-vm.kamp-intra.net [172.21.12.69]) by dns.kamp-intra.net (Postfix) with ESMTP id BEE40E0063; Mon, 23 Feb 2015 15:29:15 +0100 (CET) Received: by lieven-vm-neu (Postfix, from userid 1000) id 3592B20790; Mon, 23 Feb 2015 15:27:42 +0100 (CET) From: Peter Lieven To: qemu-devel@nongnu.org Date: Mon, 23 Feb 2015 15:27:40 +0100 Message-Id: <1424701661-21241-5-git-send-email-pl@kamp.de> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1424701661-21241-1-git-send-email-pl@kamp.de> References: <1424701661-21241-1-git-send-email-pl@kamp.de> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a02:248:0:51::16 Cc: kwolf@redhat.com, carnold@suse.com, jcody@redhat.com, Peter Lieven , mreitz@redhat.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH 4/5] block/vpc: make calculate_geometry spec conform X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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, VirtualBox 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 --- block/vpc.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 11d3c86..9c5301b 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; } @@ -642,26 +643,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; @@ -817,19 +812,27 @@ 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, + DIV_ROUND_UP(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)) - { - ret = -EFBIG; - goto out; - } + calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl); } - total_sectors = (int64_t) cyls * heads * secs_per_cyl; - total_size = total_sectors * BDRV_SECTOR_SIZE; + if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) { + total_sectors = DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE); + /* Allow a maximum disk size of approximately 2 TB */ + if (total_sectors > VHD_MAX_SECTORS) { + return -EFBIG; + } + } else { + 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);