From 52e954a3fad37facf0321bc5eab1a89fc28f90a7 Mon Sep 17 00:00:00 2001 From: pd Date: Sun, 9 Jul 2017 00:51:40 +0000 Subject: [PATCH] vmd/vmctl: Add ability to pause / unpause vms With help from Ashwin Agrawal ok reyk@ mlarkin@ --- usr.sbin/vmctl/main.c | 42 ++++++++++++++++++- usr.sbin/vmctl/vmctl.c | 80 +++++++++++++++++++++++++++++++++++- usr.sbin/vmctl/vmctl.h | 8 +++- usr.sbin/vmd/control.c | 6 ++- usr.sbin/vmd/i8253.c | 36 ++++++++++------- usr.sbin/vmd/i8253.h | 4 +- usr.sbin/vmd/mc146818.c | 12 ++++-- usr.sbin/vmd/mc146818.h | 3 +- usr.sbin/vmd/vm.c | 89 ++++++++++++++++++++++++++++++++++++----- usr.sbin/vmd/vmd.c | 43 +++++++++++++++++++- usr.sbin/vmd/vmd.h | 7 +++- usr.sbin/vmd/vmm.c | 45 ++++++++++++++++++++- 12 files changed, 338 insertions(+), 37 deletions(-) diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c index 632c22150e2..d1c0badf8ce 100644 --- a/usr.sbin/vmctl/main.c +++ b/usr.sbin/vmctl/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.29 2017/06/07 23:15:49 mlarkin Exp $ */ +/* $OpenBSD: main.c,v 1.30 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -56,6 +56,8 @@ int ctl_reset(struct parse_result *, int, char *[]); int ctl_start(struct parse_result *, int, char *[]); int ctl_status(struct parse_result *, int, char *[]); int ctl_stop(struct parse_result *, int, char *[]); +int ctl_pause(struct parse_result *, int, char *[]); +int ctl_unpause(struct parse_result *, int, char *[]); struct ctl_command ctl_commands[] = { { "console", CMD_CONSOLE, ctl_console, "id" }, @@ -69,6 +71,8 @@ struct ctl_command ctl_commands[] = { "\t\t[-n switch] [-i count] [-d disk]*" }, { "status", CMD_STATUS, ctl_status, "[id]" }, { "stop", CMD_STOP, ctl_stop, "id" }, + { "pause", CMD_PAUSE, ctl_pause, "id" }, + { "unpause", CMD_UNPAUSE, ctl_unpause, "id" }, { NULL } }; @@ -225,6 +229,12 @@ vmmaction(struct parse_result *res) imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &res->mode, sizeof(res->mode)); break; + case CMD_PAUSE: + pause_vm(res->id, res->name); + break; + case CMD_UNPAUSE: + unpause_vm(res->id, res->name); + break; case CMD_CREATE: case NONE: break; @@ -275,6 +285,12 @@ vmmaction(struct parse_result *res) case CMD_STATUS: done = add_info(&imsg, &ret); break; + case CMD_PAUSE: + done = pause_vm_complete(&imsg, &ret); + break; + case CMD_UNPAUSE: + done = unpause_vm_complete(&imsg, &ret); + break; default: done = 1; break; @@ -616,6 +632,30 @@ ctl_console(struct parse_result *res, int argc, char *argv[]) return (vmmaction(res)); } +int +ctl_pause(struct parse_result *res, int argc, char *argv[]) +{ + if (argc == 2) { + if (parse_vmid(res, argv[1]) == -1) + errx(1, "invalid id: %s", argv[1]); + } else if (argc != 2) + ctl_usage(res->ctl); + + return (vmmaction(res)); +} + +int +ctl_unpause(struct parse_result *res, int argc, char *argv[]) +{ + if (argc == 2) { + if (parse_vmid(res, argv[1]) == -1) + errx(1, "invalid id: %s", argv[1]); + } else if (argc != 2) + ctl_usage(res->ctl); + + return (vmmaction(res)); +} + __dead void ctl_openconsole(const char *name) { diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c index ee9c6db0e9d..1ae0e1d42e6 100644 --- a/usr.sbin/vmctl/vmctl.c +++ b/usr.sbin/vmctl/vmctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.c,v 1.30 2017/04/19 15:38:32 reyk Exp $ */ +/* $OpenBSD: vmctl.c,v 1.31 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2014 Mike Larkin @@ -196,6 +196,84 @@ vm_start_complete(struct imsg *imsg, int *ret, int autoconnect) return (1); } +void +pause_vm(uint32_t pause_id, const char *name) +{ + struct vmop_id vid; + + memset(&vid, 0, sizeof(vid)); + vid.vid_id = pause_id; + if (name != NULL) + (void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name)); + + imsg_compose(ibuf, IMSG_VMDOP_PAUSE_VM, 0, 0, -1, + &vid, sizeof(vid)); +} + +int +pause_vm_complete(struct imsg *imsg, int *ret) +{ + struct vmop_result *vmr; + int res; + + if (imsg->hdr.type == IMSG_VMDOP_PAUSE_VM_RESPONSE) { + vmr = (struct vmop_result *)imsg->data; + res = vmr->vmr_result; + if (res) { + errno = res; + warn("pause vm command failed"); + *ret = EIO; + } else { + warnx("paused vm %d successfully", vmr->vmr_id); + *ret = 0; + } + } else { + warnx("unexpected response received from vmd"); + *ret = EINVAL; + } + + return (1); +} + +void +unpause_vm(uint32_t pause_id, const char *name) +{ + struct vmop_id vid; + + memset(&vid, 0, sizeof(vid)); + vid.vid_id = pause_id; + if (name != NULL) + (void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name)); + + imsg_compose(ibuf, IMSG_VMDOP_UNPAUSE_VM, 0, 0, -1, + &vid, sizeof(vid)); +} + +int +unpause_vm_complete(struct imsg *imsg, int *ret) +{ + struct vmop_result *vmr; + int res; + + if (imsg->hdr.type == IMSG_VMDOP_UNPAUSE_VM_RESPONSE) { + vmr = (struct vmop_result *)imsg->data; + res = vmr->vmr_result; + if (res) { + errno = res; + warn("unpause vm command failed"); + *ret = EIO; + } else { + warnx("unpaused vm %d successfully", vmr->vmr_id); + *ret = 0; + } + } else { + warnx("unexpected response received from vmd"); + *ret = EINVAL; + } + + return (1); +} + /* * terminate_vm * diff --git a/usr.sbin/vmctl/vmctl.h b/usr.sbin/vmctl/vmctl.h index 58d03d20bd1..ca851dc8933 100644 --- a/usr.sbin/vmctl/vmctl.h +++ b/usr.sbin/vmctl/vmctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.h,v 1.14 2017/04/06 18:07:13 reyk Exp $ */ +/* $OpenBSD: vmctl.h,v 1.15 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -32,6 +32,8 @@ enum actions { CMD_START, CMD_STATUS, CMD_STOP, + CMD_PAUSE, + CMD_UNPAUSE, }; struct ctl_command; @@ -82,6 +84,10 @@ int vm_start(uint32_t, const char *, int, int, char **, int, int vm_start_complete(struct imsg *, int *, int); void terminate_vm(uint32_t, const char *); int terminate_vm_complete(struct imsg *, int *); +void pause_vm(uint32_t, const char *); +int pause_vm_complete(struct imsg *, int *); +void unpause_vm(uint32_t, const char *); +int unpause_vm_complete(struct imsg *, int *); int check_info_id(const char *, uint32_t); void get_info_vm(uint32_t, const char *, int); int add_info(struct imsg *, int *); diff --git a/usr.sbin/vmd/control.c b/usr.sbin/vmd/control.c index 1e7eba2f0b3..08baa77cf0d 100644 --- a/usr.sbin/vmd/control.c +++ b/usr.sbin/vmd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.19 2017/05/04 19:41:58 reyk Exp $ */ +/* $OpenBSD: control.c,v 1.20 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2010-2015 Reyk Floeter @@ -83,6 +83,8 @@ control_dispatch_vmd(int fd, struct privsep_proc *p, struct imsg *imsg) switch (imsg->hdr.type) { case IMSG_VMDOP_START_VM_RESPONSE: + case IMSG_VMDOP_PAUSE_VM_RESPONSE: + case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: case IMSG_VMDOP_TERMINATE_VM_RESPONSE: case IMSG_VMDOP_GET_INFO_VM_DATA: case IMSG_VMDOP_GET_INFO_VM_END_DATA: @@ -366,6 +368,8 @@ control_dispatch_imsg(int fd, short event, void *arg) log_setverbose(v); /* FALLTHROUGH */ + case IMSG_VMDOP_PAUSE_VM: + case IMSG_VMDOP_UNPAUSE_VM: case IMSG_VMDOP_LOAD: case IMSG_VMDOP_RELOAD: case IMSG_CTL_RESET: diff --git a/usr.sbin/vmd/i8253.c b/usr.sbin/vmd/i8253.c index 5fa4d8a34da..ff33c0ecae2 100644 --- a/usr.sbin/vmd/i8253.c +++ b/usr.sbin/vmd/i8253.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i8253.c,v 1.15 2017/05/08 09:08:40 reyk Exp $ */ +/* $OpenBSD: i8253.c,v 1.16 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -314,6 +314,7 @@ i8253_reset(uint8_t chn) evtimer_del(&i8253_channel[chn].timer); timerclear(&tv); + i8253_channel[chn].in_use = 1; tv.tv_usec = (i8253_channel[chn].start * NS_PER_TICK) / 1000; evtimer_add(&i8253_channel[chn].timer, &tv); } @@ -359,30 +360,37 @@ i8253_dump(int fd) int i8253_restore(int fd, uint32_t vm_id) { + int i; log_debug("%s: restoring PIT", __func__); if (atomicio(read, fd, &i8253_channel, sizeof(i8253_channel)) != sizeof(i8253_channel)) { log_warnx("%s: error reading PIT from fd", __func__); return (-1); } - memset(&i8253_channel[0].timer, 0, sizeof(struct event)); - memset(&i8253_channel[1].timer, 0, sizeof(struct event)); - memset(&i8253_channel[2].timer, 0, sizeof(struct event)); - i8253_channel[0].vm_id = vm_id; - i8253_channel[1].vm_id = vm_id; - i8253_channel[2].vm_id = vm_id; - evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]); - evtimer_set(&i8253_channel[1].timer, i8253_fire, &i8253_channel[1]); - evtimer_set(&i8253_channel[2].timer, i8253_fire, &i8253_channel[2]); - i8253_reset(0); + for (i = 0; i < 3; i++) { + memset(&i8253_channel[i].timer, 0, sizeof(struct event)); + i8253_channel[i].vm_id = vm_id; + evtimer_set(&i8253_channel[i].timer, i8253_fire, + &i8253_channel[i]); + i8253_reset(i); + } return (0); } void i8253_stop() { - evtimer_del(&i8253_channel[0].timer); - evtimer_del(&i8253_channel[1].timer); - evtimer_del(&i8253_channel[2].timer); + int i; + for (i = 0; i < 3; i++) + evtimer_del(&i8253_channel[i].timer); +} + +void +i8253_start() +{ + int i; + for (i = 0; i < 3; i++) + if(i8253_channel[i].in_use) + i8253_reset(i); } diff --git a/usr.sbin/vmd/i8253.h b/usr.sbin/vmd/i8253.h index 2bd6de8eef7..564dc5c5938 100644 --- a/usr.sbin/vmd/i8253.h +++ b/usr.sbin/vmd/i8253.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i8253.h,v 1.6 2017/05/08 09:08:40 reyk Exp $ */ +/* $OpenBSD: i8253.h,v 1.7 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -39,6 +39,7 @@ struct i8253_channel { uint8_t rbs; /* channel is in readback status mode */ struct event timer; /* timer event for this counter */ uint32_t vm_id; /* owning VM id */ + int in_use; /* denotes if this counter was ever used */ }; void i8253_init(uint32_t); @@ -49,3 +50,4 @@ int i8253_restore(int, uint32_t); uint8_t vcpu_exit_i8253(struct vm_run_params *); void i8253_do_readback(uint32_t); void i8253_stop(void); +void i8253_start(void); diff --git a/usr.sbin/vmd/mc146818.c b/usr.sbin/vmd/mc146818.c index 66656959556..2a81f17f75d 100644 --- a/usr.sbin/vmd/mc146818.c +++ b/usr.sbin/vmd/mc146818.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mc146818.c,v 1.14 2017/05/08 09:08:40 reyk Exp $ */ +/* $OpenBSD: mc146818.c,v 1.15 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -341,9 +341,6 @@ mc146818_restore(int fd, uint32_t vm_id) memset(&rtc.per, 0, sizeof(struct event)); evtimer_set(&rtc.sec, rtc_fire1, NULL); evtimer_set(&rtc.per, rtc_fireper, (void *)(intptr_t)rtc.vm_id); - - evtimer_add(&rtc.per, &rtc.per_tv); - evtimer_add(&rtc.sec, &rtc.sec_tv); return (0); } @@ -353,3 +350,10 @@ mc146818_stop() evtimer_del(&rtc.per); evtimer_del(&rtc.sec); } + +void +mc146818_start() +{ + evtimer_add(&rtc.per, &rtc.per_tv); + evtimer_add(&rtc.sec, &rtc.sec_tv); +} diff --git a/usr.sbin/vmd/mc146818.h b/usr.sbin/vmd/mc146818.h index 8eadb47d0aa..f6e3509aa60 100644 --- a/usr.sbin/vmd/mc146818.h +++ b/usr.sbin/vmd/mc146818.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mc146818.h,v 1.4 2017/05/08 09:08:40 reyk Exp $ */ +/* $OpenBSD: mc146818.h,v 1.5 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -21,3 +21,4 @@ void dump_mc146818(void); int mc146818_dump(int); int mc146818_restore(int, uint32_t); void mc146818_stop(void); +void mc146818_start(void); diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index 1c4e354422b..87b980d269c 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.20 2017/06/07 14:53:28 mlarkin Exp $ */ +/* $OpenBSD: vm.c,v 1.21 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -77,6 +77,8 @@ void vcpu_exit_inout(struct vm_run_params *); uint8_t vcpu_exit_pci(struct vm_run_params *); int vcpu_pic_intr(uint32_t, uint32_t, uint8_t); int loadfile_bios(FILE *, struct vcpu_reg_state *); +void pause_vm(struct vm_create_params *); +void unpause_vm(struct vm_create_params *); static struct vm_mem_range *find_gpa_range(struct vm_create_params *, paddr_t, size_t); @@ -345,6 +347,7 @@ void vm_dispatch_vmm(int fd, short event, void *arg) { struct vmd_vm *vm = arg; + struct vmop_result vmr; struct imsgev *iev = &vm->vm_iev; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; @@ -391,6 +394,24 @@ vm_dispatch_vmm(int fd, short event, void *arg) if (vmmci_ctl(VMMCI_REBOOT) == -1) _exit(0); break; + case IMSG_VMDOP_PAUSE_VM: + vmr.vmr_result = 0; + vmr.vmr_id = vm->vm_vmid; + pause_vm(&vm->vm_params.vmc_params); + imsg_compose_event(&vm->vm_iev, + IMSG_VMDOP_PAUSE_VM_RESPONSE, + imsg.hdr.peerid, imsg.hdr.pid, -1, &vmr, + sizeof(vmr)); + break; + case IMSG_VMDOP_UNPAUSE_VM: + vmr.vmr_result = 0; + vmr.vmr_id = vm->vm_vmid; + unpause_vm(&vm->vm_params.vmc_params); + imsg_compose_event(&vm->vm_iev, + IMSG_VMDOP_UNPAUSE_VM_RESPONSE, + imsg.hdr.peerid, imsg.hdr.pid, -1, &vmr, + sizeof(vmr)); + break; default: fatalx("%s: got invalid imsg %d from %s", __func__, imsg.hdr.type, @@ -427,6 +448,37 @@ vm_shutdown(unsigned int cmd) _exit(0); } +void +pause_vm(struct vm_create_params *vcp) +{ + if (current_vm->vm_paused) + return; + + current_vm->vm_paused = 1; + + /* XXX: vcpu_run_loop is running in another thread and we have to wait + * for the vm to exit before returning */ + sleep(1); + + i8253_stop(); + mc146818_stop(); +} + +void +unpause_vm(struct vm_create_params *vcp) +{ + unsigned int n; + if (!current_vm->vm_paused) + return; + + current_vm->vm_paused = 0; + + i8253_start(); + mc146818_start(); + for (n = 0; n <= vcp->vcp_ncpus; n++) + pthread_cond_broadcast(&vcpu_run_cond[n]); +} + /* * vcpu_reset * @@ -921,20 +973,37 @@ vcpu_run_loop(void *arg) return ((void *)ret); } - /* If we are halted, wait */ + /* If we are halted or paused, wait */ if (vcpu_hlt[n]) { - ret = pthread_cond_wait(&vcpu_run_cond[n], - &vcpu_run_mtx[n]); - - if (ret) { - log_warnx("%s: can't wait on cond (%d)", - __func__, (int)ret); - (void)pthread_mutex_unlock(&vcpu_run_mtx[n]); - break; + while (current_vm->vm_paused == 1) { + ret = pthread_cond_wait(&vcpu_run_cond[n], + &vcpu_run_mtx[n]); + if (ret) { + log_warnx( + "%s: can't wait on cond (%d)", + __func__, (int)ret); + (void)pthread_mutex_unlock( + &vcpu_run_mtx[n]); + break; + } + } + if (vcpu_hlt[n]) { + ret = pthread_cond_wait(&vcpu_run_cond[n], + &vcpu_run_mtx[n]); + + if (ret) { + log_warnx( + "%s: can't wait on cond (%d)", + __func__, (int)ret); + (void)pthread_mutex_unlock( + &vcpu_run_mtx[n]); + break; + } } } ret = pthread_mutex_unlock(&vcpu_run_mtx[n]); + if (ret) { log_warnx("%s: can't unlock mutex on cond (%d)", __func__, (int)ret); diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index 440d64f87de..ca332ae3f28 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.62 2017/05/29 07:15:22 mlarkin Exp $ */ +/* $OpenBSD: vmd.c,v 1.63 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -163,6 +163,22 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) proc_forward_imsg(ps, imsg, PROC_PRIV, -1); cmd = IMSG_CTL_OK; break; + case IMSG_VMDOP_PAUSE_VM: + case IMSG_VMDOP_UNPAUSE_VM: + IMSG_SIZE_CHECK(imsg, &vid); + memcpy(&vid, imsg->data, sizeof(vid)); + if (vid.vid_id == 0) { + if ((vm = vm_getbyname(vid.vid_name)) == NULL) { + res = ENOENT; + cmd = IMSG_VMDOP_PAUSE_VM_RESPONSE; + break; + } else { + vid.vid_id = vm->vm_vmid; + } + } + proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type, + imsg->hdr.peerid, -1, &vid, sizeof(vid)); + break; default: return (-1); } @@ -200,6 +216,30 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg) struct vmop_info_result vir; switch (imsg->hdr.type) { + case IMSG_VMDOP_PAUSE_VM_RESPONSE: + IMSG_SIZE_CHECK(imsg, &vmr); + memcpy(&vmr, imsg->data, sizeof(vmr)); + if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) + break; + proc_compose_imsg(ps, PROC_CONTROL, -1, + imsg->hdr.type, imsg->hdr.peerid, -1, + imsg->data, sizeof(imsg->data)); + log_info("%s: paused vm %d successfully", + vm->vm_params.vmc_params.vcp_name, + vm->vm_vmid); + break; + case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: + IMSG_SIZE_CHECK(imsg, &vmr); + memcpy(&vmr, imsg->data, sizeof(vmr)); + if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) + break; + proc_compose_imsg(ps, PROC_CONTROL, -1, + imsg->hdr.type, imsg->hdr.peerid, -1, + imsg->data, sizeof(imsg->data)); + log_info("%s: unpaused vm %d successfully.", + vm->vm_params.vmc_params.vcp_name, + vm->vm_vmid); + break; case IMSG_VMDOP_START_VM_RESPONSE: IMSG_SIZE_CHECK(imsg, &vmr); memcpy(&vmr, imsg->data, sizeof(vmr)); @@ -869,6 +909,7 @@ vm_register(struct privsep *ps, struct vmop_create_params *vmc, vcp = &vmc->vmc_params; vm->vm_pid = -1; vm->vm_tty = -1; + vm->vm_paused = 0; for (i = 0; i < vcp->vcp_ndisks; i++) vm->vm_disks[i] = -1; diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index be621835eaa..0cfd4cf546c 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.56 2017/06/12 13:41:24 deraadt Exp $ */ +/* $OpenBSD: vmd.h,v 1.57 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -65,6 +65,10 @@ enum imsg_type { IMSG_VMDOP_START_VM_IF, IMSG_VMDOP_START_VM_END, IMSG_VMDOP_START_VM_RESPONSE, + IMSG_VMDOP_PAUSE_VM, + IMSG_VMDOP_PAUSE_VM_RESPONSE, + IMSG_VMDOP_UNPAUSE_VM, + IMSG_VMDOP_UNPAUSE_VM_RESPONSE, IMSG_VMDOP_TERMINATE_VM_REQUEST, IMSG_VMDOP_TERMINATE_VM_RESPONSE, IMSG_VMDOP_TERMINATE_VM_EVENT, @@ -189,6 +193,7 @@ struct vmd_vm { struct imsgev vm_iev; int vm_shutdown; uid_t vm_uid; + int vm_paused; TAILQ_ENTRY(vmd_vm) vm_entry; }; diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 3b0a453032b..2e992d6cb15 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.69 2017/04/21 07:03:26 reyk Exp $ */ +/* $OpenBSD: vmm.c,v 1.70 2017/07/09 00:51:40 pd Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -105,6 +105,7 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) int res = 0, cmd = 0, verbose; struct vmd_vm *vm = NULL; struct vm_terminate_params vtp; + struct vmop_id vid; struct vmop_result vmr; uint32_t id = 0; unsigned int mode; @@ -202,6 +203,33 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) -1, &verbose, sizeof(verbose)); } break; + case IMSG_VMDOP_PAUSE_VM: + IMSG_SIZE_CHECK(imsg, &vid); + memcpy(&vid, imsg->data, sizeof(vid)); + id = vid.vid_id; + vm = vm_getbyvmid(id); + if ((vm = vm_getbyvmid(id)) == NULL) { + res = ENOENT; + cmd = IMSG_VMDOP_PAUSE_VM_RESPONSE; + break; + } + imsg_compose_event(&vm->vm_iev, + imsg->hdr.type, imsg->hdr.peerid, imsg->hdr.pid, + imsg->fd, &vid, sizeof(vid)); + break; + case IMSG_VMDOP_UNPAUSE_VM: + IMSG_SIZE_CHECK(imsg, &vid); + memcpy(&vid, imsg->data, sizeof(vid)); + id = vid.vid_id; + if ((vm = vm_getbyvmid(id)) == NULL) { + res = ENOENT; + cmd = IMSG_VMDOP_UNPAUSE_VM_RESPONSE; + break; + } + imsg_compose_event(&vm->vm_iev, + imsg->hdr.type, imsg->hdr.peerid, imsg->hdr.pid, + imsg->fd, &vid, sizeof(vid)); + break; default: return (-1); } @@ -217,6 +245,8 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) } if (id == 0) id = imsg->hdr.peerid; + case IMSG_VMDOP_PAUSE_VM_RESPONSE: + case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: case IMSG_VMDOP_TERMINATE_VM_RESPONSE: memset(&vmr, 0, sizeof(vmr)); vmr.vmr_result = res; @@ -354,6 +384,7 @@ vmm_dispatch_vm(int fd, short event, void *arg) struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; + unsigned int i; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) @@ -392,6 +423,18 @@ vmm_dispatch_vm(int fd, short event, void *arg) case IMSG_VMDOP_VM_REBOOT: vm->vm_shutdown = 0; break; + case IMSG_VMDOP_PAUSE_VM_RESPONSE: + case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: + for (i = 0; i < sizeof(procs); i++) { + if (procs[i].p_id == PROC_PARENT) { + proc_forward_imsg(procs[i].p_ps, + &imsg, PROC_PARENT, + -1); + break; + } + } + break; + default: fatalx("%s: got invalid imsg %d from %s", __func__, imsg.hdr.type, -- 2.20.1