vmd/vmctl: Add ability to pause / unpause vms
authorpd <pd@openbsd.org>
Sun, 9 Jul 2017 00:51:40 +0000 (00:51 +0000)
committerpd <pd@openbsd.org>
Sun, 9 Jul 2017 00:51:40 +0000 (00:51 +0000)
With help from Ashwin Agrawal

ok reyk@ mlarkin@

12 files changed:
usr.sbin/vmctl/main.c
usr.sbin/vmctl/vmctl.c
usr.sbin/vmctl/vmctl.h
usr.sbin/vmd/control.c
usr.sbin/vmd/i8253.c
usr.sbin/vmd/i8253.h
usr.sbin/vmd/mc146818.c
usr.sbin/vmd/mc146818.h
usr.sbin/vmd/vm.c
usr.sbin/vmd/vmd.c
usr.sbin/vmd/vmd.h
usr.sbin/vmd/vmm.c

index 632c221..d1c0bad 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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)
 {
index ee9c6db..1ae0e1d 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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
  *
index 58d03d2..ca851dc 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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 *);
index 1e7eba2..08baa77 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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:
index 5fa4d8a..ff33c0e 100644 (file)
@@ -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 <mlarkin@openbsd.org>
  *
@@ -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);
 }
index 2bd6de8..564dc5c 100644 (file)
@@ -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 <mlarkin@openbsd.org>
  *
@@ -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);
index 6665695..2a81f17 100644 (file)
@@ -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 <mlarkin@openbsd.org>
  *
@@ -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);
+}
index 8eadb47..f6e3509 100644 (file)
@@ -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 <mlarkin@openbsd.org>
  *
@@ -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);
index 1c4e354..87b980d 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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);
index 440d64f..ca332ae 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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;
index be62183..0cfd4cf 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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;
 };
index 3b0a453..2e992d6 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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,