diff options
-rw-r--r-- | tools/libxl/libxl.c | 94 | ||||
-rw-r--r-- | tools/libxl/libxl.h | 22 | ||||
-rw-r--r-- | tools/libxl/libxl_dom.c | 121 | ||||
-rw-r--r-- | tools/libxl/libxl_internal.h | 45 | ||||
-rw-r--r-- | tools/libxl/libxl_save_callout.c | 11 | ||||
-rw-r--r-- | tools/libxl/xl_cmdimpl.c | 9 |
6 files changed, 214 insertions, 88 deletions
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 205c1e61de..4d09b953bf 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -649,32 +649,51 @@ libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm_out) return ptr; } +static void remus_failover_cb(libxl__egc *egc, + libxl__domain_suspend_state *dss, int rc); + /* TODO: Explicit Checkpoint acknowledgements via recv_fd. */ int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info, - uint32_t domid, int send_fd, int recv_fd) + uint32_t domid, int send_fd, int recv_fd, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); - libxl_domain_type type = libxl__domain_type(gc, domid); - int rc = 0; + AO_CREATE(ctx, domid, ao_how); + libxl__domain_suspend_state *dss; + int rc; + libxl_domain_type type = libxl__domain_type(gc, domid); if (type == LIBXL_DOMAIN_TYPE_INVALID) { rc = ERROR_FAIL; - goto remus_fail; + goto out; } - if (info == NULL) { - LIBXL__LOG(ctx, LIBXL__LOG_ERROR, - "No remus_info structure supplied for domain %d", domid); - rc = ERROR_INVAL; - goto remus_fail; - } + GCNEW(dss); + dss->ao = ao; + dss->callback = remus_failover_cb; + dss->domid = domid; + dss->fd = send_fd; + /* TODO do something with recv_fd */ + dss->type = type; + dss->live = 1; + dss->debug = 0; + dss->remus = info; + + assert(info); /* TBD: Remus setup - i.e. attach qdisc, enable disk buffering, etc */ /* Point of no return */ - rc = libxl__domain_suspend_common(gc, domid, send_fd, type, /* live */ 1, - /* debug */ 0, info); + libxl__domain_suspend(egc, dss); + return AO_INPROGRESS; + + out: + return AO_ABORT(rc); +} +static void remus_failover_cb(libxl__egc *egc, + libxl__domain_suspend_state *dss, int rc) +{ + STATE_AO_GC(dss->ao); /* * With Remus, if we reach this point, it means either * backup died or some network error occurred preventing us @@ -684,27 +703,46 @@ int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info, /* TBD: Remus cleanup - i.e. detach qdisc, release other * resources. */ - remus_fail: - GC_FREE; - return rc; + libxl__ao_complete(egc, ao, rc); } -int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info, - uint32_t domid, int fd) +static void domain_suspend_cb(libxl__egc *egc, + libxl__domain_suspend_state *dss, int rc) { - GC_INIT(ctx); + STATE_AO_GC(dss->ao); + libxl__ao_complete(egc,ao,rc); + +} + +int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, int flags, + const libxl_asyncop_how *ao_how) +{ + AO_CREATE(ctx, domid, ao_how); + int rc; + libxl_domain_type type = libxl__domain_type(gc, domid); - int live = info != NULL && info->flags & XL_SUSPEND_LIVE; - int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG; - int rc = 0; + if (type == LIBXL_DOMAIN_TYPE_INVALID) { + rc = ERROR_FAIL; + goto out_err; + } - rc = libxl__domain_suspend_common(gc, domid, fd, type, live, debug, - /* No Remus */ NULL); + libxl__domain_suspend_state *dss; + GCNEW(dss); - if (!rc && type == LIBXL_DOMAIN_TYPE_HVM) - rc = libxl__domain_save_device_model(gc, domid, fd); - GC_FREE; - return rc; + dss->ao = ao; + dss->callback = domain_suspend_cb; + + dss->domid = domid; + dss->fd = fd; + dss->type = type; + dss->live = flags & LIBXL_SUSPEND_LIVE; + dss->debug = flags & LIBXL_SUSPEND_DEBUG; + + libxl__domain_suspend(egc, dss); + return AO_INPROGRESS; + + out_err: + return AO_ABORT(rc); } int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid) diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index e5d1f97032..371b659434 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -347,13 +347,6 @@ typedef struct libxl__ctx libxl_ctx; const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx); -typedef struct { -#define XL_SUSPEND_DEBUG 1 -#define XL_SUSPEND_LIVE 2 - int flags; - int (*suspend_callback)(void *, int); -} libxl_domain_suspend_info; - enum { ERROR_NONSPECIFIC = -1, ERROR_VERSION = -2, @@ -514,16 +507,23 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config, void libxl_domain_config_init(libxl_domain_config *d_config); void libxl_domain_config_dispose(libxl_domain_config *d_config); -int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info, - uint32_t domid, int send_fd, int recv_fd); -int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info, - uint32_t domid, int fd); + +int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, + int flags, /* LIBXL_SUSPEND_* */ + const libxl_asyncop_how *ao_how); +#define LIBXL_SUSPEND_DEBUG 1 +#define LIBXL_SUSPEND_LIVE 2 /* @param suspend_cancel [from xenctrl.h:xc_domain_resume( @param fast )] * If this parameter is true, use co-operative resume. The guest * must support this. */ int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel); + +int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info, + uint32_t domid, int send_fd, int recv_fd, + const libxl_asyncop_how *ao_how); + int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid); int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid); int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid); diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 3bf1e26eda..7f12e036d4 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -17,13 +17,11 @@ #include <glob.h> -#include <xenctrl.h> -#include <xc_dom.h> +#include "libxl_internal.h" +#include <xc_dom.h> #include <xen/hvm/hvm_info_table.h> -#include "libxl_internal.h" - libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid) { libxl_ctx *ctx = libxl__gc_owner(gc); @@ -523,11 +521,18 @@ int libxl__toolstack_restore(uint32_t domid, const uint8_t *buf, return 0; } -static int libxl__domain_suspend_common_switch_qemu_logdirty +/*==================== Domain suspend (save) ====================*/ + +static void domain_suspend_done(libxl__egc *egc, + libxl__domain_suspend_state *dss, int rc); + +/*----- callbacks, called by xc_domain_save -----*/ + +int libxl__domain_suspend_common_switch_qemu_logdirty (int domid, unsigned int enable, void *data) { libxl__domain_suspend_state *dss = data; - libxl__gc *gc = dss->gc; + STATE_AO_GC(dss->ao); char *path; bool rc; @@ -592,10 +597,10 @@ int libxl__domain_resume_device_model(libxl__gc *gc, uint32_t domid) return 0; } -static int libxl__domain_suspend_common_callback(void *data) +int libxl__domain_suspend_common_callback(void *data) { libxl__domain_suspend_state *dss = data; - libxl__gc *gc = dss->gc; + STATE_AO_GC(dss->ao); unsigned long hvm_s_state = 0, hvm_pvdrv = 0; int ret; char *state = "suspend"; @@ -716,7 +721,7 @@ static int libxl__domain_suspend_common_callback(void *data) guest_suspended: if (dss->hvm) { - ret = libxl__domain_suspend_device_model(dss->gc, dss->domid); + ret = libxl__domain_suspend_device_model(gc, dss->domid); if (ret) { LOG(ERROR, "libxl__domain_suspend_device_model failed ret=%d", ret); return 0; @@ -733,11 +738,11 @@ static inline char *save_helper(libxl__gc *gc, uint32_t domid, domid, phys_offset, node); } -static int libxl__toolstack_save(uint32_t domid, uint8_t **buf, +int libxl__toolstack_save(uint32_t domid, uint8_t **buf, uint32_t *len, void *data) { libxl__domain_suspend_state *dss = data; - libxl__gc *gc = dss->gc; + STATE_AO_GC(dss->ao); int i = 0; char *start_addr = NULL, *size = NULL, *phys_offset = NULL, *name = NULL; unsigned int num = 0; @@ -808,6 +813,8 @@ static int libxl__toolstack_save(uint32_t domid, uint8_t **buf, return 0; } +/*----- remus callbacks -----*/ + static int libxl__remus_domain_suspend_callback(void *data) { /* TODO: Issue disk and network checkpoint reqs. */ @@ -817,7 +824,7 @@ static int libxl__remus_domain_suspend_callback(void *data) static int libxl__remus_domain_resume_callback(void *data) { libxl__domain_suspend_state *dss = data; - libxl__gc *gc = dss->gc; + STATE_AO_GC(dss->ao); /* Resumes the domain and the device model */ if (libxl_domain_resume(CTX, dss->domid, /* Fast Suspend */1)) @@ -830,10 +837,11 @@ static int libxl__remus_domain_resume_callback(void *data) static int libxl__remus_domain_checkpoint_callback(void *data) { libxl__domain_suspend_state *dss = data; + STATE_AO_GC(dss->ao); /* This would go into tailbuf. */ if (dss->hvm && - libxl__domain_save_device_model(dss->gc, dss->domid, dss->save_fd)) + libxl__domain_save_device_model(gc, dss->domid, dss->fd)) return 0; /* TODO: Wait for disk and memory ack, release network buffer */ @@ -841,17 +849,23 @@ static int libxl__remus_domain_checkpoint_callback(void *data) return 1; } -int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, - libxl_domain_type type, - int live, int debug, - const libxl_domain_remus_info *r_info) +/*----- main code for suspending, in order of execution -----*/ + +void libxl__domain_suspend(libxl__egc *egc, libxl__domain_suspend_state *dss) { + STATE_AO_GC(dss->ao); int port; - struct save_callbacks callbacks[1]; - libxl__domain_suspend_state dss[1]; int rc = ERROR_FAIL; unsigned long vm_generationid_addr; + /* Convenience aliases */ + const uint32_t domid = dss->domid; + const libxl_domain_type type = dss->type; + const int live = dss->live; + const int debug = dss->debug; + const libxl_domain_remus_info *const r_info = dss->remus; + struct save_callbacks *const callbacks = &dss->callbacks; + switch (type) { case LIBXL_DOMAIN_TYPE_HVM: { char *path; @@ -870,15 +884,13 @@ int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, dss->hvm = 0; break; default: - return ERROR_INVAL; + abort(); } dss->xcflags = (live) ? XCFLAGS_LIVE : 0 | (debug) ? XCFLAGS_DEBUG : 0 | (dss->hvm) ? XCFLAGS_HVM : 0; - dss->domid = domid; - dss->gc = gc; dss->suspend_eventchn = -1; dss->guest_responded = 0; @@ -886,10 +898,7 @@ int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, dss->interval = r_info->interval; if (r_info->compression) dss->xcflags |= XCFLAGS_CHECKPOINT_COMPRESS; - dss->save_fd = fd; } - else - dss->save_fd = -1; dss->xce = xc_evtchn_open(NULL, 0); if (dss->xce == NULL) @@ -919,10 +928,28 @@ int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, callbacks->toolstack_save = libxl__toolstack_save; callbacks->data = dss; - rc = xc_domain_save(CTX->xch, fd, domid, 0, 0, dss->xcflags, callbacks, - dss->hvm, vm_generationid_addr); - if ( rc ) { - LOGE(ERROR, "saving domain: %s", + libxl__xc_domain_save(egc, dss, vm_generationid_addr); + return; + + out: + domain_suspend_done(egc, dss, rc); +} + +void libxl__xc_domain_save_done(libxl__egc *egc, + libxl__domain_suspend_state *dss, + int rc, int retval, int errnoval) +{ + STATE_AO_GC(dss->ao); + + /* Convenience aliases */ + const libxl_domain_type type = dss->type; + const uint32_t domid = dss->domid; + + if (rc) + goto out; + + if (retval) { + LOGEV(ERROR, errnoval, "saving domain: %s", dss->guest_responded ? "domain responded to suspend request" : "domain did not respond to suspend request"); @@ -930,16 +957,21 @@ int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, rc = ERROR_GUEST_TIMEDOUT; else rc = ERROR_FAIL; + goto out; } - if (dss->suspend_eventchn > 0) - xc_suspend_evtchn_release(CTX->xch, dss->xce, domid, - dss->suspend_eventchn); - if (dss->xce != NULL) - xc_evtchn_close(dss->xce); + if (type == LIBXL_DOMAIN_TYPE_HVM) { + rc = libxl__domain_suspend_device_model(gc, domid); + if (rc) goto out; + + rc = libxl__domain_save_device_model(gc, domid, dss->fd); + if (rc) goto out; + } + + rc = 0; out: - return rc; + domain_suspend_done(egc, dss, rc); } int libxl__domain_save_device_model(libxl__gc *gc, uint32_t domid, int fd) @@ -994,6 +1026,25 @@ out: return rc; } +static void domain_suspend_done(libxl__egc *egc, + libxl__domain_suspend_state *dss, int rc) +{ + STATE_AO_GC(dss->ao); + + /* Convenience aliases */ + const uint32_t domid = dss->domid; + + if (dss->suspend_eventchn > 0) + xc_suspend_evtchn_release(CTX->xch, dss->xce, domid, + dss->suspend_eventchn); + if (dss->xce != NULL) + xc_evtchn_close(dss->xce); + + dss->callback(egc, dss, rc); +} + +/*==================== Miscellaneous ====================*/ + char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid) { char *s = libxl__sprintf(gc, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(uuid)); diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 7a3b7f8722..1ee5bd2b09 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1777,16 +1777,28 @@ _hidden int libxl__datacopier_start(libxl__datacopier_state *dc); typedef struct libxl__domain_suspend_state libxl__domain_suspend_state; +typedef void libxl__domain_suspend_cb(libxl__egc*, + libxl__domain_suspend_state*, int rc); + struct libxl__domain_suspend_state { - libxl__gc *gc; + /* set by caller of libxl__domain_suspend */ + libxl__ao *ao; + libxl__domain_suspend_cb *callback; + + uint32_t domid; + int fd; + libxl_domain_type type; + int live; + int debug; + const libxl_domain_remus_info *remus; + /* private */ xc_evtchn *xce; /* event channel handle */ int suspend_eventchn; - int domid; int hvm; - unsigned int xcflags; + int xcflags; int guest_responded; - int save_fd; /* Migration stream fd (for Remus) */ int interval; /* checkpoint interval (for Remus) */ + struct save_callbacks callbacks; }; @@ -1903,10 +1915,27 @@ struct libxl__domain_create_state { /*----- Domain suspend (save) functions -----*/ -_hidden int libxl__domain_suspend_common(libxl__gc *gc, uint32_t domid, int fd, - libxl_domain_type type, - int live, int debug, - const libxl_domain_remus_info *r_info); +/* calls dss->callback when done */ +_hidden void libxl__domain_suspend(libxl__egc *egc, + libxl__domain_suspend_state *dss); + + +/* calls libxl__xc_domain_suspend_done when done */ +_hidden void libxl__xc_domain_save(libxl__egc*, libxl__domain_suspend_state*, + unsigned long vm_generationid_addr); +/* If rc==0 then retval is the return value from xc_domain_save + * and errnoval is the errno value it provided. + * If rc!=0, retval and errnoval are undefined. */ +_hidden void libxl__xc_domain_save_done(libxl__egc*, + libxl__domain_suspend_state*, + int rc, int retval, int errnoval); + +_hidden int libxl__domain_suspend_common_callback(void *data); +_hidden int libxl__domain_suspend_common_switch_qemu_logdirty + (int domid, unsigned int enable, void *data); +_hidden int libxl__toolstack_save(uint32_t domid, uint8_t **buf, + uint32_t *len, void *data); + /* calls libxl__xc_domain_restore_done when done */ _hidden void libxl__xc_domain_restore(libxl__egc *egc, diff --git a/tools/libxl/libxl_save_callout.c b/tools/libxl/libxl_save_callout.c index 2f8db9f0b6..1b481ab6be 100644 --- a/tools/libxl/libxl_save_callout.c +++ b/tools/libxl/libxl_save_callout.c @@ -35,3 +35,14 @@ void libxl__xc_domain_restore(libxl__egc *egc, libxl__domain_create_state *dcs, &state->vm_generationid_addr, &dcs->callbacks); libxl__xc_domain_restore_done(egc, dcs, 0, r, errno); } + +void libxl__xc_domain_save(libxl__egc *egc, libxl__domain_suspend_state *dss, + unsigned long vm_generationid_addr) +{ + STATE_AO_GC(dss->ao); + int r; + + r = xc_domain_save(CTX->xch, dss->fd, dss->domid, 0, 0, dss->xcflags, + &dss->callbacks, dss->hvm, vm_generationid_addr); + libxl__xc_domain_save_done(egc, dss, 0, r, errno); +} diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 4101669dc3..bcdef00e02 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -2826,7 +2826,7 @@ static int save_domain(const char *p, const char *filename, int checkpoint, save_domain_core_writeconfig(fd, filename, config_data, config_len); - CHK_ERRNO(libxl_domain_suspend(ctx, NULL, domid, fd)); + CHK_ERRNO(libxl_domain_suspend(ctx, domid, fd, 0, NULL)); close(fd); if (checkpoint) @@ -2988,7 +2988,6 @@ static void migrate_domain(const char *domain_spec, const char *rune, pid_t child = -1; int rc; int send_fd = -1, recv_fd = -1; - libxl_domain_suspend_info suspinfo; char *away_domname; char rc_buf; uint8_t *config_data; @@ -3010,9 +3009,7 @@ static void migrate_domain(const char *domain_spec, const char *rune, xtl_stdiostream_adjust_flags(logger, XTL_STDIOSTREAM_HIDE_PROGRESS, 0); - memset(&suspinfo, 0, sizeof(suspinfo)); - suspinfo.flags |= XL_SUSPEND_LIVE; - rc = libxl_domain_suspend(ctx, &suspinfo, domid, send_fd); + rc = libxl_domain_suspend(ctx, domid, send_fd, LIBXL_SUSPEND_LIVE, NULL); if (rc) { fprintf(stderr, "migration sender: libxl_domain_suspend failed" " (rc=%d)\n", rc); @@ -6584,7 +6581,7 @@ int main_remus(int argc, char **argv) } /* Point of no return */ - rc = libxl_domain_remus_start(ctx, &r_info, domid, send_fd, recv_fd); + rc = libxl_domain_remus_start(ctx, &r_info, domid, send_fd, recv_fd, 0); /* If we are here, it means backup has failed/domain suspend failed. * Try to resume the domain and exit gracefully. |