* Fix logic handling stopping a VM.  Prevents VMD from crashing.
* Add additional error code to notify the user that a vm cannot be
  stopped when not running.
* Add additional log_debug statements.

diff --git usr.sbin/vmctl/vmctl.c usr.sbin/vmctl/vmctl.c
index 64d82ca847d..d1517d0d26d 100644
--- usr.sbin/vmctl/vmctl.c
+++ usr.sbin/vmctl/vmctl.c
@@ -206,7 +206,7 @@ vm_start_complete(struct imsg *imsg, int *ret, int 
autoconnect)
                                break;
                        case VMD_DISK_INVALID:
                                warnx("specified disk image(s) are "
-                                        "not regular files");
+                                   "not regular files");
                                *ret = ENOENT;
                                break;
                        default:
@@ -439,12 +439,19 @@ terminate_vm_complete(struct imsg *imsg, int *ret)
                vmr = (struct vmop_result *)imsg->data;
                res = vmr->vmr_result;
                if (res) {
-                       errno = res;
-                       if (res == ENOENT)
+                       switch (res) {
+                       case VMD_VM_STOP_INVALID:
+                               warnx("cannot stop vm that is not running");
+                               *ret = EINVAL;
+                               break;
+                       case ENOENT:
                                warnx("vm not found");
-                       else
+                               *ret = EIO;
+                               break;
+                       default:
                                warn("terminate vm command failed");
-                       *ret = EIO;
+                               *ret = EIO;
+                       }
                } else {
                        warnx("sent request to terminate vm %d", vmr->vmr_id);
                        *ret = 0;
@@ -453,6 +460,7 @@ terminate_vm_complete(struct imsg *imsg, int *ret)
                warnx("unexpected response received from vmd");
                *ret = EINVAL;
        }
+       errno = *ret;
 
        return (1);
 }
diff --git usr.sbin/vmd/vmd.h usr.sbin/vmd/vmd.h
index 22da6d58a7b..1240339db52 100644
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -54,6 +54,7 @@
 #define VMD_BIOS_MISSING       1001
 #define VMD_DISK_MISSING       1002
 #define VMD_DISK_INVALID       1003
+#define VMD_VM_STOP_INVALID    1004
 
 /* 100.64.0.0/10 from rfc6598 (IPv4 Prefix for Shared Address Space) */
 #define VMD_DHCP_PREFIX                "100.64.0.0/10"
diff --git usr.sbin/vmd/vmm.c usr.sbin/vmd/vmm.c
index 0e5ed1ed605..e3ff3be2f35 100644
--- usr.sbin/vmd/vmm.c
+++ usr.sbin/vmd/vmm.c
@@ -150,29 +150,45 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, 
struct imsg *imsg)
 
                if (id == 0) {
                        res = ENOENT;
-               } else if ((vm = vm_getbyvmid(id)) != NULL &&
-                   vm->vm_shutdown == 0) {
-                       log_debug("%s: sending shutdown request to vm %d",
-                           __func__, id);
-
-                       /*
-                        * Request reboot but mark the VM as shutting down.
-                        * This way we can terminate the VM after the triple
-                        * fault instead of reboot and avoid being stuck in
-                        * the ACPI-less powerdown ("press any key to reboot")
-                        * of the VM.
-                        */
-                       vm->vm_shutdown = 1;
-                       if (imsg_compose_event(&vm->vm_iev,
-                           IMSG_VMDOP_VM_REBOOT, 0, 0, -1, NULL, 0) == -1)
-                               res = errno;
-                       else
-                               res = 0;
+               } else if ((vm = vm_getbyvmid(id)) != NULL) {
+                       if (vm->vm_shutdown == 0) {
+                               log_debug("%s: sending shutdown req to vm %d",
+                                   __func__, id);
+
+                               /*
+                                * Request reboot but mark the VM as shutting
+                                * down. This way we can terminate the VM after
+                                * the triple fault instead of reboot and 
+                                * avoid being stuck in the ACPI-less powerdown
+                                * ("press any key to reboot") of the VM.
+                                */
+                               vm->vm_shutdown = 1;
+                               if (imsg_compose_event(&vm->vm_iev,
+                                   IMSG_VMDOP_VM_REBOOT, 0, 0, -1, NULL, 0)
+                                   == -1)
+                                       res = errno;
+                               else
+                                       res = 0;
+                       } else {
+                               /* in the process of shutting down... */
+                               log_debug("%s: performing a forced shutdown",
+                                   __func__);
+                               vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
+                               /* ensure vm_id isn't 0 */
+                               if (vtp.vtp_vm_id != 0) {
+                                       res = terminate_vm(&vtp);
+                                       vm_remove(vm);
+                               } else {
+                                       log_debug("%s: no vm running anymore",
+                                           __func__);
+                                       res = VMD_VM_STOP_INVALID;
+                               }
+                       }
                } else {
-                       /* Terminate VMs that are unknown or shutting down */
-                       vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
-                       res = terminate_vm(&vtp);
-                       vm_remove(vm);
+                       /* vm doesn't exist, cannot stop vm */
+                       log_debug("%s: cannot stop vm that is not running",
+                           __func__);
+                       res = VMD_VM_STOP_INVALID;
                }
                cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
                break;
@@ -346,6 +362,8 @@ vmm_sighdlr(int sig, short event, void *arg)
 
                                vmid = vm->vm_params.vmc_params.vcp_id;
                                vtp.vtp_vm_id = vmid;
+                               log_debug("%s: attempting to terminate vm %d",
+                                   __func__, vm->vm_vmid);
                                if (terminate_vm(&vtp) == 0) {
                                        memset(&vmr, 0, sizeof(vmr));
                                        vmr.vmr_result = ret;
@@ -505,7 +523,7 @@ vmm_dispatch_vm(int fd, short event, void *arg)
  * supplied vm_terminate_params structure (vtp->vtp_vm_id)
  *
  * Parameters
- *  vtp: vm_create_params struct containing the ID of the VM to terminate
+ *  vtp: vm_terminate_params struct containing the ID of the VM to terminate
  *
  * Return values:
  *  0: success
@@ -515,6 +533,7 @@ vmm_dispatch_vm(int fd, short event, void *arg)
 int
 terminate_vm(struct vm_terminate_params *vtp)
 {
+       log_debug("%s: terminating vmid %d", __func__, vtp->vtp_vm_id);
        if (ioctl(env->vmd_fd, VMM_IOC_TERM, vtp) < 0)
                return (errno);
 
-- 
2.14.1

Reply via email to