debuggers.hg
changeset 13607:73b88d158ec9
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@sun.com>
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@sun.com>
author | john.levon@sun.com |
---|---|
date | Tue Jan 23 19:06:31 2007 -0800 (2007-01-23) |
parents | bea505a69722 |
children | 19e3f812805f |
files | linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c tools/libxc/xc_linux_save.c |
line diff
1.1 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Tue Jan 23 15:58:05 2007 +0000 1.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c Tue Jan 23 19:06:31 2007 -0800 1.3 @@ -1736,8 +1736,6 @@ void __init setup_arch(char **cmdline_p) 1.4 * frames that make up the p2m table. Used by save/restore 1.5 */ 1.6 pfn_to_mfn_frame_list_list = alloc_bootmem_low_pages(PAGE_SIZE); 1.7 - HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 1.8 - virt_to_mfn(pfn_to_mfn_frame_list_list); 1.9 1.10 fpp = PAGE_SIZE/sizeof(unsigned long); 1.11 for (i=0, j=0, k=-1; i< max_pfn; i+=fpp, j++) { 1.12 @@ -1754,6 +1752,8 @@ void __init setup_arch(char **cmdline_p) 1.13 virt_to_mfn(&phys_to_machine_mapping[i]); 1.14 } 1.15 HYPERVISOR_shared_info->arch.max_pfn = max_pfn; 1.16 + HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 1.17 + virt_to_mfn(pfn_to_mfn_frame_list_list); 1.18 } 1.19 1.20 /*
2.1 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c Tue Jan 23 15:58:05 2007 +0000 2.2 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c Tue Jan 23 19:06:31 2007 -0800 2.3 @@ -817,8 +817,6 @@ void __init setup_arch(char **cmdline_p) 2.4 * save/restore. 2.5 */ 2.6 pfn_to_mfn_frame_list_list = alloc_bootmem_pages(PAGE_SIZE); 2.7 - HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 2.8 - virt_to_mfn(pfn_to_mfn_frame_list_list); 2.9 2.10 fpp = PAGE_SIZE/sizeof(unsigned long); 2.11 for (i=0, j=0, k=-1; i< end_pfn; i+=fpp, j++) { 2.12 @@ -835,6 +833,8 @@ void __init setup_arch(char **cmdline_p) 2.13 virt_to_mfn(&phys_to_machine_mapping[i]); 2.14 } 2.15 HYPERVISOR_shared_info->arch.max_pfn = end_pfn; 2.16 + HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 2.17 + virt_to_mfn(pfn_to_mfn_frame_list_list); 2.18 } 2.19 2.20 }
3.1 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Tue Jan 23 15:58:05 2007 +0000 3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Tue Jan 23 19:06:31 2007 -0800 3.3 @@ -105,9 +105,6 @@ static void post_suspend(int suspend_can 3.4 3.5 memset(empty_zero_page, 0, PAGE_SIZE); 3.6 3.7 - HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 3.8 - virt_to_mfn(pfn_to_mfn_frame_list_list); 3.9 - 3.10 fpp = PAGE_SIZE/sizeof(unsigned long); 3.11 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { 3.12 if ((j % fpp) == 0) { 3.13 @@ -120,6 +117,8 @@ static void post_suspend(int suspend_can 3.14 virt_to_mfn(&phys_to_machine_mapping[i]); 3.15 } 3.16 HYPERVISOR_shared_info->arch.max_pfn = max_pfn; 3.17 + HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 3.18 + virt_to_mfn(pfn_to_mfn_frame_list_list); 3.19 } 3.20 3.21 #else /* !(defined(__i386__) || defined(__x86_64__)) */
4.1 --- a/tools/libxc/xc_linux_save.c Tue Jan 23 15:58:05 2007 +0000 4.2 +++ b/tools/libxc/xc_linux_save.c Tue Jan 23 19:06:31 2007 -0800 4.3 @@ -404,6 +404,33 @@ static int suspend_and_state(int (*suspe 4.4 return -1; 4.5 } 4.6 4.7 +/* 4.8 +** Map the top-level page of MFNs from the guest. The guest might not have 4.9 +** finished resuming from a previous restore operation, so we wait a while for 4.10 +** it to update the MFN to a reasonable value. 4.11 +*/ 4.12 +static void *map_frame_list_list(int xc_handle, uint32_t dom, 4.13 + shared_info_t *shinfo) 4.14 +{ 4.15 + int count = 100; 4.16 + void *p; 4.17 + 4.18 + while (count-- && shinfo->arch.pfn_to_mfn_frame_list_list == 0) 4.19 + usleep(10000); 4.20 + 4.21 + if (shinfo->arch.pfn_to_mfn_frame_list_list == 0) { 4.22 + ERROR("Timed out waiting for frame list updated."); 4.23 + return NULL; 4.24 + } 4.25 + 4.26 + p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, 4.27 + shinfo->arch.pfn_to_mfn_frame_list_list); 4.28 + 4.29 + if (p == NULL) 4.30 + ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno); 4.31 + 4.32 + return p; 4.33 +} 4.34 4.35 /* 4.36 ** During transfer (or in the state file), all page-table pages must be 4.37 @@ -669,14 +696,11 @@ int xc_linux_save(int xc_handle, int io_ 4.38 4.39 max_pfn = live_shinfo->arch.max_pfn; 4.40 4.41 - live_p2m_frame_list_list = 4.42 - xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, 4.43 - live_shinfo->arch.pfn_to_mfn_frame_list_list); 4.44 + live_p2m_frame_list_list = map_frame_list_list(xc_handle, dom, 4.45 + live_shinfo); 4.46 4.47 - if (!live_p2m_frame_list_list) { 4.48 - ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno); 4.49 + if (!live_p2m_frame_list_list) 4.50 goto out; 4.51 - } 4.52 4.53 live_p2m_frame_list = 4.54 xc_map_foreign_batch(xc_handle, dom, PROT_READ, 4.55 @@ -1175,8 +1199,14 @@ int xc_linux_save(int xc_handle, int io_ 4.56 ctxt.ctrlreg[3] = 4.57 xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3]))); 4.58 4.59 + /* 4.60 + * Reset the MFN to be a known-invalid value. See map_frame_list_list(). 4.61 + */ 4.62 + memcpy(page, live_shinfo, PAGE_SIZE); 4.63 + ((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0; 4.64 + 4.65 if (!write_exact(io_fd, &ctxt, sizeof(ctxt)) || 4.66 - !write_exact(io_fd, live_shinfo, PAGE_SIZE)) { 4.67 + !write_exact(io_fd, page, PAGE_SIZE)) { 4.68 ERROR("Error when writing to state file (1) (errno %d)", errno); 4.69 goto out; 4.70 }