# HG changeset patch
# User Brendan Cully <brendan@xxxxxxxxx>
# Date 1240355510 25200
# Node ID dd394ec3ad784da4cfe789c380aa47092dfb0f20
# Parent 03fd0c9729f3d87e7803afb170dfc3cdff184998
Buffer checkpoint data locally until domain has resumed execution.
Signed-off-by: Brendan Cully <brendan@xxxxxxxxx>
diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c
+++ b/tools/libxc/xc_domain_save.c
@@ -57,6 +57,15 @@
/* Address size of the guest */
unsigned int guest_width;
+/* buffer for output */
+struct outbuf {
+ void* buf;
+ size_t size;
+ size_t pos;
+};
+
+#define OUTBUF_SIZE (16384 * 1024)
+
/* grep fodder: machine_to_phys */
#define mfn_to_pfn(_mfn) (live_m2p[(_mfn)])
@@ -159,6 +168,93 @@
return rc;
}
+static int outbuf_init(struct outbuf* ob, size_t size)
+{
+ memset(ob, 0, sizeof(*ob));
+
+ if (!(ob->buf = malloc(size))) {
+ DPRINTF("error allocating output buffer of size %zu\n", size);
+ return -1;
+ }
+
+ ob->size = size;
+
+ return 0;
+}
+
+static inline int outbuf_resize(struct outbuf* ob, size_t nsize)
+{
+ void* nbuf;
+
+ if (nsize <= ob->size)
+ return 0;
+
+ if (!(nbuf = realloc(ob->buf, nsize))) {
+ DPRINTF("error reallocating output buffer from %zu to %zu\n",
+ ob->size, nsize);
+ return -1;
+ }
+
+ ob->buf = nbuf;
+
+ return 0;
+}
+
+static inline int outbuf_write(struct outbuf* ob, void* buf, size_t len)
+{
+ if (len > ob->size - ob->pos) {
+ DPRINTF("outbuf_write: %zu > %zu@%zu\n", len, ob->size - ob->pos,
ob->pos);
+ return -1;
+ }
+
+ memcpy(ob->buf + ob->pos, buf, len);
+ ob->pos += len;
+
+ return 0;
+}
+
+/* prep for nonblocking I/O */
+static int outbuf_flush(struct outbuf* ob, int fd)
+{
+ int rc;
+ int cur = 0;
+
+ if (!ob->pos)
+ return 0;
+
+ rc = write(fd, ob->buf, ob->pos);
+ while (rc < 0 || cur + rc < ob->pos) {
+ if (rc < 0 && errno != EAGAIN && errno != EINTR) {
+ DPRINTF("error flushing output: %d\n", errno);
+ return -1;
+ }
+ if (rc > 0)
+ cur += rc;
+
+ rc = write(fd, ob->buf + cur, ob->pos - cur);
+ }
+
+ ob->pos = 0;
+
+ return 0;
+}
+
+/* if there's no room in the buffer, flush it and try again. */
+static inline int outbuf_hardwrite(struct outbuf* ob, int fd, void* buf,
+ size_t len)
+{
+ if (!len)
+ return 0;
+
+ if (!outbuf_write(ob, buf, len))
+ return 0;
+
+ if (outbuf_flush(ob, fd) < 0)
+ return -1;
+
+ return outbuf_write(ob, buf, len);
+}
+
#ifdef ADAPTIVE_SAVE
/*
@@ -799,6 +895,10 @@
unsigned long mfn;
+ struct outbuf ob;
+
+ outbuf_init(&ob, OUTBUF_SIZE);
+
/* If no explicit control parameters given, use defaults */
max_iters = max_iters ? : DEF_MAX_ITERS;
max_factor = max_factor ? : DEF_MAX_FACTOR;
@@ -1171,13 +1271,21 @@
}
}
- if ( write_exact(io_fd, &batch, sizeof(unsigned int)) )
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob, io_fd, &batch, sizeof(unsigned
int));
+ else
+ rc = write_exact(io_fd, &batch, sizeof(unsigned int));
+ if ( rc )
{
PERROR("Error when writing to state file (2)");
goto out;
}
- if ( write_exact(io_fd, pfn_type, sizeof(unsigned long)*batch) )
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob, io_fd, pfn_type, sizeof(unsigned
long)*batch);
+ else
+ rc = write_exact(io_fd, pfn_type, sizeof(unsigned long)*batch);
+ if ( rc )
{
PERROR("Error when writing to state file (3)");
goto out;
@@ -1199,9 +1307,14 @@
run of pages we may have previously acumulated */
if ( run )
{
- if ( ratewrite(io_fd, live,
- (char*)region_base+(PAGE_SIZE*(j-run)),
- PAGE_SIZE*run) != PAGE_SIZE*run )
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob,
io_fd,(char*)region_base+(PAGE_SIZE*(j-run)),
+ PAGE_SIZE*run);
+ else
+ rc = ratewrite(io_fd, live,
+
(char*)region_base+(PAGE_SIZE*(j-run)),
+ PAGE_SIZE*run) != PAGE_SIZE*run;
+ if ( rc )
{
ERROR("Error when writing to state file (4a)"
" (errno %d)", errno);
@@ -1231,7 +1344,12 @@
goto out;
}
- if ( ratewrite(io_fd, live, page, PAGE_SIZE) != PAGE_SIZE )
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob, io_fd, page, PAGE_SIZE);
+ else
+ rc = ratewrite(io_fd, live, page, PAGE_SIZE) !=
+ PAGE_SIZE;
+ if ( rc )
{
ERROR("Error when writing to state file (4b)"
" (errno %d)", errno);
@@ -1240,17 +1358,37 @@
}
else
{
+#if 0
/* We have a normal page: accumulate it for writing. */
run++;
+#else
+ /* We have a normal page: just write it directly. */
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob, io_fd, spage, PAGE_SIZE);
+ else
+ rc = ratewrite(io_fd, live, spage, PAGE_SIZE) !=
+ PAGE_SIZE;
+ if ( rc )
+ {
+ ERROR("Error when writing to state file (5)"
+ " (errno %d)", errno);
+ goto out;
+ }
+#endif
}
} /* end of the write out for this batch */
if ( run )
{
/* write out the last accumulated run of pages */
- if ( ratewrite(io_fd, live,
- (char*)region_base+(PAGE_SIZE*(j-run)),
- PAGE_SIZE*run) != PAGE_SIZE*run )
+ if ( last_iter )
+ rc = outbuf_hardwrite(&ob, io_fd,
(char*)region_base+(PAGE_SIZE*(j-run)),
+ PAGE_SIZE*run);
+ else
+ rc = ratewrite(io_fd, live,
+ (char*)region_base+(PAGE_SIZE*(j-run)),
+ PAGE_SIZE*run) != PAGE_SIZE*run;
+ if ( rc )
{
ERROR("Error when writing to state file (4c)"
" (errno %d)", errno);
@@ -1275,9 +1413,11 @@
{
print_stats( xc_handle, dom, sent_this_iter, &stats, 1);
+ /*
DPRINTF("Total pages sent= %ld (%.2fx)\n",
total_sent, ((float)total_sent)/p2m_size );
DPRINTF("(of which %ld were fixups)\n", needed_to_fix );
+ */
}
if ( last_iter && debug )
@@ -1288,7 +1428,7 @@
DPRINTF("Entering debug resend-all mode\n");
/* send "-1" to put receiver into debug mode */
- if ( write_exact(io_fd, &minusone, sizeof(int)) )
+ if ( outbuf_hardwrite(&ob, io_fd, &minusone, sizeof(int)) )
{
PERROR("Error when writing to state file (6)");
goto out;
@@ -1356,7 +1496,9 @@
}
} /* end of infinite for loop */
+ /*
DPRINTF("All memory is saved\n");
+ */
{
struct {
@@ -1380,7 +1522,7 @@
}
chunk.vcpumap = vcpumap;
- if ( write_exact(io_fd, &chunk, sizeof(chunk)) )
+ if ( outbuf_hardwrite(&ob, io_fd, &chunk, sizeof(chunk)) )
{
PERROR("Error when writing to state file");
goto out;
@@ -1400,7 +1542,7 @@
(unsigned long *)&chunk.data);
if ( (chunk.data != 0) &&
- write_exact(io_fd, &chunk, sizeof(chunk)) )
+ outbuf_hardwrite(&ob, io_fd, &chunk, sizeof(chunk)) )
{
PERROR("Error when writing the ident_pt for EPT guest");
goto out;
@@ -1411,7 +1553,7 @@
(unsigned long *)&chunk.data);
if ( (chunk.data != 0) &&
- write_exact(io_fd, &chunk, sizeof(chunk)) )
+ outbuf_hardwrite(&ob, io_fd, &chunk, sizeof(chunk)) )
{
PERROR("Error when writing the vm86 TSS for guest");
goto out;
@@ -1420,7 +1562,7 @@
/* Zero terminate */
i = 0;
- if ( write_exact(io_fd, &i, sizeof(int)) )
+ if ( outbuf_hardwrite(&ob, io_fd, &i, sizeof(int)) )
{
PERROR("Error when writing to state file (6')");
goto out;
@@ -1438,7 +1580,7 @@
(unsigned long *)&magic_pfns[1]);
xc_get_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN,
(unsigned long *)&magic_pfns[2]);
- if ( write_exact(io_fd, magic_pfns, sizeof(magic_pfns)) )
+ if ( outbuf_hardwrite(&ob, io_fd, magic_pfns, sizeof(magic_pfns)) )
{
PERROR("Error when writing to state file (7)");
goto out;
@@ -1452,13 +1594,13 @@
goto out;
}
- if ( write_exact(io_fd, &rec_size, sizeof(uint32_t)) )
+ if ( outbuf_hardwrite(&ob, io_fd, &rec_size, sizeof(uint32_t)) )
{
PERROR("error write hvm buffer size");
goto out;
}
- if ( write_exact(io_fd, hvm_buf, rec_size) )
+ if ( outbuf_hardwrite(&ob, io_fd, hvm_buf, rec_size) )
{
PERROR("write HVM info failed!\n");
goto out;
@@ -1482,7 +1624,7 @@
j++;
}
- if ( write_exact(io_fd, &j, sizeof(unsigned int)) )
+ if ( outbuf_hardwrite(&ob, io_fd, &j, sizeof(unsigned int)) )
{
PERROR("Error when writing to state file (6a)");
goto out;
@@ -1496,7 +1638,7 @@
i++;
if ( (j == 1024) || (i == p2m_size) )
{
- if ( write_exact(io_fd, &pfntab, sizeof(unsigned long)*j) )
+ if ( outbuf_hardwrite(&ob, io_fd, &pfntab, sizeof(unsigned
long)*j) )
{
PERROR("Error when writing to state file (6b)");
goto out;
@@ -1567,9 +1709,9 @@
FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(ctxt.x64.ctrlreg[1])));
}
- if ( write_exact(io_fd, &ctxt, ((guest_width==8)
- ? sizeof(ctxt.x64)
- : sizeof(ctxt.x32))) )
+ if ( outbuf_hardwrite(&ob, io_fd, &ctxt, ((guest_width==8)
+ ? sizeof(ctxt.x64)
+ : sizeof(ctxt.x32))) )
{
PERROR("Error when writing to state file (1)");
goto out;
@@ -1583,7 +1725,7 @@
ERROR("No extended context for VCPU%d", i);
goto out;
}
- if ( write_exact(io_fd, &domctl.u.ext_vcpucontext, 128) )
+ if ( outbuf_hardwrite(&ob, io_fd, &domctl.u.ext_vcpucontext, 128) )
{
PERROR("Error when writing to state file (2)");
goto out;
@@ -1596,7 +1738,7 @@
memcpy(page, live_shinfo, PAGE_SIZE);
SET_FIELD(((shared_info_any_t *)page),
arch.pfn_to_mfn_frame_list_list, 0);
- if ( write_exact(io_fd, page, PAGE_SIZE) )
+ if ( outbuf_hardwrite(&ob, io_fd, page, PAGE_SIZE) )
{
PERROR("Error when writing to state file (1)");
goto out;
@@ -1610,6 +1752,11 @@
callbacks->postcopy(callbacks->data);
/* Flush last write and discard cache for file. */
+ if (outbuf_flush(&ob, io_fd) < 0) {
+ ERROR("Error when flushing output buffer\n");
+ rc = 1;
+ }
+
discard_file_cache(io_fd, 1 /* flush */);
/* checkpoint_cb can spend arbitrarily long in between rounds */
@@ -1627,9 +1774,11 @@
ERROR("Domain appears not to have suspended");
goto out;
}
+ /*
DPRINTF("SUSPEND shinfo %08lx\n", info.shared_info_frame);
+
print_stats(xc_handle, dom, 0, &stats, 1);
-
+ */
if ( xc_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_CLEAN, to_send,
p2m_size, NULL, 0, &stats) != p2m_size )
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|