Use it in /etc/rc.d/vmd accordingly.
OK sthen@
#!/bin/ksh
#
-# $OpenBSD: vmd,v 1.7 2018/02/20 10:12:14 sthen Exp $
+# $OpenBSD: vmd,v 1.8 2018/07/11 13:19:47 reyk Exp $
daemon="/usr/sbin/vmd"
rc_stop() {
for vm in $(list_running); do
- _rc_do vmctl stop "$vm"
- while list_running | fgrep -wq "$vm"; do
- sleep .1
- done
+ _rc_do vmctl stop "$vm" -w
done
pkill -T "${daemon_rtable}" -xf "${pexp}"
-/* $OpenBSD: main.c,v 1.36 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: main.c,v 1.37 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
" [-Lc] [-b image] [-r image] [-m size]\n"
"\t\t[-n switch] [-i count] [-d disk]*" },
{ "status", CMD_STATUS, ctl_status, "[id]" },
- { "stop", CMD_STOP, ctl_stop, "id [-f]" },
+ { "stop", CMD_STOP, ctl_stop, "id [-fw]" },
{ "pause", CMD_PAUSE, ctl_pause, "id" },
{ "unpause", CMD_UNPAUSE, ctl_unpause, "id" },
{ "send", CMD_SEND, ctl_send, "id", 1},
int done = 0;
int n;
int ret, action;
+ unsigned int flags;
if (ctl_sock == -1) {
if ((ctl_sock = socket(AF_UNIX,
}
break;
case CMD_STOP:
- terminate_vm(res->id, res->name, res->force);
+ terminate_vm(res->id, res->name, res->flags);
break;
case CMD_STATUS:
get_info_vm(res->id, res->name, 0);
}
action = res->action;
+ flags = res->flags;
parse_free(res);
while (ibuf->w.queued)
tty_autoconnect);
break;
case CMD_STOP:
- done = terminate_vm_complete(&imsg, &ret);
+ done = terminate_vm_complete(&imsg, &ret,
+ flags);
break;
case CMD_CONSOLE:
case CMD_STATUS:
argc--;
argv++;
- while ((ch = getopt(argc, argv, "f")) != -1) {
+ while ((ch = getopt(argc, argv, "fw")) != -1) {
switch (ch) {
case 'f':
- res->force = 1;
+ res->flags |= VMOP_FORCE;
+ break;
+ case 'w':
+ res->flags |= VMOP_WAIT;
break;
default:
ctl_usage(res->ctl);
-.\" $OpenBSD: vmctl.8,v 1.40 2018/07/11 09:35:44 reyk Exp $
+.\" $OpenBSD: vmctl.8,v 1.41 2018/07/11 13:19:47 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\"
.It Cm status Op Ar id
Lists VMs running on the host, optionally listing just the selected VM
.Ar id .
-.It Cm stop Ar id Op Fl f
+.It Cm stop Ar id Op Fl fw
Stops (terminates) a VM defined by the specified VM
.Ar id .
By default,
device.
Once stopped, if the VM was not defined in a configuration file, then it is
removed.
-The
-.Fl f
-option forcefully stops the VM without attempting a graceful shutdown.
+.Pp
+The following options can be specified when stopping a VM:
+.Bl -tag -width "-w"
+.It Fl f
+Forcefully stop the VM without attempting a graceful shutdown.
+.It Fl w
+Wait until the VM has been terminated.
+.El
+.Pp
.It Cm unpause Ar id
Unpause (resume from a paused state) a VM with the specified
.Ar id .
-/* $OpenBSD: vmctl.c,v 1.51 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: vmctl.c,v 1.52 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
* Parameters:
* terminate_id: ID of the vm to be terminated
* name: optional name of the VM to be terminated
- * force: forcefully kill the VM process
+ * flags: VMOP_FORCE or VMOP_WAIT flags
*/
void
-terminate_vm(uint32_t terminate_id, const char *name, int force)
+terminate_vm(uint32_t terminate_id, const char *name, unsigned int flags)
{
struct vmop_id vid;
- int cmd;
memset(&vid, 0, sizeof(vid));
vid.vid_id = terminate_id;
if (name != NULL)
(void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
- if (force)
- cmd = IMSG_VMDOP_KILL_VM_REQUEST;
- else
- cmd = IMSG_VMDOP_TERMINATE_VM_REQUEST;
+ vid.vid_flags = flags & (VMOP_FORCE|VMOP_WAIT);
- imsg_compose(ibuf, cmd, 0, 0, -1, &vid, sizeof(vid));
+ imsg_compose(ibuf, IMSG_VMDOP_TERMINATE_VM_REQUEST,
+ 0, 0, -1, &vid, sizeof(vid));
}
/*
* Parameters:
* imsg : response imsg received from vmd
* ret : return value
+ * flags: VMOP_FORCE or VMOP_WAIT flags
*
* Return:
* Always 1 to indicate we have processed the return message (even if it
* EIO : terminate_vm command failed
*/
int
-terminate_vm_complete(struct imsg *imsg, int *ret)
+terminate_vm_complete(struct imsg *imsg, int *ret, unsigned int flags)
{
struct vmop_result *vmr;
int res;
warn("terminate vm command failed");
*ret = EIO;
}
+ } else if (flags & VMOP_WAIT) {
+ warnx("terminated vm %d", vmr->vmr_id);
+ } else if (flags & VMOP_FORCE) {
+ warnx("requested to terminate vm %d", vmr->vmr_id);
} else {
- warnx("sent request to terminate vm %d", vmr->vmr_id);
+ warnx("requested to shutdown vm %d", vmr->vmr_id);
*ret = 0;
}
} else {
-/* $OpenBSD: vmctl.h,v 1.19 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: vmctl.h,v 1.20 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
int nnets;
size_t ndisks;
char **disks;
- int disable;
int verbose;
- int force;
+ unsigned int flags;
unsigned int mode;
struct ctl_command *ctl;
};
int vm_start(uint32_t, const char *, int, int, char **, int,
char **, char *, char *);
int vm_start_complete(struct imsg *, int *, int);
-void terminate_vm(uint32_t, const char *, int);
-int terminate_vm_complete(struct imsg *, int *);
+void terminate_vm(uint32_t, const char *, unsigned int);
+int terminate_vm_complete(struct imsg *, int *, unsigned int);
void pause_vm(uint32_t, const char *);
int pause_vm_complete(struct imsg *, int *);
void unpause_vm(uint32_t, const char *);
-/* $OpenBSD: config.c,v 1.45 2018/07/10 16:15:51 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.46 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
/* If the fd is -1, the kernel will be searched on the disk */
vm->vm_kernel = imsg->fd;
vm->vm_running = 1;
+ vm->vm_peerid = (uint32_t)-1;
return (0);
-/* $OpenBSD: control.c,v 1.26 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: control.c,v 1.27 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
switch (imsg.hdr.type) {
case IMSG_VMDOP_GET_INFO_VM_REQUEST:
case IMSG_VMDOP_TERMINATE_VM_REQUEST:
- case IMSG_VMDOP_KILL_VM_REQUEST:
case IMSG_VMDOP_START_VM_REQUEST:
case IMSG_VMDOP_PAUSE_VM:
case IMSG_VMDOP_UNPAUSE_VM:
}
break;
case IMSG_VMDOP_TERMINATE_VM_REQUEST:
- case IMSG_VMDOP_KILL_VM_REQUEST:
if (IMSG_DATA_SIZE(&imsg) < sizeof(vid))
goto fail;
memcpy(&vid, imsg.data, sizeof(vid));
-/* $OpenBSD: vmd.c,v 1.92 2018/07/11 10:31:45 reyk Exp $ */
+/* $OpenBSD: vmd.c,v 1.93 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
{
struct privsep *ps = p->p_ps;
int res = 0, ret = 0, cmd = 0, verbose;
- unsigned int v = 0;
+ unsigned int v = 0, flags;
struct vmop_create_params vmc;
struct vmop_id vid;
- struct vm_terminate_params vtp;
struct vmop_result vmr;
struct vm_dump_header vmh;
struct vmd_vm *vm = NULL;
}
break;
case IMSG_VMDOP_TERMINATE_VM_REQUEST:
- case IMSG_VMDOP_KILL_VM_REQUEST:
IMSG_SIZE_CHECK(imsg, &vid);
memcpy(&vid, imsg->data, sizeof(vid));
+ flags = vid.vid_flags;
+
if ((id = vid.vid_id) == 0) {
/* Lookup vm (id) by name */
if ((vm = vm_getbyname(vid.vid_name)) == NULL) {
cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
break;
} else if (vm->vm_shutdown &&
- imsg->hdr.type != IMSG_VMDOP_KILL_VM_REQUEST) {
+ (flags & VMOP_FORCE) == 0) {
res = EALREADY;
cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
break;
cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
break;
}
- memset(&vtp, 0, sizeof(vtp));
- vtp.vtp_vm_id = id;
+
+ memset(&vid, 0, sizeof(vid));
+ vid.vid_id = id;
+ vid.vid_flags = flags;
if (proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type,
- imsg->hdr.peerid, -1, &vtp, sizeof(vtp)) == -1)
+ imsg->hdr.peerid, -1, &vid, sizeof(vid)) == -1)
return (-1);
break;
case IMSG_VMDOP_GET_INFO_VM_REQUEST:
vm_stop(vm, 1, __func__);
config_setvm(ps, vm, (uint32_t)-1, vm->vm_uid);
}
+
+ /* Send a response if a control client is waiting for it */
+ if (imsg->hdr.peerid != (uint32_t)-1) {
+ /* the error is meaningless for deferred responses */
+ vmr.vmr_result = 0;
+
+ if (proc_compose_imsg(ps, PROC_CONTROL, -1,
+ IMSG_VMDOP_TERMINATE_VM_RESPONSE,
+ imsg->hdr.peerid, -1, &vmr, sizeof(vmr)) == -1)
+ return (-1);
+ }
break;
case IMSG_VMDOP_GET_INFO_VM_DATA:
IMSG_SIZE_CHECK(imsg, &vir);
-/* $OpenBSD: vmd.h,v 1.73 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: vmd.h,v 1.74 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
IMSG_VMDOP_RECEIVE_VM_RESPONSE,
IMSG_VMDOP_RECEIVE_VM_END,
IMSG_VMDOP_TERMINATE_VM_REQUEST,
- IMSG_VMDOP_KILL_VM_REQUEST,
IMSG_VMDOP_TERMINATE_VM_RESPONSE,
IMSG_VMDOP_TERMINATE_VM_EVENT,
IMSG_VMDOP_GET_INFO_VM_REQUEST,
uint32_t vid_id;
char vid_name[VMM_MAX_NAME_LEN];
uid_t vid_uid;
+ unsigned int vid_flags;
+#define VMOP_FORCE 0x01
+#define VMOP_WAIT 0x02
};
struct vmop_ifreq {
-/* $OpenBSD: vmm.c,v 1.85 2018/07/11 09:35:44 reyk Exp $ */
+/* $OpenBSD: vmm.c,v 1.86 2018/07/11 13:19:47 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
struct vmop_create_params vmc;
uint32_t id = 0;
pid_t pid = 0;
- unsigned int mode;
+ unsigned int mode, flags;
switch (imsg->hdr.type) {
case IMSG_VMDOP_START_VM_REQUEST:
cmd = IMSG_VMDOP_START_VM_RESPONSE;
break;
case IMSG_VMDOP_TERMINATE_VM_REQUEST:
- case IMSG_VMDOP_KILL_VM_REQUEST:
- IMSG_SIZE_CHECK(imsg, &vtp);
- memcpy(&vtp, imsg->data, sizeof(vtp));
- id = vtp.vtp_vm_id;
+ IMSG_SIZE_CHECK(imsg, &vid);
+ memcpy(&vid, imsg->data, sizeof(vid));
+ id = vid.vid_id;
+ flags = vid.vid_flags;
DPRINTF("%s: recv'ed TERMINATE_VM for %d", __func__, id);
+ cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
+
if (id == 0) {
res = ENOENT;
} else if ((vm = vm_getbyvmid(id)) != NULL) {
- if (imsg->hdr.type == IMSG_VMDOP_KILL_VM_REQUEST) {
+ if (flags & VMOP_FORCE) {
vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
vm->vm_shutdown = 1;
(void)terminate_vm(&vtp);
* Check to see if the VM process is still
* active. If not, return VMD_VM_STOP_INVALID.
*/
- vtp.vtp_vm_id = vm_vmid2id(vm->vm_vmid, vm);
- if (vtp.vtp_vm_id == 0) {
+ if (vm_vmid2id(vm->vm_vmid, vm) == 0) {
log_debug("%s: no vm running anymore",
__func__);
res = VMD_VM_STOP_INVALID;
}
}
+ if ((flags & VMOP_WAIT) &&
+ res == 0 && vm->vm_shutdown == 1) {
+ vm->vm_peerid = imsg->hdr.peerid;
+ cmd = 0;
+ }
} else {
/* 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;
case IMSG_VMDOP_GET_INFO_VM_REQUEST:
res = get_info_vm(ps, imsg, 0);
vmr.vmr_id = vm_id2vmid(vmid, vm);
if (proc_compose_imsg(ps, PROC_PARENT,
-1, IMSG_VMDOP_TERMINATE_VM_EVENT,
- 0, -1, &vmr, sizeof(vmr)) == -1)
+ vm->vm_peerid, -1,
+ &vmr, sizeof(vmr)) == -1)
log_warnx("could not signal "
"termination of VM %u to "
"parent", vm->vm_vmid);