From 5406bd946fb6932a9ab2b11d819f7d374ccdacb1 Mon Sep 17 00:00:00 2001 From: marcel Date: Wed, 24 Jun 2015 18:40:34 +0000 Subject: [PATCH] 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) git-svn-id: svn://svn.freebsd.org/base/stable/10@284773 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- usr.bin/mkimg/Makefile | 2 +- usr.bin/mkimg/format.c | 6 +-- usr.bin/mkimg/vhd.c | 120 +++++++++++++++++++++++++---------------- 3 files changed, 76 insertions(+), 52 deletions(-) diff --git a/usr.bin/mkimg/Makefile b/usr.bin/mkimg/Makefile index 9fe18e591..2284cf250 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 57bbd98d0..a21b08ad0 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 af3d95eac..eb93fac43 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,30 +204,14 @@ 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); be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer))); } -/* - * 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 * @@ -261,6 +251,16 @@ _Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2, "Wrong size for header"); #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) { @@ -349,16 +349,44 @@ 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) { @@ -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, }; -- 2.45.0