ia64/xen-unstable

view tools/python/xen/xend/XendCheckpoint.py @ 9808:83b092a2cbe6

The attached patch replaces the current numbers identifying the
individual steps of device migration with constants.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author emellor@leeni.uk.xensource.com
date Fri Apr 21 11:57:34 2006 +0100 (2006-04-21)
parents 1fe63743a147
children 36e0159c001b
line source
1 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
2 # Copyright (C) 2005 XenSource Ltd
4 # This file is subject to the terms and conditions of the GNU General
5 # Public License. See the file "COPYING" in the main directory of
6 # this archive for more details.
8 import os
9 import re
10 import string
11 import sxp
12 import threading
13 from struct import pack, unpack, calcsize
15 from xen.util.xpopen import xPopen3
17 import xen.util.auxbin
19 import xen.lowlevel.xc
21 import balloon
22 from XendError import XendError
23 from XendLogging import log
24 from XendDomainInfo import DEV_MIGRATE_STEP1, DEV_MIGRATE_STEP2
25 from XendDomainInfo import DEV_MIGRATE_STEP3
27 SIGNATURE = "LinuxGuestRecord"
28 XC_SAVE = "xc_save"
29 XC_RESTORE = "xc_restore"
32 sizeof_int = calcsize("i")
33 sizeof_unsigned_long = calcsize("L")
36 xc = xen.lowlevel.xc.xc()
39 def write_exact(fd, buf, errmsg):
40 if os.write(fd, buf) != len(buf):
41 raise XendError(errmsg)
43 def read_exact(fd, size, errmsg):
44 buf = ''
45 while size != 0:
46 str = os.read(fd, size)
47 if not len(str):
48 log.error("read_exact: EOF trying to read %d (buf='%s')" % \
49 (size, buf))
50 raise XendError(errmsg)
51 size = size - len(str)
52 buf = buf + str
53 return buf
57 def save(fd, dominfo, live, dst):
58 write_exact(fd, SIGNATURE, "could not write guest state file: signature")
60 config = sxp.to_string(dominfo.sxpr())
62 domain_name = dominfo.getName()
63 # Rename the domain temporarily, so that we don't get a name clash if this
64 # domain is migrating (live or non-live) to the local host. Doing such a
65 # thing is useful for debugging.
66 dominfo.setName('migrating-' + domain_name)
68 try:
69 dominfo.migrateDevices(live, dst, DEV_MIGRATE_STEP1, domain_name)
71 write_exact(fd, pack("!i", len(config)),
72 "could not write guest state file: config len")
73 write_exact(fd, config, "could not write guest state file: config")
75 # xc_save takes three customization parameters: maxit, max_f, and
76 # flags the last controls whether or not save is 'live', while the
77 # first two further customize behaviour when 'live' save is
78 # enabled. Passing "0" simply uses the defaults compiled into
79 # libxenguest; see the comments and/or code in xc_linux_save() for
80 # more information.
81 cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(xc.handle()), str(fd),
82 str(dominfo.getDomid()), "0", "0", str(int(live)) ]
83 log.debug("[xc_save]: %s", string.join(cmd))
85 def saveInputHandler(line, tochild):
86 log.debug("In saveInputHandler %s", line)
87 if line == "suspend":
88 log.debug("Suspending %d ...", dominfo.getDomid())
89 dominfo.shutdown('suspend')
90 dominfo.waitForShutdown()
91 dominfo.migrateDevices(live, dst, DEV_MIGRATE_STEP2,
92 domain_name)
93 log.info("Domain %d suspended.", dominfo.getDomid())
94 dominfo.migrateDevices(live, dst, DEV_MIGRATE_STEP3,
95 domain_name)
96 tochild.write("done\n")
97 tochild.flush()
98 log.debug('Written done')
100 forkHelper(cmd, fd, saveInputHandler, False)
102 dominfo.destroyDomain()
104 except Exception, exn:
105 log.exception("Save failed on domain %s (%d).", domain_name,
106 dominfo.getDomid())
107 try:
108 dominfo.setName(domain_name)
109 except:
110 log.exception("Failed to reset the migrating domain's name")
111 raise Exception, exn
114 def restore(xd, fd):
115 signature = read_exact(fd, len(SIGNATURE),
116 "not a valid guest state file: signature read")
117 if signature != SIGNATURE:
118 raise XendError("not a valid guest state file: found '%s'" %
119 signature)
121 l = read_exact(fd, sizeof_int,
122 "not a valid guest state file: config size read")
123 vmconfig_size = unpack("!i", l)[0]
124 vmconfig_buf = read_exact(fd, vmconfig_size,
125 "not a valid guest state file: config read")
127 p = sxp.Parser()
128 p.input(vmconfig_buf)
129 if not p.ready:
130 raise XendError("not a valid guest state file: config parse")
132 vmconfig = p.get_val()
134 dominfo = xd.restore_(vmconfig)
136 store_port = dominfo.getStorePort()
137 console_port = dominfo.getConsolePort()
139 assert store_port
140 assert console_port
142 try:
143 l = read_exact(fd, sizeof_unsigned_long,
144 "not a valid guest state file: pfn count read")
145 nr_pfns = unpack("L", l)[0] # native sizeof long
146 if nr_pfns > 16*1024*1024: # XXX
147 raise XendError(
148 "not a valid guest state file: pfn count out of range")
150 balloon.free(xc.pages_to_kib(nr_pfns))
152 cmd = map(str, [xen.util.auxbin.pathTo(XC_RESTORE),
153 xc.handle(), fd, dominfo.getDomid(), nr_pfns,
154 store_port, console_port])
155 log.debug("[xc_restore]: %s", string.join(cmd))
157 handler = RestoreInputHandler()
159 forkHelper(cmd, fd, handler.handler, True)
161 if handler.store_mfn is None or handler.console_mfn is None:
162 raise XendError('Could not read store/console MFN')
164 dominfo.unpause()
166 dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
168 return dominfo
169 except:
170 dominfo.destroy()
171 raise
174 class RestoreInputHandler:
175 def __init__(self):
176 self.store_mfn = None
177 self.console_mfn = None
180 def handler(self, line, _):
181 m = re.match(r"^(store-mfn) (\d+)$", line)
182 if m:
183 self.store_mfn = int(m.group(2))
184 else:
185 m = re.match(r"^(console-mfn) (\d+)$", line)
186 if m:
187 self.console_mfn = int(m.group(2))
190 def forkHelper(cmd, fd, inputHandler, closeToChild):
191 child = xPopen3(cmd, True, -1, [fd, xc.handle()])
193 if closeToChild:
194 child.tochild.close()
196 thread = threading.Thread(target = slurp, args = (child.childerr,))
197 thread.start()
199 try:
200 try:
201 while 1:
202 line = child.fromchild.readline()
203 if line == "":
204 break
205 else:
206 line = line.rstrip()
207 log.debug('%s', line)
208 inputHandler(line, child.tochild)
210 thread.join()
212 except IOError, exn:
213 raise XendError('Error reading from child process for %s: %s' %
214 (cmd, exn))
215 finally:
216 child.fromchild.close()
217 child.childerr.close()
218 if not closeToChild:
219 child.tochild.close()
221 status = child.wait()
222 if status >> 8 == 127:
223 raise XendError("%s failed: popen failed" % string.join(cmd))
224 elif status != 0:
225 raise XendError("%s failed" % string.join(cmd))
228 def slurp(infile):
229 while 1:
230 line = infile.readline()
231 if line == "":
232 break
233 else:
234 log.error('%s', line.strip())