From 299ee841cb065ba278002b8561e53b189f792652 Mon Sep 17 00:00:00 2001 From: stefan Date: Fri, 29 Jul 2016 16:36:51 +0000 Subject: [PATCH] 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@ --- usr.sbin/vmd/config.c | 3 +- usr.sbin/vmd/vmd.c | 20 ++++++++++-- usr.sbin/vmd/vmd.h | 8 +++-- usr.sbin/vmd/vmm.c | 72 +++++++++++++++++++++++++++++++++++++------ 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 @@ -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 @@ -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 @@ -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 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -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; } } -- 2.20.1