mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
bitkeeper revision 1.1488.1.1 (428e39badumj52vi-nzb7GBmoVe2dA)
XendDomainInfo.py, XendDomain.py, xc.c, xc_linux_restore.c, xc.h: Implement the parts of vm restore which need interaction with xend as part of xend, instead of using xfrd. The restore functionality using xfrd was broken anyway since xend didn't handle the callback channel from xfrd correctly. xen_domain.c: Disable restore in xfrd. Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
19a92cce63
commit
3277f00e2a
6 files changed
+187
-233
No files matched your search
@@ -334,62 +334,41 @@ static PyObject *pyxc_linux_save(PyObject *self,
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
ioctxt->io = gzip_stream_fopen(state_file, "rb");
|
||||
if ( ioctxt->io == NULL )
|
||||
{
|
||||
xcio_perror(ioctxt, "Could not open file for reading");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = xc_linux_restore(xc->xc_handle, ioctxt);
|
||||
|
||||
IOStream_close(ioctxt->io);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_linux_restore(PyObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
char *state_file;
|
||||
int progress = 1, debug = 0;
|
||||
PyObject *val = NULL;
|
||||
XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
|
||||
int rc =-1;
|
||||
int io_fd, dom;
|
||||
unsigned long nr_pfns;
|
||||
char *pfn2mfn;
|
||||
int pfn2mfn_len;
|
||||
PyObject *pfn2mfn_object;
|
||||
|
||||
static char *kwd_list[] = { "state_file", "progress", "debug", NULL };
|
||||
static char *kwd_list[] = { "fd", "dom", "pfns", "pfn2mfn", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s|ii", kwd_list,
|
||||
&state_file,
|
||||
&progress,
|
||||
&debug) )
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iilO", kwd_list,
|
||||
&io_fd, &dom, &nr_pfns,
|
||||
&pfn2mfn_object) )
|
||||
goto exit;
|
||||
|
||||
if ( progress )
|
||||
ioctxt.flags |= XCFLAGS_VERBOSE;
|
||||
if ( debug )
|
||||
ioctxt.flags |= XCFLAGS_DEBUG;
|
||||
if (PyString_AsStringAndSize(pfn2mfn_object, &pfn2mfn, &pfn2mfn_len))
|
||||
goto exit;
|
||||
|
||||
if ( (state_file == NULL) || (state_file[0] == '\0') )
|
||||
goto exit;
|
||||
if (pfn2mfn_len != PAGE_SIZE)
|
||||
goto exit;
|
||||
|
||||
rc = file_restore(xc, &ioctxt, state_file);
|
||||
rc = xc_linux_restore(xc->xc_handle, io_fd, dom, nr_pfns, pfn2mfn);
|
||||
if ( rc != 0 )
|
||||
{
|
||||
PyErr_SetFromErrno(xc_error);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
val = Py_BuildValue("{s:i,s:s}",
|
||||
"dom", ioctxt.domain,
|
||||
"vmconfig", ioctxt.vmconfig);
|
||||
Py_INCREF(zero);
|
||||
val = zero;
|
||||
|
||||
exit:
|
||||
return val;
|
||||
@@ -1061,8 +1040,9 @@ static PyMethodDef pyxc_methods[] = {
|
||||
(PyCFunction)pyxc_linux_restore,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Restore the CPU and memory state of a Linux guest OS.\n"
|
||||
" state_file [str]: Name of state file. Must not currently exist.\n"
|
||||
" progress [int, 1]: Bool - display a running progress indication?\n\n"
|
||||
" dom [int]: Identifier of domain to be restored.\n"
|
||||
" pfns [int]: Number of pages domain uses.\n"
|
||||
" pfn2mfn [str]: String containing the pfn to mfn frame list.\n\n"
|
||||
"Returns: [int] new domain identifier on success; -1 on error.\n" },
|
||||
|
||||
{ "linux_build",
|
||||
|
||||
@@ -24,6 +24,9 @@ import scheduler
|
||||
from xen.xend.server import channel
|
||||
|
||||
|
||||
import errno
|
||||
from struct import pack, unpack, calcsize
|
||||
|
||||
__all__ = [ "XendDomain" ]
|
||||
|
||||
SHUTDOWN_TIMEOUT = 30
|
||||
@@ -298,7 +301,7 @@ class XendDomain:
|
||||
[dominfo.name, dominfo.id, "fail"])
|
||||
return dominfo
|
||||
|
||||
def domain_configure(self, id, vmconfig):
|
||||
def domain_configure(self, vmconfig):
|
||||
"""Configure an existing domain. This is intended for internal
|
||||
use by domain restore and migrate.
|
||||
|
||||
@@ -306,10 +309,7 @@ class XendDomain:
|
||||
@param vmconfig: vm configuration
|
||||
"""
|
||||
config = sxp.child_value(vmconfig, 'config')
|
||||
dominfo = self.domain_lookup(id)
|
||||
log.debug('domain_configure> id=%s config=%s', str(id), str(config))
|
||||
if dominfo.config:
|
||||
raise XendError("Domain already configured: " + dominfo.id)
|
||||
dominfo = XendDomainInfo.tmp_restore_create_domain()
|
||||
dominfo.dom_construct(dominfo.dom, config)
|
||||
self._add_domain(dominfo)
|
||||
return dominfo
|
||||
@@ -320,8 +320,65 @@ class XendDomain:
|
||||
@param src: source file
|
||||
@param progress: output progress if true
|
||||
"""
|
||||
xmigrate = XendMigrate.instance()
|
||||
return xmigrate.restore_begin(src)
|
||||
|
||||
SIGNATURE = "LinuxGuestRecord"
|
||||
sizeof_int = calcsize("L")
|
||||
sizeof_unsigned_long = calcsize("i")
|
||||
PAGE_SIZE = 4096
|
||||
|
||||
class XendFile(file):
|
||||
def read_exact(self, size, error_msg):
|
||||
buf = self.read(size)
|
||||
if len(buf) != size:
|
||||
raise XendError(error_msg)
|
||||
return buf
|
||||
|
||||
try:
|
||||
fd = XendFile(src, 'rb')
|
||||
|
||||
signature = fd.read_exact(len(SIGNATURE),
|
||||
"not a valid guest state file: signature read")
|
||||
if signature != SIGNATURE:
|
||||
raise XendError("not a valid guest state file: found '%s'" %
|
||||
signature)
|
||||
|
||||
l = fd.read_exact(sizeof_unsigned_long,
|
||||
"not a valid guest state file: pfn count read")
|
||||
nr_pfns = unpack("=L", l)[0] # XXX endianess
|
||||
if nr_pfns > 1024*1024: # XXX
|
||||
raise XendError(
|
||||
"not a valid guest state file: pfn count out of range")
|
||||
|
||||
pfn_to_mfn_frame_list = fd.read_exact(PAGE_SIZE,
|
||||
"not a valid guest state file: pfn_to_mfn_frame_list read")
|
||||
|
||||
l = fd.read_exact(sizeof_int,
|
||||
"not a valid guest state file: config size read")
|
||||
vmconfig_size = unpack("i", l)[0] # XXX endianess
|
||||
vmconfig_buf = fd.read_exact(vmconfig_size,
|
||||
"not a valid guest state file: config read")
|
||||
|
||||
p = sxp.Parser()
|
||||
p.input(vmconfig_buf)
|
||||
if not p.ready:
|
||||
raise XendError("not a valid guest state file: config parse")
|
||||
|
||||
vmconfig = p.get_val()
|
||||
dominfo = self.domain_configure(vmconfig)
|
||||
|
||||
# XXXcl hack: fd.tell will sync up the object and
|
||||
# underlying file descriptor
|
||||
ignore = fd.tell()
|
||||
|
||||
xc.linux_restore(fd.fileno(), int(dominfo.id), nr_pfns,
|
||||
pfn_to_mfn_frame_list)
|
||||
return dominfo
|
||||
|
||||
except IOError, ex:
|
||||
if ex.errno == errno.ENOENT:
|
||||
raise XendError("can't open guest state file %s" % src)
|
||||
else:
|
||||
raise
|
||||
|
||||
def domain_get(self, id):
|
||||
"""Get up-to-date info about a domain.
|
||||
|
||||
@@ -183,6 +183,13 @@ def vm_create(config):
|
||||
vm.construct(config)
|
||||
return vm
|
||||
|
||||
def tmp_restore_create_domain():
|
||||
# dom input parameter is ignored
|
||||
vm = XendDomainInfo()
|
||||
dom = xc.domain_create()
|
||||
vm.setdom(dom)
|
||||
return vm
|
||||
|
||||
def vm_recreate(savedinfo, info):
|
||||
"""Create the VM object for an existing domain.
|
||||
|
||||
|
||||