mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[HVM] Control qemu's state-save via xenstore, instead of SIGUSR1
This lets us verify that qemu has indeed stopped processing before we start saving guest memory. Also allow qemu to continue processing after the save has happened, instead of exiting immediately. Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
This commit is contained in:
1 parent
ab3a30feef
commit
f6c12fc6b6
8 files changed
+132
-50
No files matched your search
@@ -98,10 +98,6 @@ def save(fd, dominfo, network, live, dst, checkpoint=False):
|
||||
log.info("Domain %d suspended.", dominfo.getDomid())
|
||||
dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP3,
|
||||
domain_name)
|
||||
#send signal to device model for save
|
||||
if hvm:
|
||||
log.info("release_devices for hvm domain")
|
||||
dominfo._releaseDevices(True)
|
||||
tochild.write("done\n")
|
||||
tochild.flush()
|
||||
log.debug('Written done')
|
||||
@@ -139,7 +135,7 @@ def save(fd, dominfo, network, live, dst, checkpoint=False):
|
||||
except Exception, exn:
|
||||
log.exception("Save failed on domain %s (%s).", domain_name,
|
||||
dominfo.getDomid())
|
||||
|
||||
|
||||
dominfo.resumeDomain()
|
||||
log.debug("XendCheckpoint.save: resumeDomain")
|
||||
|
||||
|
||||
@@ -1122,6 +1122,8 @@ class XendDomainInfo:
|
||||
self._clearRestart()
|
||||
|
||||
if reason == 'suspend':
|
||||
if self._stateGet() != DOM_STATE_SUSPENDED:
|
||||
self.image.saveDeviceModel()
|
||||
self._stateSet(DOM_STATE_SUSPENDED)
|
||||
# Don't destroy the domain. XendCheckpoint will do
|
||||
# this once it has finished. However, stop watching
|
||||
@@ -1764,6 +1766,9 @@ class XendDomainInfo:
|
||||
ResumeDomain(self.domid)
|
||||
except:
|
||||
log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid)))
|
||||
if self.is_hvm():
|
||||
self.image.resumeDeviceModel()
|
||||
|
||||
|
||||
#
|
||||
# Channels for xenstore and console
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import os, string
|
||||
import re
|
||||
import math
|
||||
import time
|
||||
import signal
|
||||
|
||||
import xen.lowlevel.xc
|
||||
@@ -27,6 +28,7 @@ from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS
|
||||
from xen.xend.XendError import VmError, XendError, HVMRequired
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend.XendOptions import instance as xenopts
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
from xen.xend.xenstore.xswatch import xswatch
|
||||
from xen.xend import arch
|
||||
|
||||
@@ -175,6 +177,14 @@ class ImageHandler:
|
||||
"""Create device model for the domain (define in subclass if needed)."""
|
||||
pass
|
||||
|
||||
def saveDeviceModel(self):
|
||||
"""Save device model for the domain (define in subclass if needed)."""
|
||||
pass
|
||||
|
||||
def resumeDeviceModel(self):
|
||||
"""Unpause device model for the domain (define in subclass if needed)."""
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
"""Extra cleanup on domain destroy (define in subclass if needed)."""
|
||||
pass
|
||||
@@ -443,17 +453,34 @@ class HVMImageHandler(ImageHandler):
|
||||
self.vm.storeDom("image/device-model-pid", self.pid)
|
||||
log.info("device model pid: %d", self.pid)
|
||||
|
||||
def saveDeviceModel(self):
|
||||
# Signal the device model to pause itself and save its state
|
||||
xstransact.Store("/local/domain/0/device-model/%i"
|
||||
% self.vm.getDomid(), ('command', 'save'))
|
||||
# Wait for confirmation. Could do this with a watch but we'd
|
||||
# still end up spinning here waiting for the watch to fire.
|
||||
state = ''
|
||||
count = 0
|
||||
while state != 'paused':
|
||||
state = xstransact.Read("/local/domain/0/device-model/%i/state"
|
||||
% self.vm.getDomid())
|
||||
time.sleep(0.1)
|
||||
count += 1
|
||||
if count > 100:
|
||||
raise VmError('Timed out waiting for device model to save')
|
||||
|
||||
def resumeDeviceModel(self):
|
||||
# Signal the device model to resume activity after pausing to save.
|
||||
xstransact.Store("/local/domain/0/device-model/%i"
|
||||
% self.vm.getDomid(), ('command', 'continue'))
|
||||
|
||||
def recreate(self):
|
||||
self.pid = self.vm.gatherDom(('image/device-model-pid', int))
|
||||
|
||||
def destroy(self, suspend = False):
|
||||
if self.pid:
|
||||
if self.pid and not suspend:
|
||||
try:
|
||||
sig = signal.SIGKILL
|
||||
if suspend:
|
||||
log.info("use sigusr1 to signal qemu %d", self.pid)
|
||||
sig = signal.SIGUSR1
|
||||
os.kill(self.pid, sig)
|
||||
os.kill(self.pid, signal.SIGKILL)
|
||||
except OSError, exn:
|
||||
log.exception(exn)
|
||||
try:
|
||||
@@ -464,6 +491,8 @@ class HVMImageHandler(ImageHandler):
|
||||
# but we can't wait for it because it's not our child.
|
||||
pass
|
||||
self.pid = None
|
||||
state = xstransact.Remove("/local/domain/0/device-model/%i"
|
||||
% self.vm.getDomid())
|
||||
|
||||
|
||||
class IA64_HVM_ImageHandler(HVMImageHandler):
|
||||
@@ -507,6 +536,7 @@ class X86_HVM_ImageHandler(HVMImageHandler):
|
||||
return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)),
|
||||
shadow_mem_kb)
|
||||
|
||||
|
||||
class X86_Linux_ImageHandler(LinuxImageHandler):
|
||||
|
||||
def buildDomain(self):
|
||||
|
||||