direct-io.hg

changeset 13569: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>
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      }