* [PATCH VERY RFC 1/5] tools/libxl: Add support for writing a set of buffers asynchronously
2014-09-03 17:14 [PATCH VERY RFC 0/5] Libxl migration v2 support Andrew Cooper
@ 2014-09-03 17:14 ` Andrew Cooper
2014-09-04 1:28 ` Wen Congyang
2014-09-03 17:14 ` [PATCH VERY RFC 2/5] tools/libxl: Stream v2 format Andrew Cooper
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Andrew Cooper @ 2014-09-03 17:14 UTC (permalink / raw)
To: Xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Ross Lagerwall
From: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
---
tools/libxl/libxl_aoutils.c | 118 ++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_internal.h | 44 ++++++++++++++++
2 files changed, 162 insertions(+)
diff --git a/tools/libxl/libxl_aoutils.c b/tools/libxl/libxl_aoutils.c
index b10d2e1..6027d05 100644
--- a/tools/libxl/libxl_aoutils.c
+++ b/tools/libxl/libxl_aoutils.c
@@ -324,6 +324,124 @@ int libxl__datacopier_start(libxl__datacopier_state *dc)
return rc;
}
+
+/*----- writer -----*/
+
+void libxl__writer_kill(libxl__writer_state *dw)
+{
+ STATE_AO_GC(dw->ao);
+ libxl__writer_buf *buf, *tbuf;
+
+ libxl__ev_fd_deregister(gc, &dw->towrite);
+ LIBXL_TAILQ_FOREACH_SAFE(buf, &dw->bufs, entry, tbuf)
+ free(buf);
+ LIBXL_TAILQ_INIT(&dw->bufs);
+}
+
+void libxl__writer_append(libxl__egc *egc, libxl__writer_state *dw,
+ const void *data, size_t len)
+{
+ EGC_GC;
+ libxl__writer_buf *buf;
+
+ assert(len < dw->maxsz - dw->used);
+
+ buf = libxl__zalloc(NOGC, sizeof(*buf));
+ buf->used = len;
+ memcpy(buf->buf, data, len);
+
+ dw->used += len;
+ LIBXL_TAILQ_INSERT_TAIL(&dw->bufs, buf, entry);
+}
+
+static int writer_pollhup_handled(libxl__egc *egc,
+ libxl__writer_state *dw,
+ short revents)
+{
+ STATE_AO_GC(dw->ao);
+
+ if (dw->callback_pollhup && (revents & POLLHUP)) {
+ LOG(DEBUG, "received POLLHUP on %s during writing of %s",
+ dw->towhat, dw->writewhat);
+ libxl__writer_kill(dw);
+ dw->callback_pollhup(egc, dw, 1, -1);
+ return 1;
+ }
+ return 0;
+}
+
+static void writer_writable(libxl__egc *egc, libxl__ev_fd *ev,
+ int fd, short events, short revents) {
+ libxl__writer_state *dw = CONTAINER_OF(ev, *dw, towrite);
+ STATE_AO_GC(dw->ao);
+
+ if (writer_pollhup_handled(egc, dw, revents))
+ return;
+
+ if (revents & ~POLLOUT) {
+ LOG(ERROR, "unexpected poll event 0x%x (should be POLLOUT)"
+ " during writing %s to %s", revents, dw->writewhat, dw->towhat);
+ libxl__writer_kill(dw);
+ dw->callback(egc, dw, -1, 0);
+ return;
+ }
+ assert(revents & POLLOUT);
+ for (;;) {
+ libxl__writer_buf *buf = LIBXL_TAILQ_FIRST(&dw->bufs);
+ if (!buf) {
+ libxl__writer_kill(dw);
+ dw->callback(egc, dw, 0, 0);
+ break;
+ }
+ if (!buf->used) {
+ LIBXL_TAILQ_REMOVE(&dw->bufs, buf, entry);
+ free(buf);
+ continue;
+ }
+ int r = write(ev->fd, buf->buf, buf->used);
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ if (errno == EWOULDBLOCK) break;
+ LOGE(ERROR, "error writing %s to %s",
+ dw->writewhat, dw->towhat);
+ libxl__writer_kill(dw);
+ dw->callback(egc, dw, 1, errno);
+ return;
+ }
+ assert(r > 0);
+ assert(r <= buf->used);
+ buf->used -= r;
+ dw->used -= r;
+ assert(dw->used >= 0);
+ memmove(buf->buf, buf->buf+r, buf->used);
+ }
+}
+
+void libxl__writer_init(libxl__writer_state *dw)
+{
+ assert(dw->ao);
+ libxl__ev_fd_init(&dw->towrite);
+ LIBXL_TAILQ_INIT(&dw->bufs);
+}
+
+int libxl__writer_start(libxl__writer_state *dw)
+{
+ int rc;
+ STATE_AO_GC(dw->ao);
+
+ libxl__writer_init(dw);
+
+ rc = libxl__ev_fd_register(gc, &dw->towrite, writer_writable,
+ dw->writefd, POLLOUT);
+ if (rc) goto out;
+
+ return 0;
+
+ out:
+ libxl__writer_kill(dw);
+ return rc;
+}
+
/*----- openpty -----*/
/* implementation */
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 04c9378..47fbf45 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -2471,6 +2471,50 @@ typedef struct libxl__save_helper_state {
* marshalling and xc callback functions */
} libxl__save_helper_state;
+/*----- writer: writes a set of buffers to an fd asynchronously -----*/
+
+typedef struct libxl__writer_state libxl__writer_state;
+typedef struct libxl__writer_buf libxl__writer_buf;
+
+/* onwrite==1 means failure happened when writing, logged, errnoval is valid
+ * onwrite==-1 means some other internal failure, errnoval not valid, logged
+ * If we get POLLHUP, we call callback_pollhup(..., 1, -1);
+ * or if callback_pollhup==0 this is an internal failure, as above.
+ * In all cases copier is killed before calling this callback */
+typedef void libxl__writer_callback(libxl__egc *egc,
+ libxl__writer_state *dw, int state, int errnoval);
+
+struct libxl__writer_buf {
+ /* private to writer */
+ LIBXL_TAILQ_ENTRY(libxl__writer_buf) entry;
+ int used;
+ char buf[1000];
+};
+
+struct libxl__writer_state {
+ /* caller must fill these in, and they must all remain valid */
+ libxl__ao *ao;
+ int writefd;
+ ssize_t maxsz;
+ const char *towhat, *writewhat; /* for error msgs */
+ libxl__writer_callback *callback;
+ libxl__writer_callback *callback_pollhup;
+ /* remaining fields are private to writer */
+ libxl__ev_fd towrite;
+ ssize_t used;
+ LIBXL_TAILQ_HEAD(libxl__writer_bufs, libxl__writer_buf) bufs;
+};
+
+_hidden void libxl__writer_init(libxl__writer_state *dc);
+_hidden void libxl__writer_kill(libxl__writer_state *dc);
+_hidden int libxl__writer_start(libxl__writer_state *dc);
+
+/* Inserts literal data into the output stream. The data is copied.
+ * May safely be used only immediately after libxl__writer_start
+ * (before the ctx is unlocked). But may be called multiple times.
+ * NB exceeding maxsz will fail an assertion! */
+_hidden void libxl__writer_append(libxl__egc*, libxl__writer_state*,
+ const void *data, size_t len);
/*----- Domain suspend (save) state structure -----*/
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH VERY RFC 1/5] tools/libxl: Add support for writing a set of buffers asynchronously
2014-09-03 17:14 ` [PATCH VERY RFC 1/5] tools/libxl: Add support for writing a set of buffers asynchronously Andrew Cooper
@ 2014-09-04 1:28 ` Wen Congyang
0 siblings, 0 replies; 7+ messages in thread
From: Wen Congyang @ 2014-09-04 1:28 UTC (permalink / raw)
To: Andrew Cooper, Xen-devel
Cc: Ian Jackson, Wei Liu, Ian Campbell, Ross Lagerwall
At 09/04/2014 01:14 AM, Andrew Cooper Write:
> From: Ross Lagerwall <ross.lagerwall@citrix.com>
If we allow datacopier's rfd is -1, we can use datacopier to implement it.
>
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> ---
> tools/libxl/libxl_aoutils.c | 118 ++++++++++++++++++++++++++++++++++++++++++
> tools/libxl/libxl_internal.h | 44 ++++++++++++++++
> 2 files changed, 162 insertions(+)
>
> diff --git a/tools/libxl/libxl_aoutils.c b/tools/libxl/libxl_aoutils.c
> index b10d2e1..6027d05 100644
> --- a/tools/libxl/libxl_aoutils.c
> +++ b/tools/libxl/libxl_aoutils.c
> @@ -324,6 +324,124 @@ int libxl__datacopier_start(libxl__datacopier_state *dc)
> return rc;
> }
>
> +
> +/*----- writer -----*/
> +
> +void libxl__writer_kill(libxl__writer_state *dw)
> +{
> + STATE_AO_GC(dw->ao);
> + libxl__writer_buf *buf, *tbuf;
> +
> + libxl__ev_fd_deregister(gc, &dw->towrite);
> + LIBXL_TAILQ_FOREACH_SAFE(buf, &dw->bufs, entry, tbuf)
> + free(buf);
> + LIBXL_TAILQ_INIT(&dw->bufs);
> +}
> +
> +void libxl__writer_append(libxl__egc *egc, libxl__writer_state *dw,
> + const void *data, size_t len)
> +{
> + EGC_GC;
> + libxl__writer_buf *buf;
> +
> + assert(len < dw->maxsz - dw->used);
> +
> + buf = libxl__zalloc(NOGC, sizeof(*buf));
> + buf->used = len;
> + memcpy(buf->buf, data, len);
> +
> + dw->used += len;
> + LIBXL_TAILQ_INSERT_TAIL(&dw->bufs, buf, entry);
> +}
> +
> +static int writer_pollhup_handled(libxl__egc *egc,
> + libxl__writer_state *dw,
> + short revents)
> +{
> + STATE_AO_GC(dw->ao);
> +
> + if (dw->callback_pollhup && (revents & POLLHUP)) {
> + LOG(DEBUG, "received POLLHUP on %s during writing of %s",
> + dw->towhat, dw->writewhat);
> + libxl__writer_kill(dw);
> + dw->callback_pollhup(egc, dw, 1, -1);
> + return 1;
> + }
> + return 0;
> +}
> +
> +static void writer_writable(libxl__egc *egc, libxl__ev_fd *ev,
> + int fd, short events, short revents) {
> + libxl__writer_state *dw = CONTAINER_OF(ev, *dw, towrite);
> + STATE_AO_GC(dw->ao);
> +
> + if (writer_pollhup_handled(egc, dw, revents))
> + return;
> +
> + if (revents & ~POLLOUT) {
> + LOG(ERROR, "unexpected poll event 0x%x (should be POLLOUT)"
> + " during writing %s to %s", revents, dw->writewhat, dw->towhat);
> + libxl__writer_kill(dw);
> + dw->callback(egc, dw, -1, 0);
> + return;
> + }
> + assert(revents & POLLOUT);
> + for (;;) {
> + libxl__writer_buf *buf = LIBXL_TAILQ_FIRST(&dw->bufs);
> + if (!buf) {
> + libxl__writer_kill(dw);
> + dw->callback(egc, dw, 0, 0);
> + break;
> + }
> + if (!buf->used) {
> + LIBXL_TAILQ_REMOVE(&dw->bufs, buf, entry);
> + free(buf);
> + continue;
> + }
> + int r = write(ev->fd, buf->buf, buf->used);
> + if (r < 0) {
> + if (errno == EINTR) continue;
> + if (errno == EWOULDBLOCK) break;
> + LOGE(ERROR, "error writing %s to %s",
> + dw->writewhat, dw->towhat);
> + libxl__writer_kill(dw);
> + dw->callback(egc, dw, 1, errno);
> + return;
> + }
> + assert(r > 0);
> + assert(r <= buf->used);
> + buf->used -= r;
> + dw->used -= r;
> + assert(dw->used >= 0);
> + memmove(buf->buf, buf->buf+r, buf->used);
> + }
> +}
> +
> +void libxl__writer_init(libxl__writer_state *dw)
> +{
> + assert(dw->ao);
> + libxl__ev_fd_init(&dw->towrite);
> + LIBXL_TAILQ_INIT(&dw->bufs);
> +}
> +
> +int libxl__writer_start(libxl__writer_state *dw)
> +{
> + int rc;
> + STATE_AO_GC(dw->ao);
> +
> + libxl__writer_init(dw);
> +
> + rc = libxl__ev_fd_register(gc, &dw->towrite, writer_writable,
> + dw->writefd, POLLOUT);
> + if (rc) goto out;
> +
> + return 0;
> +
> + out:
> + libxl__writer_kill(dw);
> + return rc;
> +}
> +
> /*----- openpty -----*/
>
> /* implementation */
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 04c9378..47fbf45 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -2471,6 +2471,50 @@ typedef struct libxl__save_helper_state {
> * marshalling and xc callback functions */
> } libxl__save_helper_state;
>
> +/*----- writer: writes a set of buffers to an fd asynchronously -----*/
> +
> +typedef struct libxl__writer_state libxl__writer_state;
> +typedef struct libxl__writer_buf libxl__writer_buf;
> +
> +/* onwrite==1 means failure happened when writing, logged, errnoval is valid
> + * onwrite==-1 means some other internal failure, errnoval not valid, logged
> + * If we get POLLHUP, we call callback_pollhup(..., 1, -1);
> + * or if callback_pollhup==0 this is an internal failure, as above.
> + * In all cases copier is killed before calling this callback */
> +typedef void libxl__writer_callback(libxl__egc *egc,
> + libxl__writer_state *dw, int state, int errnoval);
> +
> +struct libxl__writer_buf {
> + /* private to writer */
> + LIBXL_TAILQ_ENTRY(libxl__writer_buf) entry;
> + int used;
> + char buf[1000];
> +};
> +
> +struct libxl__writer_state {
> + /* caller must fill these in, and they must all remain valid */
> + libxl__ao *ao;
> + int writefd;
> + ssize_t maxsz;
> + const char *towhat, *writewhat; /* for error msgs */
> + libxl__writer_callback *callback;
> + libxl__writer_callback *callback_pollhup;
> + /* remaining fields are private to writer */
> + libxl__ev_fd towrite;
> + ssize_t used;
> + LIBXL_TAILQ_HEAD(libxl__writer_bufs, libxl__writer_buf) bufs;
> +};
> +
> +_hidden void libxl__writer_init(libxl__writer_state *dc);
> +_hidden void libxl__writer_kill(libxl__writer_state *dc);
> +_hidden int libxl__writer_start(libxl__writer_state *dc);
> +
> +/* Inserts literal data into the output stream. The data is copied.
> + * May safely be used only immediately after libxl__writer_start
> + * (before the ctx is unlocked). But may be called multiple times.
> + * NB exceeding maxsz will fail an assertion! */
> +_hidden void libxl__writer_append(libxl__egc*, libxl__writer_state*,
> + const void *data, size_t len);
>
> /*----- Domain suspend (save) state structure -----*/
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH VERY RFC 2/5] tools/libxl: Stream v2 format
2014-09-03 17:14 [PATCH VERY RFC 0/5] Libxl migration v2 support Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 1/5] tools/libxl: Add support for writing a set of buffers asynchronously Andrew Cooper
@ 2014-09-03 17:14 ` Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 3/5] tools/libxl: Implement libxl_domain_restore() for v2 streams Andrew Cooper
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Andrew Cooper @ 2014-09-03 17:14 UTC (permalink / raw)
To: Xen-devel
Cc: Wei Liu, Andrew Cooper, Ian Jackson, Ian Campbell, Ross Lagerwall
From: Ross Lagerwall <ross.lagerwall@citrix.com>
TODO: Namespacing
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/libxl/libxl_saverestore.h | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 tools/libxl/libxl_saverestore.h
diff --git a/tools/libxl/libxl_saverestore.h b/tools/libxl/libxl_saverestore.h
new file mode 100644
index 0000000..31a22d6
--- /dev/null
+++ b/tools/libxl/libxl_saverestore.h
@@ -0,0 +1,47 @@
+#ifndef LIBXL_SAVERESTORE_H
+#define LIBXL_SAVERESTORE_H
+
+#include <stdint.h>
+
+/* Definitions for LibXenLight Domain Image Format version 2 */
+struct restore_hdr
+{
+ uint64_t ident;
+ uint32_t version;
+ uint32_t options;
+};
+
+struct restore_rec_hdr
+{
+ uint32_t type;
+ uint32_t length;
+};
+
+struct restore_emulator_hdr
+{
+ uint32_t id;
+ uint32_t index;
+};
+
+#define REC_TYPE_END 0x00000000U
+#define REC_TYPE_DOMAIN_JSON 0x00000001U
+#define REC_TYPE_LIBXC_CONTEXT 0x00000002U
+#define REC_TYPE_XENSTORE_DATA 0x00000003U
+#define REC_TYPE_EMULATOR_CONTEXT 0x00000004U
+
+/* All records must be aligned up to an 8 octet boundary */
+#define REC_ALIGN_ORDER 3U
+
+#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
+
+#define EMULATOR_UNKNOWN 0x00000000U
+#define EMULATOR_QEMU_TRADITIONAL 0x00000001U
+#define EMULATOR_QEMU_UPSTREAM 0x00000002U
+
+#define RESTORE_STREAM_IDENT 0x4c6962786c466d74UL
+#define RESTORE_STREAM_VERSION 0x00000002U
+
+#define RESTORE_OPT_BIG_ENDIAN (1 << 0)
+#define RESTORE_OPT_LEGACY (1 << 1)
+
+#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH VERY RFC 3/5] tools/libxl: Implement libxl_domain_restore() for v2 streams
2014-09-03 17:14 [PATCH VERY RFC 0/5] Libxl migration v2 support Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 1/5] tools/libxl: Add support for writing a set of buffers asynchronously Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 2/5] tools/libxl: Stream v2 format Andrew Cooper
@ 2014-09-03 17:14 ` Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 4/5] tools/xl: Restore v2 streams using new libxl_domain_restore() interface Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 5/5] tools/[lib]xl: Alter libxl_domain_suspend() to write a v2 stream Andrew Cooper
4 siblings, 0 replies; 7+ messages in thread
From: Andrew Cooper @ 2014-09-03 17:14 UTC (permalink / raw)
To: Xen-devel
Cc: Wei Liu, Ross Lagerwall, Ian Jackson, Ian Campbell, Andrew Cooper
TODO:
* Make it asynchronous
* Integrate with the json series
* Support for HVM elements
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/libxl/libxl.c | 13 +++
tools/libxl/libxl.h | 12 +++
tools/libxl/libxl_create.c | 234 ++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_internal.h | 5 +
4 files changed, 264 insertions(+)
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 2ae5fca..209d56a 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -878,6 +878,19 @@ int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, int flags,
return AO_ABORT(rc);
}
+/*
+ * Restore a domain from an fd using the LibXenLight Domain Image Format v2.
+ * Returns 0 on success, non-zero otherwise.
+ */
+int libxl_domain_restore(libxl_ctx *ctx,
+ libxl_domain_config *d_config, /* TMP until json is sorted */
+ int restore_fd, uint32_t *domid,
+ const libxl_asyncop_how *ao_how,
+ const libxl_asyncprogress_how *aop_console_how)
+{
+ return libxl__domain_restore(ctx, restore_fd, domid, d_config);
+}
+
int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
{
int ret;
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 460207b..fb14a91 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -857,6 +857,18 @@ int static inline libxl_domain_create_restore_0x040200(
#endif
+/* Restore from a v2 stream
+ *
+ * TODO - Make this function properly asynchronous, and remove d_config
+ * parameter.
+ */
+int libxl_domain_restore(libxl_ctx *ctx,
+ libxl_domain_config *d_config, /* TMP until json is sorted */
+ int restore_fd, uint32_t *domid,
+ const libxl_asyncop_how *ao_how,
+ const libxl_asyncprogress_how *aop_console_how)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+
/* A progress report will be made via ao_console_how, of type
* domain_create_console_available, when the domain's primary
* console is available and can be connected to.
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index ee328e9..4f3a493 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -19,6 +19,7 @@
#include "libxl_internal.h"
#include "libxl_arch.h"
+#include "libxl_saverestore.h"
#include <xc_dom.h>
#include <xenguest.h>
@@ -1487,6 +1488,239 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
}
/*
+ * Helper for stub handlers. This should go away when the stub handlers are
+ * implemented.
+ */
+static int skip_data(int fd, int len)
+{
+ unsigned char buf[4096];
+ int ret = 0;
+ ssize_t n;
+
+ while (len > 0) {
+ n = read(fd, buf, len < sizeof(buf) ? len : sizeof(buf));
+ if (n <= 0) {
+ if (errno == EAGAIN)
+ continue;
+ ret = ERROR_FAIL;
+ goto out;
+ }
+
+ len -= n;
+ }
+
+out:
+ return ret;
+}
+
+/*
+ * Process a domain JSON string read from fd.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_domain_json(libxl_ctx *ctx, int fd, uint32_t len)
+{
+ int ret = 0;
+
+ ret = skip_data(fd, len);
+
+ return ret;
+}
+
+/*
+ * Process a libxc_context blob by passing it off to libxc.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_libxc_context(libxl_ctx *ctx, int fd,
+ libxl_domain_config *d_config, uint32_t *domid)
+{
+ return do_domain_create(ctx, d_config, domid, fd, 0, NULL, NULL);
+}
+
+/*
+ * Process a set of xenstore key-value pairs.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_xenstore_data(libxl_ctx *ctx, int fd, uint32_t len)
+{
+ int ret = 0;
+
+ ret = skip_data(fd, len);
+
+ return ret;
+}
+
+/*
+ * Process a qemu traditional emulator context.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_qemu_traditional(libxl_ctx *ctx, int fd, uint32_t len)
+{
+ return 0;
+}
+
+/*
+ * Process a qemu upstream emulator context.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_qemu_upstream(libxl_ctx *ctx, int fd, uint32_t len)
+{
+ return 0;
+}
+
+/*
+ * Process an emulator context record.
+ * Returns 0 on success, non-zero otherwise.
+ */
+static int restore_emulator_context(libxl_ctx *ctx, int fd, uint32_t len)
+{
+ struct restore_emulator_hdr hdr;
+ int ret = 0;
+
+ if (libxl_read_exactly(ctx, fd, &hdr, sizeof(hdr),
+ "restore stream", "emulator context header")) {
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ hdr.id = be32toh(hdr.id);
+ hdr.index = be32toh(hdr.index);
+ len -= sizeof(hdr);
+
+ switch (hdr.id) {
+ break;
+ case EMULATOR_QEMU_TRADITIONAL:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Emulator: QEMU traditional, index %u", hdr.index);
+ ret = restore_qemu_traditional(ctx, fd, len);
+ break;
+ case EMULATOR_QEMU_UPSTREAM:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Emulator: QEMU upstream, index %u", hdr.index);
+ ret = restore_qemu_upstream(ctx, fd, len);
+ break;
+ case EMULATOR_UNKNOWN:
+ default:
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Emulator: Unknown id 0x%08x, index %u", hdr.id, hdr.index);
+ ret = ERROR_FAIL;
+ break;
+ }
+
+ if (ret)
+ goto out;
+
+ ret = skip_data(fd, len);
+
+out:
+ return ret;
+}
+
+int libxl__domain_restore(libxl_ctx *ctx, int restore_fd, uint32_t *domid,
+ libxl_domain_config *d_config)
+{
+ GC_INIT(ctx);
+ struct restore_hdr hdr;
+ struct restore_rec_hdr rechdr;
+ int ret = 0;
+
+ if (libxl_read_exactly(ctx, restore_fd, &hdr, sizeof(hdr),
+ "restore stream", "stream header")) {
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ hdr.ident = be64toh(hdr.ident);
+ hdr.version = be32toh(hdr.version);
+ hdr.options = be32toh(hdr.options);
+
+ if (hdr.ident != RESTORE_STREAM_IDENT) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Invalid ident: Got 0x%016"PRIx64, hdr.ident);
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ if (hdr.version != RESTORE_STREAM_VERSION) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Invalid Version: Expected %u, Got %u",
+ hdr.version, RESTORE_STREAM_VERSION);
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ if (hdr.options & RESTORE_OPT_BIG_ENDIAN) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Unable to handle big endian streams");
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ if (hdr.options & RESTORE_OPT_LEGACY) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to restore legacy streams");
+ ret = ERROR_FAIL;
+ goto out;
+ }
+
+ do {
+ if (libxl_read_exactly(ctx, restore_fd, &rechdr, sizeof(rechdr),
+ "restore stream", "record header")) {
+ ret = ERROR_FAIL;
+ goto out;
+ }
+
+ switch (rechdr.type) {
+ case REC_TYPE_END:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Record: END, length %u", rechdr.length);
+ if (rechdr.length != 0) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Encountered END record with non-zero length");
+ ret = ERROR_FAIL;
+ }
+ break;
+ case REC_TYPE_DOMAIN_JSON:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Record: DOMAIN_JSON, length %u", rechdr.length);
+ ret = restore_domain_json(ctx, restore_fd, rechdr.length);
+ break;
+ case REC_TYPE_LIBXC_CONTEXT:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Record: LIBXC_CONTEXT, length %u", rechdr.length);
+ ret = restore_libxc_context(ctx, restore_fd, d_config, domid);
+ break;
+ case REC_TYPE_XENSTORE_DATA:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Record: XENSTORE_DATA, length %u", rechdr.length);
+ ret = restore_xenstore_data(ctx, restore_fd, rechdr.length);
+ break;
+ case REC_TYPE_EMULATOR_CONTEXT:
+ LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
+ "Record: EMULATOR_CONTEXT, length %u", rechdr.length);
+ ret = restore_emulator_context(ctx, restore_fd, rechdr.length);
+ break;
+ default:
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "Unknown record type: Got 0x%08x", rechdr.type);
+ ret = ERROR_FAIL;
+ break;
+ }
+
+ /* Skip until an 8 byte boundary for the next record. */
+ if (!ret) {
+ unsigned char pad[8];
+ ssize_t len = ROUNDUP(rechdr.length, REC_ALIGN_ORDER) - rechdr.length;
+
+ assert(len >= 0 && len < 8);
+
+ if (libxl_read_exactly(ctx, restore_fd, pad, len,
+ "restore stream", "padding")) {
+ ret = ERROR_FAIL;
+ goto out;
+ }
+ }
+ } while (!ret && rechdr.type != REC_TYPE_END);
+
+out:
+ GC_FREE;
+ return ret;
+}
+
+/*
* Local variables:
* mode: C
* c-basic-offset: 4
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 47fbf45..4128373 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -2876,6 +2876,11 @@ _hidden void libxl__domain_save_device_model(libxl__egc *egc,
_hidden const char *libxl__device_model_savefile(libxl__gc *gc, uint32_t domid);
+/*----- Domain restore functions -----*/
+/* TODO - make this asychronous */
+_hidden int libxl__domain_restore(libxl_ctx *ctx, int fd, uint32_t *domid,
+ libxl_domain_config *d_config /* TMP until json is sorted */
+ );
/*
* Convenience macros.
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH VERY RFC 4/5] tools/xl: Restore v2 streams using new libxl_domain_restore() interface
2014-09-03 17:14 [PATCH VERY RFC 0/5] Libxl migration v2 support Andrew Cooper
` (2 preceding siblings ...)
2014-09-03 17:14 ` [PATCH VERY RFC 3/5] tools/libxl: Implement libxl_domain_restore() for v2 streams Andrew Cooper
@ 2014-09-03 17:14 ` Andrew Cooper
2014-09-03 17:14 ` [PATCH VERY RFC 5/5] tools/[lib]xl: Alter libxl_domain_suspend() to write a v2 stream Andrew Cooper
4 siblings, 0 replies; 7+ messages in thread
From: Andrew Cooper @ 2014-09-03 17:14 UTC (permalink / raw)
To: Xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Andrew Cooper
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/libxl/xl_cmdimpl.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index e6b9615..8e0a6bb 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -136,6 +136,8 @@ static const char *action_on_shutdown_names[] = {
#define SAVEFILE_BYTEORDER_VALUE ((uint32_t)0x01020304UL)
+#define SAVEFILE_MANDATORY_STREAMV2 (1 << 0)
+
struct domain_create {
int debug;
int daemonize;
@@ -2115,7 +2117,7 @@ static uint32_t create_domain(struct domain_create *dom_info)
restore_source, hdr.mandatory_flags, hdr.optional_flags,
hdr.optional_data_len);
- badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ );
+ badflags = hdr.mandatory_flags & ~SAVEFILE_MANDATORY_STREAMV2;
if (badflags) {
fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" "
"which are not supported; need newer xl\n",
@@ -2245,12 +2247,17 @@ start:
}
if ( restoring ) {
- libxl_domain_restore_params params;
- params.checkpointed_stream = dom_info->checkpointed_stream;
- ret = libxl_domain_create_restore(ctx, &d_config,
- &domid, restore_fd,
- ¶ms,
- 0, autoconnect_console_how);
+ if ( hdr.mandatory_flags & SAVEFILE_MANDATORY_STREAMV2 ) {
+ ret = libxl_domain_restore(ctx, &d_config, restore_fd, &domid,
+ 0, autoconnect_console_how);
+ } else {
+ libxl_domain_restore_params params;
+ params.checkpointed_stream = dom_info->checkpointed_stream;
+ ret = libxl_domain_create_restore(ctx, &d_config,
+ &domid, restore_fd,
+ ¶ms,
+ 0, autoconnect_console_how);
+ }
/*
* On subsequent reboot etc we should create the domain, not
* restore/migrate-receive it again.
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH VERY RFC 5/5] tools/[lib]xl: Alter libxl_domain_suspend() to write a v2 stream
2014-09-03 17:14 [PATCH VERY RFC 0/5] Libxl migration v2 support Andrew Cooper
` (3 preceding siblings ...)
2014-09-03 17:14 ` [PATCH VERY RFC 4/5] tools/xl: Restore v2 streams using new libxl_domain_restore() interface Andrew Cooper
@ 2014-09-03 17:14 ` Andrew Cooper
4 siblings, 0 replies; 7+ messages in thread
From: Andrew Cooper @ 2014-09-03 17:14 UTC (permalink / raw)
To: Xen-devel
Cc: Wei Liu, Andrew Cooper, Ian Jackson, Ian Campbell, Ross Lagerwall
From: Ross Lagerwall <ross.lagerwall@citrix.com>
Note that for now, the xl header and device config blob at the beginning
of the stream is still written out since we don't have any domain JSON
yet.
Note that because of the removal of legacy xc_domain_save() from libxc, there
is no possible way to support the legacy behaviour of libxl_domain_save() with
older LIBXL_API versions. Bail with a clear error instead of substituing a
legacy stream with a v2 stream under the feet of an unsuspecting application.
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/libxl/libxl.h | 37 ++++++++--
tools/libxl/libxl_dom.c | 160 +++++++++++++++++++++++++++++++++++-------
tools/libxl/libxl_internal.h | 1 +
tools/libxl/xl_cmdimpl.c | 1 +
4 files changed, 166 insertions(+), 33 deletions(-)
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index fb14a91..98f586e 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -837,7 +837,15 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
const libxl_asyncprogress_how *aop_console_how)
LIBXL_EXTERNAL_CALLERS_ONLY;
-#if defined(LIBXL_API_VERSION) && LIBXL_API_VERSION < 0x040400
+#if defined(LIBXL_API_VERSION)
+
+/*
+ * The legacy xc_domain_restore() has disappeared, as it was completely unfit
+ * for purpose. Instead of leaving a subtle surprise for libxl consumers using
+ * older API versions, fail early with a clear error.
+ */
+
+#if LIBXL_API_VERSION < 0x040400
int static inline libxl_domain_create_restore_0x040200(
libxl_ctx *ctx, libxl_domain_config *d_config,
@@ -846,15 +854,32 @@ int static inline libxl_domain_create_restore_0x040200(
const libxl_asyncprogress_how *aop_console_how)
LIBXL_EXTERNAL_CALLERS_ONLY
{
- libxl_domain_restore_params params;
- params.checkpointed_stream = 0;
-
- return libxl_domain_create_restore(
- ctx, d_config, domid, restore_fd, ¶ms, ao_how, aop_console_how);
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "The legacy save/restore format is not supported. "
+ "Please update to the v2 interface");
+ return ERROR_FAIL;
}
#define libxl_domain_create_restore libxl_domain_create_restore_0x040200
+#elif LIBXL_API_VERSION < 0x040500
+
+int static inline libxl_domain_create_restore(
+ libxl_ctx *ctx, libxl_domain_config *d_config,
+ uint32_t *domid, int restore_fd,
+ const libxl_domain_restore_params *params,
+ const libxl_asyncop_how *ao_how,
+ const libxl_asyncprogress_how *aop_console_how)
+ LIBXL_EXTERNAL_CALLERS_ONLY
+{
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+ "The legacy save/restore format is not supported. "
+ "Please update to the v2 interface");
+ return ERROR_FAIL;
+}
+
+#endif
+
#endif
/* Restore from a v2 stream
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index c944804..3a698f2 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -19,6 +19,7 @@
#include "libxl_internal.h"
#include "libxl_arch.h"
+#include "libxl_saverestore.h"
#include <xc_dom.h>
#include <xen/hvm/hvm_info_table.h>
@@ -1574,11 +1575,67 @@ static void remus_checkpoint_dm_saved(libxl__egc *egc,
/*----- main code for suspending, in order of execution -----*/
+void libxl__save_write_header(libxl__egc *egc,
+ libxl__domain_suspend_state *dss);
+
void libxl__domain_suspend(libxl__egc *egc, libxl__domain_suspend_state *dss)
{
STATE_AO_GC(dss->ao);
- int port;
+
+ libxl__save_write_header(egc, dss);
+}
+
+void libxl__save_write_end(libxl__egc *egc,
+ libxl__domain_suspend_state *dss);
+
+void libxl__xc_domain_save_done(libxl__egc *egc, void *dss_void,
+ int rc, int retval, int errnoval)
+{
+ libxl__domain_suspend_state *dss = dss_void;
+ STATE_AO_GC(dss->ao);
+
+ /* Convenience aliases */
+ const libxl_domain_type type = dss->type;
+
+ if (rc)
+ goto out;
+
+ if (retval) {
+ LOGEV(ERROR, errnoval, "saving domain: %s",
+ dss->guest_responded ?
+ "domain responded to suspend request" :
+ "domain did not respond to suspend request");
+ if ( !dss->guest_responded )
+ rc = ERROR_GUEST_TIMEDOUT;
+ else
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ if (type == LIBXL_DOMAIN_TYPE_HVM) {
+ rc = libxl__domain_suspend_device_model(gc, dss);
+ if (rc) goto out;
+
+ /* XXX need to writer footer after this */
+ libxl__domain_save_device_model(egc, dss, domain_suspend_done);
+ return;
+ }
+
+ libxl__save_write_end(egc, dss);
+ return;
+
+out:
+ domain_suspend_done(egc, dss, rc);
+}
+
+static void write_header_done(libxl__egc *egc,
+ libxl__writer_state *dw, int onwrite, int errnoval)
+{
+ libxl__domain_suspend_state *dss = CONTAINER_OF(dw, *dss, writer);
+ STATE_AO_GC(dss->ao);
+
int rc = ERROR_FAIL;
+ int port;
/* Convenience aliases */
const uint32_t domid = dss->domid;
@@ -1589,6 +1646,11 @@ void libxl__domain_suspend(libxl__egc *egc, libxl__domain_suspend_state *dss)
libxl__srm_save_autogen_callbacks *const callbacks =
&dss->shs.callbacks.save.a;
+ libxl__writer_kill(dw);
+
+ if (onwrite || errnoval)
+ goto out;
+
logdirty_init(&dss->logdirty);
libxl__xswait_init(&dss->pvcontrol);
libxl__ev_evtchn_init(&dss->guest_evtchn);
@@ -1650,45 +1712,89 @@ void libxl__domain_suspend(libxl__egc *egc, libxl__domain_suspend_state *dss)
libxl__xc_domain_save(egc, dss);
return;
+out:
+ domain_suspend_done(egc, dss, rc);
+}
+
+void libxl__save_write_header(libxl__egc *egc,
+ libxl__domain_suspend_state *dss)
+{
+ STATE_AO_GC(dss->ao);
+ struct restore_hdr hdr;
+ struct restore_rec_hdr rechdr;
+ int rc = ERROR_FAIL;
+
+ libxl__writer_state *dw = &dss->writer;
+ memset(dw, 0, sizeof(*dw));
+ dw->ao = ao;
+ dw->writefd = dss->fd;
+ dw->maxsz = INT_MAX;
+ dw->towhat = "suspend stream";
+ dw->writewhat = "suspend header";
+ dw->callback = write_header_done;
+
+ rc = libxl__writer_start(dw);
+ if (rc) goto out;
+
+ hdr.ident = htobe64(RESTORE_STREAM_IDENT);
+ hdr.version = htobe32(RESTORE_STREAM_VERSION);
+ hdr.options = htobe32(0x0);
+ libxl__writer_append(egc, dw, &hdr, sizeof(hdr));
+
+ /* XXX need to write the domain config here. */
+
+ rechdr.type = REC_TYPE_LIBXC_CONTEXT;
+ rechdr.length = 0;
+ libxl__writer_append(egc, dw, &rechdr, sizeof(rechdr));
+
+ return;
+
out:
domain_suspend_done(egc, dss, rc);
}
-void libxl__xc_domain_save_done(libxl__egc *egc, void *dss_void,
- int rc, int retval, int errnoval)
+static void write_end_writer_done(libxl__egc *egc,
+ libxl__writer_state *dw, int onwrite, int errnoval)
{
- libxl__domain_suspend_state *dss = dss_void;
+ libxl__domain_suspend_state *dss = CONTAINER_OF(dw, *dss, writer);
STATE_AO_GC(dss->ao);
- /* Convenience aliases */
- const libxl_domain_type type = dss->type;
+ int rc = 0;
- if (rc)
- goto out;
+ libxl__writer_kill(dw);
- if (retval) {
- LOGEV(ERROR, errnoval, "saving domain: %s",
- dss->guest_responded ?
- "domain responded to suspend request" :
- "domain did not respond to suspend request");
- if ( !dss->guest_responded )
- rc = ERROR_GUEST_TIMEDOUT;
- else
- rc = ERROR_FAIL;
- goto out;
- }
+ if (onwrite || errnoval)
+ rc = ERROR_FAIL;
- if (type == LIBXL_DOMAIN_TYPE_HVM) {
- rc = libxl__domain_suspend_device_model(gc, dss);
- if (rc) goto out;
+ domain_suspend_done(egc, dss, rc);
+}
- libxl__domain_save_device_model(egc, dss, domain_suspend_done);
- return;
- }
+void libxl__save_write_end(libxl__egc *egc,
+ libxl__domain_suspend_state *dss)
+{
+ STATE_AO_GC(dss->ao);
+ struct restore_rec_hdr rechdr;
+ int rc = ERROR_FAIL;
- rc = 0;
+ libxl__writer_state *dw = &dss->writer;
+ memset(dw, 0, sizeof(*dw));
+ dw->ao = ao;
+ dw->writefd = dss->fd;
+ dw->maxsz = INT_MAX;
+ dw->towhat = "suspend stream";
+ dw->writewhat = "suspend footer";
+ dw->callback = write_end_writer_done;
-out:
+ rechdr.type = REC_TYPE_END;
+ rechdr.length = 0;
+
+ rc = libxl__writer_start(dw);
+ if (rc) goto out;
+
+ libxl__writer_append(egc, dw, &rechdr, sizeof(rechdr));
+ return;
+
+ out:
domain_suspend_done(egc, dss, rc);
}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 4128373..29ba2ac 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -2562,6 +2562,7 @@ struct libxl__domain_suspend_state {
/* private for libxl__domain_save_device_model */
libxl__save_device_model_cb *save_dm_callback;
libxl__datacopier_state save_dm_datacopier;
+ libxl__writer_state writer;
};
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 8e0a6bb..691a2a0 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -3410,6 +3410,7 @@ static void save_domain_core_writeconfig(int fd, const char *source,
memset(&hdr, 0, sizeof(hdr));
memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic));
hdr.byteorder = SAVEFILE_BYTEORDER_VALUE;
+ hdr.mandatory_flags = SAVEFILE_MANDATORY_STREAMV2;
optdata_begin= 0;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread