diff options
Diffstat (limited to 'tools/xc/lib/xc_linux_save.c')
-rw-r--r-- | tools/xc/lib/xc_linux_save.c | 104 |
1 files changed, 91 insertions, 13 deletions
diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c index 37dd7c6fce..ceb5f02e15 100644 --- a/tools/xc/lib/xc_linux_save.c +++ b/tools/xc/lib/xc_linux_save.c @@ -12,6 +12,7 @@ #define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */ #define DEBUG 0 +#define DDEBUG 0 #if DEBUG #define DPRINTF(_f, _a...) printf ( _f , ## _a ) @@ -19,6 +20,14 @@ #define DPRINTF(_f, _a...) ((void)0) #endif +#if DDEBUG +#define DDPRINTF(_f, _a...) printf ( _f , ## _a ) +#else +#define DDPRINTF(_f, _a...) ((void)0) +#endif + + + /* This may allow us to create a 'quiet' command-line option, if necessary. */ #define verbose_printf(_f, _a...) \ do { \ @@ -61,6 +70,18 @@ inline int test_bit ( int nr, volatile void * addr) (nr % (sizeof(unsigned long)*8) ) ) & 1; } +inline void clear_bit ( int nr, volatile void * addr) +{ + ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &= + ~(1 << (nr % (sizeof(unsigned long)*8) ) ); +} + +inline void set_bit ( int nr, volatile void * addr) +{ + ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |= + (1 << (nr % (sizeof(unsigned long)*8) ) ); +} + int xc_linux_save(int xc_handle, u64 domid, @@ -73,6 +94,7 @@ int xc_linux_save(int xc_handle, unsigned long mfn; int verbose = flags & XCFLAGS_VERBOSE; int live = flags & XCFLAGS_LIVE; + int debug = flags & XCFLAGS_DEBUG; int sent_last_iter, sent_this_iter, max_iters; /* Remember if we stopped the guest, so we can restart it on exit. */ @@ -89,6 +111,7 @@ int xc_linux_save(int xc_handle, /* A table containg the type of each PFN (/not/ MFN!). */ unsigned long *pfn_type = NULL; + unsigned long *pfn_batch = NULL; /* A temporary mapping, and a copy, of one frame of guest memory. */ unsigned long page[1024]; @@ -115,7 +138,9 @@ int xc_linux_save(int xc_handle, unsigned long nr_pfns; /* bitmap of pages left to send */ - unsigned long *to_send; + unsigned long *to_send, *to_fix; + +//live=0; if ( mlock(&ctxt, sizeof(ctxt) ) ) { @@ -274,8 +299,9 @@ int xc_linux_save(int xc_handle, int sz = (nr_pfns/8) + 8; // includes slop at end of array to_send = malloc( sz ); + to_fix = calloc( 1, sz ); - if (!to_send) + if (!to_send || !to_fix) { ERROR("Couldn't allocate to_send array"); goto out; @@ -292,8 +318,9 @@ int xc_linux_save(int xc_handle, /* We want zeroed memory so use calloc rather than malloc. */ pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long)); + pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long)); - if ( (pfn_type == NULL) ) + if ( (pfn_type == NULL) || (pfn_batch == NULL) ) { errno = ENOMEM; goto out; @@ -370,22 +397,41 @@ int xc_linux_save(int xc_handle, for( batch = 0; batch < BATCH_SIZE && n < nr_pfns ; n++ ) { - if ( !test_bit(n, to_send ) ) continue; + if(0 && debug) + fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d [mfn]= %08lx\n", + iter, n, live_pfn_to_mfn_table[n], + test_bit(n,to_send), + live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&0xFFFFF]); + + + if ( !test_bit(n, to_send ) && + !( last_iter && test_bit(n, to_fix ) ) ) continue; + + pfn_batch[batch] = n; pfn_type[batch] = live_pfn_to_mfn_table[n]; if( pfn_type[batch] == 0x80000004 ) { - DPRINTF("Skip netbuf pfn %lx. mfn %lx\n",n,pfn_type[batch]); + set_bit( n, to_fix ); + if( iter>1 ) + DDPRINTF("Urk! netbuf race: iter %d, pfn %lx. mfn %lx\n", + iter,n,pfn_type[batch]); continue; } - if(iter>1) { DPRINTF("pfn=%x mfn=%x\n",n,pfn_type[batch]); } - + if ( last_iter && test_bit(n, to_fix ) && !test_bit(n, to_send )) + { + DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n", + iter,n,pfn_type[batch]); + } + + clear_bit( n, to_fix ); + batch++; } - DPRINTF("batch %d:%d (n=%d)\n",iter,batch,n); + DDPRINTF("batch %d:%d (n=%d)\n",iter,batch,n); if(batch == 0) goto skip; // vanishingly unlikely... @@ -408,15 +454,26 @@ int xc_linux_save(int xc_handle, { if((pfn_type[j]>>29) == 7) { - DPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); + DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); continue; } + if(0 && debug) + fprintf(stderr,"%d pfn= %08lx mfn= %08lx [mfn]= %08lx sum= %08lx\n", + iter, + (pfn_type[j] & PGT_type_mask) | pfn_batch[j], + pfn_type[j], + live_mfn_to_pfn_table[pfn_type[j]&(~PGT_type_mask)], + csum_page(region_base + (PAGE_SIZE*j)) + ); + /* canonicalise mfn->pfn */ pfn_type[j] = (pfn_type[j] & PGT_type_mask) | - live_mfn_to_pfn_table[pfn_type[j]&~PGT_type_mask]; + pfn_batch[j]; + //live_mfn_to_pfn_table[pfn_type[j]&~PGT_type_mask]; + } - + if ( (*writerfn)(writerst, &batch, sizeof(int) ) ) { @@ -437,7 +494,7 @@ int xc_linux_save(int xc_handle, if((pfn_type[j]>>29) == 7) { - DPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); + DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); continue; } @@ -494,6 +551,7 @@ int xc_linux_save(int xc_handle, } /* end of it's a PT page */ else { /* normal page */ + if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j), PAGE_SIZE) ) { ERROR("Error when writing to state file (5)"); @@ -512,6 +570,23 @@ int xc_linux_save(int xc_handle, verbose_printf("\b\b\b\b100%% (%d pages)\n", sent_this_iter ); + if ( debug && last_iter ) + { + int minusone = -1; + memset( to_send, 0xff, nr_pfns/8 ); + debug = 0; + printf("Entering debug resend-all mode\n"); + + /* send "-1" to put receiver into debug mode */ + if ( (*writerfn)(writerst, &minusone, sizeof(int)) ) + { + ERROR("Error when writing to state file (6)"); + goto out; + } + + continue; + } + if ( last_iter ) break; @@ -520,7 +595,7 @@ int xc_linux_save(int xc_handle, if ( ( sent_this_iter > (sent_last_iter * 0.95) ) || (iter >= max_iters) || (sent_this_iter < 10) ) { - printf("Start last iteration\n"); + DPRINTF("Start last iteration\n"); last_iter = 1; xc_domain_stop_sync( xc_handle, domid ); @@ -536,6 +611,7 @@ int xc_linux_save(int xc_handle, } sent_last_iter = sent_this_iter; + } @@ -609,6 +685,8 @@ out: if ( pfn_type != NULL ) free(pfn_type); + + DPRINTF("Save exit rc=%d\n",rc); return !!rc; |