[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Re: [PATCH] libxl/xl: improve behaviour when guest fails to suspend itself



BTW, this depends on "libxl: allow guest to write "control/shutdown"
xenstore node"

I'm vaguely hopeful that it will cause RHEL6 HVM suspend/migration to
fail gracefully instead of collapsing in a heap.

Ian.

On Tue, 2011-02-08 at 17:24 +0000, Ian Campbell wrote:
> # HG changeset patch
> # User Ian Campbell <ian.campbell@xxxxxxxxxx>
> # Date 1297185819 0
> # Node ID d631a4996cbc69a7fa8489f28d4a3313db12e77a
> # Parent  a46b91cd8202726aecd9ddefd8e75faff48144d6
> libxl/xl: improve behaviour when guest fails to suspend itself.
> 
> The PV suspend protocol requires guest co-operating whereby the guest
> must respond to a suspend request written to the xenstore control node
> by clearing the node and then making a suspend hypercall.
> 
> Currently when a guest fails to do this libxl times out and returns
> a generic failure code to the caller.
> 
> In response to this failure xl attempts to resume the guest. However
> if the guest has not responded to the suspend request then the is no
> guarantee that the guest has made the suspend hypercall (in fact it is
> quite unlikely). Since the resume process attempts to modify the
> return value of the hypercall (to indicate a cancelled suspend) this
> results in the guest eax/rax register being corrupted!
> 
> To fix this change libxl to do the following:
>    * Wait for the guest to acknowledge the suspend request.
>      - on timeout cancel the suspend request.
>        - if cancellation is successful then return a new error code to
>          indicate that the guest is not responding.
>        - if the cancel does not succeed then we raced with the guest
>          which actually did acknowledge at the last minute, so
>          continue.
>    * Wait for the guest to suspend.
>      - on timeout return the standard error code as before
>    * Guest successfully suspended, return success.
> 
> Lastly in xl do not attempt to resume a guest if it has not responded
> to the suspend request.
> 
> Tested by live migration of PVops kernels which either ignore the
> suspend request, have already crashed and those which suspend/resume
> correctly. In the first two cases the source domain is left alone (and
> continues to function in the first case) and in the third the
> migration is successful.
> 
> Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
> 
> diff -r a46b91cd8202 -r d631a4996cbc tools/libxl/libxl.h
> --- a/tools/libxl/libxl.h     Tue Feb 08 16:26:07 2011 +0000
> +++ b/tools/libxl/libxl.h     Tue Feb 08 17:23:39 2011 +0000
> @@ -239,6 +239,7 @@ enum {
>      ERROR_NOMEM = -5,
>      ERROR_INVAL = -6,
>      ERROR_BADFAIL = -7,
> +    ERROR_GUEST_TIMEDOUT = -8,
>  };
>  
>  #define LIBXL_VERSION 0
> diff -r a46b91cd8202 -r d631a4996cbc tools/libxl/libxl_dom.c
> --- a/tools/libxl/libxl_dom.c Tue Feb 08 16:26:07 2011 +0000
> +++ b/tools/libxl/libxl_dom.c Tue Feb 08 17:23:39 2011 +0000
> @@ -320,6 +320,7 @@ struct suspendinfo {
>      int domid;
>      int hvm;
>      unsigned int flags;
> +    int guest_responded;
>  };
>  
>  static int libxl__domain_suspend_common_switch_qemu_logdirty(int domid, 
> unsigned int enable, void *data)
> @@ -347,8 +348,9 @@ static int libxl__domain_suspend_common_
>      unsigned long s_state = 0;
>      int ret;
>      char *path, *state = "suspend";
> -    int watchdog = 60;
> +    int watchdog;
>      libxl_ctx *ctx = libxl__gc_owner(si->gc);
> +    xs_transaction_t t;
>  
>      if (si->hvm)
>          xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, 
> &s_state);
> @@ -363,6 +365,7 @@ static int libxl__domain_suspend_common_
>              LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "xc_await_suspend failed 
> ret=%d", ret);
>              return 0;
>          }
> +        si->guest_responded = 1;
>          return 1;
>      }
>      path = libxl__sprintf(si->gc, "%s/control/shutdown", 
> libxl__xs_get_dompath(si->gc, si->domid));
> @@ -376,8 +379,56 @@ static int libxl__domain_suspend_common_
>              xc_domain_shutdown(ctx->xch, si->domid, SHUTDOWN_suspend);
>          }
>      }
> +
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "wait for the guest to acknowledge 
> suspend request");
> +    watchdog = 60;
> +    while (!strcmp(state, "suspend") && watchdog > 0) {
> +        usleep(100000);
> +
> +        state = libxl__xs_read(si->gc, XBT_NULL, path);
> +
> +        watchdog--;
> +    }
> +
> +    /*
> +     * 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.
> +     */
> +    if (!strcmp(state, "suspend")) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest didn't acknowledge suspend, 
> cancelling request");
> +    retry_transaction:
> +        t = xs_transaction_start(ctx->xsh);
> +
> +        state = libxl__xs_read(si->gc, t, path);
> +
> +        if (!strcmp(state, "suspend"))
> +            libxl__xs_write(si->gc, t, path, "");
> +
> +        if (!xs_transaction_end(ctx->xsh, t, 0))
> +            if (errno == EAGAIN)
> +                goto retry_transaction;
> +
> +    }
> +
> +    /*
> +     * Final check for guest acknowledgement. The guest may have
> +     * acknowledged while we were cancelling the request in which case
> +     * we lost the race while cancelling and should continue.
> +     */
> +    if (!strcmp(state, "suspend")) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest didn't acknowledge suspend, 
> request cancelled");
> +        return 0;
> +    }
> +
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "guest acknowledged suspend request");
> +    si->guest_responded = 1;
> +
>      LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "wait for the guest to suspend");
> -    while (!strcmp(state, "suspend") && watchdog > 0) {
> +    watchdog = 60;
> +    while (watchdog > 0) {
>          xc_domaininfo_t info;
>  
>          usleep(100000);
> @@ -386,17 +437,17 @@ static int libxl__domain_suspend_common_
>              int shutdown_reason;
>  
>              shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift) & 
> XEN_DOMINF_shutdownmask;
> -            if (shutdown_reason == SHUTDOWN_suspend)
> +            if (shutdown_reason == SHUTDOWN_suspend) {
> +                LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "guest has suspended");
>                  return 1;
> +            }
>          }
> -        state = libxl__xs_read(si->gc, XBT_NULL, path);
> +
>          watchdog--;
>      }
> -    if (!strcmp(state, "suspend")) {
> -        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest didn't suspend in time");
> -        libxl__xs_write(si->gc, XBT_NULL, path, "");
> -    }
> -    return 1;
> +
> +    LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest did not suspend");
> +    return 0;
>  }
>  
>  int libxl__domain_suspend_common(libxl_ctx *ctx, uint32_t domid, int fd,
> @@ -418,6 +469,7 @@ int libxl__domain_suspend_common(libxl_c
>      si.hvm = hvm;
>      si.gc = &gc;
>      si.suspend_eventchn = -1;
> +    si.guest_responded = 0;
>  
>      si.xce = xc_evtchn_open(NULL, 0);
>      if (si.xce == NULL)
> @@ -441,8 +493,14 @@ int libxl__domain_suspend_common(libxl_c
>  
>      rc = xc_domain_save(ctx->xch, fd, domid, 0, 0, flags, &callbacks, hvm);
>      if ( rc ) {
> -        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "saving domain");
> -        rc = ERROR_FAIL;
> +        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "saving domain: %s",
> +                         si.guest_responded ?
> +                         "domain responded to suspend request" :
> +                         "domain did not respond to suspend request");
> +        if ( !si.guest_responded )
> +            rc = ERROR_GUEST_TIMEDOUT;
> +        else
> +            rc = ERROR_FAIL;
>      }
>  
>      if (si.suspend_eventchn > 0)
> diff -r a46b91cd8202 -r d631a4996cbc tools/libxl/xl_cmdimpl.c
> --- a/tools/libxl/xl_cmdimpl.c        Tue Feb 08 16:26:07 2011 +0000
> +++ b/tools/libxl/xl_cmdimpl.c        Tue Feb 08 17:23:39 2011 +0000
> @@ -2583,7 +2583,10 @@ static void migrate_domain(const char *d
>      if (rc) {
>          fprintf(stderr, "migration sender: libxl_domain_suspend failed"
>                  " (rc=%d)\n", rc);
> -        goto failed_resume;
> +        if (rc == ERROR_GUEST_TIMEDOUT)
> +            goto failed_suspend;
> +        else
> +            goto failed_resume;
>      }
>  
>      //fprintf(stderr, "migration sender: Transfer complete.\n");
> @@ -2661,6 +2664,12 @@ static void migrate_domain(const char *d
>      libxl_domain_destroy(&ctx, domid, 1); /* bang! */
>      fprintf(stderr, "Migration successful.\n");
>      exit(0);
> +
> + failed_suspend:
> +    close(send_fd);
> +    migration_child_report(child, recv_fd);
> +    fprintf(stderr, "Migration failed, failed to suspend at sender.\n");
> +    exit(-ERROR_FAIL);
>  
>   failed_resume:
>      close(send_fd);



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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