Files
xen/tools/xcutils/xc_save.c
T
Olaf Hering e6c9172170 tools/xc: log pid in xc_save/xc_restore output
If several migrations log their output to xend.log its not clear which
line belongs to a which guest. Print entry/exit of xc_save and
xc_restore and also request to print pid with each log call.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
2013-02-15 13:32:13 +00:00

228 lines
6.3 KiB
C

/*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of
* this archive for more details.
*
* Copyright (C) 2005 by Christian Limpach
*
*/
#include <err.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>
#include <xenstore.h>
#include <xenctrl.h>
#include <xenguest.h>
static struct suspendinfo {
xc_interface *xch;
xc_evtchn *xce; /* event channel handle */
int suspend_evtchn;
int domid;
unsigned int flags;
} si;
/**
* Issue a suspend request through stdout, and receive the acknowledgement
* from stdin. This is handled by XendCheckpoint in the Python layer.
*/
static int compat_suspend(void)
{
char ans[30];
printf("suspend\n");
fflush(stdout);
return (fgets(ans, sizeof(ans), stdin) != NULL &&
!strncmp(ans, "done\n", 5));
}
/**
* Issue a suspend request to a dedicated event channel in the guest, and
* receive the acknowledgement from the subscribe event channel. */
static int evtchn_suspend(void)
{
int rc;
rc = xc_evtchn_notify(si.xce, si.suspend_evtchn);
if (rc < 0) {
warnx("failed to notify suspend request channel: %d", rc);
return 0;
}
if (xc_await_suspend(si.xch, si.xce, si.suspend_evtchn) < 0) {
warnx("suspend failed");
return 0;
}
/* notify xend that it can do device migration */
printf("suspended\n");
fflush(stdout);
return 1;
}
static int suspend(void* data)
{
unsigned long sx_state = 0;
/* Cannot notify guest to shut itself down if it's in ACPI sleep state. */
if (si.flags & XCFLAGS_HVM)
xc_get_hvm_param(si.xch, si.domid,
HVM_PARAM_ACPI_S_STATE, &sx_state);
if ((sx_state == 0) && (si.suspend_evtchn >= 0))
return evtchn_suspend();
return compat_suspend();
}
/* For HVM guests, there are two sources of dirty pages: the Xen shadow
* log-dirty bitmap, which we get with a hypercall, and qemu's version.
* The protocol for getting page-dirtying data from qemu uses a
* double-buffered shared memory interface directly between xc_save and
* qemu-dm.
*
* xc_save calculates the size of the bitmaps and notifies qemu-dm
* through the store that it wants to share the bitmaps. qemu-dm then
* starts filling in the 'active' buffer.
*
* To change the buffers over, xc_save writes the other buffer number to
* the store and waits for qemu to acknowledge that it is now writing to
* the new active buffer. xc_save can then process and clear the old
* active buffer. */
static int switch_qemu_logdirty(int domid, unsigned int enable, void *data)
{
struct xs_handle *xs;
char *path, *p, *ret_str, *cmd_str, **watch;
unsigned int len;
struct timeval tv;
fd_set fdset;
if ((xs = xs_daemon_open()) == NULL)
errx(1, "Couldn't contact xenstore");
if (!(path = strdup("/local/domain/0/device-model/")))
errx(1, "can't get domain path in store");
if (!(path = realloc(path, strlen(path)
+ 10
+ strlen("/logdirty/cmd") + 1)))
errx(1, "no memory for constructing xenstore path");
snprintf(path + strlen(path), 11, "%i", domid);
strcat(path, "/logdirty/");
p = path + strlen(path);
/* Watch for qemu's return value */
strcpy(p, "ret");
if (!xs_watch(xs, path, "qemu-logdirty-ret"))
errx(1, "can't set watch in store (%s)\n", path);
if (!(cmd_str = strdup( enable == 0 ? "disable" : "enable")))
errx(1, "can't get logdirty cmd path in store");
/* Tell qemu that we want it to start logging dirty page to Xen */
strcpy(p, "cmd");
if (!xs_write(xs, XBT_NULL, path, cmd_str, strlen(cmd_str)))
errx(1, "can't write to store path (%s)\n",
path);
/* Wait a while for qemu to signal that it has service logdirty command */
read_again:
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_ZERO(&fdset);
FD_SET(xs_fileno(xs), &fdset);
if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1)
errx(1, "timed out waiting for qemu logdirty response.\n");
watch = xs_read_watch(xs, &len);
free(watch);
strcpy(p, "ret");
ret_str = xs_read(xs, XBT_NULL, path, &len);
if (ret_str == NULL || strcmp(ret_str, cmd_str))
/* Watch fired but value is not yet right */
goto read_again;
free(path);
free(cmd_str);
free(ret_str);
return 0;
}
int
main(int argc, char **argv)
{
unsigned int maxit, max_f, lflags;
int io_fd, ret, port;
struct save_callbacks callbacks;
xentoollog_level lvl;
xentoollog_logger *l;
if (argc != 6)
errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
io_fd = atoi(argv[1]);
si.domid = atoi(argv[2]);
maxit = atoi(argv[3]);
max_f = atoi(argv[4]);
si.flags = atoi(argv[5]);
si.suspend_evtchn = -1;
lvl = si.flags & XCFLAGS_DEBUG ? XTL_DEBUG: XTL_DETAIL;
lflags = XTL_STDIOSTREAM_SHOW_PID | XTL_STDIOSTREAM_HIDE_PROGRESS;
l = (xentoollog_logger *)xtl_createlogger_stdiostream(stderr, lvl, lflags);
si.xch = xc_interface_open(l, 0, 0);
if (!si.xch)
errx(1, "failed to open control interface");
si.xce = xc_evtchn_open(NULL, 0);
if (si.xce == NULL)
warnx("failed to open event channel handle");
else
{
port = xs_suspend_evtchn_port(si.domid);
if (port < 0)
warnx("failed to get the suspend evtchn port\n");
else
{
si.suspend_evtchn =
xc_suspend_evtchn_init(si.xch, si.xce, si.domid, port);
if (si.suspend_evtchn < 0)
warnx("suspend event channel initialization failed, "
"using slow path");
}
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.suspend = suspend;
callbacks.switch_qemu_logdirty = switch_qemu_logdirty;
ret = xc_domain_save(si.xch, io_fd, si.domid, maxit, max_f, si.flags,
&callbacks, !!(si.flags & XCFLAGS_HVM), 0);
if (si.suspend_evtchn > 0)
xc_suspend_evtchn_release(si.xch, si.xce, si.domid, si.suspend_evtchn);
if (si.xce > 0)
xc_evtchn_close(si.xce);
xc_interface_close(si.xch);
return ret;
}