diff options
-rw-r--r-- | .rootkeys | 1 | ||||
-rw-r--r-- | BitKeeper/etc/ignore | 1 | ||||
-rw-r--r-- | tools/libxc/xc.h | 17 | ||||
-rw-r--r-- | tools/libxc/xc_linux_restore.c | 8 | ||||
-rw-r--r-- | tools/libxc/xc_linux_save.c | 339 | ||||
-rw-r--r-- | tools/python/xen/lowlevel/xc/xc.c | 96 | ||||
-rw-r--r-- | tools/python/xen/util/xpopen.py | 2 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomain.py | 90 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomainInfo.py | 16 | ||||
-rw-r--r-- | tools/xcutils/Makefile | 3 | ||||
-rw-r--r-- | tools/xcutils/xc_save.c | 29 | ||||
-rw-r--r-- | tools/xfrd/xen_domain.c | 2 |
12 files changed, 304 insertions, 300 deletions
@@ -1032,6 +1032,7 @@ 41d58ba6ijEF6fedqRO5vFu7uCirZg tools/xcs/xcsdump.c 4292540couq-V0TPwyQ6bspNEWNcvw tools/xcutils/Makefile 42925407VysDb9O06OK_RUzTZxfLoA tools/xcutils/xc_restore.c +42936745WTLYamYsmXm_JGJ72JX-_Q tools/xcutils/xc_save.c 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index a48ab6cff9..d996d45a72 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -127,6 +127,7 @@ tools/x2d2/minixend tools/xcs/xcs tools/xcs/xcsdump tools/xcutils/xc_restore +tools/xcutils/xc_save tools/xentrace/xentrace tools/xfrd/xfrd xen/BLOG diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 3c7f7e5564..c31222fc90 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -225,23 +225,22 @@ int xc_shadow_control(int xc_handle, struct XcIOContext; /** - * This function will save a domain running Linux to an IO context. This - * IO context is currently a private interface making this function difficult - * to call. It's interface will likely change in the future. + * This function will save a domain running Linux. * * @parm xc_handle a handle to an open hypervisor interface - * @parm ioctxt the IO context to save a domain to + * @parm fd the file descriptor to save a domain to + * @parm dom the id of the domain * @return 0 on success, -1 on failure */ -int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt); +int xc_linux_save(int xc_handle, int fd, u32 dom); /** - * This function will restore a saved domain running Linux to an IO context. - * Like xc_linux_save(), this function uses a parameter who's structure is - * privately defined. It's interface will also likely change. + * This function will restore a saved domain running Linux. * * @parm xc_handle a handle to an open hypervisor interface - * @parm ioctxt the IO context to restore a domain from + * @parm fd the file descriptor to restore a domain from + * @parm dom the id of the domain + * @parm nr_pfns the number of pages * @return 0 on success, -1 on failure */ int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns); diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c index c679e9dd5a..cc8e4b4d29 100644 --- a/tools/libxc/xc_linux_restore.c +++ b/tools/libxc/xc_linux_restore.c @@ -11,23 +11,23 @@ #define MAX_BATCH_SIZE 1024 -#define DEBUG 01 +#define DEBUG 0 #if 1 -#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a ) +#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a ); fflush(stderr) #else #define ERR(_f, _a...) ((void)0) #endif #if DEBUG -#define DPRINTF(_f, _a...) fprintf ( stdout, _f , ## _a ) +#define DPRINTF(_f, _a...) fprintf ( stdout, _f , ## _a ); fflush(stdout) #else #define DPRINTF(_f, _a...) ((void)0) #endif #define PROGRESS 0 #if PROGRESS -#define PPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ) +#define PPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ); fflush(stderr) #else #define PPRINTF(_f, _a...) #endif diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c index 8273f9c56c..feb051884d 100644 --- a/tools/libxc/xc_linux_save.c +++ b/tools/libxc/xc_linux_save.c @@ -17,19 +17,25 @@ #define MAX_MBIT_RATE 500 -#define DEBUG 0 -#define DDEBUG 0 +#define DEBUG 0 + +#if 1 +#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a ) +#else +#define ERR(_f, _a...) ((void)0) +#endif #if DEBUG -#define DPRINTF(_f, _a...) printf ( _f , ## _a ) +#define DPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ) #else #define DPRINTF(_f, _a...) ((void)0) #endif -#if DDEBUG -#define DDPRINTF(_f, _a...) printf ( _f , ## _a ) +#define PROGRESS 0 +#if PROGRESS +#define PPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a ) #else -#define DDPRINTF(_f, _a...) ((void)0) +#define PPRINTF(_f, _a...) #endif /* @@ -144,7 +150,7 @@ static long long tv_delta( struct timeval *new, struct timeval *old ) } -#define START_MBIT_RATE ioctxt->resource +#define START_MBIT_RATE 0 //ioctxt->resource static int mbit_rate, ombit_rate = 0; static int burst_time_us = -1; @@ -167,7 +173,8 @@ static int burst_time_us = -1; #define RATE_TO_BTU 781250 #define BURST_TIME_US burst_time_us -static int xcio_ratewrite(XcIOContext *ioctxt, void *buf, int n) +static int +ratewrite(int io_fd, void *buf, int n) { static int budget = 0; static struct timeval last_put = { 0 }; @@ -176,16 +183,15 @@ static int xcio_ratewrite(XcIOContext *ioctxt, void *buf, int n) long long delta; if (START_MBIT_RATE == 0) - return xcio_write(ioctxt, buf, n); + return write(io_fd, buf, n); budget -= n; if (budget < 0) { if (MBIT_RATE != ombit_rate) { BURST_TIME_US = RATE_TO_BTU / MBIT_RATE; ombit_rate = MBIT_RATE; - xcio_info(ioctxt, - "rate limit: %d mbit/s burst budget %d slot time %d\n", - MBIT_RATE, BURST_BUDGET, BURST_TIME_US); + 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) { budget += BURST_BUDGET; @@ -213,7 +219,7 @@ static int xcio_ratewrite(XcIOContext *ioctxt, void *buf, int n) } } } - return xcio_write(ioctxt, buf, n); + return write(io_fd, buf, n); } static int print_stats( int xc_handle, u32 domid, @@ -235,7 +241,7 @@ static int print_stats( int xc_handle, u32 domid, d1_cpu_now = xc_domain_get_cpu_usage(xc_handle, domid, /* FIXME */ 0)/1000; if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) ) - printf("ARRHHH!!\n"); + fprintf(stderr, "ARRHHH!!\n"); wall_delta = tv_delta(&wall_now,&wall_last)/1000; @@ -245,14 +251,15 @@ static int print_stats( int xc_handle, u32 domid, d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000; if ( print ) - printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " - "dirtied %dMb/s %" PRId32 " pages\n", - wall_delta, - (int)((d0_cpu_delta*100)/wall_delta), - (int)((d1_cpu_delta*100)/wall_delta), - (int)((pages_sent*PAGE_SIZE)/(wall_delta*(1000/8))), - (int)((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))), - stats->dirty_count); + fprintf(stderr, + "delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, " + "dirtied %dMb/s %" PRId32 " pages\n", + wall_delta, + (int)((d0_cpu_delta*100)/wall_delta), + (int)((d1_cpu_delta*100)/wall_delta), + (int)((pages_sent*PAGE_SIZE)/(wall_delta*(1000/8))), + (int)((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))), + stats->dirty_count); if (((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))) > mbit_rate) { mbit_rate = (int)((stats->dirty_count*PAGE_SIZE)/(wall_delta*(1000/8))) @@ -268,24 +275,6 @@ static int print_stats( int xc_handle, u32 domid, return 0; } -/** Write the vmconfig string. - * It is stored as a 4-byte count 'n' followed by n bytes. - * - * @param ioctxt i/o context - * @return 0 on success, non-zero on error. - */ -static int write_vmconfig(XcIOContext *ioctxt) -{ - int err = -1; - if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) - goto exit; - if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) - goto exit; - err = 0; - exit: - return err; -} - static int analysis_phase( int xc_handle, u32 domid, int nr_pfns, unsigned long *arr, int runs ) { @@ -302,7 +291,7 @@ static int analysis_phase( int xc_handle, u32 domid, xc_shadow_control( xc_handle, domid, DOM0_SHADOW_CONTROL_OP_CLEAN, arr, nr_pfns, NULL); - printf("#Flush\n"); + fprintf(stderr, "#Flush\n"); for ( i = 0; i < 40; i++ ) { usleep(50000); @@ -311,11 +300,11 @@ static int analysis_phase( int xc_handle, u32 domid, DOM0_SHADOW_CONTROL_OP_PEEK, NULL, 0, &stats); - printf("now= %lld faults= %" PRId32 " dirty= %" PRId32 - " dirty_net= %" PRId32 " dirty_block= %" PRId32"\n", - ((now-start)+500)/1000, - stats.fault_count, stats.dirty_count, - stats.dirty_net_count, stats.dirty_block_count); + fprintf(stderr, "now= %lld faults= %" PRId32 " dirty= %" PRId32 + " dirty_net= %" PRId32 " dirty_block= %" PRId32"\n", + ((now-start)+500)/1000, + stats.fault_count, stats.dirty_count, + stats.dirty_net_count, stats.dirty_block_count); } } @@ -323,26 +312,36 @@ static int analysis_phase( int xc_handle, u32 domid, } -int suspend_and_state(int xc_handle, XcIOContext *ioctxt, +int suspend_and_state(int xc_handle, int io_fd, int dom, xc_dominfo_t *info, vcpu_guest_context_t *ctxt) { int i=0; - - xcio_suspend_domain(ioctxt); + char ans[30]; + + printf("suspend\n"); + fflush(stdout); + if (fgets(ans, sizeof(ans), stdin) == NULL) { + ERR("failed reading suspend reply"); + return -1; + } + if (strncmp(ans, "done\n", 5)) { + ERR("suspend reply incorrect: %s", ans); + return -1; + } retry: - if ( xc_domain_getinfo(xc_handle, ioctxt->domain, 1, info) != 1) + if ( xc_domain_getinfo(xc_handle, dom, 1, info) != 1) { - xcio_error(ioctxt, "Could not get domain info"); + ERR("Could not get domain info"); return -1; } - if ( xc_domain_get_vcpu_context(xc_handle, ioctxt->domain, 0 /* XXX */, + if ( xc_domain_get_vcpu_context(xc_handle, dom, 0 /* XXX */, ctxt) ) { - xcio_error(ioctxt, "Could not get vcpu context"); + ERR("Could not get vcpu context"); } if ( info->shutdown && info->shutdown_reason == SHUTDOWN_suspend ) @@ -353,9 +352,9 @@ retry: if ( info->paused ) { // try unpausing domain, wait, and retest - xc_domain_unpause( xc_handle, ioctxt->domain ); + xc_domain_unpause( xc_handle, dom ); - xcio_error(ioctxt, "Domain was paused. Wait and re-test."); + ERR("Domain was paused. Wait and re-test."); usleep(10000); // 10ms goto retry; @@ -364,25 +363,24 @@ retry: if( ++i < 100 ) { - xcio_error(ioctxt, "Retry suspend domain."); + ERR("Retry suspend domain."); usleep(10000); // 10ms goto retry; } - xcio_error(ioctxt, "Unable to suspend domain."); + ERR("Unable to suspend domain."); return -1; } -int xc_linux_save(int xc_handle, XcIOContext *ioctxt) +int xc_linux_save(int xc_handle, int io_fd, u32 dom) { xc_dominfo_t info; int rc = 1, i, j, k, last_iter, iter = 0; unsigned long mfn; - u32 domid = ioctxt->domain; - int live = (ioctxt->flags & XCFLAGS_LIVE); - int debug = (ioctxt->flags & XCFLAGS_DEBUG); + int live = 0; // (ioctxt->flags & XCFLAGS_LIVE); + int debug = 0; // (ioctxt->flags & XCFLAGS_DEBUG); int sent_last_iter, skip_this_iter; /* Important tuning parameters */ @@ -440,29 +438,29 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) MBIT_RATE = START_MBIT_RATE; - xcio_info(ioctxt, "xc_linux_save start %d\n", domid); + DPRINTF("xc_linux_save start %d\n", dom); if (mlock(&ctxt, sizeof(ctxt))) { - xcio_perror(ioctxt, "Unable to mlock ctxt"); + ERR("Unable to mlock ctxt"); return 1; } - if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1) + if ( xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) { - xcio_error(ioctxt, "Could not get domain info"); + ERR("Could not get domain info"); goto out; } - if ( xc_domain_get_vcpu_context( xc_handle, domid, /* FIXME */ 0, + if ( xc_domain_get_vcpu_context( xc_handle, dom, /* FIXME */ 0, &ctxt) ) { - xcio_error(ioctxt, "Could not get vcpu context"); + ERR("Could not get vcpu context"); goto out; } shared_info_frame = info.shared_info_frame; /* A cheesy test to see whether the domain contains valid state. */ if ( ctxt.pt_base == 0 ){ - xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state"); + ERR("Domain is not in a valid Linux guest OS state"); goto out; } @@ -470,31 +468,29 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) /* cheesy sanity check */ if ( nr_pfns > 1024*1024 ){ - xcio_error(ioctxt, - "Invalid state record -- pfn count out of range: %lu", - nr_pfns); + ERR("Invalid state record -- pfn count out of range: %lu", nr_pfns); goto out; } /* Map the shared info frame */ - live_shinfo = xc_map_foreign_range(xc_handle, domid, + live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, shared_info_frame); if (!live_shinfo){ - xcio_error(ioctxt, "Couldn't map live_shinfo"); + ERR("Couldn't map live_shinfo"); goto out; } /* the pfn_to_mfn_frame_list fits in a single page */ live_pfn_to_mfn_frame_list = - xc_map_foreign_range(xc_handle, domid, + xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, live_shinfo->arch.pfn_to_mfn_frame_list ); if (!live_pfn_to_mfn_frame_list){ - xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list"); + ERR("Couldn't map pfn_to_mfn_frame_list"); goto out; } @@ -504,12 +500,12 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) (its not clear why it would want to change them, and we'll be OK from a safety POV anyhow. */ - live_pfn_to_mfn_table = xc_map_foreign_batch(xc_handle, domid, + live_pfn_to_mfn_table = xc_map_foreign_batch(xc_handle, dom, PROT_READ, live_pfn_to_mfn_frame_list, (nr_pfns+1023)/1024 ); if( !live_pfn_to_mfn_table ){ - xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table"); + ERR("Couldn't map pfn_to_mfn table"); goto out; } @@ -526,8 +522,7 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) for ( i = 0; i < nr_pfns; i += 1024 ){ if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){ - xcio_error(ioctxt, - "Frame# in pfn-to-mfn frame list is not in pseudophys"); + ERR("Frame# in pfn-to-mfn frame list is not in pseudophys"); goto out; } } @@ -537,10 +532,10 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) if( live ) { - if ( xc_shadow_control( xc_handle, domid, + if ( xc_shadow_control( xc_handle, dom, DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY, NULL, 0, NULL ) < 0 ) { - xcio_error(ioctxt, "Couldn't enable shadow mode"); + ERR("Couldn't enable shadow mode"); goto out; } @@ -551,9 +546,9 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) last_iter = 1; - if ( suspend_and_state( xc_handle, ioctxt, &info, &ctxt) ) + if ( suspend_and_state( xc_handle, io_fd, dom, &info, &ctxt) ) { - xcio_error(ioctxt, "Domain appears not to have suspended"); + ERR("Domain appears not to have suspended"); goto out; } @@ -577,27 +572,27 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) to_skip = malloc( sz ); if (!to_send || !to_fix || !to_skip){ - xcio_error(ioctxt, "Couldn't allocate to_send array"); + ERR("Couldn't allocate to_send array"); goto out; } memset( to_send, 0xff, sz ); if ( mlock( to_send, sz ) ){ - xcio_perror(ioctxt, "Unable to mlock to_send"); + ERR("Unable to mlock to_send"); return 1; } /* (to fix is local only) */ if ( mlock( to_skip, sz ) ){ - xcio_perror(ioctxt, "Unable to mlock to_skip"); + ERR("Unable to mlock to_skip"); return 1; } } - analysis_phase( xc_handle, domid, nr_pfns, to_skip, 0 ); + analysis_phase( xc_handle, dom, nr_pfns, to_skip, 0 ); /* We want zeroed memory so use calloc rather than malloc. */ pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long)); @@ -609,7 +604,7 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) } if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){ - xcio_error(ioctxt, "Unable to mlock"); + ERR("Unable to mlock"); goto out; } @@ -626,33 +621,29 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0xffffffffUL) ) { - printf("i=0x%x mfn=%lx live_mfn_to_pfn_table=%lx\n", - i,mfn,live_mfn_to_pfn_table[mfn]); + fprintf(stderr, "i=0x%x mfn=%lx live_mfn_to_pfn_table=%lx\n", + i,mfn,live_mfn_to_pfn_table[mfn]); err++; } } - printf("Had %d unexplained entries in p2m table\n",err); + fprintf(stderr, "Had %d unexplained entries in p2m table\n",err); } #endif /* Start writing out the saved-domain record. */ - if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) ){ - xcio_error(ioctxt, "Error writing header"); - goto out; - } - if(write_vmconfig(ioctxt)){ - xcio_error(ioctxt, "Error writing vmconfig"); - goto out; + if (write(io_fd, &nr_pfns, sizeof(unsigned long)) != + sizeof(unsigned long)) { + ERR("write: nr_pfns"); + goto out; } - if ( xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) || - xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){ - xcio_error(ioctxt, "Error writing header"); + if (write(io_fd, pfn_to_mfn_frame_list, PAGE_SIZE) != PAGE_SIZE) { + ERR("write: pfn_to_mfn_frame_list"); goto out; } - print_stats( xc_handle, domid, 0, &stats, 0 ); + print_stats( xc_handle, dom, 0, &stats, 0 ); /* Now write out each data page, canonicalising page tables as we go... */ @@ -665,13 +656,13 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) prev_pc = 0; N=0; - xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter); + DPRINTF("Saving memory pages: iter %d 0%%", iter); while( N < nr_pfns ){ unsigned int this_pc = (N * 100) / nr_pfns; if ( (this_pc - prev_pc) >= 5 ){ - xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc); + DPRINTF("\b\b\b\b%3d%%", this_pc); prev_pc = this_pc; } @@ -679,11 +670,11 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) but this is fast enough for the moment. */ if ( !last_iter && - xc_shadow_control(xc_handle, domid, + xc_shadow_control(xc_handle, dom, DOM0_SHADOW_CONTROL_OP_PEEK, to_skip, nr_pfns, NULL) != nr_pfns ) { - xcio_error(ioctxt, "Error peeking shadow bitmap"); + ERR("Error peeking shadow bitmap"); goto out; } @@ -733,8 +724,8 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) set_bit( n, to_fix ); if( iter>1 ) - DDPRINTF("netbuf race: iter %d, pfn %x. mfn %lx\n", - iter,n,pfn_type[batch]); + DPRINTF("netbuf race: iter %d, pfn %x. mfn %lx\n", + iter,n,pfn_type[batch]); continue; } @@ -752,27 +743,27 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) batch++; } -// DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n); +// DPRINTF("batch %d:%d (n=%d)\n", iter, batch, n); if ( batch == 0 ) goto skip; /* vanishingly unlikely... */ - if ( (region_base = xc_map_foreign_batch(xc_handle, domid, + if ( (region_base = xc_map_foreign_batch(xc_handle, dom, PROT_READ, pfn_type, batch)) == 0 ){ - xcio_perror(ioctxt, "map batch failed"); + ERR("map batch failed"); goto out; } - if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){ - xcio_error(ioctxt, "get_pfn_type_batch failed"); + if ( get_pfn_type_batch(xc_handle, dom, batch, pfn_type) ){ + ERR("get_pfn_type_batch failed"); goto out; } for ( j = 0; j < batch; j++ ){ if ( (pfn_type[j] & LTAB_MASK) == XTAB ){ - DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); + DPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]); continue; } @@ -789,13 +780,14 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j]; } - if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){ - xcio_error(ioctxt, "Error when writing to state file (2)"); + if (write(io_fd, &batch, sizeof(int)) != sizeof(int)) { + ERR("Error when writing to state file (2)"); goto out; } - if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){ - xcio_error(ioctxt, "Error when writing to state file (3)"); + if (write(io_fd, pfn_type, sizeof(unsigned long)*j) != + sizeof(unsigned long)*j) { + ERR("Error when writing to state file (3)"); goto out; } @@ -803,7 +795,7 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) for( j = 0; j < batch; j++ ){ /* write out pages in batch */ if( (pfn_type[j] & LTAB_MASK) == XTAB){ - DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); + DPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]); continue; } @@ -827,14 +819,14 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) { /* I don't think this should ever happen */ - printf("FNI %d : [%08lx,%d] pte=%08lx, " - "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n", - j, pfn_type[j], k, - page[k], mfn, live_mfn_to_pfn_table[mfn], - (live_mfn_to_pfn_table[mfn]<nr_pfns)? - live_pfn_to_mfn_table[ - live_mfn_to_pfn_table[mfn]] : - 0xdeadbeef); + fprintf(stderr, "FNI %d : [%08lx,%d] pte=%08lx, " + "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n", + j, pfn_type[j], k, + page[k], mfn, live_mfn_to_pfn_table[mfn], + (live_mfn_to_pfn_table[mfn]<nr_pfns)? + live_pfn_to_mfn_table[ + live_mfn_to_pfn_table[mfn]] : + 0xdeadbeef); pfn = 0; /* be suspicious */ } @@ -843,26 +835,25 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) page[k] |= pfn << PAGE_SHIFT; #if 0 - printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx " - "xpfn=%d\n", - pfn_type[j]>>28, - j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT); + fprintf(stderr, + "L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx " + "xpfn=%d\n", + pfn_type[j]>>28, + j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT); #endif - + } /* end of page table rewrite for loop */ - if ( xcio_ratewrite(ioctxt, page, PAGE_SIZE) ){ - xcio_error(ioctxt, - "Error when writing to state file (4)"); + if (ratewrite(io_fd, page, PAGE_SIZE) != PAGE_SIZE) { + ERR("Error when writing to state file (4)"); goto out; } } /* end of it's a PT page */ else { /* normal page */ - if ( xcio_ratewrite(ioctxt, region_base + (PAGE_SIZE*j), - PAGE_SIZE) ){ - xcio_error(ioctxt, - "Error when writing to state file (5)"); + if (ratewrite(io_fd, region_base + (PAGE_SIZE*j), + PAGE_SIZE) != PAGE_SIZE) { + ERR("Error when writing to state file (5)"); goto out; } } @@ -878,27 +869,26 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) total_sent += sent_this_iter; - xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ", + DPRINTF("\r %d: sent %d, skipped %d, ", iter, sent_this_iter, skip_this_iter ); if ( last_iter ) { - print_stats( xc_handle, domid, sent_this_iter, &stats, 1); + print_stats( xc_handle, dom, sent_this_iter, &stats, 1); - xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n", + DPRINTF("Total pages sent= %d (%.2fx)\n", total_sent, ((float)total_sent)/nr_pfns ); - xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix ); + DPRINTF("(of which %d were fixups)\n", needed_to_fix ); } if (last_iter && debug){ int minusone = -1; memset( to_send, 0xff, (nr_pfns+8)/8 ); debug = 0; - printf("Entering debug resend-all mode\n"); + fprintf(stderr, "Entering debug resend-all mode\n"); /* send "-1" to put receiver into debug mode */ - if ( xcio_write(ioctxt, &minusone, sizeof(int)) ) - { - xcio_error(ioctxt, "Error when writing to state file (6)"); + if (write(io_fd, &minusone, sizeof(int)) != sizeof(int)) { + ERR("Error when writing to state file (6)"); goto out; } @@ -919,30 +909,28 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) DPRINTF("Start last iteration\n"); last_iter = 1; - if ( suspend_and_state( xc_handle, ioctxt, &info, &ctxt) ) + if ( suspend_and_state( xc_handle, io_fd, dom, &info, &ctxt) ) { - xcio_error(ioctxt, - "Domain appears not to have suspended"); + ERR("Domain appears not to have suspended"); goto out; } - xcio_info(ioctxt, - "SUSPEND shinfo %08lx eip %08u esi %08u\n", - info.shared_info_frame, - ctxt.user_regs.eip, ctxt.user_regs.esi ); + DPRINTF("SUSPEND shinfo %08lx eip %08u esi %08u\n", + info.shared_info_frame, + ctxt.user_regs.eip, ctxt.user_regs.esi); } - if ( xc_shadow_control( xc_handle, domid, + if ( xc_shadow_control( xc_handle, dom, DOM0_SHADOW_CONTROL_OP_CLEAN, to_send, nr_pfns, &stats ) != nr_pfns ) { - xcio_error(ioctxt, "Error flushing shadow PT"); + ERR("Error flushing shadow PT"); goto out; } sent_last_iter = sent_this_iter; - print_stats( xc_handle, domid, sent_this_iter, &stats, 1); + print_stats( xc_handle, dom, sent_this_iter, &stats, 1); } @@ -955,9 +943,8 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) rc = 0; /* Zero terminate */ - if ( xcio_write(ioctxt, &rc, sizeof(int)) ) - { - xcio_error(ioctxt, "Error when writing to state file (6)"); + if (write(io_fd, &rc, sizeof(int)) != sizeof(int)) { + ERR("Error when writing to state file (6)"); goto out; } @@ -972,9 +959,8 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) j++; } - if ( xcio_write(ioctxt, &j, sizeof(unsigned int)) ) - { - xcio_error(ioctxt, "Error when writing to state file (6a)"); + if (write(io_fd, &j, sizeof(unsigned int)) != sizeof(unsigned int)) { + ERR("Error when writing to state file (6a)"); goto out; } @@ -987,10 +973,9 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) i++; if ( j == 1024 || i == nr_pfns ) { - if ( xcio_write(ioctxt, &pfntab, sizeof(unsigned long)*j) ) - { - xcio_error(ioctxt, - "Error when writing to state file (6b)"); + if (write(io_fd, &pfntab, sizeof(unsigned long)*j) != + sizeof(unsigned long)*j) { + ERR("Error when writing to state file (6b)"); goto out; } j = 0; @@ -999,47 +984,47 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt) } /* Map the suspend-record MFN to pin it. The page must be owned by - domid for this to succeed. */ - p_srec = xc_map_foreign_range(xc_handle, domid, + dom for this to succeed. */ + p_srec = xc_map_foreign_range(xc_handle, dom, sizeof(*p_srec), PROT_READ, ctxt.user_regs.esi); if (!p_srec){ - xcio_error(ioctxt, "Couldn't map suspend record"); + ERR("Couldn't map suspend record"); goto out; } if (nr_pfns != p_srec->nr_pfns ) { - xcio_error(ioctxt, "Suspend record nr_pfns unexpected (%ld != %ld)", + ERR("Suspend record nr_pfns unexpected (%ld != %ld)", p_srec->nr_pfns, nr_pfns); goto out; } /* Canonicalise the suspend-record frame number. */ if ( !translate_mfn_to_pfn(&ctxt.user_regs.esi) ){ - xcio_error(ioctxt, "Suspend record is not in range of pseudophys map"); + ERR("Suspend record is not in range of pseudophys map"); goto out; } /* Canonicalise each GDT frame number. */ for ( i = 0; i < ctxt.gdt_ents; i += 512 ) { if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) { - xcio_error(ioctxt, "GDT frame is not in range of pseudophys map"); + ERR("GDT frame is not in range of pseudophys map"); goto out; } } /* Canonicalise the page table base pointer. */ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) { - xcio_error(ioctxt, "PT base is not in range of pseudophys map"); + ERR("PT base is not in range of pseudophys map"); goto out; } ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT; - if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) || - xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) { - xcio_error(ioctxt, "Error when writing to state file (1)"); + if (write(io_fd, &ctxt, sizeof(ctxt)) != sizeof(ctxt) || + write(io_fd, live_shinfo, PAGE_SIZE) != PAGE_SIZE) { + ERR("Error when writing to state file (1)"); goto out; } diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 8132ff1047..653d7c01d1 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -254,93 +254,6 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, return list; } -static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file) -{ - int rc = -1; - int fd = -1; - int open_flags = (O_CREAT | O_EXCL | O_WRONLY); - int open_mode = 0644; - - printf("%s>\n", __FUNCTION__); - - if ( (fd = open(state_file, open_flags, open_mode)) < 0 ) - { - xcio_perror(ctxt, "Could not open file for writing"); - goto exit; - } - - printf("%s>gzip_stream_fdopen... \n", __FUNCTION__); - - /* Compression rate 1: we want speed over compression. - * We're mainly going for those zero pages, after all. - */ - ctxt->io = gzip_stream_fdopen(fd, "wb1"); - if ( ctxt->io == NULL ) - { - xcio_perror(ctxt, "Could not allocate compression state"); - goto exit; - } - - printf("%s> xc_linux_save...\n", __FUNCTION__); - - rc = xc_linux_save(xc->xc_handle, ctxt); - - exit: - if ( ctxt->io != NULL ) - IOStream_close(ctxt->io); - if ( fd >= 0 ) - close(fd); - unlink(state_file); - printf("%s> rc=%d\n", __FUNCTION__, rc); - return rc; -} - -static PyObject *pyxc_linux_save(PyObject *self, - PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - char *state_file; - int progress = 1, debug = 0; - PyObject *val = NULL; - int rc = -1; - XcIOContext ioctxt = { .info = iostdout, .err = iostderr }; - - static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list, - &ioctxt.domain, - &state_file, - &ioctxt.vmconfig, - &progress, - &debug) ) - goto exit; - - ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0); - - if ( progress ) - ioctxt.flags |= XCFLAGS_VERBOSE; - if ( debug ) - ioctxt.flags |= XCFLAGS_DEBUG; - - if ( (state_file == NULL) || (state_file[0] == '\0') ) - goto exit; - - rc = file_save(xc, &ioctxt, state_file); - if ( rc != 0 ) - { - PyErr_SetFromErrno(xc_error); - goto exit; - } - - Py_INCREF(zero); - val = zero; - - exit: - return val; -} - static PyObject *pyxc_linux_build(PyObject *self, PyObject *args, PyObject *kwds) @@ -999,15 +912,6 @@ static PyMethodDef pyxc_methods[] = { "reason why it shut itself down.\n" " vcpu_to_cpu [[int]]: List that maps VCPUS to CPUS\n" }, - { "linux_save", - (PyCFunction)pyxc_linux_save, - METH_VARARGS | METH_KEYWORDS, "\n" - "Save the CPU and memory state of a Linux guest OS.\n" - " dom [int]: Identifier of domain to be saved.\n" - " state_file [str]: Name of state file. Must not currently exist.\n" - " progress [int, 1]: Bool - display a running progress indication?\n\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - { "linux_build", (PyCFunction)pyxc_linux_build, METH_VARARGS | METH_KEYWORDS, "\n" diff --git a/tools/python/xen/util/xpopen.py b/tools/python/xen/util/xpopen.py index 78bbefdd2c..b0c880fafe 100644 --- a/tools/python/xen/util/xpopen.py +++ b/tools/python/xen/util/xpopen.py @@ -129,7 +129,7 @@ class xPopen3: try: os.execvp(cmd[0], cmd) finally: - os._exit(1) + os._exit(127) def poll(self): """Return the exit status of the child process if it has finished, diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 2320e8758d..2ee81c761c 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -90,7 +90,10 @@ class XendDomain: """Get info about a single domain from xc. Returns None if not found. """ - dom = int(dom) + try: + dom = int(dom) + except ValueError: + return None dominfo = xc.domain_getinfo(dom, 1) if dominfo == [] or dominfo[0]['dom'] != dom: dominfo = None @@ -198,6 +201,8 @@ class XendDomain: log.debug('XendDomain>reap> Suspended domain died id=%s', id) else: eserver.inject('xend.domain.suspended', [name, id]) + if dominfo: + dominfo.state_set("suspended") continue if reason in ['poweroff', 'reboot']: eserver.inject('xend.domain.exit', [name, id, reason]) @@ -349,7 +354,7 @@ class XendDomain: l = fd.read_exact(sizeof_int, "not a valid guest state file: config size read") - vmconfig_size = unpack("i", l)[0] # XXX endianess + vmconfig_size = unpack("!i", l)[0] vmconfig_buf = fd.read_exact(vmconfig_size, "not a valid guest state file: config read") @@ -384,17 +389,22 @@ class XendDomain: p.register(child.childerr.fileno()) while True: r = p.poll() - for l in child.childerr.readlines(): - log.error(l.rstrip()) - lasterr = l.rstrip() - for l in child.fromchild.readlines(): - log.info(l.rstrip()) + for (fd, event) in r: + if not event & select.POLLIN: + continue + if fd == child.childerr.fileno(): + l = child.childerr.readline() + log.error(l.rstrip()) + lasterr = l.rstrip() + if fd == child.fromchild.fileno(): + l = child.fromchild.readline() + log.info(l.rstrip()) if filter(lambda (fd, event): event & select.POLLHUP, r): break if child.wait() != 0: raise XendError("xc_restore failed: %s" % lasterr) - + return dominfo except IOError, ex: @@ -592,10 +602,66 @@ class XendDomain: @param dst: destination file @param progress: output progress if true """ - dominfo = self.domain_lookup(id) - xmigrate = XendMigrate.instance() - return xmigrate.save_begin(dominfo, dst) - + + SIGNATURE = "LinuxGuestRecord" + sizeof_int = calcsize("i") + PATH_XC_SAVE = "/usr/libexec/xen/xc_save" + + try: + dominfo = self.domain_lookup(id) + + fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC) + + if os.write(fd, SIGNATURE) != len(SIGNATURE): + raise XendError("could not write guest state file: signature") + + config = sxp.to_string(dominfo.sxpr()) + if os.write(fd, pack("!i", len(config))) != sizeof_int: + raise XendError("could not write guest state file: config len") + if os.write(fd, config) != len(config): + raise XendError("could not write guest state file: config") + + cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd), + dominfo.id] + log.info("[xc_save] " + join(cmd)) + child = xPopen3(cmd, True, -1, [fd, xc.handle()]) + + lasterr = "" + p = select.poll() + p.register(child.fromchild.fileno()) + p.register(child.childerr.fileno()) + while True: + r = p.poll() + for (fd, event) in r: + if not event & select.POLLIN: + continue + if fd == child.childerr.fileno(): + l = child.childerr.readline() + log.error(l.rstrip()) + lasterr = l.rstrip() + if fd == child.fromchild.fileno(): + l = child.fromchild.readline() + if l.rstrip() == "suspend": + log.info("suspending %s" % dominfo.id) + self.domain_shutdown(dominfo.id, reason='suspend') + dominfo.state_wait("suspended") + log.info("suspend %s done" % dominfo.id) + child.tochild.write("done\n") + child.tochild.flush() + if filter(lambda (fd, event): event & select.POLLHUP, r): + break + + if child.wait() >> 8 == 127: + lasterr = "popen %s failed" % PATH_XC_SAVE + if child.wait() != 0: + raise XendError("xc_save failed: %s" % lasterr) + + self.domain_destroy(dominfo.id) + return None + + except: + raise + def domain_pincpu(self, id, vcpu, cpumap): """Set which cpus vcpu can use diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index d7762fe916..8eba3a9aad 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -11,6 +11,7 @@ Author: Mike Wray <mike.wray@hp.com> import string import os import time +import threading import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() import xen.util.ip @@ -74,6 +75,7 @@ STATE_RESTART_BOOTING = 'booting' STATE_VM_OK = "ok" STATE_VM_TERMINATED = "terminated" +STATE_VM_SUSPENDED = "suspended" def domain_exists(name): @@ -288,6 +290,7 @@ class XendDomainInfo: self.netif_backend = False #todo: state: running, suspended self.state = STATE_VM_OK + self.state_updated = threading.Condition() self.shutdown_pending = None #todo: set to migrate info if migrating @@ -328,6 +331,19 @@ class XendDomainInfo: self.info = info self.memory = self.info['mem_kb'] / 1024 + def state_set(self, state): + self.state_updated.acquire() + if self.state != state: + self.state = state + self.state_updated.notifyAll() + self.state_updated.release() + + def state_wait(self, state): + self.state_updated.acquire() + while self.state != state: + self.state_updated.wait() + self.state_updated.release() + def __str__(self): s = "domain" s += " id=" + self.id diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile index 71c3c6a404..613358df8b 100644 --- a/tools/xcutils/Makefile +++ b/tools/xcutils/Makefile @@ -28,9 +28,10 @@ CFLAGS += $(INCLUDES) CFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d -PROGRAMS = xc_restore +PROGRAMS = xc_restore xc_save xc_restore_OBJS = xc_restore.o +xc_save_OBJS = xc_save.o LDLIBS = -L$(XEN_LIBXC) -L$(XEN_LIBXUTIL) -lxc -lxutil diff --git a/tools/xcutils/xc_save.c b/tools/xcutils/xc_save.c new file mode 100644 index 0000000000..6ca1d5cc6c --- /dev/null +++ b/tools/xcutils/xc_save.c @@ -0,0 +1,29 @@ +/* + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of + * this archive for more details. + * + * Copyright (C) 2005 by Christian Limpach + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <err.h> + +#include <xc.h> + +int +main(int argc, char **argv) +{ + unsigned int xc_fd, io_fd, domid; + + if (argc != 4) + errx(1, "usage: %s xcfd iofd domid", argv[0]); + + xc_fd = atoi(argv[1]); + io_fd = atoi(argv[2]); + domid = atoi(argv[3]); + + return xc_linux_save(xc_fd, io_fd, domid); +} diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c index fb2951555a..659bf39cd6 100644 --- a/tools/xfrd/xen_domain.c +++ b/tools/xfrd/xen_domain.c @@ -61,6 +61,7 @@ int xen_domain_snd(Conn *xend, IOStream *io, char *vmconfig, int vmconfig_n, int live, int resource){ int err = 0; +#if 0 XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; ioctxt->domain = dom; ioctxt->io = io; @@ -76,6 +77,7 @@ int xen_domain_snd(Conn *xend, IOStream *io, ioctxt->resource = resource; err = xc_linux_save(xcinit(), ioctxt); dprintf("< err=%d\n", err); +#endif return err; } |