Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Jun 2015 14:30:31 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r284269 - head/usr.bin/mkimg
Message-ID:  <201506111430.t5BEUVuS097557@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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,
 };
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506111430.t5BEUVuS097557>