# HG changeset patch
# User john.levon@xxxxxxx
# Date 1169607991 28800
# Node ID 18f30d7ef2b87b67e8cd1fd36acaabea39b1bfc3
# Parent 08d791bd01e95bcce6f112ccca284a662f9adc63
Close save-after-restore race.
Make xc_linux_save() wait for the frame_list_list MFN to be updated by the
domain before trying to use it. Make Linux set the top-level MFN /after/
updating the other MFN lists.
Signed-off-by: John Levon <john.levon@xxxxxxx>
Based on xen-unstable changeset 13569:73b88d158ec9.
---
linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c | 4 -
linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c | 4 -
linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c | 5 -
tools/libxc/xc_linux_save.c | 48 +++++++++++++----
4 files changed, 45 insertions(+), 16 deletions(-)
diff -r 08d791bd01e9 -r 18f30d7ef2b8
linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Fri Jan 19 10:22:03
2007 +0000
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Tue Jan 23 19:06:31
2007 -0800
@@ -1777,8 +1777,6 @@ void __init setup_arch(char **cmdline_p)
* frames that make up the p2m table. Used by save/restore
*/
pfn_to_mfn_frame_list_list = alloc_bootmem_low_pages(PAGE_SIZE);
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
- virt_to_mfn(pfn_to_mfn_frame_list_list);
fpp = PAGE_SIZE/sizeof(unsigned long);
for (i=0, j=0, k=-1; i< max_pfn; i+=fpp, j++) {
@@ -1795,6 +1793,8 @@ void __init setup_arch(char **cmdline_p)
virt_to_mfn(&phys_to_machine_mapping[i]);
}
HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
+ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
+ virt_to_mfn(pfn_to_mfn_frame_list_list);
}
/*
diff -r 08d791bd01e9 -r 18f30d7ef2b8
linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c Fri Jan 19
10:22:03 2007 +0000
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c Tue Jan 23
19:06:31 2007 -0800
@@ -862,8 +862,6 @@ void __init setup_arch(char **cmdline_p)
* save/restore.
*/
pfn_to_mfn_frame_list_list =
alloc_bootmem_pages(PAGE_SIZE);
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list
=
- virt_to_mfn(pfn_to_mfn_frame_list_list);
fpp = PAGE_SIZE/sizeof(unsigned long);
for (i=0, j=0, k=-1; i< end_pfn; i+=fpp, j++) {
@@ -880,6 +878,8 @@ void __init setup_arch(char **cmdline_p)
virt_to_mfn(&phys_to_machine_mapping[i]);
}
HYPERVISOR_shared_info->arch.max_pfn = end_pfn;
+ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list
=
+ virt_to_mfn(pfn_to_mfn_frame_list_list);
}
}
diff -r 08d791bd01e9 -r 18f30d7ef2b8
linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Fri Jan 19
10:22:03 2007 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Tue Jan 23
19:06:31 2007 -0800
@@ -98,9 +98,6 @@ static void post_suspend(void)
memset(empty_zero_page, 0, PAGE_SIZE);
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
- virt_to_mfn(pfn_to_mfn_frame_list_list);
-
fpp = PAGE_SIZE/sizeof(unsigned long);
for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
if ((j % fpp) == 0) {
@@ -113,6 +110,8 @@ static void post_suspend(void)
virt_to_mfn(&phys_to_machine_mapping[i]);
}
HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
+ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
+ virt_to_mfn(pfn_to_mfn_frame_list_list);
}
#else /* !(defined(__i386__) || defined(__x86_64__)) */
diff -r 08d791bd01e9 -r 18f30d7ef2b8 tools/libxc/xc_linux_save.c
--- a/tools/libxc/xc_linux_save.c Fri Jan 19 10:22:03 2007 +0000
+++ b/tools/libxc/xc_linux_save.c Tue Jan 23 19:06:31 2007 -0800
@@ -403,6 +403,33 @@ static int suspend_and_state(int (*suspe
return -1;
}
+/*
+** Map the top-level page of MFNs from the guest. The guest might not have
+** finished resuming from a previous restore operation, so we wait a while for
+** it to update the MFN to a reasonable value.
+*/
+static void *map_frame_list_list(int xc_handle, uint32_t dom,
+ shared_info_t *shinfo)
+{
+ int count = 100;
+ void *p;
+
+ while (count-- && shinfo->arch.pfn_to_mfn_frame_list_list == 0)
+ usleep(10000);
+
+ if (shinfo->arch.pfn_to_mfn_frame_list_list == 0) {
+ ERROR("Timed out waiting for frame list updated.");
+ return NULL;
+ }
+
+ p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
+ shinfo->arch.pfn_to_mfn_frame_list_list);
+
+ if (p == NULL)
+ ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno);
+
+ return p;
+}
/*
** During transfer (or in the state file), all page-table pages must be
@@ -663,14 +690,11 @@ int xc_linux_save(int xc_handle, int io_
max_pfn = live_shinfo->arch.max_pfn;
- live_p2m_frame_list_list =
- xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
- live_shinfo->arch.pfn_to_mfn_frame_list_list);
-
- if (!live_p2m_frame_list_list) {
- ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno);
- goto out;
- }
+ live_p2m_frame_list_list = map_frame_list_list(xc_handle, dom,
+ live_shinfo);
+
+ if (!live_p2m_frame_list_list)
+ goto out;
live_p2m_frame_list =
xc_map_foreign_batch(xc_handle, dom, PROT_READ,
@@ -1169,8 +1193,14 @@ int xc_linux_save(int xc_handle, int io_
ctxt.ctrlreg[3] =
xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
+ /*
+ * 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, live_shinfo, PAGE_SIZE)) {
+ !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
|