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

Re: [Xen-devel] [PATCH 1 of 2] libxl: async version of domain suspend



On Sunday, November 24, 2013, Shriram Rajagopalan wrote:
# HG changeset patch
# User Shriram Rajagopalan <rshriram@xxxxxxxxx>
# Date 1385309833 28800
# Node ID c7fdc18830cd46018ced3afb1cde23121a716a6e
# Parent  987d21e4498495e7bbd794bf6eb8d18a8219a081
libxl: async version of domain suspend

Add functions that can be used to implement an asynchronous version
of domain suspend.  This patch does not replace the existing synchronous
implementation of domain suspend.  The code introduced in this patch is
redundant, based on libxl__domain_suspend_common_callback.

Also add a callout to Remus (libxl__domain_suspend_callback_remus) that
gets called post domain suspend.  Remus specific post-suspend tasks can be
implemented here.

Signed-off-by: Shriram Rajagopalan <rshriram@xxxxxxxxx>

diff -r 987d21e44984 -r c7fdc18830cd tools/libxl/libxl_dom.c
--- a/tools/libxl/libxl_dom.c   Sun Nov 24 08:09:19 2013 -0800
+++ b/tools/libxl/libxl_dom.c   Sun Nov 24 08:17:13 2013 -0800
@@ -1016,6 +1016,196 @@ int libxl__domain_resume_device_model(li
     return 0;
 }

+static int cancel_xenbus_suspend_request(libxl__gc *gc, uint32_t domid);
+static void wait_for_ack_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                 const struct timeval *requested_abs);
+static void wait_for_suspend_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                     const struct timeval *requested_abs);
+static void wait_for_suspend_req_ack(libxl__domain_suspend_state *dss);
+static void wait_for_guest_suspend(libxl__domain_suspend_state *dss);
+static void guest_suspended(libxl__domain_suspend_state *dss);
+static int libxl__domain_suspend_callback_remus(libxl__domain_suspend_state *dss);
+
+/* Returns 0 if suspend request was cancelled and the guest did not
+ * respond during the cancellation process (see comments in function for
+ * explanation of race conditions).
+ * Returns 1 if guest had finally acked suspend request, during the
+ * cancellation process.
+ */
+static int cancel_xenbus_suspend_request(libxl__gc *gc, uint32_t domid)
+{
+    char *state = NULL;
+    xs_transaction_t t;
+
+    /*
+     * 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.
+     */
+    LOG(ERROR, "guest didn't acknowledge suspend, cancelling request");
+ retry_transaction:
+    t = xs_transaction_start(CTX->xsh);
+
+    state = libxl__domain_pvcontrol_read(gc, t, domid);
+    if (!state) state = "";
+
+    if (!strcmp(state, "suspend"))
+        libxl__domain_pvcontrol_write(gc, t, domid, "");
+
+    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")) {
+        LOG(ERROR, "guest didn't acknowledge suspend, request cancelled");
+        return 0;
+    }
+
+    return 1;
+}
+
+static void wait_for_ack_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                 const struct timeval *requested_abs)
+{
+    libxl__domain_suspend_state *dss = CONTAINER_OF(ev, *dss, timeout);
+    STATE_AO_GC(dss->ao);
+
+    libxl__ev_time_deregister(gc, &dss->timeout);
+    dss->watchdog--;
+    wait_for_suspend_req_ack(dss);
+}
+
+static void wait_for_suspend_req_ack(libxl__domain_suspend_state *dss)
+{
+    char *state = NULL;
+    int ret;
+    int wait_time;
+    STATE_AO_GC(dss->ao);
+
+    state = libxl__domain_pvcontrol_read(gc, XBT_NULL, dss->domid);
+
+    if (!state) state = "";
+
+    if (!strcmp(state, "suspend") && dss->watchdog > 0) {
+        /* The first timeout is a short one (10ms), hoping that the
+         * guest would respond immediately. The subsequent timeouts
+         * are longer (40ms).
+         */
+        wait_time = dss->watchdog_starting ? 10 : 40;
+        dss->watchdog_starting = 0;
+        ret = libxl__ev_time_register_rel(gc, &dss->timeout,
+                                          wait_for_ack_timeout, wait_time);
+        if (ret) {
+            LOG(ERROR, "unable to register timeout event to wait for"
+                " guest to suspend ack. Cancelling suspend request");
+            goto cancel_req;
+        }
+        return;
+    }
+
+    if (strcmp(state, "suspend")) {
+    ack:
+        LOG(DEBUG, "guest acknowledged suspend request");
+        dss->guest_responded = 1;
+        dss->watchdog = 60;
+        dss->watchdog_starting = 1;
+        wait_for_guest_suspend(dss);
+        return;
+    }
+
+ cancel_req: //either timer reg. failed or watchdog loop ended
+    if (cancel_xenbus_suspend_request(gc, dss->domid))
+        goto ack;
+
+    libxl__xc_domain_saverestore_async_callback_done(dss->shs.egc, &dss->shs, 0);
+}
+
+static void wait_for_suspend_timeout(libxl__egc *egc, libxl__ev_time *ev,
+                                     const struct timeval *requested_abs)
+{
+    libxl__domain_suspend_state *dss = CONTAINER_OF(ev, *dss, timeout);
+    STATE_AO_GC(dss->ao);
+
+    libxl__ev_time_deregister(gc, &dss->timeout);
+    dss->watchdog--;
+    wait_for_guest_suspend(dss);
+}
+
+static void wait_for_guest_suspend(libxl__domain_suspend_state *dss)
+{
+    int ret;
+    int wait_time;
+    xc_domaininfo_t info;
+    STATE_AO_GC(dss->ao);
+
+    ret = xc_domain_getinfolist(CTX->xch, dss->domid, 1, &info);
+    if (ret == 1 && info.domain == dss->domid &&
+        (info.flags & XEN_DOMINF_shutdown)) {
+        int shutdown_reason;
+
+        shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift)
+            & XEN_DOMINF_shutdownmask;
+        if (shutdown_reason == SHUTDOWN_suspend) {
+            LOG(DEBUG, "guest has suspended");
+            guest_suspended(dss);
+            return;
+        }
+    }
+
+    if (dss->watchdog > 0) {
+        /* The first timeout is a short one (10ms), hoping that the
+         * guest would respond immediately. The subsequent timeouts
+         * are longer (40ms).
+         */
+        wait_time = dss->watchdog_starting ? 10 : 40;
+        dss->watchdog_starting = 0;
+        ret = libxl__ev_time_register_rel(gc, &dss->timeout,
+                                          wait_for_suspend_timeout, wait_time);
+        if (ret) {
+            LOG(ERROR, "unable to register timeout event to wait for"
+                " guest to suspend.");
+            goto err;
+        }
+        return;
+    }
+
+    LOG(ERROR, "guest did not suspend");
+ err:
+    libxl__xc_domain_saverestore_async_callback_done(dss->shs.egc,
+                                                     &dss->shs, 0);
+}
+
+static void guest_suspended(libxl__domain_suspend_state *dss)
+{
+    int ret, ok = 1;
+    STATE_AO_GC(dss->ao);
+    if (dss->hvm) {
+        ret = libxl__domain_suspend_device_model(gc, dss);
+        if (ret) {
+            LOG(ERROR, "libxl__domain_suspend_device_model failed "
+                "ret=%d", ret);
+            ok = 0;
+            goto end;
+        }
+    }
+
+    if (dss->remus_ctx)
+        ok = libxl__domain_suspend_callback_remus(dss);
+
+ end:
+    libxl__xc_domain_saverestore_async_callback_done(dss->shs.egc,
+                                                     &dss->shs, ok);
+}
+
 int libxl__domain_suspend_common_callback(void *user)
 {
     libxl__save_helper_state *shs = user;
@@ -1285,6 +1475,28 @@ void libxl__remus_teardown_done(libxl__e

 /*----- remus callbacks -----*/

+/* Remus specific tasks to be executed post domain suspend */
+static int libxl__domain_suspend_callback_remus(libxl__domain_suspend_state *dss)
+{
+    libxl__remus_ctx *remus_ctx = dss->remus_ctx;
+    STATE_AO_GC(dss->ao);
+
+    /* REMUS TODO: Issue disk checkpoint reqs. */
+    if (!remus_ctx->netbuf_ctx)
+        return 1;
+
+    /* Start a new network
+     * buffer for the next epoch. If this operation fails, then act
+     * as though domain suspend failed -- libxc exits its infinite
+     * loop and ultimately, the replication stops.
+     */
+    if (libxl__remus_netbuf_start_new_epoch(gc, dss->domid,
+                                            remus_ctx))
+        return 0;
+
+    return 1;
+}
+
 static int libxl__remus_domain_suspend_callback(void *data)
 {
     libxl__save_helper_state *shs = data;
@@ -1416,6 +1628,7 @@ void libxl__domain_suspend(libxl__egc *e
         &dss->shs.callbacks.save.a;

     logdirty_init(&dss->logdirty);
+    libxl__ev_time_init(&dss->timeout);

     switch (type) {
     case LIBXL_DOMAIN_TYPE_HVM: {
diff -r 987d21e44984 -r c7fdc18830cd tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Sun Nov 24 08:09:19 2013 -0800
+++ b/tools/libxl/libxl_internal.h      Sun Nov 24 08:17:13 2013 -0800
@@ -2352,6 +2352,9 @@ struct libxl__domain_suspend_state {
     int hvm;
     int xcflags;
     int guest_responded;
+    int watchdog;
+    int watchdog_starting;
+    libxl__ev_time timeout;
     const char *dm_savefile;
     libxl__save_helper_state shs;
     libxl__logdirty_switch logdirty;

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

Ping! Ian J/Ian C - any comments on this? 
_______________________________________________
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®.