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)
This commit is contained in:
parent
f8c30d3e15
commit
c8b4a5d462
@ -4,7 +4,7 @@ PROG= mkimg
|
|||||||
SRCS= format.c image.c mkimg.c scheme.c
|
SRCS= format.c image.c mkimg.c scheme.c
|
||||||
MAN= mkimg.1
|
MAN= mkimg.1
|
||||||
|
|
||||||
MKIMG_VERSION=20150222
|
MKIMG_VERSION=20150620
|
||||||
mkimg.o: Makefile
|
mkimg.o: Makefile
|
||||||
|
|
||||||
CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION}
|
CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION}
|
||||||
|
@ -78,14 +78,10 @@ format_selected(void)
|
|||||||
int
|
int
|
||||||
format_write(int fd)
|
format_write(int fd)
|
||||||
{
|
{
|
||||||
lba_t size;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (format == NULL)
|
if (format == NULL)
|
||||||
return (ENOSYS);
|
return (ENOSYS);
|
||||||
size = image_get_size();
|
error = format->write(fd);
|
||||||
error = format->resize(size);
|
|
||||||
if (!error)
|
|
||||||
error = format->write(fd);
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2014 Marcel Moolenaar
|
* Copyright (c) 2014, 2015 Marcel Moolenaar
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -62,6 +62,12 @@ __FBSDID("$FreeBSD$");
|
|||||||
#define VHD_SECTOR_SIZE 512
|
#define VHD_SECTOR_SIZE 512
|
||||||
#define VHD_BLOCK_SIZE (4096 * VHD_SECTOR_SIZE) /* 2MB blocks */
|
#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 {
|
struct vhd_footer {
|
||||||
uint64_t cookie;
|
uint64_t cookie;
|
||||||
#define VHD_FOOTER_COOKIE 0x636f6e6563746978
|
#define VHD_FOOTER_COOKIE 0x636f6e6563746978
|
||||||
@ -75,14 +81,12 @@ struct vhd_footer {
|
|||||||
uint32_t creator_tool;
|
uint32_t creator_tool;
|
||||||
#define VHD_CREATOR_TOOL 0x2a696d67 /* FreeBSD mkimg */
|
#define VHD_CREATOR_TOOL 0x2a696d67 /* FreeBSD mkimg */
|
||||||
uint32_t creator_version;
|
uint32_t creator_version;
|
||||||
#define VHD_CREATOR_VERSION 0x00010000
|
#define VHD_CREATOR_VERSION 0x00020000
|
||||||
uint32_t creator_os;
|
uint32_t creator_os;
|
||||||
#define VHD_CREATOR_OS 0x46425344
|
#define VHD_CREATOR_OS 0x5769326b /* Wi2k */
|
||||||
uint64_t original_size;
|
uint64_t original_size;
|
||||||
uint64_t current_size;
|
uint64_t current_size;
|
||||||
uint16_t cylinders;
|
struct vhd_geom geometry;
|
||||||
uint8_t heads;
|
|
||||||
uint8_t sectors;
|
|
||||||
uint32_t disk_type;
|
uint32_t disk_type;
|
||||||
#define VHD_DISK_TYPE_FIXED 2
|
#define VHD_DISK_TYPE_FIXED 2
|
||||||
#define VHD_DISK_TYPE_DYNAMIC 3
|
#define VHD_DISK_TYPE_DYNAMIC 3
|
||||||
@ -111,46 +115,48 @@ vhd_checksum(void *buf, size_t sz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
lba_t imgsz;
|
||||||
long cth;
|
long cth;
|
||||||
|
|
||||||
|
imgsz = image_size / VHD_SECTOR_SIZE;
|
||||||
|
|
||||||
/* Respect command line options if possible. */
|
/* Respect command line options if possible. */
|
||||||
if (nheads > 1 && nheads < 256 &&
|
if (nheads > 1 && nheads < 256 &&
|
||||||
nsecs > 1 && nsecs < 256 &&
|
nsecs > 1 && nsecs < 256 &&
|
||||||
ncyls < 65536) {
|
ncyls < 65536) {
|
||||||
be16enc(&footer->cylinders, ncyls);
|
geom->cylinders = (ncyls != 0) ? ncyls :
|
||||||
footer->heads = nheads;
|
imgsz / (nheads * nsecs);
|
||||||
footer->sectors = nsecs;
|
geom->heads = nheads;
|
||||||
|
geom->sectors = nsecs;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
imgsz = image_size / VHD_SECTOR_SIZE;
|
|
||||||
if (imgsz > 65536 * 16 * 255)
|
if (imgsz > 65536 * 16 * 255)
|
||||||
imgsz = 65536 * 16 * 255;
|
imgsz = 65536 * 16 * 255;
|
||||||
if (imgsz >= 65535 * 16 * 63) {
|
if (imgsz >= 65535 * 16 * 63) {
|
||||||
be16enc(&footer->cylinders, imgsz / (16 * 255));
|
geom->cylinders = imgsz / (16 * 255);
|
||||||
footer->heads = 16;
|
geom->heads = 16;
|
||||||
footer->sectors = 255;
|
geom->sectors = 255;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
footer->sectors = 17;
|
geom->sectors = 17;
|
||||||
cth = imgsz / 17;
|
cth = imgsz / 17;
|
||||||
footer->heads = (cth + 1023) / 1024;
|
geom->heads = (cth + 1023) / 1024;
|
||||||
if (footer->heads < 4)
|
if (geom->heads < 4)
|
||||||
footer->heads = 4;
|
geom->heads = 4;
|
||||||
if (cth >= (footer->heads * 1024) || footer->heads > 16) {
|
if (cth >= (geom->heads * 1024) || geom->heads > 16) {
|
||||||
footer->heads = 16;
|
geom->heads = 16;
|
||||||
footer->sectors = 31;
|
geom->sectors = 31;
|
||||||
cth = imgsz / 31;
|
cth = imgsz / 31;
|
||||||
}
|
}
|
||||||
if (cth >= (footer->heads * 1024)) {
|
if (cth >= (geom->heads * 1024)) {
|
||||||
footer->heads = 16;
|
geom->heads = 16;
|
||||||
footer->sectors = 63;
|
geom->sectors = 63;
|
||||||
cth = imgsz / 63;
|
cth = imgsz / 63;
|
||||||
}
|
}
|
||||||
be16enc(&footer->cylinders, cth / footer->heads);
|
geom->cylinders = cth / geom->heads;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
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);
|
be32enc(&footer->creator_os, VHD_CREATOR_OS);
|
||||||
be64enc(&footer->original_size, image_size);
|
be64enc(&footer->original_size, image_size);
|
||||||
be64enc(&footer->current_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);
|
be32enc(&footer->disk_type, disk_type);
|
||||||
mkimg_uuid(&id);
|
mkimg_uuid(&id);
|
||||||
vhd_uuid_enc(&footer->id, &id);
|
vhd_uuid_enc(&footer->id, &id);
|
||||||
be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer)));
|
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
|
* PART 2: Dynamic VHD support
|
||||||
*
|
*
|
||||||
@ -261,6 +251,16 @@ _Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2,
|
|||||||
"Wrong size for header");
|
"Wrong size for header");
|
||||||
#endif
|
#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
|
static int
|
||||||
vhd_dyn_write(int fd)
|
vhd_dyn_write(int fd)
|
||||||
{
|
{
|
||||||
@ -349,16 +349,44 @@ vhd_dyn_write(int fd)
|
|||||||
static struct mkimg_format vhd_dyn_format = {
|
static struct mkimg_format vhd_dyn_format = {
|
||||||
.name = "vhd",
|
.name = "vhd",
|
||||||
.description = "Virtual Hard Disk",
|
.description = "Virtual Hard Disk",
|
||||||
.resize = vhd_resize,
|
.resize = vhd_dyn_resize,
|
||||||
.write = vhd_dyn_write,
|
.write = vhd_dyn_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
FORMAT_DEFINE(vhd_dyn_format);
|
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
|
static int
|
||||||
vhd_fix_write(int fd)
|
vhd_fix_write(int fd)
|
||||||
{
|
{
|
||||||
@ -379,7 +407,7 @@ vhd_fix_write(int fd)
|
|||||||
static struct mkimg_format vhd_fix_format = {
|
static struct mkimg_format vhd_fix_format = {
|
||||||
.name = "vhdf",
|
.name = "vhdf",
|
||||||
.description = "Fixed Virtual Hard Disk",
|
.description = "Fixed Virtual Hard Disk",
|
||||||
.resize = vhd_resize,
|
.resize = vhd_fix_resize,
|
||||||
.write = vhd_fix_write,
|
.write = vhd_fix_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user