summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2015-06-24 18:40:34 +0000
committermarcel <marcel@FreeBSD.org>2015-06-24 18:40:34 +0000
commitc8b4a5d462f81bded2f88253a2feb3abc492b84a (patch)
tree99ed0e0c8a504b3be81923563d997f2bf012a5f5
parentf8c30d3e154c78363d9019a4c35b0804e53656c0 (diff)
downloadFreeBSD-src-c8b4a5d462f81bded2f88253a2feb3abc492b84a.zip
FreeBSD-src-c8b4a5d462f81bded2f88253a2feb3abc492b84a.tar.gz
MFC r284269, r284270, r284655, r284656, r284658:
VHD fixes for Microsoft Azure: 1. Round the image size to the VHD geometry and then round to a multiple of 1MB. 2. Change the creator OS from "FBSD" to "Wi2k". It matters... 3. Bump the VHD tool version and the mkimg version. Approved by: re (gjb)
-rw-r--r--usr.bin/mkimg/Makefile2
-rw-r--r--usr.bin/mkimg/format.c6
-rw-r--r--usr.bin/mkimg/vhd.c120
3 files changed, 76 insertions, 52 deletions
diff --git a/usr.bin/mkimg/Makefile b/usr.bin/mkimg/Makefile
index 9fe18e5..2284cf2 100644
--- a/usr.bin/mkimg/Makefile
+++ b/usr.bin/mkimg/Makefile
@@ -4,7 +4,7 @@ PROG= mkimg
SRCS= format.c image.c mkimg.c scheme.c
MAN= mkimg.1
-MKIMG_VERSION=20150222
+MKIMG_VERSION=20150620
mkimg.o: Makefile
CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION}
diff --git a/usr.bin/mkimg/format.c b/usr.bin/mkimg/format.c
index 57bbd98..a21b08a 100644
--- a/usr.bin/mkimg/format.c
+++ b/usr.bin/mkimg/format.c
@@ -78,14 +78,10 @@ format_selected(void)
int
format_write(int fd)
{
- lba_t size;
int error;
if (format == NULL)
return (ENOSYS);
- size = image_get_size();
- error = format->resize(size);
- if (!error)
- error = format->write(fd);
+ error = format->write(fd);
return (error);
}
diff --git a/usr.bin/mkimg/vhd.c b/usr.bin/mkimg/vhd.c
index af3d95e..eb93fac 100644
--- a/usr.bin/mkimg/vhd.c
+++ b/usr.bin/mkimg/vhd.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Marcel Moolenaar
+ * Copyright (c) 2014, 2015 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -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 0x636f6e6563746978
@@ -75,14 +81,12 @@ struct vhd_footer {
uint32_t creator_tool;
#define VHD_CREATOR_TOOL 0x2a696d67 /* FreeBSD mkimg */
uint32_t creator_version;
-#define VHD_CREATOR_VERSION 0x00010000
+#define VHD_CREATOR_VERSION 0x00020000
uint32_t creator_os;
-#define VHD_CREATOR_OS 0x46425344
+#define VHD_CREATOR_OS 0x5769326b /* Wi2k */
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,46 +115,48 @@ 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;
+ imgsz = image_size / VHD_SECTOR_SIZE;
+
/* Respect command line options if possible. */
if (nheads > 1 && nheads < 256 &&
nsecs > 1 && nsecs < 256 &&
ncyls < 65536) {
- be16enc(&footer->cylinders, ncyls);
- footer->heads = nheads;
- footer->sectors = nsecs;
+ geom->cylinders = (ncyls != 0) ? ncyls :
+ imgsz / (nheads * nsecs);
+ geom->heads = nheads;
+ geom->sectors = nsecs;
return;
}
- imgsz = image_size / VHD_SECTOR_SIZE;
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 +204,8 @@ vhd_make_footer(struct vhd_footer *footer, uint64_t image_size,
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 +213,6 @@ vhd_make_footer(struct vhd_footer *footer, uint64_t image_size,
}
/*
- * 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 +252,16 @@ _Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2,
#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 +349,45 @@ 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;
+
+ /*
+ * Round the image size to the pre-determined geometry that
+ * matches the image size. This circular dependency implies
+ * that we need to loop to handle boundary conditions.
+ */
+ 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;
+ }
+ /*
+ * Azure demands that images are a whole number of megabytes.
+ */
+ imagesz = (imagesz + 0xfffffULL) & ~0xfffffULL;
+ return (image_set_size(imagesz / secsz));
+}
+
+static int
vhd_fix_write(int fd)
{
struct vhd_footer footer;
@@ -379,7 +407,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,
};
OpenPOWER on IntegriCloud