diff options
Diffstat (limited to 'tools/libxc/xc_linux_save.c')
-rw-r--r-- | tools/libxc/xc_linux_save.c | 556 |
1 files changed, 305 insertions, 251 deletions
diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c index 0636eb79ec..3b5788126e 100644 --- a/tools/libxc/xc_linux_save.c +++ b/tools/libxc/xc_linux_save.c @@ -27,7 +27,6 @@ #define DEF_MAX_ITERS 29 /* limit us to 30 times round loop */ #define DEF_MAX_FACTOR 3 /* never send more than 3x p2m_size */ - /* max mfn of the whole machine */ static unsigned long max_mfn; @@ -56,10 +55,9 @@ static unsigned long m2p_mfn0; * in the guest's pseudophysical map. */ #define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \ -(((_mfn) < (max_mfn)) && \ - ((mfn_to_pfn(_mfn) < (p2m_size)) && \ - (live_p2m[mfn_to_pfn(_mfn)] == (_mfn)))) - + (((_mfn) < (max_mfn)) && \ + ((mfn_to_pfn(_mfn) < (p2m_size)) && \ + (live_p2m[mfn_to_pfn(_mfn)] == (_mfn)))) /* Returns TRUE if MFN is successfully converted to a PFN. */ #define translate_mfn_to_pfn(_pmfn) \ @@ -116,7 +114,7 @@ static inline int count_bits ( int nr, volatile void *addr) int i, count = 0; volatile unsigned long *p = (volatile unsigned long *)addr; /* We know that the array is padded to unsigned long. */ - for( i = 0; i < (nr / (sizeof(unsigned long)*8)); i++, p++ ) + for ( i = 0; i < (nr / (sizeof(unsigned long)*8)); i++, p++ ) count += hweight32(*p); return count; } @@ -151,9 +149,6 @@ static inline int permute( int i, int nr, int order_nr ) return i; } - - - static uint64_t tv_to_us(struct timeval *new) { return (new->tv_sec * 1000000) + new->tv_usec; @@ -168,8 +163,8 @@ static uint64_t llgettimeofday(void) static uint64_t tv_delta(struct timeval *new, struct timeval *old) { - return ((new->tv_sec - old->tv_sec)*1000000 ) + - (new->tv_usec - old->tv_usec); + return (((new->tv_sec - old->tv_sec)*1000000) + + (new->tv_usec - old->tv_usec)); } static int noncached_write(int fd, int live, void *buffer, int len) @@ -179,8 +174,8 @@ static int noncached_write(int fd, int live, void *buffer, int len) int rc = write(fd,buffer,len); write_count += len; - - if (write_count >= MAX_PAGECACHE_USAGE*PAGE_SIZE) { + if ( write_count >= (MAX_PAGECACHE_USAGE * PAGE_SIZE) ) + { /* Time to discard cache - dont care if this fails */ discard_file_cache(fd, 0 /* no flush */); write_count = 0; @@ -191,7 +186,6 @@ static int noncached_write(int fd, int live, void *buffer, int len) #ifdef ADAPTIVE_SAVE - /* ** We control the rate at which we transmit (or save) to minimize impact ** on running domains (including the target if we're doing live migrate). @@ -200,27 +194,23 @@ static int noncached_write(int fd, int live, void *buffer, int len) #define MAX_MBIT_RATE 500 /* maximum transmit rate for migrate */ #define START_MBIT_RATE 100 /* initial transmit rate for migrate */ - /* Scaling factor to convert between a rate (in Mb/s) and time (in usecs) */ #define RATE_TO_BTU 781250 /* Amount in bytes we allow ourselves to send in a burst */ #define BURST_BUDGET (100*1024) - /* We keep track of the current and previous transmission rate */ static int mbit_rate, ombit_rate = 0; /* Have we reached the maximum transmission rate? */ #define RATE_IS_MAX() (mbit_rate == MAX_MBIT_RATE) - static inline void initialize_mbit_rate() { mbit_rate = START_MBIT_RATE; } - static int ratewrite(int io_fd, int live, void *buf, int n) { static int budget = 0; @@ -230,39 +220,47 @@ static int ratewrite(int io_fd, int live, void *buf, int n) struct timespec delay; long long delta; - if (START_MBIT_RATE == 0) + if ( START_MBIT_RATE == 0 ) return noncached_write(io_fd, live, buf, n); budget -= n; - if (budget < 0) { - if (mbit_rate != ombit_rate) { + if ( budget < 0 ) + { + if ( mbit_rate != ombit_rate ) + { burst_time_us = RATE_TO_BTU / mbit_rate; ombit_rate = mbit_rate; DPRINTF("rate limit: %d mbit/s burst budget %d slot time %d\n", mbit_rate, BURST_BUDGET, burst_time_us); } - if (last_put.tv_sec == 0) { + if ( last_put.tv_sec == 0 ) + { budget += BURST_BUDGET; gettimeofday(&last_put, NULL); - } else { - while (budget < 0) { + } + else + { + while ( budget < 0 ) + { gettimeofday(&now, NULL); delta = tv_delta(&now, &last_put); - while (delta > burst_time_us) { + while ( delta > burst_time_us ) + { budget += BURST_BUDGET; last_put.tv_usec += burst_time_us; - if (last_put.tv_usec > 1000000) { + if ( last_put.tv_usec > 1000000 + { last_put.tv_usec -= 1000000; last_put.tv_sec++; } delta -= burst_time_us; } - if (budget > 0) + if ( budget > 0 ) break; delay.tv_sec = 0; delay.tv_nsec = 1000 * (burst_time_us - delta); - while (delay.tv_nsec > 0) - if (nanosleep(&delay, &delay) == 0) + while ( delay.tv_nsec > 0 ) + if ( nanosleep(&delay, &delay) == 0 ) break; } } @@ -278,16 +276,11 @@ static int ratewrite(int io_fd, int live, void *buf, int n) #endif - static inline ssize_t write_exact(int fd, void *buf, size_t count) { - if(write(fd, buf, count) != count) - return 0; - return 1; + return (write(fd, buf, count) == count); } - - static int print_stats(int xc_handle, uint32_t domid, int pages_sent, xc_shadow_op_stats_t *stats, int print) { @@ -309,15 +302,14 @@ static int print_stats(int xc_handle, uint32_t domid, int pages_sent, DPRINTF("ARRHHH!!\n"); wall_delta = tv_delta(&wall_now,&wall_last)/1000; - - if (wall_delta == 0) wall_delta = 1; + if ( wall_delta == 0 ) + wall_delta = 1; d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000; d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000; - if (print) - DPRINTF( - "delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " + if ( print ) + DPRINTF("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " "dirtied %dMb/s %" PRId32 " pages\n", wall_delta, (int)((d0_cpu_delta*100)/wall_delta), @@ -327,10 +319,11 @@ static int print_stats(int xc_handle, uint32_t domid, int pages_sent, stats->dirty_count); #ifdef ADAPTIVE_SAVE - if (((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))) > mbit_rate) { + if ( ((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))) > mbit_rate ) + { mbit_rate = (int)((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))) + 50; - if (mbit_rate > MAX_MBIT_RATE) + if ( mbit_rate > MAX_MBIT_RATE ) mbit_rate = MAX_MBIT_RATE; } #endif @@ -352,18 +345,19 @@ static int analysis_phase(int xc_handle, uint32_t domid, int p2m_size, start = llgettimeofday(); - for (j = 0; j < runs; j++) { + for ( j = 0; j < runs; j++ ) + { int i; xc_shadow_control(xc_handle, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, arr, p2m_size, NULL, 0, NULL); DPRINTF("#Flush\n"); - for ( i = 0; i < 40; i++ ) { + for ( i = 0; i < 40; i++ ) + { usleep(50000); now = llgettimeofday(); xc_shadow_control(xc_handle, domid, XEN_DOMCTL_SHADOW_OP_PEEK, NULL, 0, NULL, 0, &stats); - DPRINTF("now= %lld faults= %"PRId32" dirty= %"PRId32"\n", ((now-start)+500)/1000, stats.fault_count, stats.dirty_count); @@ -380,34 +374,40 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd, { int i = 0; - if (!(*suspend)(dom)) { + if ( !(*suspend)(dom) ) + { ERROR("Suspend request failed"); return -1; } retry: - if (xc_domain_getinfo(xc_handle, dom, 1, info) != 1) { + if ( xc_domain_getinfo(xc_handle, dom, 1, info) != 1 ) + { ERROR("Could not get domain info"); return -1; } - if ( xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, ctxt)) + if ( xc_vcpu_getcontext(xc_handle, dom, 0, ctxt) ) ERROR("Could not get vcpu context"); - if (info->dying) { + if ( info->dying ) + { ERROR("domain is dying"); return -1; } - if (info->crashed) { + if ( info->crashed ) + { ERROR("domain has crashed"); return -1; } - if (info->shutdown) { - switch (info->shutdown_reason) { + if ( info->shutdown ) + { + switch ( info->shutdown_reason ) + { case SHUTDOWN_poweroff: case SHUTDOWN_reboot: ERROR("domain has shut down"); @@ -420,20 +420,19 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd, } } - if (info->paused) { - // try unpausing domain, wait, and retest + if ( info->paused ) + { + /* Try unpausing domain, wait, and retest. */ xc_domain_unpause( xc_handle, dom ); - ERROR("Domain was paused. Wait and re-test."); - usleep(10000); // 10ms - + usleep(10000); /* 10ms */ goto retry; } - - if( ++i < 100 ) { + if ( ++i < 100 ) + { ERROR("Retry suspend domain"); - usleep(10000); // 10ms + usleep(10000); /* 10ms */ goto retry; } @@ -453,18 +452,18 @@ static void *map_frame_list_list(int xc_handle, uint32_t dom, int count = 100; void *p; - while (count-- && shinfo->arch.pfn_to_mfn_frame_list_list == 0) + while ( count-- && (shinfo->arch.pfn_to_mfn_frame_list_list == 0) ) usleep(10000); - if (shinfo->arch.pfn_to_mfn_frame_list_list == 0) { + 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) + if ( p == NULL ) ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno); return p; @@ -493,10 +492,10 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, */ xen_start = xen_end = pte_last = PAGE_SIZE / ((pt_levels == 2) ? 4 : 8); - if (pt_levels == 2 && type == XEN_DOMCTL_PFINFO_L2TAB) + if ( (pt_levels == 2) && (type == XEN_DOMCTL_PFINFO_L2TAB) ) xen_start = (hvirt_start >> L2_PAGETABLE_SHIFT); - if (pt_levels == 3 && type == XEN_DOMCTL_PFINFO_L3TAB) + if ( (pt_levels == 3) && (type == XEN_DOMCTL_PFINFO_L3TAB) ) xen_start = L3_PAGETABLE_ENTRIES_PAE; /* @@ -505,27 +504,31 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, ** Xen always ensures is present in that L2. Guests must ensure ** that this check will fail for other L2s. */ - if (pt_levels == 3 && type == XEN_DOMCTL_PFINFO_L2TAB) { + if ( (pt_levels == 3) && (type == XEN_DOMCTL_PFINFO_L2TAB) ) + { int hstart; uint64_t he; hstart = (hvirt_start >> L2_PAGETABLE_SHIFT_PAE) & 0x1ff; he = ((const uint64_t *) spage)[hstart]; - if ( ((he >> PAGE_SHIFT) & MFN_MASK_X86) == m2p_mfn0 ) { + if ( ((he >> PAGE_SHIFT) & MFN_MASK_X86) == m2p_mfn0 ) + { /* hvirt starts with xen stuff... */ xen_start = hstart; - } else if ( hvirt_start != 0xf5800000 ) { + } + else if ( hvirt_start != 0xf5800000 ) + { /* old L2s from before hole was shrunk... */ hstart = (0xf5800000 >> L2_PAGETABLE_SHIFT_PAE) & 0x1ff; he = ((const uint64_t *) spage)[hstart]; - - if( ((he >> PAGE_SHIFT) & MFN_MASK_X86) == m2p_mfn0 ) + if ( ((he >> PAGE_SHIFT) & MFN_MASK_X86) == m2p_mfn0 ) xen_start = hstart; } } - if (pt_levels == 4 && type == XEN_DOMCTL_PFINFO_L4TAB) { + if ( (pt_levels == 4) && (type == XEN_DOMCTL_PFINFO_L4TAB) ) + { /* ** XXX SMH: should compute these from hvirt_start (which we have) ** and hvirt_end (which we don't) @@ -535,27 +538,29 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, } /* Now iterate through the page table, canonicalizing each PTE */ - for (i = 0; i < pte_last; i++ ) { - + for (i = 0; i < pte_last; i++ ) + { unsigned long pfn, mfn; - if (pt_levels == 2) + if ( pt_levels == 2 ) pte = ((const uint32_t*)spage)[i]; else pte = ((const uint64_t*)spage)[i]; - if (i >= xen_start && i < xen_end) + if ( (i >= xen_start) && (i < xen_end) ) pte = 0; - if (pte & _PAGE_PRESENT) { - + if ( pte & _PAGE_PRESENT ) + { mfn = (pte >> PAGE_SHIFT) & MFN_MASK_X86; - if (!MFN_IS_IN_PSEUDOPHYS_MAP(mfn)) { + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) + { /* This will happen if the type info is stale which is quite feasible under live migration */ pfn = 0; /* zap it - we'll retransmit this page later */ race = 1; /* inform the caller of race; fatal if !live */ - } else + } + else pfn = mfn_to_pfn(mfn); pte &= ~MADDR_MASK_X86; @@ -566,26 +571,21 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, * a 64bit hypervisor. We zap these here to avoid any * surprise at restore time... */ - if ( pt_levels == 3 && - type == XEN_DOMCTL_PFINFO_L3TAB && - pte & (_PAGE_USER|_PAGE_RW|_PAGE_ACCESSED) ) - { + if ( (pt_levels == 3) && + (type == XEN_DOMCTL_PFINFO_L3TAB) && + (pte & (_PAGE_USER|_PAGE_RW|_PAGE_ACCESSED)) ) pte &= ~(_PAGE_USER|_PAGE_RW|_PAGE_ACCESSED); - } } - if (pt_levels == 2) + if ( pt_levels == 2 ) ((uint32_t*)dpage)[i] = pte; else ((uint64_t*)dpage)[i] = pte; - } - return race; + return race; } - - static xen_pfn_t *xc_map_m2p(int xc_handle, unsigned long max_mfn, int prot) @@ -601,37 +601,43 @@ static xen_pfn_t *xc_map_m2p(int xc_handle, m2p_chunks = M2P_CHUNKS(max_mfn); xmml.max_extents = m2p_chunks; - if (!(extent_start = malloc(m2p_chunks * sizeof(xen_pfn_t)))) { + if ( !(extent_start = malloc(m2p_chunks * sizeof(xen_pfn_t))) ) + { ERROR("failed to allocate space for m2p mfns"); return NULL; } set_xen_guest_handle(xmml.extent_start, extent_start); - if (xc_memory_op(xc_handle, XENMEM_machphys_mfn_list, &xmml) || - (xmml.nr_extents != m2p_chunks)) { + if ( xc_memory_op(xc_handle, XENMEM_machphys_mfn_list, &xmml) || + (xmml.nr_extents != m2p_chunks) ) + { ERROR("xc_get_m2p_mfns"); return NULL; } - if ((m2p = mmap(NULL, m2p_size, prot, - MAP_SHARED, xc_handle, 0)) == MAP_FAILED) { + if ( (m2p = mmap(NULL, m2p_size, prot, + MAP_SHARED, xc_handle, 0)) == MAP_FAILED ) + { ERROR("failed to mmap m2p"); return NULL; } - if (!(entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t)))) { + if ( !(entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t))) ) + { ERROR("failed to allocate space for mmap entries"); return NULL; } - for (i=0; i < m2p_chunks; i++) { + for ( i = 0; i < m2p_chunks; i++ ) + { entries[i].va = (unsigned long)(((void *)m2p) + (i * M2P_CHUNK_SIZE)); entries[i].mfn = extent_start[i]; entries[i].npages = M2P_CHUNK_SIZE >> PAGE_SHIFT; } - if ((rc = xc_map_foreign_ranges(xc_handle, DOMID_XEN, - entries, m2p_chunks)) < 0) { + if ( (rc = xc_map_foreign_ranges(xc_handle, DOMID_XEN, + entries, m2p_chunks)) < 0 ) + { ERROR("xc_mmap_foreign_ranges failed (rc = %d)", rc); return NULL; } @@ -644,8 +650,6 @@ static xen_pfn_t *xc_map_m2p(int xc_handle, return m2p; } - - int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t max_factor, uint32_t flags, int (*suspend)(int)) { @@ -699,33 +703,35 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, uint64_t vcpumap = 1ULL; /* If no explicit control parameters given, use defaults */ - if(!max_iters) - max_iters = DEF_MAX_ITERS; - if(!max_factor) - max_factor = DEF_MAX_FACTOR; + max_iters = max_iters ? : DEF_MAX_ITERS; + max_factor = max_factor ? : DEF_MAX_FACTOR; initialize_mbit_rate(); - if(!get_platform_info(xc_handle, dom, - &max_mfn, &hvirt_start, &pt_levels)) { + if ( !get_platform_info(xc_handle, dom, + &max_mfn, &hvirt_start, &pt_levels) ) + { ERROR("Unable to get platform info."); return 1; } - if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) { + if ( xc_domain_getinfo(xc_handle, dom, 1, &info) != 1 ) + { ERROR("Could not get domain info"); return 1; } - if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) { + if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) ) + { ERROR("Could not get vcpu context"); goto out; } shared_info_frame = info.shared_info_frame; /* Map the shared info frame */ - if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, - PROT_READ, shared_info_frame))) { + if ( !(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ, shared_info_frame)) ) + { ERROR("Couldn't map live_shinfo"); goto out; } @@ -734,16 +740,15 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, live_p2m_frame_list_list = map_frame_list_list(xc_handle, dom, live_shinfo); - - if (!live_p2m_frame_list_list) + if ( !live_p2m_frame_list_list ) goto out; live_p2m_frame_list = xc_map_foreign_batch(xc_handle, dom, PROT_READ, live_p2m_frame_list_list, P2M_FLL_ENTRIES); - - if (!live_p2m_frame_list) { + if ( !live_p2m_frame_list ) + { ERROR("Couldn't map p2m_frame_list"); goto out; } @@ -756,69 +761,70 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, live_p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ, live_p2m_frame_list, P2M_FL_ENTRIES); - - if (!live_p2m) { + if ( !live_p2m ) + { ERROR("Couldn't map p2m table"); goto out; } /* Setup the mfn_to_pfn table mapping */ - if(!(live_m2p = xc_map_m2p(xc_handle, max_mfn, PROT_READ))) { + if ( !(live_m2p = xc_map_m2p(xc_handle, max_mfn, PROT_READ)) ) + { ERROR("Failed to map live M2P table"); goto out; } /* Get a local copy of the live_P2M_frame_list */ - if(!(p2m_frame_list = malloc(P2M_FL_SIZE))) { + if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) ) + { ERROR("Couldn't allocate p2m_frame_list array"); goto out; } memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE); /* Canonicalise the pfn-to-mfn table frame-number list. */ - for (i = 0; i < p2m_size; i += fpp) { - if (!translate_mfn_to_pfn(&p2m_frame_list[i/fpp])) { + for ( i = 0; i < p2m_size; i += fpp ) + { + if ( !translate_mfn_to_pfn(&p2m_frame_list[i/fpp]) ) + { ERROR("Frame# in pfn-to-mfn frame list is not in pseudophys"); ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64, i, i/fpp, - (uint64_t)p2m_frame_list[i/fpp]); + (uint64_t)p2m_frame_list[i/fpp]); goto out; } } /* Domain is still running at this point */ - if (live) { - - if (xc_shadow_control(xc_handle, dom, - XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, - NULL, 0, NULL, 0, NULL) < 0) { + if ( live ) + { + /* Live suspend. Enable log-dirty mode. */ + if ( xc_shadow_control(xc_handle, dom, + XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, + NULL, 0, NULL, 0, NULL) < 0 ) + { ERROR("Couldn't enable shadow mode"); goto out; } - - last_iter = 0; - - } else { - - /* This is a non-live suspend. Issue the call back to get the - domain suspended */ - - last_iter = 1; - - if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info, &ctxt)) { + } + else + { + /* This is a non-live suspend. Suspend the domain .*/ + if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info, &ctxt) ) + { ERROR("Domain appears not to have suspended"); goto out; } - } + last_iter = !live; + /* pretend we sent all the pages last iteration */ sent_last_iter = p2m_size; - /* calculate the power of 2 order of p2m_size, e.g. 15->4 16->4 17->5 */ - for (i = p2m_size-1, order_nr = 0; i ; i >>= 1, order_nr++) + for ( i = p2m_size-1, order_nr = 0; i ; i >>= 1, order_nr++ ) continue; /* Setup to_send / to_fix and to_skip bitmaps */ @@ -826,20 +832,23 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, to_fix = calloc(1, BITMAP_SIZE); to_skip = malloc(BITMAP_SIZE); - if (!to_send || !to_fix || !to_skip) { + if ( !to_send || !to_fix || !to_skip ) + { ERROR("Couldn't allocate to_send array"); goto out; } memset(to_send, 0xff, BITMAP_SIZE); - if (lock_pages(to_send, BITMAP_SIZE)) { + if ( lock_pages(to_send, BITMAP_SIZE) ) + { ERROR("Unable to lock to_send"); return 1; } /* (to fix is local only) */ - if (lock_pages(to_skip, BITMAP_SIZE)) { + if ( lock_pages(to_skip, BITMAP_SIZE) ) + { ERROR("Unable to lock to_skip"); return 1; } @@ -849,14 +858,15 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* We want zeroed memory so use calloc rather than malloc. */ pfn_type = calloc(MAX_BATCH_SIZE, sizeof(*pfn_type)); pfn_batch = calloc(MAX_BATCH_SIZE, sizeof(*pfn_batch)); - - if ((pfn_type == NULL) || (pfn_batch == NULL)) { + if ( (pfn_type == NULL) || (pfn_batch == NULL) ) + { ERROR("failed to alloc memory for pfn_type and/or pfn_batch arrays"); errno = ENOMEM; goto out; } - if (lock_pages(pfn_type, MAX_BATCH_SIZE * sizeof(*pfn_type))) { + if ( lock_pages(pfn_type, MAX_BATCH_SIZE * sizeof(*pfn_type)) ) + { ERROR("Unable to lock"); goto out; } @@ -867,10 +877,11 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, { int err=0; unsigned long mfn; - for (i = 0; i < p2m_size; i++) { - + for ( i = 0; i < p2m_size; i++ ) + { mfn = live_p2m[i]; - if((mfn != INVALID_P2M_ENTRY) && (mfn_to_pfn(mfn) != i)) { + if( (mfn != INVALID_P2M_ENTRY) && (mfn_to_pfn(mfn) != i) ) + { DPRINTF("i=0x%x mfn=%lx live_m2p=%lx\n", i, mfn, mfn_to_pfn(mfn)); err++; @@ -879,10 +890,9 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, DPRINTF("Had %d unexplained entries in p2m table\n", err); } - /* Start writing out the saved-domain record. */ - - if (!write_exact(io_fd, &p2m_size, sizeof(unsigned long))) { + if ( !write_exact(io_fd, &p2m_size, sizeof(unsigned long)) ) + { ERROR("write: p2m_size"); goto out; } @@ -892,23 +902,26 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, * a PAE guest understands extended CR3 (PDPTs above 4GB). Turns off * slow paths in the restore code. */ - if ((pt_levels == 3) && - (ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3))) { + if ( (pt_levels == 3) && + (ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3)) ) + { unsigned long signature = ~0UL; uint32_t tot_sz = sizeof(struct vcpu_guest_context) + 8; uint32_t chunk_sz = sizeof(struct vcpu_guest_context); char chunk_sig[] = "vcpu"; - if (!write_exact(io_fd, &signature, sizeof(signature)) || - !write_exact(io_fd, &tot_sz, sizeof(tot_sz)) || - !write_exact(io_fd, &chunk_sig, 4) || - !write_exact(io_fd, &chunk_sz, sizeof(chunk_sz)) || - !write_exact(io_fd, &ctxt, sizeof(ctxt))) { + if ( !write_exact(io_fd, &signature, sizeof(signature)) || + !write_exact(io_fd, &tot_sz, sizeof(tot_sz)) || + !write_exact(io_fd, &chunk_sig, 4) || + !write_exact(io_fd, &chunk_sz, sizeof(chunk_sz)) || + !write_exact(io_fd, &ctxt, sizeof(ctxt)) ) + { ERROR("write: extended info"); goto out; } } - if (!write_exact(io_fd, p2m_frame_list, P2M_FL_SIZE)) { + if ( !write_exact(io_fd, p2m_frame_list, P2M_FL_SIZE) ) + { ERROR("write: p2m_frame_list"); goto out; } @@ -916,57 +929,65 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, print_stats(xc_handle, dom, 0, &stats, 0); /* Now write out each data page, canonicalising page tables as we go... */ - - while(1) { - + for ( ; ; ) + { unsigned int prev_pc, sent_this_iter, N, batch; iter++; sent_this_iter = 0; skip_this_iter = 0; prev_pc = 0; - N=0; + N = 0; DPRINTF("Saving memory pages: iter %d 0%%", iter); - while( N < p2m_size ){ - + while ( N < p2m_size ) + { unsigned int this_pc = (N * 100) / p2m_size; + int rc; - if ((this_pc - prev_pc) >= 5) { + if ( (this_pc - prev_pc) >= 5 ) + { DPRINTF("\b\b\b\b%3d%%", this_pc); prev_pc = this_pc; } - /* slightly wasteful to peek the whole array evey time, - but this is fast enough for the moment. */ - if (!last_iter && xc_shadow_control( - xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK, - to_skip, p2m_size, NULL, 0, NULL) != p2m_size) { - ERROR("Error peeking shadow bitmap"); - goto out; + if ( !last_iter ) + { + /* Slightly wasteful to peek the whole array evey time, + but this is fast enough for the moment. */ + rc = xc_shadow_control( + xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK, to_skip, + p2m_size, NULL, 0, NULL); + if ( rc != p2m_size ) + { + ERROR("Error peeking shadow bitmap"); + goto out; + } } - /* load pfn_type[] with the mfn of all the pages we're doing in this batch. */ - for (batch = 0; batch < MAX_BATCH_SIZE && N < p2m_size ; N++) { - + for ( batch = 0; + (batch < MAX_BATCH_SIZE) && (N < p2m_size); + N++ ) + { int n = permute(N, p2m_size, order_nr); - if (debug) { + if ( debug ) DPRINTF("%d pfn= %08lx mfn= %08lx %d [mfn]= %08lx\n", iter, (unsigned long)n, live_p2m[n], test_bit(n, to_send), mfn_to_pfn(live_p2m[n]&0xFFFFF)); - } - if (!last_iter && test_bit(n, to_send)&& test_bit(n, to_skip)) + if ( !last_iter && + test_bit(n, to_send) && + test_bit(n, to_skip) ) skip_this_iter++; /* stats keeping */ - if (!((test_bit(n, to_send) && !test_bit(n, to_skip)) || - (test_bit(n, to_send) && last_iter) || - (test_bit(n, to_fix) && last_iter))) + if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) || + (test_bit(n, to_send) && last_iter) || + (test_bit(n, to_fix) && last_iter)) ) continue; /* @@ -979,20 +1000,22 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, pfn_batch[batch] = n; pfn_type[batch] = live_p2m[n]; - if(!is_mapped(pfn_type[batch])) { - + if ( !is_mapped(pfn_type[batch]) ) + { /* ** not currently in psuedo-physical map -- set bit ** in to_fix since we must send this page in last_iter ** unless its sent sooner anyhow, or it never enters ** pseudo-physical map (e.g. for ballooned down domains) */ - set_bit(n, to_fix); continue; } - if(last_iter && test_bit(n, to_fix) && !test_bit(n, to_send)) { + if ( last_iter && + test_bit(n, to_fix) && + !test_bit(n, to_send) ) + { needed_to_fix++; DPRINTF("Fix! iter %d, pfn %x. mfn %lx\n", iter, n, pfn_type[batch]); @@ -1003,11 +1026,13 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, batch++; } - if (batch == 0) + if ( batch == 0 ) goto skip; /* vanishingly unlikely... */ - if ((region_base = xc_map_foreign_batch( - xc_handle, dom, PROT_READ, pfn_type, batch)) == 0) { + region_base = xc_map_foreign_batch( + xc_handle, dom, PROT_READ, pfn_type, batch); + if ( region_base == NULL ) + { ERROR("map batch failed"); goto out; } @@ -1033,7 +1058,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, continue; } - if (debug) + if ( debug ) DPRINTF("%d pfn= %08lx mfn= %08lx [mfn]= %08lx" " sum= %08lx\n", iter, @@ -1049,13 +1074,15 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, pfn_batch[j]; } - if(!write_exact(io_fd, &batch, sizeof(unsigned int))) { + if ( !write_exact(io_fd, &batch, sizeof(unsigned int)) ) + { ERROR("Error when writing to state file (2) (errno %d)", errno); goto out; } - if(!write_exact(io_fd, pfn_type, sizeof(unsigned long)*j)) { + if ( !write_exact(io_fd, pfn_type, sizeof(unsigned long)*j) ) + { ERROR("Error when writing to state file (3) (errno %d)", errno); goto out; @@ -1083,22 +1110,26 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, race = canonicalize_pagetable(pagetype, pfn, spage, page); - if(race && !live) { + if ( race && !live ) + { ERROR("Fatal PT race (pfn %lx, type %08lx)", pfn, pagetype); goto out; } - if (ratewrite(io_fd, live, page, PAGE_SIZE) != PAGE_SIZE) { + if ( ratewrite(io_fd, live, page, PAGE_SIZE) != PAGE_SIZE ) + { ERROR("Error when writing to state file (4)" " (errno %d)", errno); goto out; } - - } else { - + } + else + { /* We have a normal page: just write it directly. */ - if (ratewrite(io_fd, live, spage, PAGE_SIZE) != PAGE_SIZE) { + if ( ratewrite(io_fd, live, spage, PAGE_SIZE) != + PAGE_SIZE ) + { ERROR("Error when writing to state file (5)" " (errno %d)", errno); goto out; @@ -1119,7 +1150,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, DPRINTF("\r %d: sent %d, skipped %d, ", iter, sent_this_iter, skip_this_iter ); - if (last_iter) { + if ( last_iter ) + { print_stats( xc_handle, dom, sent_this_iter, &stats, 1); DPRINTF("Total pages sent= %ld (%.2fx)\n", @@ -1127,14 +1159,16 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, DPRINTF("(of which %ld were fixups)\n", needed_to_fix ); } - if (last_iter && debug) { + if ( last_iter && debug ) + { int minusone = -1; memset(to_send, 0xff, BITMAP_SIZE); debug = 0; DPRINTF("Entering debug resend-all mode\n"); /* send "-1" to put receiver into debug mode */ - if(!write_exact(io_fd, &minusone, sizeof(int))) { + if ( !write_exact(io_fd, &minusone, sizeof(int)) ) + { ERROR("Error when writing to state file (6) (errno %d)", errno); goto out; @@ -1143,19 +1177,22 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, continue; } - if (last_iter) + if ( last_iter ) break; - if (live) { - if (((sent_this_iter > sent_last_iter) && RATE_IS_MAX()) || - (iter >= max_iters) || - (sent_this_iter+skip_this_iter < 50) || - (total_sent > p2m_size*max_factor)) { + if ( live ) + { + if ( ((sent_this_iter > sent_last_iter) && RATE_IS_MAX()) || + (iter >= max_iters) || + (sent_this_iter+skip_this_iter < 50) || + (total_sent > p2m_size*max_factor) ) + { DPRINTF("Start last iteration\n"); last_iter = 1; - if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info, - &ctxt)) { + if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info, + &ctxt) ) + { ERROR("Domain appears not to have suspended"); goto out; } @@ -1166,9 +1203,10 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, (unsigned long)ctxt.user_regs.edx); } - if (xc_shadow_control(xc_handle, dom, - XEN_DOMCTL_SHADOW_OP_CLEAN, to_send, - p2m_size, NULL, 0, &stats) != p2m_size) { + if ( xc_shadow_control(xc_handle, dom, + XEN_DOMCTL_SHADOW_OP_CLEAN, to_send, + p2m_size, NULL, 0, &stats) != p2m_size ) + { ERROR("Error flushing shadow PT"); goto out; } @@ -1178,7 +1216,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, print_stats(xc_handle, dom, sent_this_iter, &stats, 1); } - } /* end of while 1 */ + } /* end of infinite for loop */ DPRINTF("All memory is saved\n"); @@ -1189,20 +1227,23 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, uint64_t vcpumap; } chunk = { -2, info.max_vcpu_id }; - if (info.max_vcpu_id >= 64) { + if ( info.max_vcpu_id >= 64 ) + { ERROR("Too many VCPUS in guest!"); goto out; } - for (i = 1; i <= info.max_vcpu_id; i++) { + 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) + 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))) { + if ( !write_exact(io_fd, &chunk, sizeof(chunk)) ) + { ERROR("Error when writing to state file (errno %d)", errno); goto out; } @@ -1210,7 +1251,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* Zero terminate */ i = 0; - if (!write_exact(io_fd, &i, sizeof(int))) { + if ( !write_exact(io_fd, &i, sizeof(int)) ) + { ERROR("Error when writing to state file (6') (errno %d)", errno); goto out; } @@ -1220,24 +1262,28 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, unsigned int i,j; unsigned long pfntab[1024]; - for (i = 0, j = 0; i < p2m_size; i++) { - if (!is_mapped(live_p2m[i])) + for ( i = 0, j = 0; i < p2m_size; i++ ) + { + if ( !is_mapped(live_p2m[i]) ) j++; } - if(!write_exact(io_fd, &j, sizeof(unsigned int))) { + if ( !write_exact(io_fd, &j, sizeof(unsigned int)) ) + { ERROR("Error when writing to state file (6a) (errno %d)", errno); goto out; } - for (i = 0, j = 0; i < p2m_size; ) { - - if (!is_mapped(live_p2m[i])) + for ( i = 0, j = 0; i < p2m_size; ) + { + if ( !is_mapped(live_p2m[i]) ) pfntab[j++] = i; i++; - if (j == 1024 || i == p2m_size) { - if(!write_exact(io_fd, &pfntab, sizeof(unsigned long)*j)) { + if ( (j == 1024) || (i == p2m_size) ) + { + if ( !write_exact(io_fd, &pfntab, sizeof(unsigned long)*j) ) + { ERROR("Error when writing to state file (6b) (errno %d)", errno); goto out; @@ -1245,34 +1291,39 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, j = 0; } } - } /* Canonicalise the suspend-record frame number. */ - if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) ){ + if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) ) + { ERROR("Suspend record is not in range of pseudophys map"); goto out; } - for (i = 0; i <= info.max_vcpu_id; i++) { - if (!(vcpumap & (1ULL << i))) + 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)) { + if ( (i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt) ) + { ERROR("No context for VCPU%d", i); goto out; } /* Canonicalise each GDT frame number. */ - for ( j = 0; (512*j) < ctxt.gdt_ents; j++ ) { - if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[j]) ) { + 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])) ) { + 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; } @@ -1282,7 +1333,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */ if ( (pt_levels == 4) && ctxt.ctrlreg[1] ) { - if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) ) { + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) ) + { ERROR("PT base is not in range of pseudophys map"); goto out; } @@ -1291,7 +1343,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[1]))); } - if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) { + if ( !write_exact(io_fd, &ctxt, sizeof(ctxt)) ) + { ERROR("Error when writing to state file (1) (errno %d)", errno); goto out; } @@ -1302,7 +1355,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, */ memcpy(page, live_shinfo, PAGE_SIZE); ((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0; - if (!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; } @@ -1312,30 +1366,30 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, out: - if (live) { - if(xc_shadow_control(xc_handle, dom, - XEN_DOMCTL_SHADOW_OP_OFF, - NULL, 0, NULL, 0, NULL) < 0) { + if ( live ) + { + if ( xc_shadow_control(xc_handle, dom, + XEN_DOMCTL_SHADOW_OP_OFF, + NULL, 0, NULL, 0, NULL) < 0 ) DPRINTF("Warning - couldn't disable shadow mode"); - } } - // flush last write and discard cache for file + /* Flush last write and discard cache for file. */ discard_file_cache(io_fd, 1 /* flush */); - if (live_shinfo) + if ( live_shinfo ) munmap(live_shinfo, PAGE_SIZE); - if (live_p2m_frame_list_list) + if ( live_p2m_frame_list_list ) munmap(live_p2m_frame_list_list, PAGE_SIZE); - if (live_p2m_frame_list) + if ( live_p2m_frame_list ) munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE); - if (live_p2m) + if ( live_p2m ) munmap(live_p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT)); - if (live_m2p) + if ( live_m2p ) munmap(live_m2p, M2P_SIZE(max_mfn)); free(pfn_type); |