diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/xc/lib/xc.h | 1 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_restore.c | 67 | ||||
-rw-r--r-- | tools/xc/lib/xc_linux_save.c | 104 | ||||
-rw-r--r-- | tools/xc/lib/xc_private.c | 20 | ||||
-rw-r--r-- | tools/xc/py/Xc.c | 10 |
5 files changed, 172 insertions, 30 deletions
diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h index 2132d6e7c1..223710fad1 100644 --- a/tools/xc/lib/xc.h +++ b/tools/xc/lib/xc.h @@ -64,6 +64,7 @@ int xc_shadow_control(int xc_handle, #define XCFLAGS_VERBOSE 1 #define XCFLAGS_LIVE 2 +#define XCFLAGS_DEBUG 4 int xc_linux_save(int xc_handle, u64 domid, diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c index 1bbc575889..d66e22fd0a 100644 --- a/tools/xc/lib/xc_linux_restore.c +++ b/tools/xc/lib/xc_linux_restore.c @@ -67,6 +67,7 @@ int xc_linux_restore(int xc_handle, unsigned long mfn, pfn, xpfn; unsigned int prev_pc, this_pc; int verbose = flags & XCFLAGS_VERBOSE; + int verify = 0; /* Number of page frames in use by this Linux session. */ unsigned long nr_pfns; @@ -106,6 +107,8 @@ int xc_linux_restore(int xc_handle, int pm_handle = -1; + /* used by debug verify code */ + unsigned long buf[PAGE_SIZE/sizeof(unsigned long)]; if ( mlock(&ctxt, sizeof(ctxt) ) ) { @@ -241,8 +244,17 @@ int xc_linux_restore(int xc_handle, DPRINTF("batch %d\n",j); + if (j == -1) + { + verify = 1; + printf("Entering page verify mode\n"); + continue; + } + if (j == 0) + { break; // our work here is done + } if( j > MAX_BATCH_SIZE ) { @@ -296,7 +308,10 @@ int xc_linux_restore(int xc_handle, mfn = pfn_to_mfn_table[pfn]; - ppage = (unsigned long*) (region_base + i*PAGE_SIZE); + if ( verify ) + ppage = (unsigned long*) buf; // debug case + else + ppage = (unsigned long*) (region_base + i*PAGE_SIZE); if ( (*readerfn)(readerst, ppage, PAGE_SIZE) ) { @@ -364,6 +379,24 @@ int xc_linux_restore(int xc_handle, } // end of page type switch statement + if ( verify ) + { + int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE ); + if (res) + { + int v; + printf("************** pfn=%x type=%x gotcs=%08lx actualcs=%08lx\n",pfn,pfn_type[pfn],csum_page(region_base + i*PAGE_SIZE),csum_page(buf)); + for(v=0;v<4;v++) + { + unsigned long * p = (unsigned long *) (region_base + i*PAGE_SIZE); + if ( buf[v] != p[v] ) + printf(" %d: %08lx %08lx\n", + v, buf[v], p[v] ); + } + + } + } + if ( add_mmu_update(xc_handle, mmu, (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) ) goto out; @@ -421,7 +454,6 @@ int xc_linux_restore(int xc_handle, goto out; } - /* Uncanonicalise the suspend-record frame number and poke resume rec. */ pfn = ctxt.cpu_ctxt.esi; if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) ) @@ -464,6 +496,12 @@ int xc_linux_restore(int xc_handle, } ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT; + + /* clear any pending events and the selector */ + memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]), + 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+ + sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) ); + /* Copy saved contents of shared-info page. No checking needed. */ ppage = map_pfn_writeable(pm_handle, shared_info_frame); memcpy(ppage, shared_info, sizeof(shared_info_t)); @@ -543,13 +581,18 @@ int xc_linux_restore(int xc_handle, op.u.builddomain.ctxt = &ctxt; rc = do_dom0_op(xc_handle, &op); - DPRINTF("Everything OK!\n"); + /* don't start the domain as we have console etc to set up */ + + if( rc == 0 ) + { + /* Success: print the domain id. */ + verbose_printf("DOM=%llu\n", dom); + return 0; + } - out: - if ( mmu != NULL ) - free(mmu); - if ( rc != 0 ) + out: + if ( rc != 0 ) // destroy is something went wrong { if ( dom != 0 ) { @@ -559,11 +602,9 @@ int xc_linux_restore(int xc_handle, (void)do_dom0_op(xc_handle, &op); } } - else - { - /* Success: print the domain id. */ - verbose_printf("DOM=%llu\n", dom); - } + + if ( mmu != NULL ) + free(mmu); if ( pm_handle >= 0 ) (void)close_pfn_mapper(pm_handle); @@ -577,5 +618,7 @@ int xc_linux_restore(int xc_handle, if ( rc == 0 ) *pdomid = dom; + DPRINTF("Restore exit with rc=%d\n",rc); + return rc; } 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; diff --git a/tools/xc/lib/xc_private.c b/tools/xc/lib/xc_private.c index 41eb2e744a..430dc6ec11 100644 --- a/tools/xc/lib/xc_private.c +++ b/tools/xc/lib/xc_private.c @@ -410,7 +410,7 @@ int xc_domain_stop_sync( int xc_handle, domid_t domid ) if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED ) { - printf("\nDomain %lld stopped\n",domid); + printf("Domain %lld stopped\n",domid); return 0; } @@ -420,3 +420,21 @@ int xc_domain_stop_sync( int xc_handle, domid_t domid ) out: return -1; } + +/**********************************************************************/ + +// this is shared between save and restore, and may be useful. + +unsigned long csum_page ( void * page ) +{ + int i; + unsigned long *p = page; + unsigned long long sum=0; + + for (i=0;i<PAGE_SIZE/sizeof(unsigned long);i++) + { + sum += p[i]; + } + + return sum ^ (sum>>32); +} diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index b2ae143eda..7bb1d877bd 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -191,17 +191,18 @@ static PyObject *pyxc_linux_save(PyObject *self, u64 dom; char *state_file; - int progress = 1, live = -1; + int progress = 1, live = -1, debug = 0; unsigned int flags = 0; - static char *kwd_list[] = { "dom", "state_file", "progress", "live", NULL }; + static char *kwd_list[] = { "dom", "state_file", "progress", "live", "debug", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ii", kwd_list, - &dom, &state_file, &progress, &live) ) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|iii", kwd_list, + &dom, &state_file, &progress, &live, &debug) ) return NULL; if (progress) flags |= XCFLAGS_VERBOSE; if (live == 1) flags |= XCFLAGS_LIVE; + if (debug) flags |= XCFLAGS_DEBUG; if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 ) { @@ -362,6 +363,7 @@ static PyObject *pyxc_linux_restore(PyObject *self, do { rc = read( (int) fd, ((char*)buf)+tot, count-tot ); if ( rc < 0 ) { perror("READ"); return rc; } + if ( rc == 0 ) { printf("read: need %d, tot=%d got zero\n"); return -1; } tot += rc; } while ( tot < count ); |