|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 2/6] tools/libxl: move domain suspend code into libxl_dom_suspend.c
On Wed, 2015-06-03 at 16:01 +0800, Yang Hongyang wrote:
> Move domain suspend code into a separate file libxl_dom_suspend.c.
> export an API libxl__domain_suspend() which wrappers the static
just "..which wraps the..."
> function domain_suspend_callback_common() for internal use.
>
> Note that the newly added file libxl_dom_suspend.c is used for
> suspend/resume code.
>
> Signed-off-by: Yang Hongyang <yanghy@xxxxxxxxxxxxxx>
> CC: Ian Campbell <Ian.Campbell@xxxxxxxxxx>
> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
> CC: Wei Liu <wei.liu2@xxxxxxxxxx>
> CC: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> Acked-by: Ian Campbell <Ian.Campbell@xxxxxxxxxx>
> ---
> tools/libxl/Makefile | 3 +-
> tools/libxl/libxl_dom.c | 350 +-----------------------------------
> tools/libxl/libxl_dom_suspend.c | 381
> ++++++++++++++++++++++++++++++++++++++++
> tools/libxl/libxl_internal.h | 6 +
> 4 files changed, 393 insertions(+), 347 deletions(-)
> create mode 100644 tools/libxl/libxl_dom_suspend.c
>
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index cc9c152..3f98d62 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -95,7 +95,8 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o
> libxl_pci.o \
> libxl_internal.o libxl_utils.o libxl_uuid.o \
> libxl_json.o libxl_aoutils.o libxl_numa.o libxl_vnuma.o
> \
> libxl_save_callout.o _libxl_save_msgs_callout.o \
> - libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
> + libxl_qmp.o libxl_event.o libxl_fork.o
> libxl_dom_suspend.o \
> + $(LIBXL_OBJS-y)
> LIBXL_OBJS += libxl_genid.o
> LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
>
> diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
> index cce04dd..9444329 100644
> --- a/tools/libxl/libxl_dom.c
> +++ b/tools/libxl/libxl_dom.c
> @@ -1103,11 +1103,6 @@ int libxl__toolstack_restore(uint32_t domid, const
> uint8_t *buf,
>
> /*==================== Domain suspend (save) ====================*/
>
> -static void domain_save_done(libxl__egc *egc,
> - libxl__domain_suspend_state *dss, int rc);
> -static void domain_suspend_callback_common_done(libxl__egc *egc,
> - libxl__domain_suspend_state *dss, int ok);
> -
> /*----- complicated callback, called by xc_domain_save -----*/
>
> /*
> @@ -1324,35 +1319,6 @@ static void switch_logdirty_done(libxl__egc *egc,
>
> /*----- callbacks, called by xc_domain_save -----*/
>
> -int libxl__domain_suspend_device_model(libxl__gc *gc,
> - libxl__domain_suspend_state *dss)
> -{
> - int ret = 0;
> - uint32_t const domid = dss->domid;
> - const char *const filename = dss->dm_savefile;
> -
> - switch (libxl__device_model_version_running(gc, domid)) {
> - case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL: {
> - LOG(DEBUG, "Saving device model state to %s", filename);
> - libxl__qemu_traditional_cmd(gc, domid, "save");
> - libxl__wait_for_device_model_deprecated(gc, domid, "paused", NULL,
> NULL, NULL);
> - break;
> - }
> - case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
> - if (libxl__qmp_stop(gc, domid))
> - return ERROR_FAIL;
> - /* Save DM state into filename */
> - ret = libxl__qmp_save(gc, domid, filename);
> - if (ret)
> - unlink(filename);
> - break;
> - default:
> - return ERROR_INVAL;
> - }
> -
> - return ret;
> -}
> -
> int libxl__domain_resume_device_model(libxl__gc *gc, uint32_t domid)
> {
>
> @@ -1373,301 +1339,6 @@ int libxl__domain_resume_device_model(libxl__gc *gc,
> uint32_t domid)
> return 0;
> }
>
> -static void domain_suspend_common_wait_guest(libxl__egc *egc,
> - libxl__domain_suspend_state
> *dss);
> -static void domain_suspend_common_guest_suspended(libxl__egc *egc,
> - libxl__domain_suspend_state *dss);
> -
> -static void domain_suspend_common_pvcontrol_suspending(libxl__egc *egc,
> - libxl__xswait_state *xswa, int rc, const char *state);
> -static void domain_suspend_common_wait_guest_evtchn(libxl__egc *egc,
> - libxl__ev_evtchn *evev);
> -static void suspend_common_wait_guest_watch(libxl__egc *egc,
> - libxl__ev_xswatch *xsw, const char *watch_path, const char
> *event_path);
> -static void suspend_common_wait_guest_check(libxl__egc *egc,
> - libxl__domain_suspend_state *dss);
> -static void suspend_common_wait_guest_timeout(libxl__egc *egc,
> - libxl__ev_time *ev, const struct timeval *requested_abs);
> -
> -static void domain_suspend_common_failed(libxl__egc *egc,
> - libxl__domain_suspend_state *dss);
> -static void domain_suspend_common_done(libxl__egc *egc,
> - libxl__domain_suspend_state *dss,
> - bool ok);
> -
> -static bool domain_suspend_pvcontrol_acked(const char *state) {
> - /* any value other than "suspend", including ENOENT (i.e. !state), is OK
> */
> - if (!state) return 1;
> - return strcmp(state,"suspend");
> -}
> -
> -/* calls dss->callback_common_done when done */
> -static void domain_suspend_callback_common(libxl__egc *egc,
> - libxl__domain_suspend_state *dss)
> -{
> - STATE_AO_GC(dss->ao);
> - uint64_t hvm_s_state = 0, hvm_pvdrv = 0;
> - int ret, rc;
> -
> - /* Convenience aliases */
> - const uint32_t domid = dss->domid;
> -
> - if (dss->hvm) {
> - xc_hvm_param_get(CTX->xch, domid, HVM_PARAM_CALLBACK_IRQ,
> &hvm_pvdrv);
> - xc_hvm_param_get(CTX->xch, domid, HVM_PARAM_ACPI_S_STATE,
> &hvm_s_state);
> - }
> -
> - if ((hvm_s_state == 0) && (dss->guest_evtchn.port >= 0)) {
> - LOG(DEBUG, "issuing %s suspend request via event channel",
> - dss->hvm ? "PVHVM" : "PV");
> - ret = xc_evtchn_notify(CTX->xce, dss->guest_evtchn.port);
> - if (ret < 0) {
> - LOG(ERROR, "xc_evtchn_notify failed ret=%d", ret);
> - goto err;
> - }
> -
> - dss->guest_evtchn.callback = domain_suspend_common_wait_guest_evtchn;
> - rc = libxl__ev_evtchn_wait(gc, &dss->guest_evtchn);
> - if (rc) goto err;
> -
> - rc = libxl__ev_time_register_rel(gc, &dss->guest_timeout,
> - suspend_common_wait_guest_timeout,
> - 60*1000);
> - if (rc) goto err;
> -
> - return;
> - }
> -
> - if (dss->hvm && (!hvm_pvdrv || hvm_s_state)) {
> - LOG(DEBUG, "Calling xc_domain_shutdown on HVM domain");
> - ret = xc_domain_shutdown(CTX->xch, domid, SHUTDOWN_suspend);
> - if (ret < 0) {
> - LOGE(ERROR, "xc_domain_shutdown failed");
> - goto err;
> - }
> - /* The guest does not (need to) respond to this sort of request. */
> - dss->guest_responded = 1;
> - domain_suspend_common_wait_guest(egc, dss);
> - return;
> - }
> -
> - LOG(DEBUG, "issuing %s suspend request via XenBus control node",
> - dss->hvm ? "PVHVM" : "PV");
> -
> - libxl__domain_pvcontrol_write(gc, XBT_NULL, domid, "suspend");
> -
> - dss->pvcontrol.path = libxl__domain_pvcontrol_xspath(gc, domid);
> - if (!dss->pvcontrol.path) goto err;
> -
> - dss->pvcontrol.ao = ao;
> - dss->pvcontrol.what = "guest acknowledgement of suspend request";
> - dss->pvcontrol.timeout_ms = 60 * 1000;
> - dss->pvcontrol.callback = domain_suspend_common_pvcontrol_suspending;
> - libxl__xswait_start(gc, &dss->pvcontrol);
> - return;
> -
> - err:
> - domain_suspend_common_failed(egc, dss);
> -}
> -
> -static void domain_suspend_common_wait_guest_evtchn(libxl__egc *egc,
> - libxl__ev_evtchn *evev)
> -{
> - libxl__domain_suspend_state *dss = CONTAINER_OF(evev, *dss,
> guest_evtchn);
> - STATE_AO_GC(dss->ao);
> - /* If we should be done waiting, suspend_common_wait_guest_check
> - * will end up calling domain_suspend_common_guest_suspended or
> - * domain_suspend_common_failed, both of which cancel the evtchn
> - * wait. So re-enable it now. */
> - libxl__ev_evtchn_wait(gc, &dss->guest_evtchn);
> - suspend_common_wait_guest_check(egc, dss);
> -}
> -
> -static void domain_suspend_common_pvcontrol_suspending(libxl__egc *egc,
> - libxl__xswait_state *xswa, int rc, const char *state)
> -{
> - libxl__domain_suspend_state *dss = CONTAINER_OF(xswa, *dss, pvcontrol);
> - STATE_AO_GC(dss->ao);
> - xs_transaction_t t = 0;
> -
> - if (!rc && !domain_suspend_pvcontrol_acked(state))
> - /* keep waiting */
> - return;
> -
> - libxl__xswait_stop(gc, &dss->pvcontrol);
> -
> - if (rc == ERROR_TIMEDOUT) {
> - /*
> - * Guest appears to not be responding. Cancel the suspend
> - * request.
> - *
> - * We re-read the suspend node and clear it within a
> - * transaction in order to handle the case where we race
> - * against the guest catching up and acknowledging the request
> - * at the last minute.
> - */
> - for (;;) {
> - rc = libxl__xs_transaction_start(gc, &t);
> - if (rc) goto err;
> -
> - rc = libxl__xs_read_checked(gc, t, xswa->path, &state);
> - if (rc) goto err;
> -
> - if (domain_suspend_pvcontrol_acked(state))
> - /* last minute ack */
> - break;
> -
> - rc = libxl__xs_write_checked(gc, t, xswa->path, "");
> - if (rc) goto err;
> -
> - rc = libxl__xs_transaction_commit(gc, &t);
> - if (!rc) {
> - LOG(ERROR,
> - "guest didn't acknowledge suspend, cancelling request");
> - goto err;
> - }
> - if (rc<0) goto err;
> - }
> - } else if (rc) {
> - /* some error in xswait's read of xenstore, already logged */
> - goto err;
> - }
> -
> - assert(domain_suspend_pvcontrol_acked(state));
> - LOG(DEBUG, "guest acknowledged suspend request");
> -
> - libxl__xs_transaction_abort(gc, &t);
> - dss->guest_responded = 1;
> - domain_suspend_common_wait_guest(egc,dss);
> - return;
> -
> - err:
> - libxl__xs_transaction_abort(gc, &t);
> - domain_suspend_common_failed(egc, dss);
> - return;
> -}
> -
> -static void domain_suspend_common_wait_guest(libxl__egc *egc,
> - libxl__domain_suspend_state
> *dss)
> -{
> - STATE_AO_GC(dss->ao);
> - int rc;
> -
> - LOG(DEBUG, "wait for the guest to suspend");
> -
> - rc = libxl__ev_xswatch_register(gc, &dss->guest_watch,
> - suspend_common_wait_guest_watch,
> - "@releaseDomain");
> - if (rc) goto err;
> -
> - rc = libxl__ev_time_register_rel(gc, &dss->guest_timeout,
> - suspend_common_wait_guest_timeout,
> - 60*1000);
> - if (rc) goto err;
> - return;
> -
> - err:
> - domain_suspend_common_failed(egc, dss);
> -}
> -
> -static void suspend_common_wait_guest_watch(libxl__egc *egc,
> - libxl__ev_xswatch *xsw, const char *watch_path, const char *event_path)
> -{
> - libxl__domain_suspend_state *dss = CONTAINER_OF(xsw, *dss, guest_watch);
> - suspend_common_wait_guest_check(egc, dss);
> -}
> -
> -static void suspend_common_wait_guest_check(libxl__egc *egc,
> - libxl__domain_suspend_state *dss)
> -{
> - STATE_AO_GC(dss->ao);
> - xc_domaininfo_t info;
> - int ret;
> - int shutdown_reason;
> -
> - /* Convenience aliases */
> - const uint32_t domid = dss->domid;
> -
> - ret = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
> - if (ret < 0) {
> - LOGE(ERROR, "unable to check for status of guest %"PRId32"", domid);
> - goto err;
> - }
> -
> - if (!(ret == 1 && info.domain == domid)) {
> - LOGE(ERROR, "guest %"PRId32" we were suspending has been destroyed",
> - domid);
> - goto err;
> - }
> -
> - if (!(info.flags & XEN_DOMINF_shutdown))
> - /* keep waiting */
> - return;
> -
> - shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift)
> - & XEN_DOMINF_shutdownmask;
> - if (shutdown_reason != SHUTDOWN_suspend) {
> - LOG(DEBUG, "guest %"PRId32" we were suspending has shut down"
> - " with unexpected reason code %d", domid, shutdown_reason);
> - goto err;
> - }
> -
> - LOG(DEBUG, "guest has suspended");
> - domain_suspend_common_guest_suspended(egc, dss);
> - return;
> -
> - err:
> - domain_suspend_common_failed(egc, dss);
> -}
> -
> -static void suspend_common_wait_guest_timeout(libxl__egc *egc,
> - libxl__ev_time *ev, const struct timeval *requested_abs)
> -{
> - libxl__domain_suspend_state *dss = CONTAINER_OF(ev, *dss, guest_timeout);
> - STATE_AO_GC(dss->ao);
> - LOG(ERROR, "guest did not suspend, timed out");
> - domain_suspend_common_failed(egc, dss);
> -}
> -
> -static void domain_suspend_common_guest_suspended(libxl__egc *egc,
> - libxl__domain_suspend_state *dss)
> -{
> - STATE_AO_GC(dss->ao);
> - int ret;
> -
> - libxl__ev_evtchn_cancel(gc, &dss->guest_evtchn);
> - libxl__ev_xswatch_deregister(gc, &dss->guest_watch);
> - libxl__ev_time_deregister(gc, &dss->guest_timeout);
> -
> - if (dss->hvm) {
> - ret = libxl__domain_suspend_device_model(gc, dss);
> - if (ret) {
> - LOG(ERROR, "libxl__domain_suspend_device_model failed ret=%d",
> ret);
> - domain_suspend_common_failed(egc, dss);
> - return;
> - }
> - }
> - domain_suspend_common_done(egc, dss, 1);
> -}
> -
> -static void domain_suspend_common_failed(libxl__egc *egc,
> - libxl__domain_suspend_state *dss)
> -{
> - domain_suspend_common_done(egc, dss, 0);
> -}
> -
> -static void domain_suspend_common_done(libxl__egc *egc,
> - libxl__domain_suspend_state *dss,
> - bool ok)
> -{
> - EGC_GC;
> - assert(!libxl__xswait_inuse(&dss->pvcontrol));
> - libxl__ev_evtchn_cancel(gc, &dss->guest_evtchn);
> - libxl__ev_xswatch_deregister(gc, &dss->guest_watch);
> - libxl__ev_time_deregister(gc, &dss->guest_timeout);
> - dss->callback_common_done(egc, dss, ok);
> -}
> -
> static inline char *physmap_path(libxl__gc *gc, uint32_t dm_domid,
> uint32_t domid,
> char *phys_offset, char *node)
> @@ -1758,22 +1429,6 @@ int libxl__toolstack_save(uint32_t domid, uint8_t
> **buf,
> return 0;
> }
>
> -static void libxl__domain_suspend_callback(void *data)
> -{
> - libxl__save_helper_state *shs = data;
> - libxl__egc *egc = shs->egc;
> - libxl__domain_suspend_state *dss = CONTAINER_OF(shs, *dss, shs);
> -
> - dss->callback_common_done = domain_suspend_callback_common_done;
> - domain_suspend_callback_common(egc, dss);
> -}
> -
> -static void domain_suspend_callback_common_done(libxl__egc *egc,
> - libxl__domain_suspend_state *dss, int ok)
> -{
> - libxl__xc_domain_saverestore_async_callback_done(egc, &dss->shs, ok);
> -}
> -
> /*----- remus callbacks -----*/
> static void remus_domain_suspend_callback_common_done(libxl__egc *egc,
> libxl__domain_suspend_state *dss, int ok);
> @@ -1791,7 +1446,7 @@ static void libxl__remus_domain_suspend_callback(void
> *data)
> libxl__domain_suspend_state *dss = CONTAINER_OF(shs, *dss, shs);
>
> dss->callback_common_done = remus_domain_suspend_callback_common_done;
> - domain_suspend_callback_common(egc, dss);
> + libxl__domain_suspend(egc, dss);
> }
>
> static void remus_domain_suspend_callback_common_done(libxl__egc *egc,
> @@ -1959,6 +1614,9 @@ static void remus_next_checkpoint(libxl__egc *egc,
> libxl__ev_time *ev,
>
> /*----- main code for suspending, in order of execution -----*/
>
> +static void domain_save_done(libxl__egc *egc,
> + libxl__domain_suspend_state *dss, int rc);
> +
> void libxl__domain_save(libxl__egc *egc, libxl__domain_suspend_state *dss)
> {
> STATE_AO_GC(dss->ao);
> diff --git a/tools/libxl/libxl_dom_suspend.c b/tools/libxl/libxl_dom_suspend.c
> new file mode 100644
> index 0000000..ef8d60b
> --- /dev/null
> +++ b/tools/libxl/libxl_dom_suspend.c
> @@ -0,0 +1,381 @@
> +/*
> + * Copyright (C) 2009 Citrix Ltd.
> + * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include "libxl_osdeps.h" /* must come before any other headers */
> +
> +#include "libxl_internal.h"
> +
> +/*==================== Domain suspend ====================*/
> +
> +static void domain_suspend_callback_common_done(libxl__egc *egc,
> + libxl__domain_suspend_state *dss, int ok);
> +
> +/*----- callbacks, called by xc_domain_save -----*/
> +
> +int libxl__domain_suspend_device_model(libxl__gc *gc,
> + libxl__domain_suspend_state *dss)
> +{
> + int ret = 0;
> + uint32_t const domid = dss->domid;
> + const char *const filename = dss->dm_savefile;
> +
> + switch (libxl__device_model_version_running(gc, domid)) {
> + case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL: {
> + LOG(DEBUG, "Saving device model state to %s", filename);
> + libxl__qemu_traditional_cmd(gc, domid, "save");
> + libxl__wait_for_device_model_deprecated(gc, domid, "paused", NULL,
> NULL, NULL);
> + break;
> + }
> + case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
> + if (libxl__qmp_stop(gc, domid))
> + return ERROR_FAIL;
> + /* Save DM state into filename */
> + ret = libxl__qmp_save(gc, domid, filename);
> + if (ret)
> + unlink(filename);
> + break;
> + default:
> + return ERROR_INVAL;
> + }
> +
> + return ret;
> +}
> +
> +static void domain_suspend_common_wait_guest(libxl__egc *egc,
> + libxl__domain_suspend_state
> *dss);
> +static void domain_suspend_common_guest_suspended(libxl__egc *egc,
> + libxl__domain_suspend_state *dss);
> +
> +static void domain_suspend_common_pvcontrol_suspending(libxl__egc *egc,
> + libxl__xswait_state *xswa, int rc, const char *state);
> +static void domain_suspend_common_wait_guest_evtchn(libxl__egc *egc,
> + libxl__ev_evtchn *evev);
> +static void suspend_common_wait_guest_watch(libxl__egc *egc,
> + libxl__ev_xswatch *xsw, const char *watch_path, const char
> *event_path);
> +static void suspend_common_wait_guest_check(libxl__egc *egc,
> + libxl__domain_suspend_state *dss);
> +static void suspend_common_wait_guest_timeout(libxl__egc *egc,
> + libxl__ev_time *ev, const struct timeval *requested_abs);
> +
> +static void domain_suspend_common_failed(libxl__egc *egc,
> + libxl__domain_suspend_state *dss);
> +static void domain_suspend_common_done(libxl__egc *egc,
> + libxl__domain_suspend_state *dss,
> + bool ok);
> +static void domain_suspend_callback_common(libxl__egc *egc,
> + libxl__domain_suspend_state *dss);
> +
> +static bool domain_suspend_pvcontrol_acked(const char *state) {
> + /* any value other than "suspend", including ENOENT (i.e. !state), is OK
> */
> + if (!state) return 1;
> + return strcmp(state,"suspend");
> +}
> +
> +/* calls dss->callback_common_done when done */
> +void libxl__domain_suspend(libxl__egc *egc,
> + libxl__domain_suspend_state *dss)
> +{
> + domain_suspend_callback_common(egc, dss);
> +}
> +
> +/* calls dss->callback_common_done when done */
> +static void domain_suspend_callback_common(libxl__egc *egc,
> + libxl__domain_suspend_state *dss)
> +{
> + STATE_AO_GC(dss->ao);
> + uint64_t hvm_s_state = 0, hvm_pvdrv = 0;
> + int ret, rc;
> +
> + /* Convenience aliases */
> + const uint32_t domid = dss->domid;
> +
> + if (dss->hvm) {
> + xc_hvm_param_get(CTX->xch, domid, HVM_PARAM_CALLBACK_IRQ,
> &hvm_pvdrv);
> + xc_hvm_param_get(CTX->xch, domid, HVM_PARAM_ACPI_S_STATE,
> &hvm_s_state);
> + }
> +
> + if ((hvm_s_state == 0) && (dss->guest_evtchn.port >= 0)) {
> + LOG(DEBUG, "issuing %s suspend request via event channel",
> + dss->hvm ? "PVHVM" : "PV");
> + ret = xc_evtchn_notify(CTX->xce, dss->guest_evtchn.port);
> + if (ret < 0) {
> + LOG(ERROR, "xc_evtchn_notify failed ret=%d", ret);
> + goto err;
> + }
> +
> + dss->guest_evtchn.callback = domain_suspend_common_wait_guest_evtchn;
> + rc = libxl__ev_evtchn_wait(gc, &dss->guest_evtchn);
> + if (rc) goto err;
> +
> + rc = libxl__ev_time_register_rel(gc, &dss->guest_timeout,
> + suspend_common_wait_guest_timeout,
> + 60*1000);
> + if (rc) goto err;
> +
> + return;
> + }
> +
> + if (dss->hvm && (!hvm_pvdrv || hvm_s_state)) {
> + LOG(DEBUG, "Calling xc_domain_shutdown on HVM domain");
> + ret = xc_domain_shutdown(CTX->xch, domid, SHUTDOWN_suspend);
> + if (ret < 0) {
> + LOGE(ERROR, "xc_domain_shutdown failed");
> + goto err;
> + }
> + /* The guest does not (need to) respond to this sort of request. */
> + dss->guest_responded = 1;
> + domain_suspend_common_wait_guest(egc, dss);
> + return;
> + }
> +
> + LOG(DEBUG, "issuing %s suspend request via XenBus control node",
> + dss->hvm ? "PVHVM" : "PV");
> +
> + libxl__domain_pvcontrol_write(gc, XBT_NULL, domid, "suspend");
> +
> + dss->pvcontrol.path = libxl__domain_pvcontrol_xspath(gc, domid);
> + if (!dss->pvcontrol.path) goto err;
> +
> + dss->pvcontrol.ao = ao;
> + dss->pvcontrol.what = "guest acknowledgement of suspend request";
> + dss->pvcontrol.timeout_ms = 60 * 1000;
> + dss->pvcontrol.callback = domain_suspend_common_pvcontrol_suspending;
> + libxl__xswait_start(gc, &dss->pvcontrol);
> + return;
> +
> + err:
> + domain_suspend_common_failed(egc, dss);
> +}
> +
> +static void domain_suspend_common_wait_guest_evtchn(libxl__egc *egc,
> + libxl__ev_evtchn *evev)
> +{
> + libxl__domain_suspend_state *dss = CONTAINER_OF(evev, *dss,
> guest_evtchn);
> + STATE_AO_GC(dss->ao);
> + /* If we should be done waiting, suspend_common_wait_guest_check
> + * will end up calling domain_suspend_common_guest_suspended or
> + * domain_suspend_common_failed, both of which cancel the evtchn
> + * wait. So re-enable it now. */
> + libxl__ev_evtchn_wait(gc, &dss->guest_evtchn);
> + suspend_common_wait_guest_check(egc, dss);
> +}
> +
> +static void domain_suspend_common_pvcontrol_suspending(libxl__egc *egc,
> + libxl__xswait_state *xswa, int rc, const char *state)
> +{
> + libxl__domain_suspend_state *dss = CONTAINER_OF(xswa, *dss, pvcontrol);
> + STATE_AO_GC(dss->ao);
> + xs_transaction_t t = 0;
> +
> + if (!rc && !domain_suspend_pvcontrol_acked(state))
> + /* keep waiting */
> + return;
> +
> + libxl__xswait_stop(gc, &dss->pvcontrol);
> +
> + if (rc == ERROR_TIMEDOUT) {
> + /*
> + * Guest appears to not be responding. Cancel the suspend
> + * request.
> + *
> + * We re-read the suspend node and clear it within a
> + * transaction in order to handle the case where we race
> + * against the guest catching up and acknowledging the request
> + * at the last minute.
> + */
> + for (;;) {
> + rc = libxl__xs_transaction_start(gc, &t);
> + if (rc) goto err;
> +
> + rc = libxl__xs_read_checked(gc, t, xswa->path, &state);
> + if (rc) goto err;
> +
> + if (domain_suspend_pvcontrol_acked(state))
> + /* last minute ack */
> + break;
> +
> + rc = libxl__xs_write_checked(gc, t, xswa->path, "");
> + if (rc) goto err;
> +
> + rc = libxl__xs_transaction_commit(gc, &t);
> + if (!rc) {
> + LOG(ERROR,
> + "guest didn't acknowledge suspend, cancelling request");
> + goto err;
> + }
> + if (rc<0) goto err;
> + }
> + } else if (rc) {
> + /* some error in xswait's read of xenstore, already logged */
> + goto err;
> + }
> +
> + assert(domain_suspend_pvcontrol_acked(state));
> + LOG(DEBUG, "guest acknowledged suspend request");
> +
> + libxl__xs_transaction_abort(gc, &t);
> + dss->guest_responded = 1;
> + domain_suspend_common_wait_guest(egc,dss);
> + return;
> +
> + err:
> + libxl__xs_transaction_abort(gc, &t);
> + domain_suspend_common_failed(egc, dss);
> + return;
> +}
> +
> +static void domain_suspend_common_wait_guest(libxl__egc *egc,
> + libxl__domain_suspend_state
> *dss)
> +{
> + STATE_AO_GC(dss->ao);
> + int rc;
> +
> + LOG(DEBUG, "wait for the guest to suspend");
> +
> + rc = libxl__ev_xswatch_register(gc, &dss->guest_watch,
> + suspend_common_wait_guest_watch,
> + "@releaseDomain");
> + if (rc) goto err;
> +
> + rc = libxl__ev_time_register_rel(gc, &dss->guest_timeout,
> + suspend_common_wait_guest_timeout,
> + 60*1000);
> + if (rc) goto err;
> + return;
> +
> + err:
> + domain_suspend_common_failed(egc, dss);
> +}
> +
> +static void suspend_common_wait_guest_watch(libxl__egc *egc,
> + libxl__ev_xswatch *xsw, const char *watch_path, const char *event_path)
> +{
> + libxl__domain_suspend_state *dss = CONTAINER_OF(xsw, *dss, guest_watch);
> + suspend_common_wait_guest_check(egc, dss);
> +}
> +
> +static void suspend_common_wait_guest_check(libxl__egc *egc,
> + libxl__domain_suspend_state *dss)
> +{
> + STATE_AO_GC(dss->ao);
> + xc_domaininfo_t info;
> + int ret;
> + int shutdown_reason;
> +
> + /* Convenience aliases */
> + const uint32_t domid = dss->domid;
> +
> + ret = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
> + if (ret < 0) {
> + LOGE(ERROR, "unable to check for status of guest %"PRId32"", domid);
> + goto err;
> + }
> +
> + if (!(ret == 1 && info.domain == domid)) {
> + LOGE(ERROR, "guest %"PRId32" we were suspending has been destroyed",
> + domid);
> + goto err;
> + }
> +
> + if (!(info.flags & XEN_DOMINF_shutdown))
> + /* keep waiting */
> + return;
> +
> + shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift)
> + & XEN_DOMINF_shutdownmask;
> + if (shutdown_reason != SHUTDOWN_suspend) {
> + LOG(DEBUG, "guest %"PRId32" we were suspending has shut down"
> + " with unexpected reason code %d", domid, shutdown_reason);
> + goto err;
> + }
> +
> + LOG(DEBUG, "guest has suspended");
> + domain_suspend_common_guest_suspended(egc, dss);
> + return;
> +
> + err:
> + domain_suspend_common_failed(egc, dss);
> +}
> +
> +static void suspend_common_wait_guest_timeout(libxl__egc *egc,
> + libxl__ev_time *ev, const struct timeval *requested_abs)
> +{
> + libxl__domain_suspend_state *dss = CONTAINER_OF(ev, *dss, guest_timeout);
> + STATE_AO_GC(dss->ao);
> + LOG(ERROR, "guest did not suspend, timed out");
> + domain_suspend_common_failed(egc, dss);
> +}
> +
> +static void domain_suspend_common_guest_suspended(libxl__egc *egc,
> + libxl__domain_suspend_state *dss)
> +{
> + STATE_AO_GC(dss->ao);
> + int ret;
> +
> + libxl__ev_evtchn_cancel(gc, &dss->guest_evtchn);
> + libxl__ev_xswatch_deregister(gc, &dss->guest_watch);
> + libxl__ev_time_deregister(gc, &dss->guest_timeout);
> +
> + if (dss->hvm) {
> + ret = libxl__domain_suspend_device_model(gc, dss);
> + if (ret) {
> + LOG(ERROR, "libxl__domain_suspend_device_model failed ret=%d",
> ret);
> + domain_suspend_common_failed(egc, dss);
> + return;
> + }
> + }
> + domain_suspend_common_done(egc, dss, 1);
> +}
> +
> +static void domain_suspend_common_failed(libxl__egc *egc,
> + libxl__domain_suspend_state *dss)
> +{
> + domain_suspend_common_done(egc, dss, 0);
> +}
> +
> +static void domain_suspend_common_done(libxl__egc *egc,
> + libxl__domain_suspend_state *dss,
> + bool ok)
> +{
> + EGC_GC;
> + assert(!libxl__xswait_inuse(&dss->pvcontrol));
> + libxl__ev_evtchn_cancel(gc, &dss->guest_evtchn);
> + libxl__ev_xswatch_deregister(gc, &dss->guest_watch);
> + libxl__ev_time_deregister(gc, &dss->guest_timeout);
> + dss->callback_common_done(egc, dss, ok);
> +}
> +
> +void libxl__domain_suspend_callback(void *data)
> +{
> + libxl__save_helper_state *shs = data;
> + libxl__egc *egc = shs->egc;
> + libxl__domain_suspend_state *dss = CONTAINER_OF(shs, *dss, shs);
> +
> + dss->callback_common_done = domain_suspend_callback_common_done;
> + domain_suspend_callback_common(egc, dss);
> +}
> +
> +static void domain_suspend_callback_common_done(libxl__egc *egc,
> + libxl__domain_suspend_state *dss, int ok)
> +{
> + libxl__xc_domain_saverestore_async_callback_done(egc, &dss->shs, ok);
> +}
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index e765d68..8e59b98 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -3185,6 +3185,12 @@ _hidden void
> libxl__domain_save_device_model(libxl__egc *egc,
>
> _hidden const char *libxl__device_model_savefile(libxl__gc *gc, uint32_t
> domid);
>
> +/* calls dss->callback_common_done when done */
> +_hidden void libxl__domain_suspend(libxl__egc *egc,
> + libxl__domain_suspend_state *dss);
> +
> +/* used by libxc to suspend the guest during migration */
> +_hidden void libxl__domain_suspend_callback(void *data);
>
> /*
> * Convenience macros.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |