summaryrefslogtreecommitdiffstats
path: root/usr.sbin/vmctl
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2018-10-08 16:32:01 +0000
committerreyk <reyk@openbsd.org>2018-10-08 16:32:01 +0000
commit7361395374362d014ae90cba8e4ce848295ac0b4 (patch)
tree5a2e96be8dac013055f0f9b19897aecf982df4c5 /usr.sbin/vmctl
parentmerge 1.8.1 (diff)
downloadwireguard-openbsd-7361395374362d014ae90cba8e4ce848295ac0b4.tar.xz
wireguard-openbsd-7361395374362d014ae90cba8e4ce848295ac0b4.zip
Add support for qcow2 base images (external snapshots).
This works is from Ori Bernstein, committing on his behalf: Add support to vmd for external snapshots. That is, snapshots that are derived from a base image. Data lookups start in the derived image, and if the derived image does not contain some data, the search proceeds ot the base image. Multiple derived images may exist off of a single base image. A limitation of this format is that modifying the base image will corrupt the derived image. This change also adds support for creating disk derived disk images to vmctl. To use it: vmctl create derived.qcow2 -s 16G -b base.qcow2 From Ori Bernstein OK mlarkin@ reyk@
Diffstat (limited to 'usr.sbin/vmctl')
-rw-r--r--usr.sbin/vmctl/main.c37
-rw-r--r--usr.sbin/vmctl/vmctl.823
-rw-r--r--usr.sbin/vmctl/vmctl.c44
-rw-r--r--usr.sbin/vmctl/vmctl.h4
4 files changed, 75 insertions, 33 deletions
diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c
index 69c5e013f4c..45cd5cab753 100644
--- a/usr.sbin/vmctl/main.c
+++ b/usr.sbin/vmctl/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.45 2018/10/05 12:54:57 reyk Exp $ */
+/* $OpenBSD: main.c,v 1.46 2018/10/08 16:32:01 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -67,7 +67,8 @@ int ctl_receive(struct parse_result *, int, char *[]);
struct ctl_command ctl_commands[] = {
{ "console", CMD_CONSOLE, ctl_console, "id" },
- { "create", CMD_CREATE, ctl_create, "\"path\" -s size", 1 },
+ { "create", CMD_CREATE, ctl_create,
+ "\"path\" [-s size] [-b base]", 1 },
{ "load", CMD_LOAD, ctl_load, "\"path\"" },
{ "log", CMD_LOG, ctl_log, "[verbose|brief]" },
{ "reload", CMD_RELOAD, ctl_reload, "" },
@@ -539,47 +540,55 @@ int
ctl_create(struct parse_result *res, int argc, char *argv[])
{
int ch, ret, type;
- const char *paths[2], *disk, *format;
+ const char *disk, *format, *base;
if (argc < 2)
ctl_usage(res->ctl);
+ base = NULL;
type = parse_disktype(argv[1], &disk);
- paths[0] = disk;
- paths[1] = NULL;
-
- if (unveil(paths[0], "rwc") == -1)
+ if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
+ err(1, "pledge");
+ if (unveil(disk, "rwc") == -1)
err(1, "unveil");
- if (pledge("stdio rpath wpath cpath", NULL) == -1)
- err(1, "pledge");
argc--;
argv++;
- while ((ch = getopt(argc, argv, "s:")) != -1) {
+ while ((ch = getopt(argc, argv, "s:b:")) != -1) {
switch (ch) {
case 's':
if (parse_size(res, optarg, 0) != 0)
errx(1, "invalid size: %s", optarg);
break;
+ case 'b':
+ base = optarg;
+ if (unveil(base, "r") == -1)
+ err(1, "unveil");
+ break;
default:
ctl_usage(res->ctl);
/* NOTREACHED */
}
}
+ if (unveil(NULL, NULL))
+ err(1, "unveil");
- if (res->size == 0) {
- fprintf(stderr, "missing size argument\n");
+ if (base && type != VMDF_QCOW2)
+ errx(1, "base images require qcow2 disk format");
+ if (res->size == 0 && !base) {
+ fprintf(stderr, "could not create %s: missing size argument\n",
+ disk);
ctl_usage(res->ctl);
}
if (type == VMDF_QCOW2) {
format = "qcow2";
- ret = create_qc2_imagefile(paths[0], res->size);
+ ret = create_qc2_imagefile(disk, base, res->size);
} else {
format = "raw";
- ret = create_raw_imagefile(paths[0], res->size);
+ ret = create_raw_imagefile(disk, res->size);
}
if (ret != 0) {
diff --git a/usr.sbin/vmctl/vmctl.8 b/usr.sbin/vmctl/vmctl.8
index f7890ac99f8..f450ae49e11 100644
--- a/usr.sbin/vmctl/vmctl.8
+++ b/usr.sbin/vmctl/vmctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vmctl.8,v 1.50 2018/10/01 09:31:15 reyk Exp $
+.\" $OpenBSD: vmctl.8,v 1.51 2018/10/08 16:32:01 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 1 2018 $
+.Dd $Mdocdate: October 8 2018 $
.Dt VMCTL 8
.Os
.Sh NAME
@@ -50,7 +50,7 @@ Using
.Xr cu 1
connect to the console of the VM with the specified
.Ar id .
-.It Cm create Ar path Fl s Ar size
+.It Cm create Ar path Fl s Op Ar size Op Fl b Ar base
Creates a VM disk image file with the specified
.Ar path
and
@@ -59,13 +59,22 @@ rounded to megabytes.
The disk
.Ar path
may be prefixed with a format prefix
-.Pf ( Pa raw:
+.Pf ( Pa raw :
or
-.Pa qcow2: )
+.Pa qcow2 : )
in order to specify the disk format.
If left unspecified, the format defaults to
.Pa raw
if it cannot be derived automatically.
+For qcow2, a
+.Ar base
+image may be specified.
+The base image is not modified.
+The derived image contains only the changes written by the VM.
+When creating a derived image, the
+.Ar size
+may be omitted, and probed from the base image.
+If it is provided, it must match the base image size.
.It Cm load Ar filename
Load additional configuration from the specified file.
.It Cm log brief
@@ -127,9 +136,9 @@ Disk image file (may be specified multiple times to add multiple disk images).
The disk
.Ar path
may be prefixed with a format prefix
-.Pf ( Pa raw:
+.Pf ( Pa raw :
or
-.Pa qcow2: )
+.Pa qcow2 : )
in order to specify the disk format.
If left unspecified, the format defaults to
.Pa raw
diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c
index b09e1115ff7..a311ed0a512 100644
--- a/usr.sbin/vmctl/vmctl.c
+++ b/usr.sbin/vmctl/vmctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.c,v 1.60 2018/10/02 16:42:38 reyk Exp $ */
+/* $OpenBSD: vmctl.c,v 1.61 2018/10/08 16:32:01 reyk Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
@@ -847,7 +847,8 @@ create_raw_imagefile(const char *imgfile_path, long imgsize)
#define ALIGN(sz, align) \
((sz + align - 1) & ~(align - 1))
int
-create_qc2_imagefile(const char *imgfile_path, long imgsize)
+create_qc2_imagefile(const char *imgfile_path,
+ const char *base_path, long imgsize)
{
struct qcheader {
char magic[4];
@@ -869,15 +870,33 @@ create_qc2_imagefile(const char *imgfile_path, long imgsize)
uint64_t autoclearfeatures;
uint32_t reforder;
uint32_t headersz;
- } __packed hdr;
+ } __packed hdr, basehdr;
int fd, ret;
+ ssize_t base_len;
uint64_t l1sz, refsz, disksz, initsz, clustersz;
uint64_t l1off, refoff, v, i, l1entrysz, refentrysz;
uint16_t refs;
- disksz = 1024*1024*imgsize;
+ disksz = 1024 * 1024 * imgsize;
+
+ if (base_path) {
+ fd = open(base_path, O_RDONLY);
+ if (read(fd, &basehdr, sizeof(basehdr)) != sizeof(basehdr))
+ err(1, "failure to read base image header");
+ close(fd);
+ if (strncmp(basehdr.magic,
+ VM_MAGIC_QCOW, strlen(VM_MAGIC_QCOW)) != 0)
+ errx(1, "base image is not a qcow2 file");
+ if (!disksz)
+ disksz = betoh64(basehdr.disksz);
+ else if (disksz != betoh64(basehdr.disksz))
+ errx(1, "base size does not match requested size");
+ }
+ if (!base_path && !disksz)
+ errx(1, "missing disk size");
+
clustersz = (1<<16);
- l1off = ALIGN(sizeof hdr, clustersz);
+ l1off = ALIGN(sizeof(hdr), clustersz);
l1entrysz = clustersz * clustersz / 8;
l1sz = (disksz + l1entrysz - 1) / l1entrysz;
@@ -887,11 +906,12 @@ create_qc2_imagefile(const char *imgfile_path, long imgsize)
refsz = (disksz + refentrysz - 1) / refentrysz;
initsz = ALIGN(refoff + refsz*clustersz, clustersz);
+ base_len = base_path ? strlen(base_path) : 0;
- memcpy(hdr.magic, "QFI\xfb", 4);
+ memcpy(hdr.magic, VM_MAGIC_QCOW, strlen(VM_MAGIC_QCOW));
hdr.version = htobe32(3);
- hdr.backingoff = htobe64(0);
- hdr.backingsz = htobe32(0);
+ hdr.backingoff = htobe64(base_path ? sizeof(hdr) : 0);
+ hdr.backingsz = htobe32(base_len);
hdr.clustershift = htobe32(16);
hdr.disksz = htobe64(disksz);
hdr.cryptmethod = htobe32(0);
@@ -905,7 +925,7 @@ create_qc2_imagefile(const char *imgfile_path, long imgsize)
hdr.compatfeatures = htobe64(0);
hdr.autoclearfeatures = htobe64(0);
hdr.reforder = htobe32(4);
- hdr.headersz = htobe32(sizeof hdr);
+ hdr.headersz = htobe32(sizeof(hdr));
/* Refuse to overwrite an existing image */
fd = open(imgfile_path, O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
@@ -914,7 +934,11 @@ create_qc2_imagefile(const char *imgfile_path, long imgsize)
return (errno);
/* Write out the header */
- if (write(fd, &hdr, sizeof hdr) != sizeof hdr)
+ if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+ goto error;
+
+ /* Add the base image */
+ if (base_path && write(fd, base_path, base_len) != base_len)
goto error;
/* Extend to desired size, and add one refcount cluster */
diff --git a/usr.sbin/vmctl/vmctl.h b/usr.sbin/vmctl/vmctl.h
index 006411d9785..5ae88268fd7 100644
--- a/usr.sbin/vmctl/vmctl.h
+++ b/usr.sbin/vmctl/vmctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.h,v 1.25 2018/10/01 09:31:15 reyk Exp $ */
+/* $OpenBSD: vmctl.h,v 1.26 2018/10/08 16:32:01 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -87,7 +87,7 @@ __dead void
/* vmctl.c */
int create_raw_imagefile(const char *, long);
-int create_qc2_imagefile(const char *, long);
+int create_qc2_imagefile(const char *, const char *, long);
int vm_start(uint32_t, const char *, int, int, char **, int,
char **, int *, char *, char *, char *);
int vm_start_complete(struct imsg *, int *, int);