MFC r286660, r286419, r286417, r286395, r286215, r284883

-   Add the ntfs alias
-   Fix the dynamic VHD format to work with qemu
-   Update manpage

MFH:
Differential Revision:
This commit is contained in:
marcel 2015-08-25 04:03:51 +00:00
parent f7a0594beb
commit d53cfebe2f
8 changed files with 151 additions and 46 deletions

View File

@ -57,6 +57,7 @@ static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
static uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
static struct mkimg_alias gpt_aliases[] = {
{ ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
@ -68,6 +69,7 @@ static struct mkimg_alias gpt_aliases[] = {
{ ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
{ ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
{ ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
{ ALIAS_NTFS, ALIAS_PTR2TYPE(&gpt_uuid_ms_basic_data) },
{ ALIAS_NONE, 0 } /* Keep last! */
};

View File

@ -517,14 +517,14 @@ image_copyout_memory(int fd, size_t size, void *ptr)
return (0);
}
static int
image_copyout_zeroes(int fd, size_t size)
int
image_copyout_zeroes(int fd, size_t count)
{
static uint8_t *zeroes = NULL;
size_t sz;
int error;
if (lseek(fd, (off_t)size, SEEK_CUR) != -1)
if (lseek(fd, (off_t)count, SEEK_CUR) != -1)
return (0);
/*
@ -537,12 +537,12 @@ image_copyout_zeroes(int fd, size_t size)
return (ENOMEM);
}
while (size > 0) {
sz = (size > secsz) ? secsz : size;
while (count > 0) {
sz = (count > secsz) ? secsz : count;
error = image_copyout_memory(fd, sz, zeroes);
if (error)
return (error);
size -= sz;
count -= sz;
}
return (0);
}

View File

@ -35,6 +35,7 @@ int image_copyin(lba_t blk, int fd, uint64_t *sizep);
int image_copyout(int fd);
int image_copyout_done(int fd);
int image_copyout_region(int fd, lba_t blk, lba_t size);
int image_copyout_zeroes(int fd, size_t count);
int image_data(lba_t blk, lba_t size);
lba_t image_get_size(void);
int image_init(void);

View File

@ -51,6 +51,7 @@ static struct mkimg_alias mbr_aliases[] = {
{ ALIAS_EFI, ALIAS_INT2TYPE(DOSPTYP_EFI) },
{ ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) },
{ ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) },
{ ALIAS_NTFS, ALIAS_INT2TYPE(DOSPTYP_NTFS) },
{ ALIAS_NONE, 0 } /* Keep last! */
};

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 22, 2015
.Dd August 7, 2015
.Dt MKIMG 1
.Os
.Sh NAME
@ -141,7 +141,7 @@ utility will create images that are identical.
.Pp
A set of long options exist to query about the
.Nm
utilty itself.
utility itself.
Options in this set should be given by themselves because the
.Nm
utility exits immediately after providing the requested information.
@ -165,6 +165,85 @@ run the
.Nm
utility without any arguments.
This will print a usage message with all the necessary details.
.Sh DISK FORMATS
The
.Nm
utility supports a number of output file formats.
A short description of these is given below.
.Ss QCOW and QCOW2
QCOW stands for "QEMU Copy On Write".
It's a sparse file format akin to VHD and VMDK and QCOW represents the
first version.
QCOW2 represents version 2 of the file format.
Version 2 is not backward compatible with version 1 and adds support for
snapshots among other things.
The QCOW file formats are natively supported by QEMU and Xen.
To write QCOW, specify
.Fl f Ar qcow
on the command line.
To write version 2 QCOW, specify
.Fl f Ar qcow2
on the command line.
The preferred file extension is ".qcow" and ".qcow2" for QCOW and QCOW2
(resp.), but ".qcow" is sometimes used for version 2 files as well.
.Ss RAW file format
This file format is a sector by sector representation of an actual disk.
There is no extra information that describes or relates to the format
itself. The size of the file is the size of the (virtual) disk.
This file format is suitable for being copyied onto a disk with utilities
like
.Nm dd .
To write a raw disk file, either omit the
.Fl f
option, or specify
.Fl f Ar raw
on the command line.
The preferred file extension is one of ".img" or ".raw", but there's no
real convention for it.
.Ss Dynamic VHD and Fixed VHD
Microsoft's "Virtual Hard Disk" file formats.
The dynamic format is a sparse format akin to QCOW and VMDK.
The fixed format is effectively a raw format with a footer appended to the
file and as such it's often indistinguishable from the raw format.
The fixed file format has been added to support Microsoft's Azure platform
and due to inconsistencies in interpretation of the footer is not compatible
with utilities like
.Nm qemu
when it is specifically instructed to interpreted the file as a VHD file.
By default
.Nm qemu
will treat the file as a raw disk file, which mostly works fine.
To have
.Nm
create a dynamic VHD file, specify
.Fl f Ar vhd
on the command line.
To create a fixed VHD file for use by Azure, specify
.Fl f Ar vhdf
on the command line.
The preferred file extension is ".vhd".
.Ss VMDK
VMware's "Virtual Machine Disk" file format.
It's a sparse file format akin to QCOW and VHD and supported by many
virtualization solutions.
To create a VMDK file, specify
.Fl f Ar vmdk
on the command line.
The preferred file extension is ".vmdk".
.Pp
Not all virtualization solutions support all file formats, but often those
virtualization environments have utilities to convert from one format to
another.
Note however that conversion may require that the virtual disk size is
changed to match the constraints of the output format and this may invalidate
the contents of the disk image.
For example, the GUID Partition Table (GPT) scheme has a header in the last
sector on the disk.
When changing the disk size, the GPT must be changed so that the last header
is moved accordingly.
This is typically not part of the conversion process.
If possible, use an output format specifically for the environment in which
the file is intended to be used.
.Sh ENVIRONMENT
.Bl -tag -width "TMPDIR" -compact
.It Ev TMPDIR
@ -235,6 +314,7 @@ utility supports assigning labels to the partitions specified.
In the following example the file system partition is labeled as 'backup':
.Dl % mkimg -s gpt -p freebsd-ufs/backup:=file-system.ufs -o gpt.img
.Sh SEE ALSO
.Xr dd 1 ,
.Xr gpart 8 ,
.Xr makefs 8 ,
.Xr mdconfig 8 ,
@ -247,4 +327,5 @@ utility first appeared in
.Sh AUTHORS
The
.Nm
utility and manpage were written by Marcel Moolenaar <marcelm@juniper.net>
utility and manpage were written by
.An Marcel Moolenaar Aq Mt marcelm@juniper.net .

View File

@ -59,6 +59,7 @@ static struct {
{ "freebsd-vinum", ALIAS_FREEBSD_VINUM },
{ "freebsd-zfs", ALIAS_FREEBSD_ZFS },
{ "mbr", ALIAS_MBR },
{ "ntfs", ALIAS_NTFS },
{ NULL, ALIAS_NONE } /* Keep last! */
};

View File

@ -45,6 +45,7 @@ enum alias {
ALIAS_FREEBSD_VINUM,
ALIAS_FREEBSD_ZFS,
ALIAS_MBR,
ALIAS_NTFS,
/* end */
ALIAS_COUNT /* Keep last! */
};

View File

@ -159,6 +159,34 @@ vhd_geometry(uint64_t image_size, struct vhd_geom *geom)
geom->cylinders = cth / geom->heads;
}
static uint64_t
vhd_resize(uint64_t origsz)
{
struct vhd_geom geom;
uint64_t newsz;
/*
* 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.
* The first time, newsz equals origsz and the geometry will
* typically yield a new size that's smaller. We keep adding
* cylinder's worth of sectors to the new size until its
* larger or equal or origsz. But during those iterations,
* the geometry can change, so we need to account for that.
*/
newsz = origsz;
while (1) {
vhd_geometry(newsz, &geom);
newsz = (int64_t)geom.cylinders * geom.heads *
geom.sectors * VHD_SECTOR_SIZE;
if (newsz >= origsz)
break;
newsz += geom.heads * geom.sectors * VHD_SECTOR_SIZE;
}
return (newsz);
}
static uint32_t
vhd_timestamp(void)
{
@ -256,8 +284,7 @@ vhd_dyn_resize(lba_t imgsz)
{
uint64_t imagesz;
imagesz = imgsz * secsz;
imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
imagesz = vhd_resize(imgsz * secsz);
return (image_set_size(imagesz / secsz));
}
@ -266,7 +293,7 @@ vhd_dyn_write(int fd)
{
struct vhd_footer footer;
struct vhd_dyn_header header;
uint64_t imgsz;
uint64_t imgsz, rawsz;
lba_t blk, blkcnt, nblks;
uint32_t *bat;
void *bitmap;
@ -274,13 +301,14 @@ vhd_dyn_write(int fd)
uint32_t sector;
int bat_entries, error, entry;
imgsz = image_get_size() * secsz;
bat_entries = imgsz / VHD_BLOCK_SIZE;
rawsz = image_get_size() * secsz;
imgsz = (rawsz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer));
vhd_make_footer(&footer, rawsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer));
if (sparse_write(fd, &footer, sizeof(footer)) < 0)
return (errno);
bat_entries = imgsz / VHD_BLOCK_SIZE;
memset(&header, 0, sizeof(header));
be64enc(&header.cookie, VHD_HEADER_COOKIE);
be64enc(&header.data_offset, ~0ULL);
@ -321,7 +349,7 @@ vhd_dyn_write(int fd)
blk = 0;
blkcnt = VHD_BLOCK_SIZE / secsz;
error = 0;
nblks = image_get_size();
nblks = rawsz / secsz;
while (blk < nblks) {
if (!image_data(blk, blkcnt)) {
blk += blkcnt;
@ -331,15 +359,20 @@ vhd_dyn_write(int fd)
error = errno;
break;
}
/* Handle partial last block */
if (blk + blkcnt > nblks)
blkcnt = nblks - blk;
error = image_copyout_region(fd, blk, blkcnt);
if (error)
break;
blk += blkcnt;
}
free(bitmap);
if (blk != nblks)
if (error)
return (error);
error = image_copyout_zeroes(fd, imgsz - rawsz);
if (error)
return (error);
if (sparse_write(fd, &footer, sizeof(footer)) < 0)
return (errno);
@ -362,24 +395,9 @@ FORMAT_DEFINE(vhd_dyn_format);
static int
vhd_fix_resize(lba_t imgsz)
{
struct vhd_geom geom;
int64_t imagesz;
uint64_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;
}
imagesz = vhd_resize(imgsz * secsz);
/*
* Azure demands that images are a whole number of megabytes.
*/
@ -391,24 +409,24 @@ static int
vhd_fix_write(int fd)
{
struct vhd_footer footer;
uint64_t imgsz;
uint64_t imagesz;
int error;
error = image_copyout(fd);
if (!error) {
imgsz = image_get_size() * secsz;
vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_FIXED, ~0ULL);
if (sparse_write(fd, &footer, sizeof(footer)) < 0)
error = errno;
}
if (error)
return (error);
imagesz = image_get_size() * secsz;
vhd_make_footer(&footer, imagesz, VHD_DISK_TYPE_FIXED, ~0ULL);
error = (sparse_write(fd, &footer, sizeof(footer)) < 0) ? errno : 0;
return (error);
}
static struct mkimg_format vhd_fix_format = {
.name = "vhdf",
.description = "Fixed Virtual Hard Disk",
.resize = vhd_fix_resize,
.write = vhd_fix_write,
.name = "vhdf",
.description = "Fixed Virtual Hard Disk",
.resize = vhd_fix_resize,
.write = vhd_fix_write,
};
FORMAT_DEFINE(vhd_fix_format);