aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.rootkeys1
-rw-r--r--BitKeeper/etc/ignore1
-rw-r--r--tools/libxc/xc.h17
-rw-r--r--tools/libxc/xc_linux_restore.c8
-rw-r--r--tools/libxc/xc_linux_save.c339
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c96
-rw-r--r--tools/python/xen/util/xpopen.py2
-rw-r--r--tools/python/xen/xend/XendDomain.py90
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py16
-rw-r--r--tools/xcutils/Makefile3
-rw-r--r--tools/xcutils/xc_save.c29
-rw-r--r--tools/xfrd/xen_domain.c2
12 files changed, 304 insertions, 300 deletions
diff --git a/.rootkeys b/.rootkeys
index f1618d901c..26b7f664a7 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -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;
}