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:
parent
f7a0594beb
commit
d53cfebe2f
@ -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! */
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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! */
|
||||
};
|
||||
|
||||
|
@ -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 .
|
||||
|
@ -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! */
|
||||
};
|
||||
|
||||
|
@ -45,6 +45,7 @@ enum alias {
|
||||
ALIAS_FREEBSD_VINUM,
|
||||
ALIAS_FREEBSD_ZFS,
|
||||
ALIAS_MBR,
|
||||
ALIAS_NTFS,
|
||||
/* end */
|
||||
ALIAS_COUNT /* Keep last! */
|
||||
};
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user