Start xenpaging via config option. TODO: add config option for different pagefile directory TODO: add libxl support TODO: parse config values like 42K, 42M, 42G, 42% Signed-off-by: Olaf Hering --- v3: move debug for stopping xenpaging to destroyXenPaging v2: unlink logfile instead of truncating it. allows hardlinking for further inspection tools/examples/xmexample.hvm | 3 + tools/python/README.XendConfig | 1 tools/python/README.sxpcfg | 1 tools/python/xen/xend/XendConfig.py | 3 + tools/python/xen/xend/XendDomainInfo.py | 5 + tools/python/xen/xend/image.py | 87 ++++++++++++++++++++++++++++++++ tools/python/xen/xm/create.py | 5 + tools/python/xen/xm/xenapi_create.py | 1 8 files changed, 106 insertions(+) --- xen-unstable.hg-4.1.22571.orig/tools/examples/xmexample.hvm +++ xen-unstable.hg-4.1.22571/tools/examples/xmexample.hvm @@ -127,6 +127,9 @@ disk = [ 'file:/var/images/min-el3-i386. # Device Model to be used device_model = 'qemu-dm' +# xenpaging, number of pages, or -1 for entire guest memory range +xenpaging = 42 + #----------------------------------------------------------------------------- # boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) # default: hard disk, cd-rom, floppy --- xen-unstable.hg-4.1.22571.orig/tools/python/README.XendConfig +++ xen-unstable.hg-4.1.22571/tools/python/README.XendConfig @@ -120,6 +120,7 @@ otherConfig image.vncdisplay image.vncunused image.hvm.device_model + image.hvm.xenpaging image.hvm.display image.hvm.xauthority image.hvm.vncconsole --- xen-unstable.hg-4.1.22571.orig/tools/python/README.sxpcfg +++ xen-unstable.hg-4.1.22571/tools/python/README.sxpcfg @@ -51,6 +51,7 @@ image - vncunused (HVM) - device_model + - xenpaging - display - xauthority - vncconsole --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendConfig.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendConfig.py @@ -147,6 +147,7 @@ XENAPI_PLATFORM_CFG_TYPES = { 'apic': int, 'boot': str, 'device_model': str, + 'xenpaging': int, 'loader': str, 'display' : str, 'fda': str, @@ -508,6 +509,8 @@ class XendConfig(dict): self['platform']['nomigrate'] = 0 if self.is_hvm(): + if 'xenpaging' not in self['platform']: + self['platform']['xenpaging'] = None if 'timer_mode' not in self['platform']: self['platform']['timer_mode'] = 1 if 'viridian' not in self['platform']: --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendDomainInfo.py @@ -2390,6 +2390,7 @@ class XendDomainInfo: if self.image: self.image.createDeviceModel() + self.image.createXenPaging() #if have pass-through devs, need the virtual pci slots info from qemu self.pci_device_configure_boot() @@ -2402,6 +2403,10 @@ class XendDomainInfo: self.image.destroyDeviceModel() except Exception, e: log.exception("Device model destroy failed %s" % str(e)) + try: + self.image.destroyXenPaging() + except Exception, e: + log.exception("stopping xenpaging failed %s" % str(e)) else: log.debug("No device model") --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/image.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/image.py @@ -122,12 +122,16 @@ class ImageHandler: self.vm.permissionsVm("image/cmdline", { 'dom': self.vm.getDomid(), 'read': True } ) self.device_model = vmConfig['platform'].get('device_model') + self.xenpaging = vmConfig['platform'].get('xenpaging') + if self.xenpaging == 0: + self.xenpaging = None self.display = vmConfig['platform'].get('display') self.xauthority = vmConfig['platform'].get('xauthority') self.vncconsole = int(vmConfig['platform'].get('vncconsole', 0)) self.dmargs = self.parseDeviceModelArgs(vmConfig) self.pid = None + self.xenpaging_pid = None rtc_timeoffset = int(vmConfig['platform'].get('rtc_timeoffset', 0)) if int(vmConfig['platform'].get('localtime', 0)): if time.localtime(time.time())[8]: @@ -392,6 +396,89 @@ class ImageHandler: sentinel_fifos_inuse[sentinel_path_fifo] = 1 self.sentinel_path_fifo = sentinel_path_fifo + def createXenPaging(self): + if self.xenpaging is None: + return + if self.xenpaging_pid: + return + xenpaging_bin = auxbin.pathTo("xenpaging") + args = [xenpaging_bin] + args = args + ([ "%d" % self.vm.getDomid()]) + args = args + ([ "%s" % self.xenpaging]) + env = dict(os.environ) + self.xenpaging_logfile = "/var/log/xen/xenpaging-%s.log" % str(self.vm.info['name_label']) + logfile_mode = os.O_WRONLY|os.O_CREAT|os.O_APPEND|os.O_TRUNC + null = os.open("/dev/null", os.O_RDONLY) + try: + os.unlink(self.xenpaging_logfile) + except: + pass + logfd = os.open(self.xenpaging_logfile, logfile_mode, 0644) + sys.stderr.flush() + contract = osdep.prefork("%s:%d" % (self.vm.getName(), self.vm.getDomid())) + xenpaging_pid = os.fork() + if xenpaging_pid == 0: #child + try: + xenpaging_dir = "/var/lib/xen/xenpaging" + osdep.postfork(contract) + os.dup2(null, 0) + os.dup2(logfd, 1) + os.dup2(logfd, 2) + try: + os.chdir(xenpaging_dir) + except: + log.warn("chdir %s failed" % xenpaging_dir) + try: + log.info("starting %s" % args) + os.execve(xenpaging_bin, args, env) + except Exception, e: + print >>sys.stderr, ( + 'failed to execute xenpaging: %s: %s' % + xenpaging_bin, utils.exception_string(e)) + os._exit(126) + except Exception, e: + log.warn("staring xenpaging in %s failed" % xenpaging_dir) + os._exit(127) + else: + osdep.postfork(contract, abandon=True) + self.xenpaging_pid = xenpaging_pid + os.close(null) + os.close(logfd) + + def destroyXenPaging(self): + if self.xenpaging is None: + return + log.debug("stopping xenpaging") + if self.xenpaging_pid: + try: + os.kill(self.xenpaging_pid, signal.SIGHUP) + except OSError, exn: + log.exception(exn) + for i in xrange(100): + try: + (p, rv) = os.waitpid(self.xenpaging_pid, os.WNOHANG) + if p == self.xenpaging_pid: + break + except OSError: + # This is expected if Xend has been restarted within + # the life of this domain. In this case, we can kill + # the process, but we can't wait for it because it's + # not our child. We continue this loop, and after it is + # terminated make really sure the process is going away + # (SIGKILL). + pass + time.sleep(0.1) + else: + log.warning("xenpaging %d took more than 10s " + "to terminate: sending SIGKILL" % self.xenpaging_pid) + try: + os.kill(self.xenpaging_pid, signal.SIGKILL) + os.waitpid(self.xenpaging_pid, 0) + except OSError: + # This happens if the process doesn't exist. + pass + self.xenpaging_pid = None + def createDeviceModel(self, restore = False): if self.device_model is None: return --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/create.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/create.py @@ -491,6 +491,10 @@ gopts.var('nfs_root', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") +gopts.var('xenpaging', val='NUM', + fn=set_int, default=None, + use="Number of pages to swap.") + gopts.var('device_model', val='FILE', fn=set_value, default=None, use="Path to device model program.") @@ -1076,6 +1080,7 @@ def configure_hvm(config_image, vals): args = [ 'acpi', 'apic', 'boot', 'cpuid', 'cpuid_check', + 'xenpaging', 'device_model', 'display', 'fda', 'fdb', 'gfx_passthru', 'guest_os_type', --- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/xenapi_create.py +++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/xenapi_create.py @@ -1085,6 +1085,7 @@ class sxp2xml: 'acpi', 'apic', 'boot', + 'xenpaging', 'device_model', 'loader', 'fda',