f43e68d196
libvirt xen-4.4.0-testing-src.tar.bz2 - bnc#863297: xend/pvscsi: recognize also SCSI CDROM devices xend-pvscsi-recognize-also-SCSI-CDROM-devices.patch - fate#316614: set migration constraints from cmdline fix xl migrate to print the actual error string libxc-pass-errno-to-callers-of-xc_domain_save.patch - Include additional help docs for xl in xen-tools - Apply all patches including those for unpackaged xend xen.spec - fate#316614: set migration constraints from cmdline split existing changes into libxl and xend part added libxl.set-migration-constraints-from-cmdline.patch added xend-set-migration-constraints-from-cmdline.patch removed xen.migrate.tools_add_xm_migrate_--log_progress_option.patch removed xen.migrate.tools_set_number_of_dirty_pages_during_migration.patch removed xen.migrate.tools_set_migration_constraints_from_cmdline.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=299
367 lines
15 KiB
Diff
367 lines
15 KiB
Diff
From aa0cecb067ca6077c67cfc13f0ce31af7a3b72bb Mon Sep 17 00:00:00 2001
|
|
From: Olaf Hering <olaf@aepfle.de>
|
|
Date: Mon, 10 Feb 2014 09:43:40 +0100
|
|
Subject: xend: set migration constraints from cmdline
|
|
|
|
xend part of required libxl change to tweak parameters of xc_domain_save
|
|
|
|
Add xm migrate --log_progress option. xc_domain_save does print progress
|
|
messages. These verbose messages are disabled per default to avoid flood
|
|
in xend.log. Sometimes it is helpful to see progress when migrating
|
|
large and busy guests. So add a new option to xm migrate to actually
|
|
enable the printing of progress messsages.
|
|
|
|
Print messages from xc_save with xc_report. Make use of xc_report in
|
|
xc_save to log also pid if some error occoured.
|
|
|
|
Signed-off-by: Olaf Hering <olaf@aepfle.de>
|
|
---
|
|
tools/libxc/xc_private.h | 1 +
|
|
tools/libxc/xenguest.h | 1 +
|
|
tools/python/xen/xend/XendCheckpoint.py | 22 +++++++++-
|
|
tools/python/xen/xend/XendDomain.py | 14 ++++++
|
|
tools/python/xen/xend/XendDomainInfo.py | 16 +++++++
|
|
tools/python/xen/xm/migrate.py | 26 +++++++++++
|
|
tools/xcutils/xc_save.c | 76 +++++++++++++++++++++------------
|
|
7 files changed, 127 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
|
|
index 92271c9..947991a 100644
|
|
--- a/tools/libxc/xc_private.h
|
|
+++ b/tools/libxc/xc_private.h
|
|
@@ -119,6 +119,7 @@ void xc_report_progress_step(xc_interface *xch,
|
|
|
|
/* anamorphic macros: struct xc_interface *xch must be in scope */
|
|
|
|
+#define WPRINTF(_f, _a...) xc_report(xch, xch->error_handler, XTL_WARN,0, _f , ## _a)
|
|
#define IPRINTF(_f, _a...) xc_report(xch, xch->error_handler, XTL_INFO,0, _f , ## _a)
|
|
#define DPRINTF(_f, _a...) xc_report(xch, xch->error_handler, XTL_DETAIL,0, _f , ## _a)
|
|
#define DBGPRINTF(_f, _a...) xc_report(xch, xch->error_handler, XTL_DEBUG,0, _f , ## _a)
|
|
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
|
|
index fc255c7..172d98a 100644
|
|
--- a/tools/libxc/xenguest.h
|
|
+++ b/tools/libxc/xenguest.h
|
|
@@ -29,6 +29,7 @@
|
|
#define XCFLAGS_STDVGA (1 << 3)
|
|
#define XCFLAGS_CHECKPOINT_COMPRESS (1 << 4)
|
|
#define XCFLAGS_DOMSAVE_ABORT_IF_BUSY (1 << 5)
|
|
+#define XCFLAGS_PROGRESS (1 << 6)
|
|
|
|
#define X86_64_B_SIZE 64
|
|
#define X86_32_B_SIZE 32
|
|
diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py
|
|
index b8caf02..4233e49 100644
|
|
--- a/tools/python/xen/xend/XendCheckpoint.py
|
|
+++ b/tools/python/xen/xend/XendCheckpoint.py
|
|
@@ -118,9 +118,27 @@ def save(fd, dominfo, network, live, dst, checkpoint=False, node=-1,sock=None):
|
|
# enabled. Passing "0" simply uses the defaults compiled into
|
|
# libxenguest; see the comments and/or code in xc_linux_save() for
|
|
# more information.
|
|
+ max_iters = dominfo.info.get('max_iters', "0")
|
|
+ max_factor = dominfo.info.get('max_factor', "0")
|
|
+ min_remaining = dominfo.info.get('min_remaining', "0")
|
|
+ abort_if_busy = dominfo.info.get('abort_if_busy', "0")
|
|
+ log_save_progress = dominfo.info.get('log_save_progress', "0")
|
|
+ if max_iters == "None":
|
|
+ max_iters = "0"
|
|
+ if max_factor == "None":
|
|
+ max_factor = "0"
|
|
+ if min_remaining == "None":
|
|
+ min_remaining = "0"
|
|
+ if abort_if_busy == "None":
|
|
+ abort_if_busy = "0"
|
|
+ if log_save_progress == "None":
|
|
+ log_save_progress = "0"
|
|
cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(fd),
|
|
- str(dominfo.getDomid()), "0", "0",
|
|
- str(int(live) | (int(hvm) << 2)) ]
|
|
+ str(dominfo.getDomid()),
|
|
+ max_iters, max_factor,
|
|
+ str( int(live) | (int(hvm) << 2) | (int(abort_if_busy) << 5) | (int(log_save_progress) << 6) ),
|
|
+ min_remaining
|
|
+ ]
|
|
log.debug("[xc_save]: %s", string.join(cmd))
|
|
|
|
def saveInputHandler(line, tochild):
|
|
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
|
|
index 1d4da8f..6d873d6 100644
|
|
--- a/tools/python/xen/xend/XendDomain.py
|
|
+++ b/tools/python/xen/xend/XendDomain.py
|
|
@@ -1832,6 +1832,20 @@ class XendDomain:
|
|
log.exception(ex)
|
|
raise XendError(str(ex))
|
|
|
|
+ def domain_migrate_constraints_set(self, domid, max_iters, max_factor, min_remaining, abort_if_busy, log_save_progress):
|
|
+ """Set the Migrate Constraints of this domain.
|
|
+ @param domid: Domain ID or Name
|
|
+ @param max_iters: Number of iterations before final suspend
|
|
+ @param max_factor: Max amount of memory to transfer before final suspend
|
|
+ @param min_remaining: Number of dirty pages before final suspend
|
|
+ @param abort_if_busy: Abort migration instead of doing final suspend
|
|
+ @param log_save_progress: Log progress of migrate to xend.log
|
|
+ """
|
|
+ dominfo = self.domain_lookup_nr(domid)
|
|
+ if not dominfo:
|
|
+ raise XendInvalidDomain(str(domid))
|
|
+ dominfo.setMigrateConstraints(max_iters, max_factor, min_remaining, abort_if_busy, log_save_progress)
|
|
+
|
|
def domain_maxmem_set(self, domid, mem):
|
|
"""Set the memory limit for a domain.
|
|
|
|
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
|
|
index 8d4ff5c..f77b270 100644
|
|
--- a/tools/python/xen/xend/XendDomainInfo.py
|
|
+++ b/tools/python/xen/xend/XendDomainInfo.py
|
|
@@ -1461,6 +1461,22 @@ class XendDomainInfo:
|
|
pci_conf = self.info['devices'][dev_uuid][1]
|
|
return map(pci_dict_to_bdf_str, pci_conf['devs'])
|
|
|
|
+ def setMigrateConstraints(self, max_iters, max_factor, min_remaining, abort_if_busy, log_save_progress):
|
|
+ """Set the Migrate Constraints of this domain.
|
|
+ @param max_iters: Number of iterations before final suspend
|
|
+ @param max_factor: Max amount of memory to transfer before final suspend
|
|
+ @param min_remaining: Number of dirty pages before final suspend
|
|
+ @param abort_if_busy: Abort migration instead of doing final suspend
|
|
+ @param log_save_progress: Log progress of migrate to xend.log
|
|
+ """
|
|
+ log.debug("Setting migration constraints of domain %s (%s) to '%s' '%s' '%s' '%s'.",
|
|
+ self.info['name_label'], str(self.domid), max_iters, max_factor, min_remaining, abort_if_busy)
|
|
+ self.info['max_iters'] = str(max_iters)
|
|
+ self.info['max_factor'] = str(max_factor)
|
|
+ self.info['min_remaining'] = str(min_remaining)
|
|
+ self.info['abort_if_busy'] = str(abort_if_busy)
|
|
+ self.info['log_save_progress'] = str(log_save_progress)
|
|
+
|
|
def setMemoryTarget(self, target):
|
|
"""Set the memory target of this domain.
|
|
@param target: In MiB.
|
|
diff --git a/tools/python/xen/xm/migrate.py b/tools/python/xen/xm/migrate.py
|
|
index c1ea19d..c5c9500 100644
|
|
--- a/tools/python/xen/xm/migrate.py
|
|
+++ b/tools/python/xen/xm/migrate.py
|
|
@@ -55,6 +55,26 @@ gopts.opt('change_home_server', short='c',
|
|
fn=set_true, default=0,
|
|
use="Change home server for managed domains.")
|
|
|
|
+gopts.opt('max_iters', val='max_iters',
|
|
+ fn=set_int, default=0,
|
|
+ use="Number of iterations before final suspend (default: 30).")
|
|
+
|
|
+gopts.opt('max_factor', val='max_factor',
|
|
+ fn=set_int, default=0,
|
|
+ use="Max amount of memory to transfer before final suspend (default: 3*RAM).")
|
|
+
|
|
+gopts.opt('min_remaining', val='min_remaining',
|
|
+ fn=set_int, default=0,
|
|
+ use="Number of dirty pages before final suspend (default: 50).")
|
|
+
|
|
+gopts.opt('abort_if_busy',
|
|
+ fn=set_true, default=0,
|
|
+ use="Abort migration instead of doing final suspend.")
|
|
+
|
|
+gopts.opt('log_progress',
|
|
+ fn=set_true, default=0,
|
|
+ use="Log progress of migration to xend.log")
|
|
+
|
|
def help():
|
|
return str(gopts)
|
|
|
|
@@ -80,6 +100,12 @@ def main(argv):
|
|
server.xenapi.VM.migrate(vm_ref, dst, bool(opts.vals.live),
|
|
other_config)
|
|
else:
|
|
+ server.xend.domain.migrate_constraints_set(dom,
|
|
+ opts.vals.max_iters,
|
|
+ opts.vals.max_factor,
|
|
+ opts.vals.min_remaining,
|
|
+ opts.vals.abort_if_busy,
|
|
+ opts.vals.log_progress)
|
|
server.xend.domain.migrate(dom, dst, opts.vals.live,
|
|
opts.vals.port,
|
|
opts.vals.node,
|
|
diff --git a/tools/xcutils/xc_save.c b/tools/xcutils/xc_save.c
|
|
index e34bd2c..08ad224 100644
|
|
--- a/tools/xcutils/xc_save.c
|
|
+++ b/tools/xcutils/xc_save.c
|
|
@@ -7,6 +7,7 @@
|
|
*
|
|
*/
|
|
|
|
+#include <unistd.h>
|
|
#include <err.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
@@ -19,6 +20,7 @@
|
|
#include <fcntl.h>
|
|
#include <err.h>
|
|
|
|
+#include <xc_private.h>
|
|
#include <xenstore.h>
|
|
#include <xenctrl.h>
|
|
#include <xenguest.h>
|
|
@@ -51,16 +53,17 @@ static int compat_suspend(void)
|
|
* receive the acknowledgement from the subscribe event channel. */
|
|
static int evtchn_suspend(void)
|
|
{
|
|
+ xc_interface *xch = si.xch;
|
|
int rc;
|
|
|
|
rc = xc_evtchn_notify(si.xce, si.suspend_evtchn);
|
|
if (rc < 0) {
|
|
- warnx("failed to notify suspend request channel: %d", rc);
|
|
+ WPRINTF("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");
|
|
+ if (xc_await_suspend(xch, si.xce, si.suspend_evtchn) < 0) {
|
|
+ WPRINTF("suspend failed");
|
|
return 0;
|
|
}
|
|
|
|
@@ -104,20 +107,27 @@ static int suspend(void* data)
|
|
|
|
static int switch_qemu_logdirty(int domid, unsigned int enable, void *data)
|
|
{
|
|
+ xc_interface *xch = si.xch;
|
|
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 ((xs = xs_daemon_open()) == NULL) {
|
|
+ PERROR("Couldn't contact xenstore");
|
|
+ exit(1);
|
|
+ }
|
|
+ if (!(path = strdup("/local/domain/0/device-model/"))) {
|
|
+ PERROR("can't get domain path in store");
|
|
+ exit(1);
|
|
+ }
|
|
if (!(path = realloc(path, strlen(path)
|
|
+ 10
|
|
- + strlen("/logdirty/cmd") + 1)))
|
|
- errx(1, "no memory for constructing xenstore path");
|
|
+ + strlen("/logdirty/cmd") + 1))) {
|
|
+ PERROR("no memory for constructing xenstore path");
|
|
+ exit(1);
|
|
+ }
|
|
snprintf(path + strlen(path), 11, "%i", domid);
|
|
strcat(path, "/logdirty/");
|
|
p = path + strlen(path);
|
|
@@ -126,16 +136,22 @@ static int switch_qemu_logdirty(int domid, unsigned int enable, void *data)
|
|
/* 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);
|
|
+ {
|
|
+ ERROR("can't set watch in store (%s)\n", path);
|
|
+ exit(1);
|
|
+ }
|
|
|
|
- if (!(cmd_str = strdup( enable == 0 ? "disable" : "enable")))
|
|
- errx(1, "can't get logdirty cmd path in store");
|
|
+ if (!(cmd_str = strdup( enable == 0 ? "disable" : "enable"))) {
|
|
+ PERROR("can't get logdirty cmd path in store");
|
|
+ exit(1);
|
|
+ }
|
|
|
|
/* 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);
|
|
+ if (!xs_write(xs, XBT_NULL, path, cmd_str, strlen(cmd_str))) {
|
|
+ PERROR("can't write to store path (%s)\n", path);
|
|
+ exit(1);
|
|
+ }
|
|
|
|
/* Wait a while for qemu to signal that it has service logdirty command */
|
|
read_again:
|
|
@@ -144,8 +160,10 @@ static int switch_qemu_logdirty(int domid, unsigned int enable, void *data)
|
|
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");
|
|
+ if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) {
|
|
+ PERROR("timed out waiting for qemu logdirty response.\n");
|
|
+ exit(1);
|
|
+ }
|
|
|
|
watch = xs_read_watch(xs, &len);
|
|
free(watch);
|
|
@@ -166,53 +184,57 @@ static int switch_qemu_logdirty(int domid, unsigned int enable, void *data)
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
- unsigned int maxit, max_f, lflags;
|
|
+ xc_interface *xch;
|
|
+ unsigned int maxit, max_f, lflags, min_r;
|
|
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]);
|
|
+ if (argc != 7)
|
|
+ errx(1, "usage: %s iofd domid maxit maxf flags minr", 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]);
|
|
+ min_r = atoi(argv[6]);
|
|
|
|
si.suspend_evtchn = -1;
|
|
|
|
lvl = si.flags & XCFLAGS_DEBUG ? XTL_DEBUG: XTL_DETAIL;
|
|
- lflags = XTL_STDIOSTREAM_SHOW_PID | XTL_STDIOSTREAM_HIDE_PROGRESS;
|
|
+ lflags = XTL_STDIOSTREAM_SHOW_PID;
|
|
+ if (si.flags & XCFLAGS_PROGRESS)
|
|
+ lflags |= XTL_STDIOSTREAM_HIDE_PROGRESS;
|
|
l = (xentoollog_logger *)xtl_createlogger_stdiostream(stderr, lvl, lflags);
|
|
- si.xch = xc_interface_open(l, 0, 0);
|
|
+ xch = si.xch = xc_interface_open(l, 0, 0);
|
|
if (!si.xch)
|
|
- errx(1, "failed to open control interface");
|
|
+ errx(1, "[%lu] failed to open control interface", (unsigned long)getpid());
|
|
|
|
si.xce = xc_evtchn_open(NULL, 0);
|
|
if (si.xce == NULL)
|
|
- warnx("failed to open event channel handle");
|
|
+ WPRINTF("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");
|
|
+ WPRINTF("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, "
|
|
+ WPRINTF("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,
|
|
+ ret = xc_domain_save_suse(si.xch, io_fd, si.domid, maxit, max_f, min_r, si.flags,
|
|
&callbacks, !!(si.flags & XCFLAGS_HVM), 0);
|
|
|
|
if (si.suspend_evtchn > 0)
|