ia64/xen-unstable

view tools/python/xen/xend/XendCheckpoint.py @ 6695:7bc32f4c67fb

merge?
author cl349@firebug.cl.cam.ac.uk
date Wed Sep 07 21:34:17 2005 +0000 (2005-09-07)
parents a39b1fa10edc 1f460d0fd6c6
children b2f4823b6ff0 b35215021b32 c2558a2fe658 8ca0f98ba8e2 72e4e2aab342
line source
1 # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
3 # This file is subject to the terms and conditions of the GNU General
4 # Public License. See the file "COPYING" in the main directory of
5 # this archive for more details.
7 import errno
8 import os
9 import re
10 import select
11 import sxp
12 from string import join
13 from struct import pack, unpack, calcsize
14 from xen.util.xpopen import xPopen3
15 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
17 from XendError import XendError
18 from XendLogging import log
20 SIGNATURE = "LinuxGuestRecord"
21 PATH_XC_SAVE = "/usr/libexec/xen/xc_save"
22 PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
24 sizeof_int = calcsize("i")
25 sizeof_unsigned_long = calcsize("L")
27 def write_exact(fd, buf, errmsg):
28 if os.write(fd, buf) != len(buf):
29 raise XendError(errmsg)
31 def read_exact(fd, size, errmsg):
32 buf = os.read(fd, size)
33 if len(buf) != size:
34 raise XendError(errmsg)
35 return buf
37 def save(xd, fd, dominfo, live):
38 write_exact(fd, SIGNATURE, "could not write guest state file: signature")
40 config = sxp.to_string(dominfo.sxpr())
41 write_exact(fd, pack("!i", len(config)),
42 "could not write guest state file: config len")
43 write_exact(fd, config, "could not write guest state file: config")
45 # xc_save takes three customization parameters: maxit, max_f, and flags
46 # the last controls whether or not save is 'live', while the first two
47 # further customize behaviour when 'live' save is enabled. Passing "0"
48 # simply uses the defaults compiled into libxenguest; see the comments
49 # and/or code in xc_linux_save() for more information.
50 cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
51 str(dominfo.id), "0", "0", str(int(live)) ]
52 log.info("[xc_save] " + join(cmd))
53 child = xPopen3(cmd, True, -1, [fd, xc.handle()])
55 lasterr = ""
56 p = select.poll()
57 p.register(child.fromchild.fileno())
58 p.register(child.childerr.fileno())
59 while True:
60 r = p.poll()
61 for (fd, event) in r:
62 if not event & select.POLLIN:
63 continue
64 if fd == child.childerr.fileno():
65 l = child.childerr.readline()
66 log.error(l.rstrip())
67 lasterr = l.rstrip()
68 if fd == child.fromchild.fileno():
69 l = child.fromchild.readline()
70 if l.rstrip() == "suspend":
71 log.info("suspending %d" % dominfo.id)
72 xd.domain_shutdown(dominfo.id, reason='suspend')
73 dominfo.state_wait("suspended")
74 log.info("suspend %d done" % dominfo.id)
75 if dominfo.store_channel:
76 try:
77 dominfo.db.releaseDomain(dominfo.id)
78 except Exception, ex:
79 log.warning(
80 "error in domain release on xenstore: %s",
81 ex)
82 pass
83 child.tochild.write("done\n")
84 child.tochild.flush()
85 if filter(lambda (fd, event): event & select.POLLHUP, r):
86 break
88 if child.wait() >> 8 == 127:
89 lasterr = "popen %s failed" % PATH_XC_SAVE
90 if child.wait() != 0:
91 raise XendError("xc_save failed: %s" % lasterr)
93 if dominfo.store_channel:
94 dominfo.store_channel.close()
95 dominfo.db['store_channel'].delete()
96 dominfo.db.saveDB(save=True)
97 dominfo.store_channel = None
98 xd.domain_destroy(dominfo.id)
99 return None
101 def restore(xd, fd):
102 signature = read_exact(fd, len(SIGNATURE),
103 "not a valid guest state file: signature read")
104 if signature != SIGNATURE:
105 raise XendError("not a valid guest state file: found '%s'" %
106 signature)
108 l = read_exact(fd, sizeof_int,
109 "not a valid guest state file: config size read")
110 vmconfig_size = unpack("!i", l)[0]
111 vmconfig_buf = read_exact(fd, vmconfig_size,
112 "not a valid guest state file: config read")
114 p = sxp.Parser()
115 p.input(vmconfig_buf)
116 if not p.ready:
117 raise XendError("not a valid guest state file: config parse")
119 vmconfig = p.get_val()
120 dominfo = xd.domain_configure(vmconfig)
122 l = read_exact(fd, sizeof_unsigned_long,
123 "not a valid guest state file: pfn count read")
124 nr_pfns = unpack("=L", l)[0] # XXX endianess
125 if nr_pfns > 1024*1024: # XXX
126 raise XendError(
127 "not a valid guest state file: pfn count out of range")
129 if dominfo.store_channel:
130 store_evtchn = dominfo.store_channel.port2
131 else:
132 store_evtchn = 0
134 if dominfo.console_channel:
135 console_evtchn = dominfo.console_channel.port2
136 else:
137 console_evtchn = 0
139 cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
140 str(dominfo.id), str(nr_pfns),
141 str(store_evtchn), str(console_evtchn)]
142 log.info("[xc_restore] " + join(cmd))
143 child = xPopen3(cmd, True, -1, [fd, xc.handle()])
144 child.tochild.close()
146 lasterr = ""
147 p = select.poll()
148 p.register(child.fromchild.fileno())
149 p.register(child.childerr.fileno())
150 while True:
151 r = p.poll()
152 for (fd, event) in r:
153 if not event & select.POLLIN:
154 continue
155 if fd == child.childerr.fileno():
156 l = child.childerr.readline()
157 log.error(l.rstrip())
158 lasterr = l.rstrip()
159 if fd == child.fromchild.fileno():
160 l = child.fromchild.readline()
161 while l:
162 log.info(l.rstrip())
163 m = re.match(r"^(store-mfn) (\d+)\n$", l)
164 if m:
165 if dominfo.store_channel:
166 dominfo.store_mfn = int(m.group(2))
167 if dominfo.store_mfn >= 0:
168 dominfo.db.introduceDomain(dominfo.id,
169 dominfo.store_mfn,
170 dominfo.store_channel)
171 dominfo.exportToDB(save=True, sync=True)
172 m = re.match(r"^(console-mfn) (\d+)\n$", l)
173 if m:
174 dominfo.console_mfn = int(m.group(2))
175 dominfo.exportToDB(save=True, sync=True)
176 try:
177 l = child.fromchild.readline()
178 except:
179 l = None
180 if filter(lambda (fd, event): event & select.POLLHUP, r):
181 break
183 if child.wait() >> 8 == 127:
184 lasterr = "popen %s failed" % PATH_XC_RESTORE
185 if child.wait() != 0:
186 raise XendError("xc_restore failed: %s" % lasterr)
188 return dominfo