diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 591f9ae187..99b55f50b5 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -244,7 +244,8 @@ int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt); * @parm ioctxt the IO context to restore a domain from * @return 0 on success, -1 on failure */ -int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt); +int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns, + unsigned char *pfn2mfn); int xc_linux_build(int xc_handle, u32 domid, diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c index afabadb17a..fe92441511 100644 --- a/tools/libxc/xc_linux_restore.c +++ b/tools/libxc/xc_linux_restore.c @@ -13,59 +13,34 @@ #define DEBUG 0 +#if 1 +#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a ) +#else +#define ERR(_f, _a...) ((void)0) +#endif + #if DEBUG -#define DPRINTF(_f, _a...) printf ( _f , ## _a ) +#define DPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ) #else #define DPRINTF(_f, _a...) ((void)0) #endif -/** Read the vmconfig string from the state input. - * It is stored as a 4-byte count 'n' followed by n bytes. - * The config data is stored in a new string in 'ioctxt->vmconfig', - * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'. - * - * @param ioctxt i/o context - * @return 0 on success, non-zero on error. - */ -static int read_vmconfig(XcIOContext *ioctxt) -{ - int err = -1; +#define PROGRESS 0 +#if PROGRESS +#define PPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ) +#else +#define PPRINTF(_f, _a...) +#endif - if ( xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n)) ) - goto exit; - - ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1); - if ( ioctxt->vmconfig == NULL ) - goto exit; - - if ( xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n) ) - goto exit; - - ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0'; - err = 0; - - exit: - if ( err ) - { - if ( ioctxt->vmconfig != NULL ) - free(ioctxt->vmconfig); - ioctxt->vmconfig = NULL; - ioctxt->vmconfig_n = 0; - } - return err; -} - -int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) +int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns, + unsigned char *pfn2mfn) { dom0_op_t op; int rc = 1, i, n, k; unsigned long mfn, pfn, xpfn; unsigned int prev_pc, this_pc; - u32 dom = 0; - int verify = 0; - - /* Number of page frames in use by this Linux session. */ - unsigned long nr_pfns; + int verify = 0; + int err; /* The new domain's shared-info frame number. */ unsigned long shared_info_frame; @@ -75,9 +50,6 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) /* A copy of the CPU context of the guest. */ vcpu_guest_context_t ctxt; - /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */ - char signature[16]; - /* A table containg the type of each PFN (/not/ MFN!). */ unsigned long *pfn_type = NULL; @@ -88,7 +60,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) unsigned long *ppage = NULL; /* A copy of the pfn-to-mfn table frame list. */ - unsigned long pfn_to_mfn_frame_list[1024]; + unsigned long *pfn_to_mfn_frame_list = (void *)pfn2mfn; // [1024]; /* A table mapping each PFN to its new MFN. */ unsigned long *pfn_to_mfn_table = NULL; @@ -110,126 +82,68 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) struct mmuext_op pin[MAX_PIN_BATCH]; unsigned int nr_pins = 0; - xcio_info(ioctxt, "xc_linux_restore start\n"); + DPRINTF("xc_linux_restore start\n"); - if ( mlock(&ctxt, sizeof(ctxt) ) ) - { + if (mlock(&ctxt, sizeof(ctxt))) { /* needed for when we do the build dom0 op, but might as well do early */ - PERROR("Unable to mlock ctxt"); + ERR("Unable to mlock ctxt"); return 1; } - /* Start reading the saved-domain record. */ - if ( xcio_read(ioctxt, signature, 16) || - (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) - { - xcio_error(ioctxt, "Unrecognised state format -- no signature found"); - goto out; - } - - if ( xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) || - xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) - { - xcio_error(ioctxt, "Error reading header"); - goto out; - } - - if ( read_vmconfig(ioctxt) ) - { - xcio_error(ioctxt, "Error writing vmconfig"); - goto out; - } - - if ( nr_pfns > 1024*1024 ) - { - xcio_error(ioctxt, "Invalid state file -- pfn count out of range"); - goto out; - } - /* We want zeroed memory so use calloc rather than malloc. */ - pfn_to_mfn_table = calloc(1, 4 * nr_pfns); - pfn_type = calloc(1, 4 * nr_pfns); - region_mfn = calloc(1, 4 * MAX_BATCH_SIZE); + pfn_to_mfn_table = calloc(4, nr_pfns); + pfn_type = calloc(4, nr_pfns); + region_mfn = calloc(4, MAX_BATCH_SIZE); - if ( (pfn_to_mfn_table == NULL) || - (pfn_type == NULL) || - (region_mfn == NULL) ) - { + if ((pfn_to_mfn_table == NULL) || (pfn_type == NULL) || + (region_mfn == NULL)) { + ERR("memory alloc failed"); errno = ENOMEM; goto out; } - if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) - { - xcio_error(ioctxt, "Could not mlock region_mfn"); + if (mlock(region_mfn, 4 * MAX_BATCH_SIZE)) { + ERR("Could not mlock region_mfn"); goto out; } - /* Create domain on CPU -1 so that it may auto load-balance in future. */ - if ( xc_domain_create(xc_handle, &dom) ) - { - xcio_error(ioctxt, "Could not create domain."); - goto out; - } - if ( xc_domain_setcpuweight(xc_handle, dom, 1) ) - { - xcio_error(ioctxt, "Could not set domain cpuweight."); - goto out; - } - if ( xc_domain_setmaxmem(xc_handle, dom, nr_pfns * (PAGE_SIZE / 1024)) ) - { - xcio_error(ioctxt, "Could not set domain maxmem. pfns=%ld, %ldKB", - nr_pfns, nr_pfns * (PAGE_SIZE / 1024)); - goto out; - } - if ( xc_domain_memory_increase_reservation(xc_handle, dom, - nr_pfns * (PAGE_SIZE / 1024)) ) - { - xcio_error(ioctxt, - "Could not increase domain memory reservation. pfns=%ld", - nr_pfns); - goto out; - } - - ioctxt->domain = dom; - xcio_info(ioctxt, "Created domain %u\n", dom); - /* Get the domain's shared-info frame. */ op.cmd = DOM0_GETDOMAININFO; op.u.getdomaininfo.domain = (domid_t)dom; - if ( do_dom0_op(xc_handle, &op) < 0 ) - { - xcio_error(ioctxt, "Could not get information on new domain"); + if (do_dom0_op(xc_handle, &op) < 0) { + ERR("Could not get information on new domain"); goto out; } shared_info_frame = op.u.getdomaininfo.shared_info_frame; - if(ioctxt->flags & XCFLAGS_CONFIGURE) - { - if(xcio_configure_domain(ioctxt)) - { - xcio_error(ioctxt, "Configuring domain failed"); - goto out; - } + err = xc_domain_setmaxmem(xc_handle, dom, nr_pfns * PAGE_SIZE / 1024); + if (err != 0) { + errno = ENOMEM; + goto out; + } + + err = xc_domain_memory_increase_reservation(xc_handle, dom, + nr_pfns * PAGE_SIZE / 1024); + if (err != 0) { + errno = ENOMEM; + goto out; } /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */ - if ( xc_get_pfn_list(xc_handle, dom, - pfn_to_mfn_table, nr_pfns) != nr_pfns ) - { - xcio_error(ioctxt, "Did not read correct number of frame " - "numbers for new dom"); + if (xc_get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != + nr_pfns) { + ERR("Did not read correct number of frame numbers for new dom"); goto out; } - if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) - { - xcio_error(ioctxt, "Could not initialise for MMU updates"); + mmu = init_mmu_updates(xc_handle, dom); + if (mmu == NULL) { + ERR("Could not initialise for MMU updates"); goto out; } - xcio_info(ioctxt, "Reloading memory pages: 0%%"); + DPRINTF("Reloading memory pages: 0%%"); /* * Now simply read each saved frame into its new machine frame. @@ -246,17 +160,17 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) this_pc = (n * 100) / nr_pfns; if ( (this_pc - prev_pc) >= 5 ) { - xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); + PPRINTF("\b\b\b\b%3d%%", this_pc); prev_pc = this_pc; } - if ( xcio_read(ioctxt, &j, sizeof(int)) ) + if ( read(io_fd, &j, sizeof(int)) != sizeof(int) ) { - xcio_error(ioctxt, "Error when reading from state file"); + ERR("Error when reading from state file"); goto out; } - DPRINTF("batch %d\n",j); + PPRINTF("batch %d\n",j); if ( j == -1 ) { @@ -270,12 +184,13 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) if ( j > MAX_BATCH_SIZE ) { - xcio_error(ioctxt, "Max batch size exceeded. Giving up."); + ERR("Max batch size exceeded. Giving up."); goto out; } - if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) { - xcio_error(ioctxt, "Error when reading from state file"); + if ( read(io_fd, region_pfn_type, j*sizeof(unsigned long)) != + j*sizeof(unsigned long) ) { + ERR("Error when reading from state file"); goto out; } @@ -297,7 +212,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) region_mfn, j )) == 0 ) { - xcio_error(ioctxt, "map batch failed"); + ERR("map batch failed"); goto out; } @@ -311,7 +226,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) if (pfn>nr_pfns) { - xcio_error(ioctxt, "pfn out of range"); + ERR("pfn out of range"); goto out; } @@ -326,9 +241,9 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) else ppage = (unsigned long*) (region_base + i*PAGE_SIZE); - if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) + if ( read(io_fd, ppage, PAGE_SIZE) != PAGE_SIZE ) { - xcio_error(ioctxt, "Error when reading from state file"); + ERR("Error when reading from state file"); goto out; } @@ -346,7 +261,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) xpfn = ppage[k] >> PAGE_SHIFT; if ( xpfn >= nr_pfns ) { - xcio_error(ioctxt, "Frame number in type %lu page " + ERR("Frame number in type %lu page " "table is out of range. i=%d k=%d " "pfn=0x%lx nr_pfns=%lu", region_pfn_type[i]>>28, i, @@ -374,7 +289,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) if ( xpfn >= nr_pfns ) { - xcio_error(ioctxt, "Frame number in type %lu page" + ERR("Frame number in type %lu page" " table is out of range. i=%d k=%d " "pfn=%lu nr_pfns=%lu", region_pfn_type[i]>>28, i, k, @@ -391,7 +306,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) break; default: - xcio_error(ioctxt, "Bogus page type %lx page table is " + ERR("Bogus page type %lx page table is " "out of range. i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns); goto out; @@ -432,7 +347,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) n+=j; /* crude stats */ } - xcio_info(ioctxt, "Received all pages\n"); + DPRINTF("Received all pages\n"); if ( finish_mmu_updates(xc_handle, mmu) ) goto out; @@ -462,30 +377,31 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) (do_mmuext_op(xc_handle, pin, nr_pins, dom) < 0) ) goto out; - xcio_info(ioctxt, "\b\b\b\b100%%\n"); - xcio_info(ioctxt, "Memory reloaded.\n"); + DPRINTF("\b\b\b\b100%%\n"); + DPRINTF("Memory reloaded.\n"); /* Get the list of PFNs that are not in the psuedo-phys map */ { unsigned int count, *pfntab; int rc; - if ( xcio_read(ioctxt, &count, sizeof(count)) ) + if ( read(io_fd, &count, sizeof(count)) != sizeof(count) ) { - xcio_error(ioctxt, "Error when reading from state file"); + ERR("Error when reading from state file"); goto out; } pfntab = malloc( sizeof(unsigned int) * count ); if ( pfntab == NULL ) { - xcio_error(ioctxt, "Out of memory"); + ERR("Out of memory"); goto out; } - if ( xcio_read(ioctxt, pfntab, sizeof(unsigned int)*count) ) + if ( read(io_fd, pfntab, sizeof(unsigned int)*count) != + sizeof(unsigned int)*count ) { - xcio_error(ioctxt, "Error when reading pfntab from state file"); + ERR("Error when reading pfntab from state file"); goto out; } @@ -502,7 +418,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) MEMOP_decrease_reservation, pfntab, count, 0, dom )) <0 ) { - xcio_error(ioctxt, "Could not decrease reservation : %d",rc); + ERR("Could not decrease reservation : %d",rc); goto out; } else @@ -512,10 +428,10 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) } } - if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) || - xcio_read(ioctxt, shared_info_page, PAGE_SIZE) ) + if ( read(io_fd, &ctxt, sizeof(ctxt)) != sizeof(ctxt) || + read(io_fd, shared_info_page, PAGE_SIZE) != PAGE_SIZE ) { - xcio_error(ioctxt, "Error when reading from state file"); + ERR("Error when reading from state file"); goto out; } @@ -523,7 +439,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) pfn = ctxt.user_regs.esi; if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { - xcio_error(ioctxt, "Suspend record frame number is bad"); + ERR("Suspend record frame number is bad"); goto out; } ctxt.user_regs.esi = mfn = pfn_to_mfn_table[pfn]; @@ -537,7 +453,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) /* Uncanonicalise each GDT frame number. */ if ( ctxt.gdt_ents > 8192 ) { - xcio_error(ioctxt, "GDT entry count out of range"); + ERR("GDT entry count out of range"); goto out; } @@ -546,7 +462,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) pfn = ctxt.gdt_frames[i]; if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { - xcio_error(ioctxt, "GDT frame number is bad"); + ERR("GDT frame number is bad"); goto out; } ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn]; @@ -558,7 +474,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) { printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n", pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB); - xcio_error(ioctxt, "PT base is bad."); + ERR("PT base is bad."); goto out; } ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT; @@ -583,7 +499,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) pfn = pfn_to_mfn_frame_list[i]; if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) { - xcio_error(ioctxt, "PFN-to-MFN frame number is bad"); + ERR("PFN-to-MFN frame number is bad"); goto out; } mfn = pfn_to_mfn_table[pfn]; @@ -596,7 +512,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) pfn_to_mfn_frame_list, (nr_pfns+1023)/1024 )) == 0 ) { - xcio_error(ioctxt, "Couldn't map pfn_to_mfn table"); + ERR("Couldn't map pfn_to_mfn table"); goto out; } @@ -636,11 +552,11 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) (ctxt.ldt_base > HYPERVISOR_VIRT_START) || ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) ) { - xcio_error(ioctxt, "Bad LDT base or size"); + ERR("Bad LDT base or size"); goto out; } - xcio_info(ioctxt, "Domain ready to be built.\n"); + DPRINTF("Domain ready to be built.\n"); op.cmd = DOM0_SETDOMAININFO; op.u.setdomaininfo.domain = (domid_t)dom; @@ -650,26 +566,20 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) if ( rc != 0 ) { - xcio_error(ioctxt, "Couldn't build the domain"); + ERR("Couldn't build the domain"); goto out; } - if ( ioctxt->flags & XCFLAGS_CONFIGURE ) - { - xcio_info(ioctxt, "Domain ready to be unpaused\n"); - op.cmd = DOM0_UNPAUSEDOMAIN; - op.u.unpausedomain.domain = (domid_t)dom; - rc = do_dom0_op(xc_handle, &op); - } - - if ( rc == 0 ) - { + DPRINTF("Domain ready to be unpaused\n"); + op.cmd = DOM0_UNPAUSEDOMAIN; + op.u.unpausedomain.domain = (domid_t)dom; + rc = do_dom0_op(xc_handle, &op); + if (rc == 0) { /* Success: print the domain id. */ - xcio_info(ioctxt, "DOM=%u\n", dom); + DPRINTF("DOM=%u\n", dom); return 0; } - out: if ( (rc != 0) && (dom != 0) ) xc_domain_destroy(xc_handle, dom); @@ -680,9 +590,6 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt) if ( pfn_type != NULL ) free(pfn_type); - if ( rc == 0 ) - ioctxt->domain = dom; - - DPRINTF("Restore exit with rc=%d\n",rc); + DPRINTF("Restore exit with rc=%d\n", rc); return rc; } diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 39045370c7..b1dff53a87 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -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", diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 24f8cdd31a..91ae01f85a 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -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. diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 8383ee7470..e87f8d3211 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -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. diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c index 9f9d1f15a6..fb2951555a 100644 --- a/tools/xfrd/xen_domain.c +++ b/tools/xfrd/xen_domain.c @@ -87,6 +87,7 @@ int xen_domain_rcv(IOStream *io, char **vmconfig, int *vmconfig_n, int *configured){ int err = 0; +#if 0 XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; dprintf(">\n"); ioctxt->io = io; @@ -102,6 +103,7 @@ int xen_domain_rcv(IOStream *io, *vmconfig_n = ioctxt->vmconfig_n; *configured = (ioctxt->flags & XCFLAGS_CONFIGURE); dprintf("< err=%d\n", err); +#endif return err; }