This patch series provides support for "xl migrate". There are a number of bugfixes and extensions to libxl, followed by a new savefile format (which can contain the domain config file and is more extensible), followed by actual migration support. Changes since the previous version of this patch series: * libxl: caller userdata is stored indexed by the domain uuid, not domid. * xl: Global struct libxl_ctx, domid and domname are used everywhere; many copies of initialisation boilerplate for these eliminated; other new global variables (eg, comon_config etc.) abolished. * xl: Support for old-format save files removed. * xl: Command-line visibility of uuids. * libxenstore, libxl: Safer handling of xenstore connections across fork(). * Consequential changes and a few other small bugfixes. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 01/16] libxl: Make logging functions preserve errno
This is needed by the following patches. It makes it much more convenient for libxl functions to return the errno value from the failure, when they fail. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_internal.c | 5 ++++- tools/libxl/libxl_internal.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index f48e9eb..4dcdabe 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -156,11 +156,13 @@ void xl_logv(struct libxl_ctx *ctx, int loglevel, int errnoval, { char *enomem = "[out of memory formatting log message]"; char *s; - int rc; + int rc, esave; if (!ctx->log_callback) return; + esave = errno; + rc = vasprintf(&s, fmt, ap); if (rc<0) { s = enomem; goto x; } @@ -180,6 +182,7 @@ void xl_logv(struct libxl_ctx *ctx, int loglevel, int errnoval, ctx->log_callback(ctx->log_userdata, loglevel, file, line, func, s); if (s != enomem) free(s); + errno = esave; } void xl_log(struct libxl_ctx *ctx, int loglevel, int errnoval, diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 300c108..10e72e5 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -47,6 +47,7 @@ #define XL_LOG_ERRNO(ctx, loglevel, _f, _a...) #define XL_LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...) #endif + /* all of these macros preserve errno (saving and restoring) */ #define XL_LOG_DEBUG 3 #define XL_LOG_INFO 2 @@ -56,6 +57,7 @@ /* logging */ void xl_logv(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, va_list al); void xl_log(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, ...); + /* these functions preserve errno (saving and restoring) */ typedef enum { -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 02/16] libxl: Report error if logfile rotation fails
Check the return values from renames and errors from stat in libxl_create_logfile (which, misleadingly, does not actually create the logfile). Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_utils.c | 28 +++++++++++++++++++++++++--- 1 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index 1ba9431..afc852a 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -101,11 +101,25 @@ int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t *target_dom return 1; } +static int logrename(struct libxl_ctx *ctx, const char *old, const char *new) { + int r; + + r = rename(old, new); + if (r) { + if (errno == ENOENT) return 0; /* ok */ + + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to rotate logfile - could not" + " rename %s to %s", old, new); + return ERROR_FAIL; + } + return 0; +} + int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name) { struct stat stat_buf; char *logfile, *logfile_new; - int i; + int i, rc; logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name); if (stat(logfile, &stat_buf) == 0) { @@ -115,11 +129,19 @@ int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name) for (i = 9; i > 0; i--) { logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i); logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i + 1); - rename(logfile, logfile_new); + rc = logrename(ctx, logfile, logfile_new); + if (rc) return rc; } logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name); logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.1", name); - rename(logfile, logfile_new); + + rc = logrename(ctx, logfile, logfile_new); + if (rc) return rc; + } else { + if (errno != ENOENT) + XL_LOG_ERRNO(ctx, XL_LOG_WARNING, "problem checking existence of" + " logfile %s, which might have needed to be rotated", + name); } *full_name = strdup(logfile); return 0; -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 03/16] libxl: New utility functions in for reading and writing files.
We introduce these functions in libxl_utils.h: int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename, void **data_r, int *datalen_r); int libxl_read_exactly(struct libxl_ctx *ctx, int fd, void *data, ssize_t sz, const char *filename, const char *what); int libxl_write_exactly(struct libxl_ctx *ctx, int fd, const void *data, ssize_t sz, const char *filename, const char *what); They will be needed by the following patches. They have to be in libxl.a rather than libxutil.a because they will be used, amongst other places, in libxl itself. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_utils.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_utils.h | 18 ++++++++ 2 files changed, 121 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index afc852a..3a1f095 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -26,6 +26,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> +#include <assert.h> #include "libxl_utils.h" #include "libxl_internal.h" @@ -177,3 +178,105 @@ out: return rc; } +int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename, + void **data_r, int *datalen_r) { + FILE *f = 0; + uint8_t *data = 0; + int datalen = 0; + int e; + struct stat stab; + ssize_t rs; + + f = fopen(filename, "r"); + if (!f) { + if (errno == ENOENT) return ENOENT; + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to open %s", filename); + goto xe; + } + + if (fstat(fileno(f), &stab)) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to fstat %s", filename); + goto xe; + } + + if (!S_ISREG(stab.st_mode)) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "%s is not a plain file", filename); + errno = ENOTTY; + goto xe; + } + + if (stab.st_size > INT_MAX) { + XL_LOG(ctx, XL_LOG_ERROR, "file %s is far too large", filename); + errno = EFBIG; + goto xe; + } + + datalen = stab.st_size; + + if (stab.st_size && data_r) { + data = malloc(datalen); + if (!data) goto xe; + + rs = fread(data, 1, datalen, f); + if (rs != datalen) { + if (ferror(f)) + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to read %s", filename); + else if (feof(f)) + XL_LOG(ctx, XL_LOG_ERROR, "%s changed size while we" + " were reading it", filename); + else + abort(); + goto xe; + } + } + + if (fclose(f)) { + f = 0; + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to close %s", filename); + goto xe; + } + + if (data_r) *data_r = data; + if (datalen_r) *datalen_r = datalen; + + return 0; + + xe: + e = errno; + assert(e != ENOENT); + if (f) fclose(f); + if (data) free(data); + return e; +} + +#define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \ + \ + int libxl_##rw##_exactly(struct libxl_ctx *ctx, int fd, \ + constdata void *data, ssize_t sz, \ + const char *filename, const char *what) { \ + ssize_t got; \ + \ + while (sz > 0) { \ + got = rw(fd, data, sz); \ + if (got == -1) { \ + if (errno == EINTR) continue; \ + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to " #rw " %s%s%s", \ + what?what:"", what?" from ":"", filename); \ + return errno; \ + } \ + if (got == 0) { \ + XL_LOG(ctx, XL_LOG_ERROR, \ + zero_is_eof \ + ? "file/stream truncated reading %s%s%s" \ + : "file/stream write returned 0! writing %s%s%s", \ + what?what:"", what?" from ":"", filename); \ + return EPROTO; \ + } \ + sz -= got; \ + data = (char*)data + got; \ + } \ + return 0; \ + } + +READ_WRITE_EXACTLY(read, 1, /* */) +READ_WRITE_EXACTLY(write, 0, const) diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 05fa4e3..65e7e31 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -26,5 +26,23 @@ int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t *target_dom int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name); int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype); +int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename, + void **data_r, int *datalen_r); + /* Reads the contents of the plain file filename into a mallocd + * buffer. Returns 0 or errno. Any errors other than ENOENT are logged. + * If the file is empty, *data_r and *datalen_r are set to 0. + * On error, *data_r and *datalen_r are undefined. + * data_r and/or datalen_r may be 0. + */ + +int libxl_read_exactly(struct libxl_ctx *ctx, int fd, void *data, ssize_t sz, + const char *filename, const char *what); +int libxl_write_exactly(struct libxl_ctx *ctx, int fd, const void *data, + ssize_t sz, const char *filename, const char *what); + /* Returns 0 or errno. If file is truncated on reading, returns + * EPROTO and you have no way to tell how much was read. Errors are + * logged using filename (which is only used for logging) and what + * (which may be 0). */ + #endif -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 04/16] libxl: libxl_domain_restore: Put fd back to blocking mode
libxl_domain_restore calls, indirectly, xc_domain_restore. The latter, when doing a live migration, sets the fd from blocking mode (which it must be on entry, or things go wrong) to nonblocking mode and leaves it this way. Arguably this is a bug in libxc, but to avoid disrupting any callers we fix it in libxl. So libxl_domain_restore now puts the fd back into blocking mode before returning. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 46a42a5..87a51fa 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -221,7 +221,7 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info, libxl_device_model_info *dm_info) { char **vments = NULL, **localents = NULL; - int i, ret; + int i, ret, esave, flags; ret = build_pre(ctx, domid, info, state); if (ret) goto out; @@ -259,6 +259,19 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info, else dm_info->saved_state = NULL; out: + esave = errno; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to get flags on restore fd"); + } else { + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) == -1) + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to put restore fd" + " back to blocking mode"); + } + + errno = esave; return ret; } -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 05/16] libxl: Provide libxl_domain_rename
Provide a new function libxl_domain_rename. It can check that the domain being renamed has the expected name, to avoid races. Use the new function to set the name during domain creation. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++- tools/libxl/libxl.h | 6 ++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 87a51fa..4d80be5 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -82,7 +82,7 @@ int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, vo int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, uint32_t *domid) { - int flags, ret, i; + int flags, ret, i, rc; char *uuid_string; char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"}; char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers", @@ -146,7 +146,8 @@ retry_transaction: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path)); xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path)); - xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name)); + rc = libxl_domain_rename(ctx, *domid, 0, info->name, t); + if (rc) return rc; for (i = 0; i < ARRAY_SIZE(rw_paths); i++) { char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]); @@ -175,6 +176,84 @@ retry_transaction: return 0; } +int libxl_domain_rename(struct libxl_ctx *ctx, uint32_t domid, + const char *old_name, const char *new_name, + xs_transaction_t trans) { + char *dom_path = 0; + const char *name_path; + char *got_old_name; + unsigned int got_old_len; + xs_transaction_t our_trans = 0; + int rc; + + dom_path = libxl_xs_get_dompath(ctx, domid); + if (!dom_path) goto x_nomem; + + name_path= libxl_sprintf(ctx, "%s/name", dom_path); + if (!name_path) goto x_nomem; + + retry_transaction: + if (!trans) { + trans = our_trans = xs_transaction_start(ctx->xsh); + if (!our_trans) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno, + "create xs transaction for domain (re)name"); + goto x_fail; + } + } + + if (old_name) { + got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len); + if (!got_old_name) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno, "check old name" + " for domain %"PRIu32" allegedly named `%s''", + domid, old_name); + goto x_fail; + } + if (strcmp(old_name, got_old_name)) { + XL_LOG(ctx, XL_LOG_ERROR, "domain %"PRIu32" allegedly named " + "`%s'' is actually named `%s'' - racing ?", + domid, old_name, got_old_name); + free(got_old_name); + goto x_fail; + } + free(got_old_name); + } + if (!xs_write(ctx->xsh, trans, name_path, + new_name, strlen(new_name))) { + XL_LOG(ctx, XL_LOG_ERROR, "failed to write new name `%s''" + " for domain %"PRIu32" previously named `%s''", + domid, new_name, old_name); + goto x_fail; + } + + if (our_trans) { + if (!xs_transaction_end(ctx->xsh, our_trans, 0)) { + trans = our_trans = 0; + if (errno != EAGAIN) { + XL_LOG(ctx, XL_LOG_ERROR, "failed to commit new name `%s''" + " for domain %"PRIu32" previously named `%s''", + domid, new_name, old_name); + goto x_fail; + } + XL_LOG(ctx, XL_LOG_DEBUG, "need to retry rename transaction" + " for domain %"PRIu32" (name_path=\"%s\", new_name=\"%s\")", + domid, name_path, new_name); + goto retry_transaction; + } + our_trans = 0; + } + + rc = 0; + x_rc: + if (dom_path) libxl_free(ctx, dom_path); + if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1); + return rc; + + x_fail: rc = ERROR_FAIL; goto x_rc; + x_nomem: rc = ERROR_NOMEM; goto x_rc; +} + int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state) { char **vments = NULL, **localents = NULL; diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 959d9f5..fea552b 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -297,6 +297,12 @@ int libxl_free_waiter(libxl_waiter *waiter); int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_domaininfo_t *info); int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk); +int libxl_domain_rename(struct libxl_ctx *ctx, uint32_t domid, + const char *old_name, const char *new_name, + xs_transaction_t trans); + /* if old_name is NULL, any old name is OK; otherwise we check + * transactionally that the domain has the old old name; if + * trans is not 0 we use caller''s transaction and caller must do retries */ int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid); int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid); -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 06/16] libxl: Expose functions for helping with subprocesses.
* Expose libxl_fork in libxl_utils.h * Expose libxl_pipe in libxl_utils.h * Make libxl_exec put SIGPIPE back (so that libxl callers may have SIGPIPE ignored) xl would like to use libxl_fork (which is like fork(2) except that it logs errors) and also a similar function libxl_pipe. So put these in libxl_utils.[ch] and use them in libxl.c as appropriate, to avoid having to duplicate code between xl and libxl. Also, make sure that subprocesses spawned by libxl have SIGPIPE set back to SIG_DFL as they are entitled to expect. This means that a libxl caller which sets SIGPIPE to SIG_IGN is no longer buggy. (This is relevant for xl migration, because xl would like to be such a caller.) Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 12 +++--------- tools/libxl/libxl_exec.c | 18 +++++------------- tools/libxl/libxl_utils.c | 23 +++++++++++++++++++++++ tools/libxl/libxl_utils.h | 4 ++++ 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 4d80be5..2cc9602 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1238,15 +1238,9 @@ int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_di char buf[1024], *dev; dev = get_blktap2_device(ctx, disk->physpath, device_disk_string_of_phystype(disk->phystype)); if (dev == NULL) { - if (pipe(p) < 0) { - XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe"); - return -1; - } - rc = fork(); - if (rc < 0) { - XL_LOG(ctx, XL_LOG_ERROR, "Failed to fork a new process"); - return -1; - } else if (!rc) { /* child */ + rc= libxl_pipe(ctx, p); if (rc==-1) return -1; + rc= libxl_fork(ctx); if (rc==-1) return -1; + if (!rc) { /* child */ int null_r, null_w; char *args[4]; args[0] = "tapdisk2"; diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c index e8cc74c..6d4a5c5 100644 --- a/tools/libxl/libxl_exec.c +++ b/tools/libxl/libxl_exec.c @@ -30,19 +30,6 @@ #include "libxl.h" #include "libxl_internal.h" -static pid_t libxl_fork(struct libxl_ctx *ctx) -{ - pid_t pid; - - pid = fork(); - if (pid == -1) { - XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed"); - return -1; - } - - return pid; -} - static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int *status, int options) { return (waitpid_cb) ? waitpid_cb(pid, status, options) : waitpid(pid, status, options); @@ -61,6 +48,11 @@ void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args dup2(stderrfd, STDERR_FILENO); for (i = 4; i < 256; i++) close(i); + + signal(SIGPIPE, SIG_DFL); + /* in case our caller set it to IGN. subprocesses are entitled + * to assume they got DFL. */ + execv(arg0, args); _exit(-1); } diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index 3a1f095..c6989ce 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -280,3 +280,26 @@ int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename, READ_WRITE_EXACTLY(read, 1, /* */) READ_WRITE_EXACTLY(write, 0, const) + + +pid_t libxl_fork(struct libxl_ctx *ctx) +{ + pid_t pid; + + pid = fork(); + if (pid == -1) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed"); + return -1; + } + + return pid; +} + +int libxl_pipe(struct libxl_ctx *ctx, int pipes[2]) +{ + if (pipe(pipes) < 0) { + XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe"); + return -1; + } + return 0; +} diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 65e7e31..fe8b975 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -44,5 +44,9 @@ int libxl_write_exactly(struct libxl_ctx *ctx, int fd, const void *data, * logged using filename (which is only used for logging) and what * (which may be 0). */ +pid_t libxl_fork(struct libxl_ctx *ctx); +int libxl_pipe(struct libxl_ctx *ctx, int pipes[2]); + /* Just like fork(2), pipe(2), but log errors. */ + #endif -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 07/16] xenstore, libxl: cleanup of xenstore connections across fork()
Provide a new function xs_daemon_destroy_postfork which can be called by a libxenstore user who has called fork, to close the fd for the connection to xenstored and free the memory, without trying to do anything to any threads which libxenstore may have created. Use this new function in libxl_fork, to avoid accidental use of a xenstore connection in both parent and child. Also, fix the doc comment for libxl_spawn_spawn to have the success return codes the right way round. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 2 +- tools/libxl/libxl.h | 1 + tools/libxl/libxl_internal.h | 4 +- tools/libxl/libxl_utils.c | 15 ++++++++++++ tools/xenstore/xs.c | 52 ++++++++++++++++++++++++++--------------- tools/xenstore/xs.h | 3 ++ 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 2cc9602..f96b3ae 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -66,7 +66,7 @@ int libxl_ctx_free(struct libxl_ctx *ctx) libxl_free_all(ctx); free(ctx->alloc_ptrs); xc_interface_close(ctx->xch); - xs_daemon_close(ctx->xsh); + if (ctx->xsh) xs_daemon_close(ctx->xsh); return 0; } diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index fea552b..02bdd21 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -250,6 +250,7 @@ enum { int libxl_ctx_init(struct libxl_ctx *ctx, int version); int libxl_ctx_free(struct libxl_ctx *ctx); int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data); +int libxl_ctx_postfork(struct libxl_ctx *ctx); /* domain related functions */ int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, uint32_t *domid); diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 10e72e5..29816e7 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -185,8 +185,8 @@ int libxl_spawn_spawn(struct libxl_ctx *ctx, void (*intermediate_hook)(void *for_spawn, pid_t innerchild)); /* Logs errors. A copy of "what" is taken. Return values: * < 0 error, for_spawn need not be detached - * +1 caller is now the inner child, should probably call libxl_exec - * 0 caller is the parent, must call detach on *for_spawn eventually + * +1 caller is the parent, must call detach on *for_spawn eventually + * 0 caller is now the inner child, should probably call libxl_exec * Caller, may pass 0 for for_spawn, in which case no need to detach. */ int libxl_spawn_detach(struct libxl_ctx *ctx, diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index c6989ce..c4dc74c 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -282,6 +282,13 @@ READ_WRITE_EXACTLY(read, 1, /* */) READ_WRITE_EXACTLY(write, 0, const) +int libxl_ctx_postfork(struct libxl_ctx *ctx) { + if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh); + ctx->xsh = xs_daemon_open(); + if (!ctx->xsh) return ERROR_FAIL; + return 0; +} + pid_t libxl_fork(struct libxl_ctx *ctx) { pid_t pid; @@ -292,6 +299,14 @@ pid_t libxl_fork(struct libxl_ctx *ctx) return -1; } + if (!pid) { + if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh); + ctx->xsh = 0; + /* This ensures that anyone who forks but doesn''t exec, + * and doesn''t reinitialise the libxl_ctx, is OK. + * It also means they can safely call libxl_ctx_free. */ + } + return pid; } diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index 9707d19..5b05268 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -223,10 +223,39 @@ struct xs_handle *xs_domain_open(void) return get_handle(xs_domain_dev()); } -void xs_daemon_close(struct xs_handle *h) -{ +static void close_free_msgs(struct xs_handle *h) { struct xs_stored_msg *msg, *tmsg; + list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) { + free(msg->body); + free(msg); + } + + list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) { + free(msg->body); + free(msg); + } +} + +static void close_fds_free(struct xs_handle *h) { + if (h->watch_pipe[0] != -1) { + close(h->watch_pipe[0]); + close(h->watch_pipe[1]); + } + + close(h->fd); + + free(h); +} + +void xs_daemon_destroy_postfork(struct xs_handle *h) +{ + close_free_msgs(h); + close_fds_free(h); +} + +void xs_daemon_close(struct xs_handle *h) +{ mutex_lock(&h->request_mutex); mutex_lock(&h->reply_mutex); mutex_lock(&h->watch_mutex); @@ -239,28 +268,13 @@ void xs_daemon_close(struct xs_handle *h) } #endif - list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) { - free(msg->body); - free(msg); - } - - list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) { - free(msg->body); - free(msg); - } + close_free_msgs(h); mutex_unlock(&h->request_mutex); mutex_unlock(&h->reply_mutex); mutex_unlock(&h->watch_mutex); - if (h->watch_pipe[0] != -1) { - close(h->watch_pipe[0]); - close(h->watch_pipe[1]); - } - - close(h->fd); - - free(h); + close_fds_free(h); } static bool read_all(int fd, void *data, unsigned int len) diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index bd36a0b..4dae594 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -48,6 +48,9 @@ struct xs_handle *xs_daemon_open_readonly(void); /* Close the connection to the xs daemon. */ void xs_daemon_close(struct xs_handle *); +/* Throw away the connection to the xs daemon, for use after fork(). */ +void xs_daemon_destroy_postfork(struct xs_handle *); + /* Get contents of a directory. * Returns a malloced array: call free() on it after use. * Num indicates size. -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 08/16] libxl: Expose libxl_report_exitstatus
xl would like to use libxl_report_exitstatus, so expose it in libxl_utils.h to avoid having to write it twice. Also, give it a "level" argument to set the loglevel of the resulting message. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_exec.c | 16 +++++++--------- tools/libxl/libxl_internal.h | 5 ----- tools/libxl/libxl_utils.h | 11 +++++++++++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c index 6d4a5c5..52dda97 100644 --- a/tools/libxl/libxl_exec.c +++ b/tools/libxl/libxl_exec.c @@ -57,34 +57,32 @@ void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args _exit(-1); } -void libxl_report_child_exitstatus(struct libxl_ctx *ctx, +void libxl_report_child_exitstatus(struct libxl_ctx *ctx, int level, const char *what, pid_t pid, int status) { - /* treats all exit statuses as errors; if that''s not what you want, - * check status yourself first */ if (WIFEXITED(status)) { int st = WEXITSTATUS(status); if (st) - XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] exited" + XL_LOG(ctx, level, "%s [%ld] exited" " with error status %d", what, (unsigned long)pid, st); else - XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] unexpectedly" + XL_LOG(ctx, level, "%s [%ld] unexpectedly" " exited status zero", what, (unsigned long)pid); } else if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); const char *str = strsignal(sig); const char *coredump = WCOREDUMP(status) ? " (core dumped)" : ""; if (str) - XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to" + XL_LOG(ctx, level, "%s [%ld] died due to" " fatal signal %s%s", what, (unsigned long)pid, str, coredump); else - XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to unknown" + XL_LOG(ctx, level, "%s [%ld] died due to unknown" " fatal signal number %d%s", what, (unsigned long)pid, sig, coredump); } else { - XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] gave unknown" + XL_LOG(ctx, level, "%s [%ld] gave unknown" " wait status 0x%x", what, (unsigned long)pid, status); } } @@ -145,7 +143,7 @@ static void report_spawn_intermediate_status(struct libxl_ctx *ctx, char *intermediate_what = libxl_sprintf(ctx, "%s intermediate process (startup monitor)", for_spawn->what); - libxl_report_child_exitstatus(ctx, intermediate_what, + libxl_report_child_exitstatus(ctx, XL_LOG_ERROR, intermediate_what, for_spawn->intermediate, status); } } diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 29816e7..de9a756 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -49,11 +49,6 @@ #endif /* all of these macros preserve errno (saving and restoring) */ -#define XL_LOG_DEBUG 3 -#define XL_LOG_INFO 2 -#define XL_LOG_WARNING 1 -#define XL_LOG_ERROR 0 - /* logging */ void xl_logv(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, va_list al); void xl_log(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, ...); diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index fe8b975..4c04c46 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -48,5 +48,16 @@ pid_t libxl_fork(struct libxl_ctx *ctx); int libxl_pipe(struct libxl_ctx *ctx, int pipes[2]); /* Just like fork(2), pipe(2), but log errors. */ +void libxl_report_child_exitstatus(struct libxl_ctx *ctx, int level, + const char *what, pid_t pid, int status); + /* treats all exit statuses as errors; if that''s not what you want, + * check status yourself first */ + +/* log levels: */ +#define XL_LOG_DEBUG 3 +#define XL_LOG_INFO 2 +#define XL_LOG_WARNING 1 +#define XL_LOG_ERROR 0 + #endif -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 09/16] xl, libxl: xl list -v shows the uuid too
Break uuid to string conversion (including logging) out into a new function libxl_uuid2string for reuse, and expose it for the convenience of callers. Provide a new -v option to xl list which shows the domain''s uuid. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 7 ++----- tools/libxl/libxl.h | 3 +++ tools/libxl/libxl_dom.c | 6 ++++++ tools/libxl/xl.c | 20 ++++++++++++++------ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index f96b3ae..663cbc1 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -93,11 +93,8 @@ int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, xs_transaction_t t; xen_domain_handle_t handle; - uuid_string = string_of_uuid(ctx, info->uuid); - if (!uuid_string) { - XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate uuid string"); - return ERROR_FAIL; - } + uuid_string = libxl_uuid2string(ctx, info->uuid); + if (!uuid_string) return ERROR_NOMEM; flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0; flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0; diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 02bdd21..2ef8640 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -264,6 +264,9 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid); int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req); int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force); +char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]); + /* 0 means ERROR_ENOMEM, which we have logged */ + /* events handling */ typedef enum { diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index c213792..57b800a 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -350,3 +350,9 @@ int save_device_model(struct libxl_ctx *ctx, uint32_t domid, int fd) unlink(filename); return 0; } + +char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]) { + char *s = string_of_uuid(ctx, uuid); + if (!s) XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate for uuid"); + return s; +} diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index d99e637..41dada7 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -891,7 +891,7 @@ static void help(char *command) printf("-d Enable debug messages.\n"); printf("-e Do not wait in the background for the death of the domain.\n"); } else if(!strcmp(command, "list")) { - printf("Usage: xl list [Domain]\n\n"); + printf("Usage: xl list [-v] [Domain]\n\n"); printf("List information about all/some domains.\n\n"); } else if(!strcmp(command, "pci-attach")) { printf("Usage: xl pci-attach <Domain> <BDF> [Virtual Slot]\n\n"); @@ -1368,7 +1368,7 @@ void destroy_domain(char *p) libxl_domain_destroy(&ctx, domid, 0); } -void list_domains(void) +void list_domains(int verbose) { struct libxl_ctx ctx; struct libxl_dominfo *info; @@ -1388,7 +1388,7 @@ void list_domains(void) } printf("Name ID Mem VCPUs\tState\tTime(s)\n"); for (i = 0; i < nb_domain; i++) { - printf("%-40s %5d %5lu %5d %c%c%c %8.1f\n", + printf("%-40s %5d %5lu %5d %c%c%c %8.1f", libxl_domid_to_name(&ctx, info[i].domid), info[i].domid, (unsigned long) (info[i].max_memkb / 1024), @@ -1397,6 +1397,11 @@ void list_domains(void) info[i].paused ? ''p'' : ''-'', info[i].dying ? ''d'' : ''-'', ((float)info[i].cpu_time / 1e9)); + if (verbose) { + char *uuid = libxl_uuid2string(&ctx, info[i].uuid); + printf(" %s", uuid); + } + putchar(''\n''); } free(info); } @@ -1614,20 +1619,23 @@ int main_destroy(int argc, char **argv) int main_list(int argc, char **argv) { - int opt; + int opt, verbose = 0; - while ((opt = getopt(argc, argv, "h")) != -1) { + while ((opt = getopt(argc, argv, "hv")) != -1) { switch (opt) { case ''h'': help("list"); exit(0); + case ''v'': + verbose = 1; + break; default: fprintf(stderr, "option not supported\n"); break; } } - list_domains(); + list_domains(verbose); exit(0); } -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 10/16] libxl: New function libxl_domain_info
libxl_domain_info provides a way to get the struct libxl_dominfo for a single domain given its domid. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 50 +++++++++++++++++++++++++++++++++++--------------- tools/libxl/libxl.h | 4 +++- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 663cbc1..d3d73be 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -373,6 +373,24 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid) return 0; } +static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo, + struct libxl_dominfo *xlinfo) { + memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t)); + xlinfo->domid = xcinfo->domain; + + if (xcinfo->flags & XEN_DOMINF_dying) + xlinfo->dying = 1; + else if (xcinfo->flags & XEN_DOMINF_paused) + xlinfo->paused = 1; + else if (xcinfo->flags & XEN_DOMINF_blocked || + xcinfo->flags & XEN_DOMINF_running) + xlinfo->running = 1; + xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages); + xlinfo->cpu_time = xcinfo->cpu_time; + xlinfo->vcpu_max_id = xcinfo->max_vcpu_id; + xlinfo->vcpu_online = xcinfo->nr_online_vcpus; +} + struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain) { struct libxl_dominfo *ptr; @@ -381,29 +399,31 @@ struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain) int size = 1024; ptr = calloc(size, sizeof(struct libxl_dominfo)); - if (!ptr) - return NULL; + if (!ptr) return NULL; ret = xc_domain_getinfolist(ctx->xch, 0, 1024, info); + if (ret<0) return NULL; + for (i = 0; i < ret; i++) { - memcpy(&(ptr[i].uuid), info[i].handle, sizeof(xen_domain_handle_t)); - ptr[i].domid = info[i].domain; - - if (info[i].flags & XEN_DOMINF_dying) - ptr[i].dying = 1; - else if (info[i].flags & XEN_DOMINF_paused) - ptr[i].paused = 1; - else if (info[i].flags & XEN_DOMINF_blocked || info[i].flags & XEN_DOMINF_running) - ptr[i].running = 1; - ptr[i].max_memkb = PAGE_TO_MEMKB(info[i].tot_pages); - ptr[i].cpu_time = info[i].cpu_time; - ptr[i].vcpu_max_id = info[i].max_vcpu_id; - ptr[i].vcpu_online = info[i].nr_online_vcpus; + xcinfo2xlinfo(&info[i], &ptr[i]); } *nb_domain = ret; return ptr; } +int libxl_domain_info(struct libxl_ctx *ctx, struct libxl_dominfo *info_r, + uint32_t domid) { + xc_domaininfo_t xcinfo; + int ret; + + ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo); + if (ret<0) return ERROR_FAIL; + if (ret==0 || xcinfo.domain != domid) return ERROR_INVAL; + + xcinfo2xlinfo(&xcinfo, info_r); + return 0; +} + /* this API call only list VM running on this host. a VM can be an aggregate of multiple domains. */ struct libxl_vminfo * libxl_list_vm(struct libxl_ctx *ctx, int *nb_vm) { diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 2ef8640..43db1f6 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -315,7 +315,9 @@ int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t targ int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num); -struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain); +int libxl_domain_info(struct libxl_ctx*, struct libxl_dominfo *info_r, + uint32_t domid); +struct libxl_dominfo * libxl_list_domain(struct libxl_ctx*, int *nb_domain); struct libxl_vminfo * libxl_list_vm(struct libxl_ctx *ctx, int *nb_vm); typedef struct libxl_device_model_starting libxl_device_model_starting; -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 11/16] libxl: Per-domain data storage for the convenience of the library user
We provide a mechanism whereby a user of the libxl library is able to store some information alongside the domain. The information stored is a block of bytes. Its lifetime is that of the domain - ie the userdata is garbage collected alongside the domain if the domain is destroyed. (This is why the feature needs to be in libxl and cannot be implemented in the user itself or in libxlutil.) If a libxl caller does not need to use this feature it can ignore it. The data is tagged with the (self-declared) name of the libxl user, so that different users cannot accidentally trip over each others'' userdata. The data is not interpreted at all by libxl. To assist developers and people debugging, there is a registry of the known userdata userids, and the corresponding data format as declared by that libxl user, in libxl.h next to these declarations: int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid, const char *userdata_userid, const uint8_t *data, int datalen); int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid, const char *userdata_userid, uint8_t **data_r, int *datalen_r); The next patch will introduce the data for the userid "xl". Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.c | 2 + tools/libxl/libxl.h | 31 ++++++++++ tools/libxl/libxl_dom.c | 127 ++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_internal.h | 1 + 4 files changed, 161 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index d3d73be..f1fe35d 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -725,6 +725,8 @@ int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force) if (!xs_rm(ctx->xsh, XBT_NULL, xapi_path)) XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", xapi_path); + libxl__userdata_destroyall(ctx, domid); + rc = xc_domain_destroy(ctx->xch, domid); if (rc < 0) { XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_destroy failed for %d", domid); diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 43db1f6..cc09cb0 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -366,6 +366,37 @@ int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain, unsigned int bus, unsigned int dev, unsigned int func, unsigned int vdevfn); +/* + * Functions for allowing users of libxl to store private data + * relating to a domain. The data is an opaque sequence of bytes and + * is not interpreted or used by libxl. + * + * Data is indexed by the userdata userid, which is a short printable + * ASCII string. The following list is a registry of userdata userids + * (the registry may be updated by posting a patch to xen-devel): + * + * userid Data contents + * "xl" domain config file in xl format, Unix line endings + * + * libxl does not enforce the registration of userdata userids or the + * semantics of the data. For specifications of the data formats + * see the code or documentation for the libxl caller in question. + */ +int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + const uint8_t *data, int datalen); + /* If datalen==0, data is not used and the user data for + * that domain and userdata_userid is deleted. */ +int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + uint8_t **data_r, int *datalen_r); + /* On successful return, *data_r is from malloc. + * If there is no data for that domain and userdata_userid, + * *data_r and *datalen_r will be set to 0. + * data_r and datalen_r may be 0. + * On error return, *data_r and *datalen_r are undefined. + */ + typedef enum { POWER_BUTTON, SLEEP_BUTTON diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 57b800a..1ea9964 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -16,6 +16,8 @@ #include "libxl_osdeps.h" #include <stdio.h> +#include <assert.h> +#include <glob.h> #include <inttypes.h> #include <string.h> #include <sys/time.h> /* for struct timeval */ @@ -356,3 +358,128 @@ char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]) { if (!s) XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate for uuid"); return s; } + +static const char *userdata_path(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + const char *wh) { + char *path, *uuid_string; + struct libxl_dominfo info; + int rc; + + rc = libxl_domain_info(ctx, &info, domid); + if (rc) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to find domain info" + " for domain %l"PRIu32, domid); + return 0; + } + uuid_string = string_of_uuid(ctx, info.uuid); + + path = libxl_sprintf(ctx, "/var/lib/xen/" + "userdata-%s.%s.%s", + wh, uuid_string, userdata_userid); + if (!path) + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to allocate for" + " userdata path"); + return path; +} + +static int userdata_delete(struct libxl_ctx *ctx, const char *path) { + int r; + r = unlink(path); + if (r) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "remove failed for %s", path); + return errno; + } + return 0; +} + +void libxl__userdata_destroyall(struct libxl_ctx *ctx, uint32_t domid) { + const char *pattern; + glob_t gl; + int r, i; + + pattern = userdata_path(ctx, domid, "*", "?"); + if (!pattern) return; + + gl.gl_pathc = 0; + gl.gl_pathv = 0; + gl.gl_offs = 0; + r = glob(pattern, GLOB_ERR|GLOB_NOSORT|GLOB_MARK, 0, &gl); + if (r == GLOB_NOMATCH) return; + if (r) XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "glob failed for %s", pattern); + + for (i=0; i<gl.gl_pathc; i++) { + userdata_delete(ctx, gl.gl_pathv[i]); + } + globfree(&gl); +} + +int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + const uint8_t *data, int datalen) { + const char *filename; + const char *newfilename; + int e; + int fd = -1; + FILE *f = 0; + size_t rs; + + filename = userdata_path(ctx, domid, userdata_userid, "d"); + if (!filename) return ENOMEM; + + if (!datalen) + return userdata_delete(ctx, filename); + + newfilename = userdata_path(ctx, domid, userdata_userid, "n"); + if (!newfilename) return ENOMEM; + + fd= open(newfilename, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd<0) goto xe; + + f= fdopen(fd, "wb"); + if (!f) goto xe; + fd = -1; + + rs = fwrite(data, 1, datalen, f); + if (rs != datalen) { assert(ferror(f)); goto xe; } + + if (fclose(f)) goto xe; + f = 0; + + if (rename(newfilename,filename)) goto xe; + + return 0; + + xe: + e = errno; + if (f) fclose(f); + if (fd>=0) close(fd); + + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot write %s for %s", + newfilename, filename); + return e; +} + +int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + uint8_t **data_r, int *datalen_r) { + const char *filename; + int e; + int datalen = 0; + void *data = 0; + + filename = userdata_path(ctx, domid, userdata_userid, "d"); + if (!filename) return ENOMEM; + + e = libxl_read_file_contents(ctx, filename, data_r ? &data : 0, &datalen); + + if (!e && !datalen) { + XL_LOG(ctx, XL_LOG_ERROR, "userdata file %s is empty", filename); + if (data_r) assert(!*data_r); + return EPROTO; + } + + if (data_r) *data_r = data; + if (datalen_r) *datalen_r = datalen; + return 0; +} diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index de9a756..0dc48f1 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -130,6 +130,7 @@ int restore_common(struct libxl_ctx *ctx, uint32_t domid, libxl_domain_build_info *info, libxl_domain_build_state *state, int fd); int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int live, int debug); int save_device_model(struct libxl_ctx *ctx, uint32_t domid, int fd); +void libxl__userdata_destroyall(struct libxl_ctx *ctx, uint32_t domid); /* from xl_device */ char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype); -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 12/16] xl: Remove some duplicated boilerplate. (Improves logging slightly.)
We remove six lines of boilerplate from the top of each function, and instead have a single struct libxl_ctx which is initialised once at the top of main. Likewise we wrap domain_qualifier_to_domid in a new function find_domain, which does the error handling, and stores the domid and the specified name (if applicable). This reduces the size of xl.c by 7% (!) As a beneficial side effect, the earlier call to libxl_ctx_set_log in main makes some lost messages appear. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_utils.c | 3 +- tools/libxl/libxl_utils.h | 2 +- tools/libxl/xl.c | 255 ++++++++++----------------------------------- 3 files changed, 60 insertions(+), 200 deletions(-) diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c index c4dc74c..8fc7d0d 100644 --- a/tools/libxl/libxl_utils.c +++ b/tools/libxl/libxl_utils.c @@ -55,7 +55,8 @@ char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid) return s; } -int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid) +int libxl_name_to_domid(struct libxl_ctx *ctx, const char *name, + uint32_t *domid) { int i, nb_domains; char *domname; diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h index 4c04c46..5d80181 100644 --- a/tools/libxl/libxl_utils.h +++ b/tools/libxl/libxl_utils.h @@ -19,7 +19,7 @@ #include "libxl.h" unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus); -int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid); +int libxl_name_to_domid(struct libxl_ctx *ctx, const char *name, uint32_t *domid); char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid); int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid); int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid); diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index 41dada7..fcb4fc4 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -37,7 +37,14 @@ #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" -int logfile = 2; +static int logfile = 2; + +/* every libxl action in xl uses this same libxl context */ +static struct libxl_ctx ctx; + +/* when we operate on a domain, it is this one: */ +static uint32_t domid; +static const char *common_domname; void log_callback(void *userdata, int loglevel, const char *file, int line, const char *func, char *s) { @@ -47,7 +54,8 @@ void log_callback(void *userdata, int loglevel, const char *file, int line, cons write(logfile, str, strlen(str)); } -static int domain_qualifier_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *domid) +static int domain_qualifier_to_domid(const char *p, uint32_t *domid_r, + int *was_name_r) { int i, alldigit; @@ -60,12 +68,26 @@ static int domain_qualifier_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *d } if (i > 0 && alldigit) { - *domid = strtoul(p, NULL, 10); + *domid_r = strtoul(p, NULL, 10); + if (was_name_r) *was_name_r = 0; return 0; } else { /* check here if it''s a uuid and do proper conversion */ } - return libxl_name_to_domid(ctx, p, domid); + if (was_name_r) *was_name_r = 1; + return libxl_name_to_domid(&ctx, p, domid_r); +} + +static void find_domain(const char *p) +{ + int rc, was_name; + + rc = domain_qualifier_to_domid(p, &domid, &was_name); + if (rc) { + fprintf(stderr, "%s is an invalid domain identifier (rc=%d)\n", p, rc); + exit(2); + } + common_domname = was_name ? p : 0; } #define LOG(_f, _a...) dolog(__FILE__, __LINE__, __func__, _f "\n", ##_a) @@ -681,8 +703,6 @@ skip_pci: static void create_domain(int debug, int daemonize, const char *config_file, const char *restore_file, int paused) { - struct libxl_ctx ctx; - uint32_t domid; libxl_domain_create_info info1; libxl_domain_build_info info2; libxl_domain_build_state state; @@ -709,13 +729,6 @@ static void create_domain(int debug, int daemonize, const char *config_file, con start: domid = 0; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - - libxl_ctx_set_log(&ctx, log_callback, NULL); - ret = libxl_domain_make(&ctx, &info1, &domid); if (ret) { fprintf(stderr, "cannot make domain: %d\n", ret); @@ -834,7 +847,6 @@ start: libxl_free_waiter(w2); free(w1); free(w2); - libxl_ctx_free(&ctx); LOG("Done. Rebooting now"); goto start; } @@ -954,21 +966,11 @@ static void help(char *command) void set_memory_target(char *p, char *mem) { - struct libxl_ctx ctx; - uint32_t domid; - uint32_t memorykb; char *endptr; + uint32_t memorykb; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(p); - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } memorykb = strtoul(mem, &endptr, 10); if (*endptr != ''\0'') { fprintf(stderr, "invalid memory size: %s\n", mem); @@ -1007,39 +1009,16 @@ int main_memset(int argc, char **argv) void console(char *p, int cons_num) { - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); libxl_console_attach(&ctx, domid, cons_num); } void cd_insert(char *dom, char *virtdev, char *phys) { - struct libxl_ctx ctx; - uint32_t domid; libxl_device_disk disk; char *p; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", dom); - exit(2); - } + find_domain(dom); disk.backend_domid = 0; disk.domid = domid; @@ -1161,21 +1140,11 @@ int main_console(int argc, char **argv) void pcilist(char *dom) { - struct libxl_ctx ctx; - uint32_t domid; libxl_device_pci *pcidevs; int num, i; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(dom); - if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", dom); - exit(2); - } pcidevs = libxl_device_pci_list(&ctx, domid, &num); if (!num) return; @@ -1214,21 +1183,11 @@ int main_pcilist(int argc, char **argv) void pcidetach(char *dom, char *bdf) { - struct libxl_ctx ctx; - uint32_t domid; libxl_device_pci pcidev; unsigned int domain, bus, dev, func; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(dom); - if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", dom); - exit(2); - } memset(&pcidev, 0x00, sizeof(pcidev)); sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func); libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0); @@ -1263,21 +1222,11 @@ int main_pcidetach(int argc, char **argv) } void pciattach(char *dom, char *bdf, char *vs) { - struct libxl_ctx ctx; - uint32_t domid; libxl_device_pci pcidev; unsigned int domain, bus, dev, func; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(dom); - if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", dom); - exit(2); - } memset(&pcidev, 0x00, sizeof(pcidev)); sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func); libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0); @@ -1316,70 +1265,27 @@ int main_pciattach(int argc, char **argv) void pause_domain(char *p) { - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); libxl_domain_pause(&ctx, domid); } void unpause_domain(char *p) { - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); libxl_domain_unpause(&ctx, domid); } void destroy_domain(char *p) { - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); libxl_domain_destroy(&ctx, domid, 0); } void list_domains(int verbose) { - struct libxl_ctx ctx; struct libxl_dominfo *info; int nb_domain, i; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - info = libxl_list_domain(&ctx, &nb_domain); if (info < 0) { @@ -1408,16 +1314,9 @@ void list_domains(int verbose) void list_vm(void) { - struct libxl_ctx ctx; struct libxl_vminfo *info; int nb_vm, i; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - info = libxl_list_vm(&ctx, &nb_vm); if (info < 0) { @@ -1438,20 +1337,9 @@ void list_vm(void) int save_domain(char *p, char *filename, int checkpoint) { - struct libxl_ctx ctx; - uint32_t domid; int fd; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - exit(2); - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd < 0) { fprintf(stderr, "Failed to open temp file %s for writing\n", filename); @@ -1693,17 +1581,9 @@ int main_create(int argc, char **argv) void button_press(char *p, char *b) { - struct libxl_ctx ctx; - uint32_t domid; libxl_button button; - libxl_ctx_init(&ctx, LIBXL_VERSION); - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } + find_domain(p); if (!strcmp(b, "power")) { button = POWER_BUTTON; @@ -1745,7 +1625,7 @@ int main_button_press(int argc, char **argv) exit(0); } -static void print_vcpuinfo(struct libxl_ctx *ctx, uint32_t domid, +static void print_vcpuinfo(uint32_t tdomid, const struct libxl_vcpuinfo *vcpuinfo, uint32_t nr_cpus) { @@ -1755,7 +1635,7 @@ static void print_vcpuinfo(struct libxl_ctx *ctx, uint32_t domid, /* NAME ID VCPU */ printf("%-32s %5u %5u", - libxl_domid_to_name(ctx, domid), domid, vcpuinfo->vcpuid); + libxl_domid_to_name(&ctx, tdomid), tdomid, vcpuinfo->vcpuid); if (!vcpuinfo->online) { /* CPU STA */ printf("%5c %3c%cp ", ''-'', ''-'', ''-''); @@ -1813,19 +1693,11 @@ static void print_vcpuinfo(struct libxl_ctx *ctx, uint32_t domid, void vcpulist(int argc, char **argv) { - struct libxl_ctx ctx; struct libxl_dominfo *dominfo; - uint32_t domid; struct libxl_vcpuinfo *vcpuinfo; struct libxl_physinfo physinfo; int nb_vcpu, nb_domain, cpusize; - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - if (libxl_get_physinfo(&ctx, &physinfo) != 0) { fprintf(stderr, "libxl_physinfo failed.\n"); goto vcpulist_out; @@ -1843,12 +1715,12 @@ void vcpulist(int argc, char **argv) goto vcpulist_out; } for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) { - print_vcpuinfo(&ctx, dominfo->domid, vcpuinfo, physinfo.nr_cpus); + print_vcpuinfo(dominfo->domid, vcpuinfo, physinfo.nr_cpus); } } } else { for (; argc > 0; ++argv, --argc) { - if (domain_qualifier_to_domid(&ctx, *argv, &domid) < 0) { + if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) { fprintf(stderr, "%s is an invalid domain identifier\n", *argv); } if (!(vcpuinfo = libxl_list_vcpu(&ctx, domid, &nb_vcpu, &cpusize))) { @@ -1856,12 +1728,12 @@ void vcpulist(int argc, char **argv) goto vcpulist_out; } for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) { - print_vcpuinfo(&ctx, domid, vcpuinfo, physinfo.nr_cpus); + print_vcpuinfo(domid, vcpuinfo, physinfo.nr_cpus); } } } vcpulist_out: - libxl_ctx_free(&ctx); + ; } void main_vcpulist(int argc, char **argv) @@ -1885,12 +1757,11 @@ void main_vcpulist(int argc, char **argv) void vcpupin(char *d, const char *vcpu, char *cpu) { - struct libxl_ctx ctx; struct libxl_vcpuinfo *vcpuinfo; struct libxl_physinfo physinfo; uint64_t *cpumap = NULL; - uint32_t domid, vcpuid, cpuida, cpuidb; + uint32_t vcpuid, cpuida, cpuidb; char *endptr, *toka, *tokb; int i, nb_vcpu, cpusize; @@ -1903,16 +1774,8 @@ void vcpupin(char *d, const char *vcpu, char *cpu) vcpuid = -1; } - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(d); - if (domain_qualifier_to_domid(&ctx, d, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", d); - goto vcpupin_out1; - } if (libxl_get_physinfo(&ctx, &physinfo) != 0) { fprintf(stderr, "libxl_get_physinfo failed.\n"); goto vcpupin_out1; @@ -1970,7 +1833,7 @@ void vcpupin(char *d, const char *vcpu, char *cpu) vcpupin_out1: free(cpumap); vcpupin_out: - libxl_ctx_free(&ctx); + ; } int main_vcpupin(int argc, char **argv) @@ -1998,9 +1861,7 @@ int main_vcpupin(int argc, char **argv) void vcpuset(char *d, char* nr_vcpus) { - struct libxl_ctx ctx; char *endptr; - uint32_t domid; unsigned int max_vcpus; max_vcpus = strtoul(nr_vcpus, &endptr, 10); @@ -2009,22 +1870,11 @@ void vcpuset(char *d, char* nr_vcpus) return; } - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); + find_domain(d); - if (domain_qualifier_to_domid(&ctx, d, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", d); - goto vcpuset_out; - } if (libxl_set_vcpucount(&ctx, domid, max_vcpus) == ERROR_INVAL) { fprintf(stderr, "Error: Cannot set vcpus greater than max vcpus on running domain or lesser than 1.\n"); } - - vcpuset_out: - libxl_ctx_free(&ctx); } int main_vcpuset(int argc, char **argv) @@ -2057,6 +1907,15 @@ int main(int argc, char **argv) exit(1); } + if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { + fprintf(stderr, "cannot init xl context\n"); + exit(1); + } + if (libxl_ctx_set_log(&ctx, log_callback, NULL)) { + fprintf(stderr, "cannot set xl log callback\n"); + exit(-ERROR_FAIL); + } + srand(time(0)); if (!strcmp(argv[1], "create")) { -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 13/16] libxl, xl: Fix two minor bugs in domain destruction
* If /local/domain/<domid>/device does not exist, this is not necessarily an error. It probably means the domain has been partially destroyed already. * Have xl report errors from libxl_domain_destroy. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl_device.c | 2 +- tools/libxl/xl.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index 9fdd0b4..ca20080 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -301,7 +301,7 @@ int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force) if (!l1) { XL_LOG(&clone, XL_LOG_ERROR, "%s is empty", path); libxl_ctx_free(&clone); - return -1; + return 0; } for (i = 0; i < num1; i++) { if (!strcmp("vfs", l1[i])) diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index fcb4fc4..f1b54e4 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -1277,8 +1277,10 @@ void unpause_domain(char *p) void destroy_domain(char *p) { + int rc; find_domain(p); - libxl_domain_destroy(&ctx, domid, 0); + rc = libxl_domain_destroy(&ctx, domid, 0); + if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n.",rc); exit(-1); } } void list_domains(int verbose) -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 14/16] xl: New savefile format. Save domain config when saving a domain.
We introduce a new format for saved domains. The new format, in contrast to the old: * Has a magic number which can distinguish it from other kinds of file * Is extensible * Can contains the domain configuration file On domain creation we remember the actual config file used (using the toolstack data feature of libxl, just introduced), and by default save it to the save file. However, options are provided for the following: * When saving a domain, supplying an alternative config file to store in the savefile. * When restoring a domain, supplying an alternative config file. If a domain is restored with a different config file, it is the responsibility of the xl user to ensure that the two configs are "compatible". Changing the targets of virtual devices is supported; changing other features of the domain is not recommended. Bad changes may lead to undefined behaviour in the domain, and are in practice likely to cause resume failures or crashes. Old format save files generated by old versions of xl are not supported. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxlu_cfg.c | 37 +++++++ tools/libxl/libxlutil.h | 3 +- tools/libxl/xl.c | 253 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 269 insertions(+), 24 deletions(-) diff --git a/tools/libxl/libxlu_cfg.c b/tools/libxl/libxlu_cfg.c index 632c371..0a5ccef 100644 --- a/tools/libxl/libxlu_cfg.c +++ b/tools/libxl/libxlu_cfg.c @@ -53,6 +53,43 @@ int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) { return ctx.err; } +int xlu_cfg_readdata(XLU_Config *cfg, const char *data, int length) { + CfgParseContext ctx; + int e, r; + YY_BUFFER_STATE buf= 0; + + ctx.scanner= 0; + ctx.cfg= cfg; + ctx.err= 0; + ctx.lexerrlineno= -1; + + e= xlu__cfg_yylex_init_extra(&ctx, &ctx.scanner); + if (e) { + fprintf(cfg->report,"%s: unable to create scanner: %s\n", + cfg->filename, strerror(e)); + ctx.err= e; + ctx.scanner= 0; + goto xe; + } + + buf = xlu__cfg_yy_scan_bytes(data, length, ctx.scanner); + if (!buf) { + fprintf(cfg->report,"%s: unable to allocate scanner buffer\n", + cfg->filename); + ctx.err= ENOMEM; + goto xe; + } + + r= xlu__cfg_yyparse(&ctx); + if (r) assert(ctx.err); + + xe: + if (buf) xlu__cfg_yy_delete_buffer(buf, ctx.scanner); + if (ctx.scanner) xlu__cfg_yylex_destroy(ctx.scanner); + + return ctx.err; +} + void xlu__cfg_set_free(XLU_ConfigSetting *set) { free(set->name); free(set->values); diff --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h index 97b16aa..0262e55 100644 --- a/tools/libxl/libxlutil.h +++ b/tools/libxl/libxlutil.h @@ -30,7 +30,8 @@ XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename); * until the Config is destroyed. */ int xlu_cfg_readfile(XLU_Config*, const char *real_filename); - /* If this fails, then it is undefined behaviour to call xlu_cfg_get_... +int xlu_cfg_readdata(XLU_Config*, const char *data, int length); + /* If these fail, then it is undefined behaviour to call xlu_cfg_get_... * functions. You have to just xlu_cfg_destroy. */ void xlu_cfg_destroy(XLU_Config*); diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index f1b54e4..ff605aa 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -30,6 +30,7 @@ #include <arpa/inet.h> #include <xenctrl.h> #include <ctype.h> +#include <inttypes.h> #include "libxl.h" #include "libxl_utils.h" @@ -46,6 +47,25 @@ static struct libxl_ctx ctx; static uint32_t domid; static const char *common_domname; +static const char savefileheader_magic[32]+ "Xen saved domain, xl format\n \0 \r"; + +struct save_file_header { + char magic[32]; /* savefileheader_magic */ + /* All uint32_ts are in domain''s byte order. */ + uint32_t byteorder; /* SAVEFILE_BYTEORDER_VALUE */ + uint32_t mandatory_flags; /* unknown flags => reject restore */ + uint32_t optional_flags; /* unknown flags => reject restore */ + uint32_t optional_data_len; /* skip, or skip tail, if not understood */ +}; + +/* Optional data, in order: + * 4 bytes uint32_t config file size + * n bytes config file in Unix text file format + */ + +#define SAVEFILE_BYTEORDER_VALUE ((uint32_t)0x01020304UL) + void log_callback(void *userdata, int loglevel, const char *file, int line, const char *func, char *s) { char str[1024]; @@ -343,7 +363,9 @@ static void printf_info(libxl_domain_create_info *c_info, } } -static void parse_config_file(const char *filename, +static void parse_config_data(const char *configfile_filename_report, + const char *configfile_data, + int configfile_len, libxl_domain_create_info *c_info, libxl_domain_build_info *b_info, libxl_device_disk **disks, @@ -366,13 +388,13 @@ static void parse_config_file(const char *filename, int pci_msitranslate = 1; int i, e; - config= xlu_cfg_init(stderr, filename); + config= xlu_cfg_init(stderr, configfile_filename_report); if (!config) { fprintf(stderr, "Failed to allocate for configuration\n"); exit(1); } - e= xlu_cfg_readfile (config, filename); + e= xlu_cfg_readdata(config, configfile_data, configfile_len); if (e) { fprintf(stderr, "Failed to parse config file: %s\n", strerror(e)); exit(1); @@ -692,6 +714,15 @@ skip_pci: xlu_cfg_destroy(config); } +#define CHK_ERRNO( call ) ({ \ + int chk_errno = (call); \ + if (chk_errno) { \ + fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n", \ + __FILE__,__LINE__, strerror(chk_errno), #call); \ + exit(-ERROR_FAIL); \ + } \ + }) + #define MUST( call ) ({ \ int must_rc = (call); \ if (must_rc) { \ @@ -701,6 +732,26 @@ skip_pci: } \ }) +static void *xmalloc(size_t sz) { + void *r; + r = malloc(sz); + if (!r) { fprintf(stderr,"xl: Unable to malloc %lu bytes.\n", + (unsigned long)sz); exit(-ERROR_FAIL); } + return r; +} + +static void *xrealloc(void *ptr, size_t sz) { + void *r; + if (!sz) { free(ptr); return 0; } + /* realloc(non-0, 0) has a useless return value; + * but xrealloc(anything, 0) is like free + */ + r = realloc(ptr, sz); + if (!r) { fprintf(stderr,"xl: Unable to realloc to %lu bytes.\n", + (unsigned long)sz); exit(-ERROR_FAIL); } + return r; +} + static void create_domain(int debug, int daemonize, const char *config_file, const char *restore_file, int paused) { libxl_domain_create_info info1; @@ -719,10 +770,100 @@ static void create_domain(int debug, int daemonize, const char *config_file, con int ret; libxl_device_model_starting *dm_starting = 0; libxl_waiter *w1 = NULL, *w2 = NULL; + void *config_data = 0; + int config_len = 0; + int restore_fd = -1; + struct save_file_header hdr; + memset(&dm_info, 0x00, sizeof(dm_info)); + if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { + fprintf(stderr, "cannot init xl context\n"); + exit(1); + } + + if (restore_file) { + uint8_t *optdata_begin = 0; + const uint8_t *optdata_here = 0; + union { uint32_t u32; char b[4]; } u32buf; + uint32_t badflags; + + restore_fd = open(restore_file, O_RDONLY); + + CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, &hdr, + sizeof(hdr), restore_file, "header") ); + if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) { + fprintf(stderr, "File has wrong magic number -" + " corrupt or for a different tool?\n"); + exit(2); + } + if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) { + fprintf(stderr, "File has wrong byte order\n"); + exit(2); + } + fprintf(stderr, "Loading new save file %s" + " (new xl fmt info" + " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", + restore_file, hdr.mandatory_flags, hdr.optional_flags, + hdr.optional_data_len); + + badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ ); + if (badflags) { + fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" " + "which are not supported; need newer xl\n", + badflags); + exit(2); + } + if (hdr.optional_data_len) { + optdata_begin = xmalloc(hdr.optional_data_len); + CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, optdata_begin, + hdr.optional_data_len, restore_file, "optdata") ); + } + +#define OPTDATA_LEFT (hdr.optional_data_len - (optdata_here - optdata_begin)) +#define WITH_OPTDATA(amt, body) \ + if (OPTDATA_LEFT < (amt)) { \ + fprintf(stderr, "Savefile truncated.\n"); exit(2); \ + } else { \ + body; \ + optdata_here += (amt); \ + } + + optdata_here = optdata_begin; + + if (OPTDATA_LEFT) { + fprintf(stderr, " Savefile contains xl domain config\n"); + WITH_OPTDATA(4, { + memcpy(u32buf.b, optdata_here, 4); + config_len = u32buf.u32; + }); + WITH_OPTDATA(config_len, { + config_data = xmalloc(config_len); + memcpy(config_data, optdata_here, config_len); + }); + } + + } + + if (config_file) { + free(config_data); config_data = 0; + ret = libxl_read_file_contents(&ctx, config_file, + &config_data, &config_len); + if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n", + config_file, strerror(errno)); exit(1); } + } else { + if (!config_data) { + fprintf(stderr, "Config file not specified and" + " none in save file\n"); + exit(1); + } + config_file = "<saved>"; + } + printf("Parsing config file %s\n", config_file); - parse_config_file(config_file, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, &dm_info); + + parse_config_data(config_file, config_data, config_len, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, &dm_info); + if (debug) printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info); @@ -732,7 +873,14 @@ start: ret = libxl_domain_make(&ctx, &info1, &domid); if (ret) { fprintf(stderr, "cannot make domain: %d\n", ret); - return; + exit(1); + } + + ret = libxl_userdata_store(&ctx, domid, "xl", + config_data, config_len); + if (ret) { + perror("cannot save config file"); + exit(1); } if (!restore_file || !need_daemon) { @@ -742,16 +890,13 @@ start: } ret = libxl_domain_build(&ctx, &info2, domid, &state); } else { - int restore_fd; - - restore_fd = open(restore_file, O_RDONLY); ret = libxl_domain_restore(&ctx, &info2, domid, restore_fd, &state, &dm_info); close(restore_fd); } if (ret) { fprintf(stderr, "cannot (re-)build domain: %d\n", ret); - return; + exit(1); } for (i = 0; i < num_disks; i++) { @@ -759,7 +904,7 @@ start: ret = libxl_device_disk_add(&ctx, domid, &disks[i]); if (ret) { fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret); - return; + exit(1); } } for (i = 0; i < num_vifs; i++) { @@ -767,7 +912,7 @@ start: ret = libxl_device_nic_add(&ctx, domid, &vifs[i]); if (ret) { fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret); - return; + exit(1); } } if (info1.hvm) { @@ -814,8 +959,8 @@ start: need_daemon = 0; } LOG("Waiting for domain %s (domid %d) to die", info1.name, domid); - w1 = (libxl_waiter*) malloc(sizeof(libxl_waiter) * num_disks); - w2 = (libxl_waiter*) malloc(sizeof(libxl_waiter)); + w1 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter) * num_disks); + w2 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter)); libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1); libxl_wait_for_domain_death(&ctx, domid, w2); libxl_get_wait_fd(&ctx, &fd); @@ -870,6 +1015,7 @@ start: free(vfbs); free(vkbs); free(pcidevs); + free(config_data); } static void help(char *command) @@ -921,13 +1067,13 @@ static void help(char *command) printf("Usage: xl unpause <Domain>\n\n"); printf("Unpause a paused domain.\n\n"); } else if(!strcmp(command, "save")) { - printf("Usage: xl save [options] <Domain> <CheckpointFile>\n\n"); + printf("Usage: xl save [options] <Domain> <CheckpointFile> [<ConfigFile>]\n\n"); printf("Save a domain state to restore later.\n\n"); printf("Options:\n\n"); printf("-h Print this help.\n"); printf("-c Leave domain running after creating the snapshot.\n"); } else if(!strcmp(command, "restore")) { - printf("Usage: xl restore [options] <ConfigFile> <CheckpointFile>\n\n"); + printf("Usage: xl restore [options] [<ConfigFile>] <CheckpointFile>\n\n"); printf("Restore a domain from a saved state.\n\n"); printf("Options:\n\n"); printf("-h Print this help.\n"); @@ -1337,9 +1483,15 @@ void list_vm(void) free(info); } -int save_domain(char *p, char *filename, int checkpoint) +int save_domain(char *p, char *filename, int checkpoint, + const char *override_config_file) { - int fd; + int fd, rc; + struct save_file_header hdr; + uint8_t *config_data = 0; + int config_len; + uint8_t *optdata_begin; + union { uint32_t u32; char b[4]; } u32buf; find_domain(p); fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); @@ -1347,6 +1499,57 @@ int save_domain(char *p, char *filename, int checkpoint) fprintf(stderr, "Failed to open temp file %s for writing\n", filename); exit(2); } + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic)); + hdr.byteorder = SAVEFILE_BYTEORDER_VALUE; + + optdata_begin= 0; + +#define ADD_OPTDATA(ptr, len) ({ \ + if ((len)) { \ + hdr.optional_data_len += (len); \ + optdata_begin = xrealloc(optdata_begin, hdr.optional_data_len); \ + memcpy(optdata_begin + hdr.optional_data_len - (len), \ + (ptr), (len)); \ + } \ + }) + + /* configuration file in optional data: */ + + if (override_config_file) { + void *config_v = 0; + rc = libxl_read_file_contents(&ctx, override_config_file, + &config_v, &config_len); + config_data = config_v; + } else { + rc = libxl_userdata_retrieve(&ctx, domid, "xl", + &config_data, &config_len); + } + if (rc) { + fputs("Unable to get config file\n",stderr); + exit(2); + } + if (!config_len) { + fputs(" Savefile will not contain xl domain config\n", stderr); + } + + u32buf.u32 = config_len; + ADD_OPTDATA(u32buf.b, 4); + ADD_OPTDATA(config_data, config_len); + + /* that''s the optional data */ + + CHK_ERRNO( libxl_write_exactly(&ctx, fd, + &hdr, sizeof(hdr), filename, "header") ); + CHK_ERRNO( libxl_write_exactly(&ctx, fd, + optdata_begin, hdr.optional_data_len, filename, "header") ); + + fprintf(stderr, "Saving to %s new xl format (info" + " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", + filename, hdr.mandatory_flags, hdr.optional_flags, + hdr.optional_data_len); + libxl_domain_suspend(&ctx, NULL, domid, fd); close(fd); @@ -1385,13 +1588,15 @@ int main_restore(int argc, char **argv) } } - if (optind >= argc - 1) { + if (argc-optind == 1) { + checkpoint_file = argv[optind]; + } else if (argc-optind == 2) { + config_file = argv[optind]; + checkpoint_file = argv[optind + 1]; + } else { help("restore"); exit(2); } - - config_file = argv[optind]; - checkpoint_file = argv[optind + 1]; create_domain(debug, daemonize, config_file, checkpoint_file, paused); exit(0); } @@ -1399,6 +1604,7 @@ int main_restore(int argc, char **argv) int main_save(int argc, char **argv) { char *filename = NULL, *p = NULL; + const char *config_filename; int checkpoint = 0; int opt; @@ -1416,14 +1622,15 @@ int main_save(int argc, char **argv) } } - if (optind >= argc - 1) { + if (argc-optind < 1 || argc-optind > 3) { help("save"); exit(2); } p = argv[optind]; filename = argv[optind + 1]; - save_domain(p, filename, checkpoint); + config_filename = argv[optind + 2]; + save_domain(p, filename, checkpoint, config_filename); exit(0); } -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Apr-12 14:41 UTC
[Xen-devel] [PATCH 15/16] xl: Domain creation logging fixes
* Make create_domain always return to caller * Have create_domain set its log callback sooner * Actually write things to logfile, and some error checking With some combinations of options, create_domain would never return to the caller, since it would have called daemon and will later exit. So we fork an additional time, so that we can call daemon in the child and also return to the caller in the parent. It''s a shame that there''s no version of daemon(3) that allows us to do this without the extra code and pointless extra fork. daemon(0,0) closes all the fds. So we need to call daemon(0,1) and organise detaching our stdin/out/err ourselves. Doing this makes messages actually appear in the xl logfile in /var/log/xen. Finally, make create_domain call libxl_ctx_set_log sooner. This makes some lost messages appear. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/xl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 45 insertions(+), 5 deletions(-) diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index ff605aa..82cd25e 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -767,7 +767,7 @@ static void create_domain(int debug, int daemonize, const char *config_file, con int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 0; int i, fd; int need_daemon = 1; - int ret; + int ret, rc; libxl_device_model_starting *dm_starting = 0; libxl_waiter *w1 = NULL, *w2 = NULL; void *config_data = 0; @@ -781,6 +781,7 @@ static void create_domain(int debug, int daemonize, const char *config_file, con fprintf(stderr, "cannot init xl context\n"); exit(1); } + libxl_ctx_set_log(&ctx, log_callback, NULL); if (restore_file) { uint8_t *optdata_begin = 0; @@ -948,17 +949,56 @@ start: if (need_daemon) { char *fullname, *name; + pid_t child1, got_child; + int nullfd; + + child1 = libxl_fork(&ctx); + if (child1) { + int status; + for (;;) { + got_child = waitpid(child1, &status, 0); + if (got_child == child1) break; + assert(got_child == -1); + if (errno != EINTR) { + perror("failed to wait for daemonizing child"); + return ERROR_FAIL; + } + } + if (status) { + libxl_report_child_exitstatus(&ctx, XL_LOG_ERROR, + "daemonizing child", child1, status); + return ERROR_FAIL; + } + return 0; /* caller gets success in parent */ + } + + rc = libxl_ctx_postfork(&ctx); + if (rc) { + LOG("failed to reinitialise context after fork"); + exit(-1); + } asprintf(&name, "xl-%s", info1.name); - libxl_create_logfile(&ctx, name, &fullname); - logfile = open(fullname, O_WRONLY|O_CREAT, 0644); + rc = libxl_create_logfile(&ctx, name, &fullname); + if (rc) { + LOG("failed to open logfile %s",fullname,strerror(errno)); + exit(-1); + } + + CHK_ERRNO(( logfile = open(fullname, O_WRONLY|O_CREAT, 0644) )<0); free(fullname); free(name); - daemon(0, 0); + CHK_ERRNO(( nullfd = open("/dev/null", O_RDONLY) )<0); + dup2(nullfd, 0); + dup2(logfile, 1); + dup2(logfile, 2); + + daemon(0, 1); need_daemon = 0; } - LOG("Waiting for domain %s (domid %d) to die", info1.name, domid); + LOG("Waiting for domain %s (domid %d) to die [pid %ld]", + info1.name, domid, (long)getpid()); w1 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter) * num_disks); w2 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter)); libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1); -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Implement "xl migrate". ssh is used as the transport by default, although this can be overridden by specifying a different sshcommand. This is a very standard approach nowadays and avoids the need for daemons at the target host in the default configuration, while providing flexibility to admins. (In the future it might be nice to support plain unencrypted migration over TCP, which we do not rule out now, although it is not currently implemented.) Properties of the migration protocol: * The domain on the target machine is named "<domname>--incoming" while it is being transferred. * The domain on the source machine is renamed "<domain>--migratedaway" before we give the target permission to rename and unpause. * The locking in libxl_domain_rename ensures that of two simultaneous migration attempts no more than one will succeed. * We go to some considerable effort to avoid leaving the domain in a bad state if something goes wrong with one of the ends or the network, although there is still (inevitably) a possibility of a unresolvable state (in case of very badly timed network failure) which is probably best resolved by destroying the domain at both ends. Incidental changes: create_domain now returns a libxl error code rather than exiting on error. New ERROR_BADFAIL error code for reporting unpleasant failures. Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> --- tools/libxl/libxl.h | 1 + tools/libxl/xl.c | 628 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 560 insertions(+), 69 deletions(-) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index cc09cb0..1279345 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -242,6 +242,7 @@ enum { ERROR_NI = -3, ERROR_NOMEM = -4, ERROR_INVAL = -5, + ERROR_BADFAIL = -6, }; #define LIBXL_VERSION 0 diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c index 82cd25e..c32b9d9 100644 --- a/tools/libxl/xl.c +++ b/tools/libxl/xl.c @@ -17,6 +17,7 @@ #include "libxl_osdeps.h" #include <stdio.h> +#include <assert.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -47,9 +48,26 @@ static struct libxl_ctx ctx; static uint32_t domid; static const char *common_domname; + static const char savefileheader_magic[32] "Xen saved domain, xl format\n \0 \r"; +static const char migrate_receiver_banner[]+ "xl migration receiver ready, send binary domain data.\n"; +static const char migrate_receiver_ready[]+ "domain received, ready to unpause"; +static const char migrate_permission_to_go[]+ "domain is yours, you are cleared to unpause"; +static const char migrate_report[]+ "my copy unpause results are as follows"; + /* followed by one byte: + * 0: everything went well, domain is running + * next thing is we all exit + * non-0: things went badly + * next thing should be a migrate_permission_to_go + * from target to source + */ + struct save_file_header { char magic[32]; /* savefileheader_magic */ /* All uint32_ts are in domain''s byte order. */ @@ -752,7 +770,7 @@ static void *xrealloc(void *ptr, size_t sz) { return r; } -static void create_domain(int debug, int daemonize, const char *config_file, const char *restore_file, int paused) +static int create_domain(int debug, int daemonize, const char *config_file, const char *restore_file, int paused, int migrate_fd /* -1 means none */, char **migration_domname_r) { libxl_domain_create_info info1; libxl_domain_build_info info2; @@ -777,30 +795,25 @@ static void create_domain(int debug, int daemonize, const char *config_file, con memset(&dm_info, 0x00, sizeof(dm_info)); - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - exit(1); - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - if (restore_file) { uint8_t *optdata_begin = 0; const uint8_t *optdata_here = 0; union { uint32_t u32; char b[4]; } u32buf; uint32_t badflags; - - restore_fd = open(restore_file, O_RDONLY); + + restore_fd = migrate_fd >= 0 ? migrate_fd : + open(restore_file, O_RDONLY); CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, &hdr, sizeof(hdr), restore_file, "header") ); if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) { fprintf(stderr, "File has wrong magic number -" " corrupt or for a different tool?\n"); - exit(2); + return ERROR_INVAL; } if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) { fprintf(stderr, "File has wrong byte order\n"); - exit(2); + return ERROR_INVAL; } fprintf(stderr, "Loading new save file %s" " (new xl fmt info" @@ -813,7 +826,7 @@ static void create_domain(int debug, int daemonize, const char *config_file, con fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" " "which are not supported; need newer xl\n", badflags); - exit(2); + return ERROR_INVAL; } if (hdr.optional_data_len) { optdata_begin = xmalloc(hdr.optional_data_len); @@ -822,12 +835,13 @@ static void create_domain(int debug, int daemonize, const char *config_file, con } #define OPTDATA_LEFT (hdr.optional_data_len - (optdata_here - optdata_begin)) -#define WITH_OPTDATA(amt, body) \ - if (OPTDATA_LEFT < (amt)) { \ - fprintf(stderr, "Savefile truncated.\n"); exit(2); \ - } else { \ - body; \ - optdata_here += (amt); \ +#define WITH_OPTDATA(amt, body) \ + if (OPTDATA_LEFT < (amt)) { \ + fprintf(stderr, "Savefile truncated.\n"); \ + return ERROR_INVAL; \ + } else { \ + body; \ + optdata_here += (amt); \ } optdata_here = optdata_begin; @@ -851,12 +865,12 @@ static void create_domain(int debug, int daemonize, const char *config_file, con ret = libxl_read_file_contents(&ctx, config_file, &config_data, &config_len); if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n", - config_file, strerror(errno)); exit(1); } + config_file, strerror(errno)); return ERROR_FAIL; } } else { if (!config_data) { fprintf(stderr, "Config file not specified and" " none in save file\n"); - exit(1); + return ERROR_INVAL; } config_file = "<saved>"; } @@ -865,6 +879,17 @@ static void create_domain(int debug, int daemonize, const char *config_file, con parse_config_data(config_file, config_data, config_len, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, &dm_info); + if (migrate_fd >= 0) { + if (info1.name) { + /* when we receive a domain we get its name from the config + * file; and we receive it to a temporary name */ + assert(!common_domname); + common_domname = info1.name; + asprintf(migration_domname_r, "%s--incoming", info1.name); + info1.name = *migration_domname_r; + } + } + if (debug) printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info); @@ -874,14 +899,14 @@ start: ret = libxl_domain_make(&ctx, &info1, &domid); if (ret) { fprintf(stderr, "cannot make domain: %d\n", ret); - exit(1); + return ERROR_FAIL; } ret = libxl_userdata_store(&ctx, domid, "xl", config_data, config_len); if (ret) { perror("cannot save config file"); - exit(1); + return ERROR_FAIL; } if (!restore_file || !need_daemon) { @@ -892,12 +917,11 @@ start: ret = libxl_domain_build(&ctx, &info2, domid, &state); } else { ret = libxl_domain_restore(&ctx, &info2, domid, restore_fd, &state, &dm_info); - close(restore_fd); } if (ret) { fprintf(stderr, "cannot (re-)build domain: %d\n", ret); - exit(1); + return ERROR_FAIL; } for (i = 0; i < num_disks; i++) { @@ -905,7 +929,7 @@ start: ret = libxl_device_disk_add(&ctx, domid, &disks[i]); if (ret) { fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret); - exit(1); + return ERROR_FAIL; } } for (i = 0; i < num_vifs; i++) { @@ -913,7 +937,7 @@ start: ret = libxl_device_nic_add(&ctx, domid, &vifs[i]); if (ret) { fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret); - exit(1); + return ERROR_FAIL; } } if (info1.hvm) { @@ -945,7 +969,7 @@ start: libxl_domain_unpause(&ctx, domid); if (!daemonize) - exit(0); + return 0; /* caller gets success in parent */ if (need_daemon) { char *fullname, *name; @@ -1050,12 +1074,7 @@ start: } close(logfile); - free(disks); - free(vifs); - free(vfbs); - free(vkbs); - free(pcidevs); - free(config_data); + exit(0); } static void help(char *command) @@ -1119,6 +1138,25 @@ static void help(char *command) printf("-h Print this help.\n"); printf("-p Do not unpause domain after restoring it.\n"); printf("-e Do not wait in the background for the death of the domain.\n"); + printf("-d Enable debug messages.\n"); + } else if(!strcmp(command, "migrate")) { + printf("Usage: xl migrate [options] <Domain> <host>\n\n"); + printf("Save a domain state to restore later.\n\n"); + printf("Options:\n\n"); + printf("-h Print this help.\n"); + printf("-C <config> Send <config> instead of config file from creation.\n"); + printf("-s <sshcommand> Use <sshcommand> instead of ssh. String will be passed to sh. If empty, run <host> instead of ssh <host> xl migrate-receive [-d -e]\n"); + printf("-e Do not wait in the background (on <host>) for the death of the domain.\n"); + } else if(!strcmp(command, "migrate-receive")) { + printf("Usage: xl migrate-receive - for internal use only"); + } else if(!strcmp(command, "restore")) { + printf("Usage: xl restore [options] [<ConfigFile>] <CheckpointFile>\n\n"); + printf("Restore a domain from a saved state.\n\n"); + printf("Options:\n\n"); + printf("-h Print this help.\n"); + printf("-O Old (configless) xl save format.\n"); + printf("-p Do not unpause domain after restoring it.\n"); + printf("-e Do not wait in the background for the death of the domain.\n"); } else if(!strcmp(command, "destroy")) { printf("Usage: xl destroy <Domain>\n\n"); printf("Terminate a domain immediately.\n\n"); @@ -1523,22 +1561,38 @@ void list_vm(void) free(info); } -int save_domain(char *p, char *filename, int checkpoint, - const char *override_config_file) +static void save_domain_core_begin(char *domain_spec, + const char *override_config_file, + uint8_t **config_data_r, + int *config_len_r) { - int fd, rc; - struct save_file_header hdr; - uint8_t *config_data = 0; - int config_len; - uint8_t *optdata_begin; - union { uint32_t u32; char b[4]; } u32buf; + int rc; - find_domain(p); - fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (fd < 0) { - fprintf(stderr, "Failed to open temp file %s for writing\n", filename); + find_domain(domain_spec); + + /* configuration file in optional data: */ + + if (override_config_file) { + void *config_v = 0; + rc = libxl_read_file_contents(&ctx, override_config_file, + &config_v, config_len_r); + *config_data_r = config_v; + } else { + rc = libxl_userdata_retrieve(&ctx, domid, "xl", + config_data_r, config_len_r); + } + if (rc) { + fputs("Unable to get config file\n",stderr); exit(2); } +} + +void save_domain_core_writeconfig(int fd, const char *filename, + const uint8_t *config_data, int config_len) +{ + struct save_file_header hdr; + uint8_t *optdata_begin; + union { uint32_t u32; char b[4]; } u32buf; memset(&hdr, 0, sizeof(hdr)); memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic)); @@ -1555,25 +1609,6 @@ int save_domain(char *p, char *filename, int checkpoint, } \ }) - /* configuration file in optional data: */ - - if (override_config_file) { - void *config_v = 0; - rc = libxl_read_file_contents(&ctx, override_config_file, - &config_v, &config_len); - config_data = config_v; - } else { - rc = libxl_userdata_retrieve(&ctx, domid, "xl", - &config_data, &config_len); - } - if (rc) { - fputs("Unable to get config file\n",stderr); - exit(2); - } - if (!config_len) { - fputs(" Savefile will not contain xl domain config\n", stderr); - } - u32buf.u32 = config_len; ADD_OPTDATA(u32buf.b, 4); ADD_OPTDATA(config_data, config_len); @@ -1589,6 +1624,28 @@ int save_domain(char *p, char *filename, int checkpoint, " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", filename, hdr.mandatory_flags, hdr.optional_flags, hdr.optional_data_len); +} + +int save_domain(char *p, char *filename, int checkpoint, + const char *override_config_file) +{ + int fd; + uint8_t *config_data; + int config_len; + + save_domain_core_begin(p, override_config_file, &config_data, &config_len); + + if (!config_len) { + fputs(" Savefile will not contain xl domain config\n", stderr); + } + + fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0) { + fprintf(stderr, "Failed to open temp file %s for writing\n", filename); + exit(2); + } + + save_domain_core_writeconfig(fd, filename, config_data, config_len); libxl_domain_suspend(&ctx, NULL, domid, fd); close(fd); @@ -1601,12 +1658,355 @@ int save_domain(char *p, char *filename, int checkpoint, exit(0); } +static int migrate_read_fixedmessage(int fd, const void *msg, int msgsz, + const char *what, const char *rune) { + char buf[msgsz]; + const char *stream; + int rc; + + stream = rune ? "migration receiver stream" : "migration stream"; + rc = libxl_read_exactly(&ctx, fd, buf, msgsz, stream, what); + if (rc) return ERROR_FAIL; + + if (memcmp(buf, msg, msgsz)) { + fprintf(stderr, "%s contained unexpected data instead of %s\n", + stream, what); + if (rune) + fprintf(stderr, "(command run was: %s )\n", rune); + return ERROR_FAIL; + } + return 0; +} + +static void migration_child_report(pid_t migration_child, int recv_fd) { + pid_t child; + int status, sr; + struct timeval now, waituntil, timeout; + static const struct timeval pollinterval = { 0, 1000 }; /* 1ms */ + + if (!migration_child) return; + + CHK_ERRNO( gettimeofday(&waituntil, 0) ); + waituntil.tv_sec += 2; + + for (;;) { + child = waitpid(migration_child, &status, WNOHANG); + + if (child == migration_child) { + if (status) + libxl_report_child_exitstatus(&ctx, XL_LOG_INFO, + "migration target process", + migration_child, status); + break; + } + if (child == -1) { + if (errno == EINTR) continue; + fprintf(stderr, "wait for migration child [%ld] failed: %s\n", + (long)migration_child, strerror(errno)); + break; + } + assert(child == 0); + + CHK_ERRNO( gettimeofday(&now, 0) ); + if (timercmp(&now, &waituntil, >)) { + fprintf(stderr, "migration child [%ld] not exiting, no longer" + " waiting (exit status will be unreported)\n", + (long)migration_child); + break; + } + timersub(&waituntil, &now, &timeout); + + if (recv_fd >= 0) { + fd_set readfds, exceptfds; + FD_ZERO(&readfds); + FD_ZERO(&exceptfds); + FD_SET(recv_fd, &readfds); + FD_SET(recv_fd, &exceptfds); + sr = select(recv_fd+1, &readfds,0,&exceptfds, &timeout); + } else { + if (timercmp(&timeout, &pollinterval, >)) + timeout = pollinterval; + sr = select(0,0,0,0, &timeout); + } + if (sr > 0) { + recv_fd = -1; + } else if (sr == 0) { + } else if (sr == -1) { + if (errno != EINTR) { + fprintf(stderr, "migration child [%ld] exit wait select" + " failed unexpectedly: %s\n", + (long)migration_child, strerror(errno)); + break; + } + } + } + migration_child = 0; +} + +static void migrate_domain(char *domain_spec, const char *rune, + const char *override_config_file) +{ + pid_t child = -1; + int rc; + int sendpipe[2], recvpipe[2]; + int send_fd, recv_fd; + libxl_domain_suspend_info suspinfo; + char *away_domname; + char rc_buf; + uint8_t *config_data; + int config_len; + + save_domain_core_begin(domain_spec, override_config_file, + &config_data, &config_len); + + if (!common_domname) { + common_domname = libxl_domid_to_name(&ctx, domid); + /* libxl_domid_to_name fails ? don''t bother with names then */ + } + + if (!config_len) { + fprintf(stderr, "No config file stored for running domain and " + "none supplied - cannot migrate.\n"); + exit(1); + } + + MUST( libxl_pipe(&ctx, sendpipe) ); + MUST( libxl_pipe(&ctx, recvpipe) ); + + child = libxl_fork(&ctx); + if (child==-1) exit(1); + + if (!child) { + dup2(sendpipe[0], 0); + dup2(recvpipe[1], 1); + close(sendpipe[0]); close(sendpipe[1]); + close(recvpipe[0]); close(recvpipe[1]); + execlp("sh","sh","-c",rune,(char*)0); + perror("failed to exec sh"); + exit(-1); + } + + close(sendpipe[0]); + close(recvpipe[1]); + send_fd = sendpipe[1]; + recv_fd = recvpipe[0]; + + signal(SIGPIPE, SIG_IGN); + /* if receiver dies, we get an error and can clean up + rather than just dying */ + + rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_banner, + sizeof(migrate_receiver_banner)-1, + "banner", rune); + if (rc) { + close(send_fd); + migration_child_report(child, recv_fd); + exit(-rc); + } + + save_domain_core_writeconfig(send_fd, "migration stream", + config_data, config_len); + + memset(&suspinfo, 0, sizeof(suspinfo)); + suspinfo.flags |= XL_SUSPEND_LIVE; + rc = libxl_domain_suspend(&ctx, &suspinfo, domid, send_fd); + if (rc) { + fprintf(stderr, "migration sender: libxl_domain_suspend failed" + " (rc=%d)\n", rc); + goto failed_resume; + } + + fprintf(stderr, "migration sender: Transfer complete.\n"); + + rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_ready, + sizeof(migrate_receiver_ready), + "ready message", rune); + if (rc) goto failed_resume; + + /* right, at this point we are about give the destination + * permission to rename and resume, so we must first rename the + * domain away ourselves */ + + fprintf(stderr, "migration sender: Target has acknowledged transfer.\n"); + + if (common_domname) { + asprintf(&away_domname, "%s--migratedaway", common_domname); + rc = libxl_domain_rename(&ctx, domid, + common_domname, away_domname, 0); + if (rc) goto failed_resume; + } + + /* point of no return - as soon as we have tried to say + * "go" to the receiver, it''s not safe to carry on. We leave + * the domain renamed to %s--migratedaway in case that''s helpful. + */ + + fprintf(stderr, "migration sender: Giving target permission to start.\n"); + + rc = libxl_write_exactly(&ctx, send_fd, + migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "migration stream", "GO message"); + if (rc) goto failed_badly; + + rc = migrate_read_fixedmessage(recv_fd, migrate_report, + sizeof(migrate_report), + "success/failure report message", rune); + if (rc) goto failed_badly; + + rc = libxl_read_exactly(&ctx, recv_fd, + &rc_buf, 1, + "migration ack stream", "success/failure status"); + if (rc) goto failed_badly; + + if (rc_buf) { + fprintf(stderr, "migration sender: Target reports startup failure" + " (status code %d).\n", rc_buf); + + rc = migrate_read_fixedmessage(recv_fd, migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "permission for sender to resume", + rune); + if (rc) goto failed_badly; + + fprintf(stderr, "migration sender: Trying to resume at our end.\n"); + + if (common_domname) { + libxl_domain_rename(&ctx, domid, + away_domname, common_domname, 0); + } + rc = libxl_domain_resume(&ctx, domid); + if (!rc) fprintf(stderr, "migration sender: Resumed OK.\n"); + + fprintf(stderr, "Migration failed due to problems at target.\n"); + exit(-ERROR_FAIL); + } + + fprintf(stderr, "migration sender: Target reports successful startup.\n"); + libxl_domain_destroy(&ctx, domid, 1); /* bang! */ + fprintf(stderr, "Migration successful.\n"); + exit(0); + + failed_resume: + close(send_fd); + migration_child_report(child, recv_fd); + fprintf(stderr, "Migration failed, resuming at sender.\n"); + libxl_domain_resume(&ctx, domid); + exit(-ERROR_FAIL); + + failed_badly: + fprintf(stderr, + "** Migration failed during final handshake **\n" + "Domain state is now undefined !\n" + "Please CHECK AT BOTH ENDS for running instances, before renaming and\n" + " resuming at most one instance. Two simultaneous instances of the domain\n" + " would probably result in SEVERE DATA LOSS and it is now your\n" + " responsibility to avoid that. Sorry.\n"); + + close(send_fd); + migration_child_report(child, recv_fd); + exit(-ERROR_BADFAIL); +} + +static void migrate_receive(int debug, int daemonize) +{ + int rc, rc2; + char rc_buf; + char *migration_domname; + + signal(SIGPIPE, SIG_IGN); + /* if we get SIGPIPE we''d rather just have it as an error */ + + fprintf(stderr, "migration target: Ready to receive domain.\n"); + + CHK_ERRNO( libxl_write_exactly(&ctx, 1, + migrate_receiver_banner, + sizeof(migrate_receiver_banner)-1, + "migration ack stream", + "banner") ); + + rc = create_domain(debug, daemonize, + 0 /* no config file, use incoming */, + "incoming migration stream", 1, + 0, &migration_domname); + if (rc) { + fprintf(stderr, "migration target: Domain creation failed" + " (code %d).\n", rc); + exit(-rc); + } + + fprintf(stderr, "migration target: Transfer complete," + " requesting permission to start domain.\n"); + + rc = libxl_write_exactly(&ctx, 1, + migrate_receiver_ready, + sizeof(migrate_receiver_ready), + "migration ack stream", "ready message"); + if (rc) exit(-rc); + + rc = migrate_read_fixedmessage(0, migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "GO message", 0); + if (rc) goto perhaps_destroy_notify_rc; + + fprintf(stderr, "migration target: Got permission, starting domain.\n"); + + if (migration_domname) { + rc = libxl_domain_rename(&ctx, domid, + migration_domname, common_domname, 0); + if (rc) goto perhaps_destroy_notify_rc; + } + + rc = libxl_domain_unpause(&ctx, domid); + if (rc) goto perhaps_destroy_notify_rc; + + fprintf(stderr, "migration target: Domain started successsfully.\n"); + rc = 0; + + perhaps_destroy_notify_rc: + rc2 = libxl_write_exactly(&ctx, 1, + migrate_report, sizeof(migrate_report), + "migration ack stream", + "success/failure report"); + if (rc2) exit(-ERROR_BADFAIL); + + rc_buf = -rc; + assert(!!rc_buf == !!rc); + rc2 = libxl_write_exactly(&ctx, 1, &rc_buf, 1, + "migration ack stream", + "success/failure code"); + if (rc2) exit(-ERROR_BADFAIL); + + if (rc) { + fprintf(stderr, "migration target: Failure, destroying our copy.\n"); + + rc2 = libxl_domain_destroy(&ctx, domid, 1); + if (rc2) { + fprintf(stderr, "migration target: Failed to destroy our copy" + " (code %d).\n", rc2); + exit(-ERROR_BADFAIL); + } + + fprintf(stderr, "migration target: Cleanup OK, granting sender" + " permission to resume.\n"); + + rc2 = libxl_write_exactly(&ctx, 1, + migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "migration ack stream", + "permission to sender to have domain back"); + if (rc2) exit(-ERROR_BADFAIL); + } + + exit(0); +} + int main_restore(int argc, char **argv) { char *checkpoint_file = NULL; char *config_file = NULL; int paused = 0, debug = 0, daemonize = 1; - int opt; + int opt, rc; while ((opt = getopt(argc, argv, "hpde")) != -1) { switch (opt) { @@ -1637,7 +2037,39 @@ int main_restore(int argc, char **argv) help("restore"); exit(2); } - create_domain(debug, daemonize, config_file, checkpoint_file, paused); + rc = create_domain(debug, daemonize, config_file, + checkpoint_file, paused, -1, 0); + exit(-rc); +} + +int main_migrate_receive(int argc, char **argv) +{ + int debug = 0, daemonize = 1; + int opt; + + while ((opt = getopt(argc, argv, "hed")) != -1) { + switch (opt) { + case ''h'': + help("restore"); + exit(2); + break; + case ''e'': + daemonize = 0; + break; + case ''d'': + debug = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind != 0) { + help("restore"); + exit(2); + } + migrate_receive(debug, daemonize); exit(0); } @@ -1674,6 +2106,59 @@ int main_save(int argc, char **argv) exit(0); } +int main_migrate(int argc, char **argv) +{ + char *p = NULL; + const char *config_filename = NULL; + const char *ssh_command = "ssh"; + char *rune = NULL; + char *host; + int opt, daemonize = 1, debug = 0; + + while ((opt = getopt(argc, argv, "hC:s:ed")) != -1) { + switch (opt) { + case ''h'': + help("migrate"); + exit(0); + case ''C'': + config_filename = optarg; + break; + case ''s'': + ssh_command = optarg; + break; + case ''e'': + daemonize = 0; + break; + case ''d'': + debug = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind < 2 || argc-optind > 2) { + help("save"); + exit(2); + } + + p = argv[optind]; + host = argv[optind + 1]; + + if (!ssh_command[0]) { + rune= host; + } else { + asprintf(&rune, "exec %s %s xl migrate-receive%s%s", + ssh_command, host, + daemonize ? "" : " -e", + debug ? " -d" : ""); + } + + migrate_domain(p, rune, config_filename); + exit(0); +} + int main_pause(int argc, char **argv) { int opt; @@ -1799,7 +2284,7 @@ int main_create(int argc, char **argv) { char *filename = NULL; int debug = 0, daemonize = 1; - int opt; + int opt, rc; while ((opt = getopt(argc, argv, "hde")) != -1) { switch (opt) { @@ -1824,8 +2309,9 @@ int main_create(int argc, char **argv) } filename = argv[optind]; - create_domain(debug, daemonize, filename, NULL, 0); - exit(0); + rc = create_domain(debug, daemonize, filename, NULL, 0, + -1, 0); + exit(-rc); } void button_press(char *p, char *b) @@ -2189,8 +2675,12 @@ int main(int argc, char **argv) main_console(argc - 1, argv + 1); } else if (!strcmp(argv[1], "save")) { main_save(argc - 1, argv + 1); + } else if (!strcmp(argv[1], "migrate")) { + main_migrate(argc - 1, argv + 1); } else if (!strcmp(argv[1], "restore")) { main_restore(argc - 1, argv + 1); + } else if (!strcmp(argv[1], "migrate-receive")) { + main_migrate_receive(argc - 1, argv + 1); } else if (!strcmp(argv[1], "cd-insert")) { main_cd_insert(argc - 1, argv + 1); } else if (!strcmp(argv[1], "cd-eject")) { -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel