summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstefan <stefan@openbsd.org>2016-07-29 16:36:51 +0000
committerstefan <stefan@openbsd.org>2016-07-29 16:36:51 +0000
commit299ee841cb065ba278002b8561e53b189f792652 (patch)
tree4762916d314b0f1bec9a5fad41bce3b0d138eb94
parentBump copyright in files that I touched last. (diff)
downloadwireguard-openbsd-299ee841cb065ba278002b8561e53b189f792652.tar.xz
wireguard-openbsd-299ee841cb065ba278002b8561e53b189f792652.zip
Allow starting a VM again after it was terminated
If a VM exits, terminate it and remove it from the list of available VMs. That allows a VM with name `foo' to be restarted after it has exited. This changes structures shared between vmd and vmctl. You need to rebuild vmctl also. ok mlarkin@
-rw-r--r--usr.sbin/vmd/config.c3
-rw-r--r--usr.sbin/vmd/vmd.c20
-rw-r--r--usr.sbin/vmd/vmd.h8
-rw-r--r--usr.sbin/vmd/vmm.c72
4 files changed, 89 insertions, 14 deletions
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c
index 06f2399ebdc..42d94bdbc9c 100644
--- a/usr.sbin/vmd/config.c
+++ b/usr.sbin/vmd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.9 2015/12/07 15:57:53 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.10 2016/07/29 16:36:51 stefan Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -135,6 +135,7 @@ config_getvm(struct privsep *ps, struct vm_create_params *vcp,
goto fail;
memcpy(&vm->vm_params, vcp, sizeof(vm->vm_params));
+ vm->vm_pid = -1;
for (i = 0; i < vcp->vcp_ndisks; i++)
vm->vm_disks[i] = -1;
diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c
index 03ec2c1620a..06e30965db3 100644
--- a/usr.sbin/vmd/vmd.c
+++ b/usr.sbin/vmd/vmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.c,v 1.27 2016/02/05 11:40:15 reyk Exp $ */
+/* $OpenBSD: vmd.c,v 1.28 2016/07/29 16:36:51 stefan Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -148,6 +148,7 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
memcpy(&vmr, imsg->data, sizeof(vmr));
if ((vm = vm_getbyvmid(imsg->hdr.peerid)) == NULL)
fatalx("%s: invalid vm response", __func__);
+ vm->vm_pid = vmr.vmr_pid;
vcp = &vm->vm_params;
vcp->vcp_id = vmr.vmr_id;
@@ -181,9 +182,11 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
}
break;
case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
+ case IMSG_VMDOP_TERMINATE_VM_EVENT:
IMSG_SIZE_CHECK(imsg, &vmr);
memcpy(&vmr, imsg->data, sizeof(vmr));
- proc_forward_imsg(ps, imsg, PROC_CONTROL, -1);
+ if (imsg->hdr.type == IMSG_VMDOP_TERMINATE_VM_RESPONSE)
+ proc_forward_imsg(ps, imsg, PROC_CONTROL, -1);
if (vmr.vmr_result == 0) {
/* Remove local reference */
vm = vm_getbyid(vmr.vmr_id);
@@ -508,6 +511,19 @@ vm_getbyname(const char *name)
return (NULL);
}
+struct vmd_vm *
+vm_getbypid(pid_t pid)
+{
+ struct vmd_vm *vm;
+
+ TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
+ if (vm->vm_pid == pid)
+ return (vm);
+ }
+
+ return (NULL);
+}
+
void
vm_remove(struct vmd_vm *vm)
{
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index 386ba12f79a..38ebc7f1cab 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.21 2016/07/09 09:06:22 stefan Exp $ */
+/* $OpenBSD: vmd.h,v 1.22 2016/07/29 16:36:51 stefan Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -57,12 +57,14 @@ enum imsg_type {
IMSG_VMDOP_GET_INFO_VM_DATA,
IMSG_VMDOP_GET_INFO_VM_END_DATA,
IMSG_VMDOP_LOAD,
- IMSG_VMDOP_RELOAD
+ IMSG_VMDOP_RELOAD,
+ IMSG_VMDOP_TERMINATE_VM_EVENT
};
struct vmop_result {
int vmr_result;
uint32_t vmr_id;
+ pid_t vmr_pid;
char vmr_ttyname[VM_TTYNAME_MAX];
};
@@ -78,6 +80,7 @@ struct vmop_id {
struct vmd_vm {
struct vm_create_params vm_params;
+ pid_t vm_pid;
uint32_t vm_vmid;
int vm_kernel;
int vm_disks[VMM_MAX_DISKS_PER_VM];
@@ -109,6 +112,7 @@ void vmd_reload(int, const char *);
struct vmd_vm *vm_getbyvmid(uint32_t);
struct vmd_vm *vm_getbyid(uint32_t);
struct vmd_vm *vm_getbyname(const char *);
+struct vmd_vm *vm_getbypid(pid_t);
void vm_remove(struct vmd_vm *);
char *get_string(uint8_t *, size_t);
diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c
index 826b4cc21ef..59403d59ec4 100644
--- a/usr.sbin/vmd/vmm.c
+++ b/usr.sbin/vmd/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.33 2016/07/19 09:52:34 natano Exp $ */
+/* $OpenBSD: vmm.c,v 1.34 2016/07/29 16:36:51 stefan Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -19,6 +19,7 @@
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
+#include <sys/wait.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -103,6 +104,7 @@ struct i8253_counter i8253_counter[3];
struct ns8250_regs com1_regs;
io_fn_t ioports_map[MAX_PORTS];
+void vmm_sighdlr(int, short, void *);
int start_client_vmd(void);
int opentap(void);
int start_vm(struct imsg *, uint32_t *);
@@ -191,6 +193,10 @@ vmm_run(struct privsep *ps, struct privsep_proc *p, void *arg)
if (config_init(ps->ps_env) == -1)
fatal("failed to initialize configuration");
+ signal_del(&ps->ps_evsigchld);
+ signal_set(&ps->ps_evsigchld, SIGCHLD, vmm_sighdlr, ps);
+ signal_add(&ps->ps_evsigchld, NULL);
+
#if 0
/*
* pledge in the vmm process:
@@ -296,6 +302,60 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
return (0);
}
+void
+vmm_sighdlr(int sig, short event, void *arg)
+{
+ struct privsep *ps = arg;
+ int status;
+ uint32_t vmid;
+ pid_t pid;
+ struct vmop_result vmr;
+ struct vmd_vm *vm;
+ struct vm_terminate_params vtp;
+
+ switch (sig) {
+ case SIGCHLD:
+ do {
+ pid = waitpid(-1, &status, WNOHANG);
+ if (pid <= 0)
+ continue;
+
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ vm = vm_getbypid(pid);
+ if (vm == NULL) {
+ /*
+ * If the VM is gone already, it
+ * got terminated via a
+ * IMSG_VMDOP_TERMINATE_VM_REQUEST.
+ */
+ continue;
+ }
+
+ vmid = vm->vm_params.vcp_id;
+ vtp.vtp_vm_id = vmid;
+ if (terminate_vm(&vtp) == 0) {
+ memset(&vmr, 0, sizeof(vmr));
+ vmr.vmr_result = 0;
+ vmr.vmr_id = vmid;
+ vm_remove(vm);
+ if (proc_compose_imsg(ps, PROC_PARENT,
+ -1, IMSG_VMDOP_TERMINATE_VM_EVENT,
+ 0, -1, &vmr, sizeof(vmr)) == -1)
+ log_warnx("could not signal "
+ "termination of VM %u to "
+ "parent", vmid);
+ } else
+ log_warnx("could not terminate VM %u",
+ vmid);
+ } else
+ fatalx("unexpected cause of SIGCHLD");
+ } while (pid > 0 || (pid == -1 && errno == EINTR));
+ break;
+ default:
+ fatalx("unexpected signal");
+ }
+}
+
/*
* vcpu_reset
*
@@ -436,6 +496,8 @@ start_vm(struct imsg *imsg, uint32_t *id)
if (ret > 0) {
/* Parent */
+ vm->vm_pid = ret;
+
for (i = 0 ; i < vcp->vcp_ndisks; i++) {
close(vm->vm_disks[i]);
vm->vm_disks[i] = -1;
@@ -864,7 +926,6 @@ run_vm(int *child_disks, int *child_taps, struct vm_create_params *vcp,
pthread_t *tid;
void *exit_status;
struct vm_run_params **vrp;
- struct vm_terminate_params vtp;
if (vcp == NULL)
return (EINVAL);
@@ -949,13 +1010,6 @@ run_vm(int *child_disks, int *child_taps, struct vm_create_params *vcp,
if (exit_status != NULL) {
log_warnx("%s: vm %d vcpu run thread %zd exited "
"abnormally", __progname, vcp->vcp_id, i);
- /* Terminate the VM if we can */
- memset(&vtp, 0, sizeof(vtp));
- vtp.vtp_vm_id = vcp->vcp_id;
- if (terminate_vm(&vtp)) {
- log_warnx("%s: could not terminate vm %d",
- __progname, vcp->vcp_id);
- }
ret = EIO;
}
}