From owner-svn-src-head@FreeBSD.ORG Thu Jun 11 14:30:32 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 1A290C7E; Thu, 11 Jun 2015 14:30:32 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F11301D30; Thu, 11 Jun 2015 14:30:31 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5BEUVqj097558; Thu, 11 Jun 2015 14:30:31 GMT (envelope-from marcel@FreeBSD.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t5BEUVuS097557; Thu, 11 Jun 2015 14:30:31 GMT (envelope-from marcel@FreeBSD.org) Message-Id: <201506111430.t5BEUVuS097557@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marcel set sender to marcel@FreeBSD.org using -f From: Marcel Moolenaar Date: Thu, 11 Jun 2015 14:30:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r284269 - head/usr.bin/mkimg X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jun 2015 14:30:32 -0000 Author: marcel Date: Thu Jun 11 14:30:31 2015 New Revision: 284269 URL: https://svnweb.freebsd.org/changeset/base/284269 Log: For the fixed VHD format, round the raw image size to the next multiple of the cylinder size. This is what qemu-img seems to be doing. Make sure to handle boundary cases where increasing the image size by 1 cyclinder's worth would also result in a change of geometry. Modified: head/usr.bin/mkimg/vhd.c Modified: head/usr.bin/mkimg/vhd.c ============================================================================== --- head/usr.bin/mkimg/vhd.c Thu Jun 11 14:25:53 2015 (r284268) +++ head/usr.bin/mkimg/vhd.c Thu Jun 11 14:30:31 2015 (r284269) @@ -62,6 +62,12 @@ __FBSDID("$FreeBSD$"); #define VHD_SECTOR_SIZE 512 #define VHD_BLOCK_SIZE (4096 * VHD_SECTOR_SIZE) /* 2MB blocks */ +struct vhd_geom { + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; +}; + struct vhd_footer { uint64_t cookie; #define VHD_FOOTER_COOKIE 0x636f6e6563746978ULL @@ -80,9 +86,7 @@ struct vhd_footer { #define VHD_CREATOR_OS 0x46425344 uint64_t original_size; uint64_t current_size; - uint16_t cylinders; - uint8_t heads; - uint8_t sectors; + struct vhd_geom geometry; uint32_t disk_type; #define VHD_DISK_TYPE_FIXED 2 #define VHD_DISK_TYPE_DYNAMIC 3 @@ -111,7 +115,7 @@ vhd_checksum(void *buf, size_t sz) } static void -vhd_geometry(struct vhd_footer *footer, uint64_t image_size) +vhd_geometry(uint64_t image_size, struct vhd_geom *geom) { lba_t imgsz; long cth; @@ -120,9 +124,9 @@ vhd_geometry(struct vhd_footer *footer, if (nheads > 1 && nheads < 256 && nsecs > 1 && nsecs < 256 && ncyls < 65536) { - be16enc(&footer->cylinders, ncyls); - footer->heads = nheads; - footer->sectors = nsecs; + geom->cylinders = ncyls; + geom->heads = nheads; + geom->sectors = nsecs; return; } @@ -130,27 +134,27 @@ vhd_geometry(struct vhd_footer *footer, if (imgsz > 65536 * 16 * 255) imgsz = 65536 * 16 * 255; if (imgsz >= 65535 * 16 * 63) { - be16enc(&footer->cylinders, imgsz / (16 * 255)); - footer->heads = 16; - footer->sectors = 255; + geom->cylinders = imgsz / (16 * 255); + geom->heads = 16; + geom->sectors = 255; return; } - footer->sectors = 17; + geom->sectors = 17; cth = imgsz / 17; - footer->heads = (cth + 1023) / 1024; - if (footer->heads < 4) - footer->heads = 4; - if (cth >= (footer->heads * 1024) || footer->heads > 16) { - footer->heads = 16; - footer->sectors = 31; + geom->heads = (cth + 1023) / 1024; + if (geom->heads < 4) + geom->heads = 4; + if (cth >= (geom->heads * 1024) || geom->heads > 16) { + geom->heads = 16; + geom->sectors = 31; cth = imgsz / 31; } - if (cth >= (footer->heads * 1024)) { - footer->heads = 16; - footer->sectors = 63; + if (cth >= (geom->heads * 1024)) { + geom->heads = 16; + geom->sectors = 63; cth = imgsz / 63; } - be16enc(&footer->cylinders, cth / footer->heads); + geom->cylinders = cth / geom->heads; } static uint32_t @@ -198,7 +202,8 @@ vhd_make_footer(struct vhd_footer *foote be32enc(&footer->creator_os, VHD_CREATOR_OS); be64enc(&footer->original_size, image_size); be64enc(&footer->current_size, image_size); - vhd_geometry(footer, image_size); + vhd_geometry(image_size, &footer->geometry); + be16enc(&footer->geometry.cylinders, footer->geometry.cylinders); be32enc(&footer->disk_type, disk_type); mkimg_uuid(&id); vhd_uuid_enc(&footer->id, &id); @@ -206,23 +211,6 @@ vhd_make_footer(struct vhd_footer *foote } /* - * We round the image size to 2MB for both the dynamic and - * fixed VHD formats. For dynamic VHD, this is needed to - * have the image size be a multiple of the grain size. For - * fixed VHD this is not really needed, but makes sure that - * it's easy to convert from fixed VHD to dynamic VHD. - */ -static int -vhd_resize(lba_t imgsz) -{ - uint64_t imagesz; - - imagesz = imgsz * secsz; - imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1); - return (image_set_size(imagesz / secsz)); -} - -/* * PART 2: Dynamic VHD support * * Notes: @@ -262,6 +250,16 @@ _Static_assert(sizeof(struct vhd_dyn_hea #endif static int +vhd_dyn_resize(lba_t imgsz) +{ + uint64_t imagesz; + + imagesz = imgsz * secsz; + imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1); + return (image_set_size(imagesz / secsz)); +} + +static int vhd_dyn_write(int fd) { struct vhd_footer footer; @@ -349,17 +347,36 @@ vhd_dyn_write(int fd) static struct mkimg_format vhd_dyn_format = { .name = "vhd", .description = "Virtual Hard Disk", - .resize = vhd_resize, + .resize = vhd_dyn_resize, .write = vhd_dyn_write, }; FORMAT_DEFINE(vhd_dyn_format); /* - * PART 2: Fixed VHD + * PART 3: Fixed VHD */ static int +vhd_fix_resize(lba_t imgsz) +{ + struct vhd_geom geom; + int64_t imagesz; + + imgsz *= secsz; + imagesz = imgsz; + while (1) { + vhd_geometry(imagesz, &geom); + imagesz = (int64_t)geom.cylinders * geom.heads * + geom.sectors * VHD_SECTOR_SIZE; + if (imagesz >= imgsz) + break; + imagesz += geom.heads * geom.sectors * VHD_SECTOR_SIZE; + } + return (image_set_size(imagesz / secsz)); +} + +static int vhd_fix_write(int fd) { struct vhd_footer footer; @@ -379,7 +396,7 @@ vhd_fix_write(int fd) static struct mkimg_format vhd_fix_format = { .name = "vhdf", .description = "Fixed Virtual Hard Disk", - .resize = vhd_resize, + .resize = vhd_fix_resize, .write = vhd_fix_write, };