# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1172771957 0
# Node ID 139794d55898642e3f0bef2f771a83979333ee1e
# Parent 33d733c3649df6e6713de5852892d7ffd74f3170
Save/restore context of all online VCPUs in PV save/restore/migrate.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/libxc/xc_linux_restore.c | 167 +++++++++++++++++++++++------------------
tools/libxc/xc_linux_save.c | 85 +++++++++++++-------
2 files changed, 153 insertions(+), 99 deletions(-)
diff -r 33d733c3649d -r 139794d55898 tools/libxc/xc_linux_restore.c
--- a/tools/libxc/xc_linux_restore.c Thu Mar 01 17:28:31 2007 +0000
+++ b/tools/libxc/xc_linux_restore.c Thu Mar 01 17:59:17 2007 +0000
@@ -144,7 +144,7 @@ int xc_linux_restore(int xc_handle, int
unsigned int console_evtchn, unsigned long *console_mfn)
{
DECLARE_DOMCTL;
- int rc = 1, i, n, m, pae_extended_cr3 = 0;
+ int rc = 1, i, j, n, m, pae_extended_cr3 = 0;
unsigned long mfn, pfn;
unsigned int prev_pc, this_pc;
int verify = 0;
@@ -187,6 +187,8 @@ int xc_linux_restore(int xc_handle, int
struct mmuext_op pin[MAX_PIN_BATCH];
unsigned int nr_pins;
+ uint64_t vcpumap = 1ULL;
+ unsigned int max_vcpu_id = 0;
max_pfn = nr_pfns;
@@ -366,6 +368,16 @@ int xc_linux_restore(int xc_handle, int
if (j == -1) {
verify = 1;
DPRINTF("Entering page verify mode\n");
+ continue;
+ }
+
+ if (j == -2) {
+ if (!read_exact(io_fd, &max_vcpu_id, sizeof(int)) ||
+ (max_vcpu_id >= 64) ||
+ !read_exact(io_fd, &vcpumap, sizeof(uint64_t))) {
+ ERROR("Error when reading max_vcpu_id");
+ goto out;
+ }
continue;
}
@@ -776,64 +788,90 @@ int xc_linux_restore(int xc_handle, int
}
}
- if (!read_exact(io_fd, &ctxt, sizeof(ctxt)) ||
- !read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
- ERROR("Error when reading ctxt or shared info page");
- goto out;
- }
-
- /* Uncanonicalise the suspend-record frame number and poke resume rec. */
- pfn = ctxt.user_regs.edx;
- if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
- ERROR("Suspend record frame number is bad");
- goto out;
- }
- ctxt.user_regs.edx = mfn = p2m[pfn];
- start_info = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
- start_info->nr_pages = max_pfn;
- start_info->shared_info = shared_info_frame << PAGE_SHIFT;
- start_info->flags = 0;
- *store_mfn = start_info->store_mfn = p2m[start_info->store_mfn];
- start_info->store_evtchn = store_evtchn;
- start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
- start_info->console.domU.evtchn = console_evtchn;
- *console_mfn = start_info->console.domU.mfn;
- munmap(start_info, PAGE_SIZE);
-
- /* Uncanonicalise each GDT frame number. */
- if (ctxt.gdt_ents > 8192) {
- ERROR("GDT entry count out of range");
- goto out;
- }
-
- for (i = 0; (512*i) < ctxt.gdt_ents; i++) {
- pfn = ctxt.gdt_frames[i];
- if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
- ERROR("GDT frame number is bad");
- goto out;
- }
- ctxt.gdt_frames[i] = p2m[pfn];
- }
-
- /* Uncanonicalise the page table base pointer. */
- pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
-
- if (pfn >= max_pfn) {
- ERROR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
- pfn, max_pfn, pfn_type[pfn]);
- goto out;
- }
-
- if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
- ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
- ERROR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
- pfn, max_pfn, pfn_type[pfn],
- (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
- goto out;
- }
-
- ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
+ for (i = 0; i <= max_vcpu_id; i++) {
+ if (!(vcpumap & (1ULL << i)))
+ continue;
+
+ if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
+ ERROR("Error when reading ctxt %d", i);
+ goto out;
+ }
+
+ if (i == 0) {
+ /*
+ * Uncanonicalise the suspend-record frame number and poke
+ * resume record.
+ */
+ pfn = ctxt.user_regs.edx;
+ if ((pfn >= max_pfn) ||
+ (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
+ ERROR("Suspend record frame number is bad");
+ goto out;
+ }
+ ctxt.user_regs.edx = mfn = p2m[pfn];
+ start_info = xc_map_foreign_range(
+ xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
+ start_info->nr_pages = max_pfn;
+ start_info->shared_info = shared_info_frame << PAGE_SHIFT;
+ start_info->flags = 0;
+ *store_mfn = start_info->store_mfn = p2m[start_info->store_mfn];
+ start_info->store_evtchn = store_evtchn;
+ start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
+ start_info->console.domU.evtchn = console_evtchn;
+ *console_mfn = start_info->console.domU.mfn;
+ munmap(start_info, PAGE_SIZE);
+ }
+
+ /* Uncanonicalise each GDT frame number. */
+ if (ctxt.gdt_ents > 8192) {
+ ERROR("GDT entry count out of range");
+ goto out;
+ }
+
+ for (j = 0; (512*j) < ctxt.gdt_ents; j++) {
+ pfn = ctxt.gdt_frames[j];
+ if ((pfn >= max_pfn) ||
+ (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
+ ERROR("GDT frame number is bad");
+ goto out;
+ }
+ ctxt.gdt_frames[j] = p2m[pfn];
+ }
+
+ /* Uncanonicalise the page table base pointer. */
+ pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
+
+ if (pfn >= max_pfn) {
+ ERROR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
+ pfn, max_pfn, pfn_type[pfn]);
+ goto out;
+ }
+
+ if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
+ ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
+ ERROR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
+ pfn, max_pfn, pfn_type[pfn],
+ (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
+ goto out;
+ }
+
+ ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
+
+ domctl.cmd = XEN_DOMCTL_setvcpucontext;
+ domctl.domain = (domid_t)dom;
+ domctl.u.vcpucontext.vcpu = i;
+ set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
+ rc = xc_domctl(xc_handle, &domctl);
+ if (rc != 0) {
+ ERROR("Couldn't build vcpu%d", i);
+ goto out;
+ }
+ }
+
+ if (!read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
+ ERROR("Error when reading shared info page");
+ goto out;
+ }
/* clear any pending events and the selector */
memset(&(shared_info->evtchn_pending[0]), 0,
@@ -869,17 +907,6 @@ int xc_linux_restore(int xc_handle, int
munmap(live_p2m, P2M_SIZE);
DPRINTF("Domain ready to be built.\n");
-
- domctl.cmd = XEN_DOMCTL_setvcpucontext;
- domctl.domain = (domid_t)dom;
- domctl.u.vcpucontext.vcpu = 0;
- set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
- rc = xc_domctl(xc_handle, &domctl);
-
- if (rc != 0) {
- ERROR("Couldn't build the domain");
- goto out;
- }
out:
if ( (rc != 0) && (dom != 0) )
diff -r 33d733c3649d -r 139794d55898 tools/libxc/xc_linux_save.c
--- a/tools/libxc/xc_linux_save.c Thu Mar 01 17:28:31 2007 +0000
+++ b/tools/libxc/xc_linux_save.c Thu Mar 01 17:59:17 2007 +0000
@@ -696,6 +696,7 @@ int xc_linux_save(int xc_handle, int io_
unsigned long needed_to_fix = 0;
unsigned long total_sent = 0;
+ uint64_t vcpumap = 1ULL;
/* If no explicit control parameters given, use defaults */
if(!max_iters)
@@ -716,24 +717,11 @@ int xc_linux_save(int xc_handle, int io_
return 1;
}
- if (lock_pages(&ctxt, sizeof(ctxt))) {
- ERROR("Unable to lock ctxt");
- return 1;
- }
-
- /* Only have to worry about vcpu 0 even for SMP */
if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) {
ERROR("Could not get vcpu context");
goto out;
}
shared_info_frame = info.shared_info_frame;
-
- /* A cheesy test to see whether the domain contains valid state. */
- if (ctxt.ctrlreg[3] == 0)
- {
- ERROR("Domain is not in a valid Linux guest OS state");
- goto out;
- }
/* Map the shared info frame */
if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
@@ -1194,6 +1182,32 @@ int xc_linux_save(int xc_handle, int io_
DPRINTF("All memory is saved\n");
+ {
+ struct {
+ int minustwo;
+ int max_vcpu_id;
+ uint64_t vcpumap;
+ } chunk = { -2, info.max_vcpu_id };
+
+ if (info.max_vcpu_id >= 64) {
+ ERROR("Too many VCPUS in guest!");
+ goto out;
+ }
+
+ for (i = 1; i <= info.max_vcpu_id; i++) {
+ xc_vcpuinfo_t vinfo;
+ if ((xc_vcpu_getinfo(xc_handle, dom, i, &vinfo) == 0) &&
+ vinfo.online)
+ vcpumap |= 1ULL << i;
+ }
+
+ chunk.vcpumap = vcpumap;
+ if(!write_exact(io_fd, &chunk, sizeof(chunk))) {
+ ERROR("Error when writing to state file (errno %d)", errno);
+ goto out;
+ }
+ }
+
/* Zero terminate */
i = 0;
if (!write_exact(io_fd, &i, sizeof(int))) {
@@ -1240,30 +1254,43 @@ int xc_linux_save(int xc_handle, int io_
goto out;
}
- /* Canonicalise each GDT frame number. */
- for ( i = 0; (512*i) < ctxt.gdt_ents; i++ ) {
- if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
- ERROR("GDT frame is not in range of pseudophys map");
+ for (i = 0; i <= info.max_vcpu_id; i++) {
+ if (!(vcpumap & (1ULL << i)))
+ continue;
+
+ if ((i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt)) {
+ ERROR("No context for VCPU%d", i);
goto out;
}
- }
-
- /* Canonicalise the page table base pointer. */
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) ) {
- ERROR("PT base is not in range of pseudophys map");
- goto out;
- }
- ctxt.ctrlreg[3] =
- xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
+
+ /* Canonicalise each GDT frame number. */
+ for ( j = 0; (512*j) < ctxt.gdt_ents; j++ ) {
+ if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[j]) ) {
+ ERROR("GDT frame is not in range of pseudophys map");
+ goto out;
+ }
+ }
+
+ /* Canonicalise the page table base pointer. */
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) ) {
+ ERROR("PT base is not in range of pseudophys map");
+ goto out;
+ }
+ ctxt.ctrlreg[3] =
+ xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
+
+ if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
+ ERROR("Error when writing to state file (1) (errno %d)", errno);
+ goto out;
+ }
+ }
/*
* Reset the MFN to be a known-invalid value. See map_frame_list_list().
*/
memcpy(page, live_shinfo, PAGE_SIZE);
((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0;
-
- if (!write_exact(io_fd, &ctxt, sizeof(ctxt)) ||
- !write_exact(io_fd, page, PAGE_SIZE)) {
+ if (!write_exact(io_fd, page, PAGE_SIZE)) {
ERROR("Error when writing to state file (1) (errno %d)", errno);
goto out;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|