user: Olaf Hering date: Wed Mar 06 17:05:14 2013 +0100 files: docs/man/xl.pod.1 tools/libxc/xc_domain_save.c tools/libxc/xenguest.h tools/libxl/Makefile tools/libxl/libxl.c tools/libxl/libxl.h tools/libxl/libxl_dom.c tools/libxl/libxl_internal.h tools/libxl/libxl_save_callout.c tools/libxl/xl_cmdimpl.c tools/libxl/xl_cmdtable.c tools/python/xen/xend/XendCheckpoint.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xm/migrate.py description: tools: set migration constraints from cmdline Add new options to xm/xl migrate to control the process of migration. The intention is to optionally abort the migration if it takes too long to migrate a busy guest due to the high number of dirty pages. Currently the guest is suspended to transfer the remaining dirty pages. This transfer can take too long, which can confuse the guest if its suspended for too long. -M Number of iterations before final suspend (default: 30) --max_iters -m Max amount of memory to transfer before final suspend (default: 3*RAM) --max_factor -A Abort migration instead of doing final suspend. --abort_if_busy The changes to libxl change the API, handle LIBXL_API_VERSION == 0x040200. TODO: eventually add also --min_remaining (default value 50) in a seperate patch v6: - update the LIBXL_API_VERSION handling for libxl_domain_suspend change it to an inline function if LIBXL_API_VERSION is defined to 4.2.0 - rename libxl_save_properties to libxl_domain_suspend_properties - rename ->xlflags to ->flags within that struct v5: - adjust libxl_domain_suspend prototype, move flags, max_iters, max_factor into a new, optional struct libxl_save_properties - rename XCFLAGS_DOMSAVE_NOSUSPEND to XCFLAGS_DOMSAVE_ABORT_IF_BUSY - rename LIBXL_SUSPEND_NO_FINAL_SUSPEND to LIBXL_SUSPEND_ABORT_IF_BUSY - rename variables no_suspend to abort_if_busy - rename option -N/--no_suspend to -A/--abort_if_busy - update xl.1, extend description of -A option v4: - update default for no_suspend from None to 0 in XendCheckpoint.py:save - update logoutput in setMigrateConstraints - change xm migrate defaults from None to 0 - add new options to xl.1 - fix syntax error in XendDomain.py:domain_migrate_constraints_set - fix xm migrate -N option name to match xl migrate v3: - move logic errors in libxl__domain_suspend and fixed help text in cmd_table to separate patches - fix syntax error in XendCheckpoint.py - really pass max_iters and max_factor in libxl__xc_domain_save - make libxl_domain_suspend_0x040200 declaration globally visible - bump libxenlight.so SONAME from 2.0 to 2.1 due to changed libxl_domain_suspend v2: - use LIBXL_API_VERSION and define libxl_domain_suspend_0x040200 - fix logic error in min_reached check in xc_domain_save - add longopts - update --help text - correct description of migrate --help text Signed-off-by: Olaf Hering --- tools/libxc/xc_domain_save.c | 13 ++++++++++++- tools/libxc/xenguest.h | 1 + tools/python/xen/xend/XendCheckpoint.py | 14 ++++++++++++-- tools/python/xen/xend/XendDomain.py | 12 ++++++++++++ tools/python/xen/xend/XendDomainInfo.py | 12 ++++++++++++ tools/python/xen/xm/migrate.py | 16 ++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) Index: xen-4.4.0-testing/tools/libxc/xc_domain_save.c =================================================================== --- xen-4.4.0-testing.orig/tools/libxc/xc_domain_save.c +++ xen-4.4.0-testing/tools/libxc/xc_domain_save.c @@ -809,6 +809,7 @@ int xc_domain_save(xc_interface *xch, in int rc = 1, frc, i, j, last_iter = 0, iter = 0; int live = (flags & XCFLAGS_LIVE); int debug = (flags & XCFLAGS_DEBUG); + int abort_if_busy = (flags & XCFLAGS_DOMSAVE_ABORT_IF_BUSY); int superpages = !!hvm; int race = 0, sent_last_iter, skip_this_iter = 0; unsigned int sent_this_iter = 0; @@ -1532,10 +1533,20 @@ int xc_domain_save(xc_interface *xch, in if ( live ) { + int min_reached = sent_this_iter + skip_this_iter < 50; if ( (iter >= max_iters) || - (sent_this_iter+skip_this_iter < 50) || + min_reached || (total_sent > dinfo->p2m_size*max_factor) ) { + if ( !min_reached && abort_if_busy ) + { + ERROR("Live migration aborted, as requested. (guest too busy?)" + " total_sent %lu iter %d, max_iters %u max_factor %u", + total_sent, iter, max_iters, max_factor); + rc = 1; + goto out; + } + DPRINTF("Start last iteration\n"); last_iter = 1; Index: xen-4.4.0-testing/tools/libxc/xenguest.h =================================================================== --- xen-4.4.0-testing.orig/tools/libxc/xenguest.h +++ xen-4.4.0-testing/tools/libxc/xenguest.h @@ -28,6 +28,7 @@ #define XCFLAGS_HVM (1 << 2) #define XCFLAGS_STDVGA (1 << 3) #define XCFLAGS_CHECKPOINT_COMPRESS (1 << 4) +#define XCFLAGS_DOMSAVE_ABORT_IF_BUSY (1 << 5) #define X86_64_B_SIZE 64 #define X86_32_B_SIZE 32 Index: xen-4.4.0-testing/tools/python/xen/xend/XendCheckpoint.py =================================================================== --- xen-4.4.0-testing.orig/tools/python/xen/xend/XendCheckpoint.py +++ xen-4.4.0-testing/tools/python/xen/xend/XendCheckpoint.py @@ -118,9 +118,19 @@ def save(fd, dominfo, network, live, dst # 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") + abort_if_busy = dominfo.info.get('abort_if_busy', "0") + if max_iters == "None": + max_iters = "0" + if max_factor == "None": + max_factor = "0" + if abort_if_busy == "None": + abort_if_busy = "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) ) ] log.debug("[xc_save]: %s", string.join(cmd)) def saveInputHandler(line, tochild): Index: xen-4.4.0-testing/tools/python/xen/xend/XendDomain.py =================================================================== --- xen-4.4.0-testing.orig/tools/python/xen/xend/XendDomain.py +++ xen-4.4.0-testing/tools/python/xen/xend/XendDomain.py @@ -1832,6 +1832,18 @@ class XendDomain: log.exception(ex) raise XendError(str(ex)) + def domain_migrate_constraints_set(self, domid, max_iters, max_factor, abort_if_busy): + """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 abort_if_busy: Abort migration instead of doing final suspend + """ + dominfo = self.domain_lookup_nr(domid) + if not dominfo: + raise XendInvalidDomain(str(domid)) + dominfo.setMigrateConstraints(max_iters, max_factor, abort_if_busy) + def domain_maxmem_set(self, domid, mem): """Set the memory limit for a domain. Index: xen-4.4.0-testing/tools/python/xen/xend/XendDomainInfo.py =================================================================== --- xen-4.4.0-testing.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-4.4.0-testing/tools/python/xen/xend/XendDomainInfo.py @@ -1475,6 +1475,18 @@ class XendDomainInfo: break xen.xend.XendDomain.instance().managed_config_save(self) + def setMigrateConstraints(self, max_iters, max_factor, abort_if_busy): + """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 abort_if_busy: Abort migration instead of doing final suspend + """ + log.debug("Setting migration constraints of domain %s (%s) to '%s' '%s' '%s'.", + self.info['name_label'], str(self.domid), max_iters, max_factor, abort_if_busy) + self.info['max_iters'] = str(max_iters) + self.info['max_factor'] = str(max_factor) + self.info['abort_if_busy'] = str(abort_if_busy) + def setMemoryTarget(self, target): """Set the memory target of this domain. @param target: In MiB. Index: xen-4.4.0-testing/tools/python/xen/xm/migrate.py =================================================================== --- xen-4.4.0-testing.orig/tools/python/xen/xm/migrate.py +++ xen-4.4.0-testing/tools/python/xen/xm/migrate.py @@ -55,6 +55,18 @@ 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('abort_if_busy', + fn=set_true, default=0, + use="Abort migration instead of doing final suspend.") + def help(): return str(gopts) @@ -80,6 +92,10 @@ 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.abort_if_busy) server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.port, opts.vals.node,