[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.