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

[Xen-devel] [PATCH RFC v2 8/8] Added support to handle QMP events



---
 tools/libxl/libxl_dom_save.c |  71 ++++++++------------
 tools/libxl/libxl_qmp.c      | 150 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 170 insertions(+), 51 deletions(-)

diff --git a/tools/libxl/libxl_dom_save.c b/tools/libxl/libxl_dom_save.c
index ddfe2f8..d188dd2 100644
--- a/tools/libxl/libxl_dom_save.c
+++ b/tools/libxl/libxl_dom_save.c
@@ -432,63 +432,44 @@ static void mirror_qemu_disks(libxl__egc *egc, 
libxl__stream_write_state *sws,
 {
     int counter = 20;
     char* target;
-    bool job_is_ready = false;
     libxl__domain_save_state *dss = sws->dss;
     const uint32_t domid = dss->domid;
     STATE_AO_GC(dss->ao);
 
-    if (dss->mirror_qemu_disks) {
+    if (rc)
+        goto err;
     /*
      * If the -q was provided, the drive-mirror job is started.
-     * TODO: Move the following code as part of the domain_suspend
      * TODO: The port should be sent by the destination.
-    */
-start_mirror:
-        LOGD(DEBUG, domid, "Sleeping for a bit so that source can start 
NBD\n");
-        sleep(30);
-        LOGD(DEBUG, domid, "Starting mirror-drive of device %s\n",
-             QEMU_DRIVE_MIRROR_DEVICE);
-        target = GCSPRINTF("nbd:%s:%s:exportname=%s", dss->hostname,
-                           QEMU_DRIVE_MIRROR_PORT, QEMU_DRIVE_MIRROR_DEVICE);
-        rc = libxl__qmp_drive_mirror(gc, dss->domid, QEMU_DRIVE_MIRROR_DEVICE,
+     */
+ start_mirror:
+    LOGD(DEBUG, domid, "Sleeping for a bit so that source can start NBD\n");
+    sleep(30);
+    LOGD(DEBUG, domid, "Starting mirror-drive of device %s\n",
+         QEMU_DRIVE_MIRROR_DEVICE);
+    target = GCSPRINTF("nbd:%s:%s:exportname=%s", dss->hostname,
+                       QEMU_DRIVE_MIRROR_PORT, QEMU_DRIVE_MIRROR_DEVICE);
+    rc = libxl__qmp_drive_mirror(gc, dss->domid, QEMU_DRIVE_MIRROR_DEVICE,
                                      target, "raw");
-        if (!rc) {
-            LOGD(INFO, domid, "Drive mirror command returned successfully\n");
+    if (!rc) {
+        LOGD(DEBUG, domid, "Drive mirror command returned successfully\n");
+    }else{
+        LOGD(ERROR, domid, "Sending drive mirror command failed\n");
+        if(counter > 0){
+            LOGD(INFO, domid, "Counter: %d. Sleeping for 10 sec and retry\n", 
counter);
+            sleep(10);
+            counter--;
+            goto start_mirror;
         }else{
-            LOGD(ERROR, domid, "Sending drive mirror command failed\n");
-            if(counter > 0){
-                LOGD(INFO, domid, "Counter: %d. Sleeping for 10 sec and 
retry\n", counter);
-                sleep(10);
-                counter--;
-                goto start_mirror;
-            }else{
-                goto cont;
-            }
-        }
-
-        /*
-         * Query job status until it is ready
-         * TODO: This code is just an inefficient busy wait. QMP sends an
-         * TODO: asynchronous message when mirroring job is completed. Consider
-         * TODO: adding the capability to handle asynchronous QMP messages 
(already done?)
-         */
-        while(!job_is_ready) {
-            LOGD(INFO, domid, "Checking for drive-mirror job");
-            rc = libxl__qmp_query_block_jobs(gc, dss->domid, &job_is_ready);
-            if(rc){
-                LOGD(ERROR, domid, "Checking block job failed\n");
-                goto cont;
-            }else{
-                LOGD(INFO, domid, "Checking block job succeeded\n");
-            }
-            if(!job_is_ready){
-                LOGD(INFO, domid, "Sleeping 5 sec\n");
-                sleep(5);
-            }
+            goto err;
         }
     }
-cont:
+
     libxl__stream_write_start(egc, &sws->dss->sws);
+    return;
+
+ err:
+   dss->callback(egc, dss, rc);
 }
 
 static void stream_done(libxl__egc *egc,
diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index fe6f076..5ef5fb1 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -59,6 +59,13 @@ typedef struct callback_id_pair {
     LIBXL_STAILQ_ENTRY(struct callback_id_pair) next;
 } callback_id_pair;
 
+typedef struct handler_event_pair {
+    const char* event_type;
+    void *opaque;
+    qmp_request_context *context;
+    qmp_callback_t event_handler;
+} event_handler_pair;
+
 struct libxl__qmp_handler {
     struct sockaddr_un addr;
     int qmp_fd;
@@ -66,6 +73,9 @@ struct libxl__qmp_handler {
     time_t timeout;
     /* wait_for_id will be used by the synchronous send function */
     int wait_for_id;
+    /* wait_for_event_type is used to wait on QMP events */
+    const char* wait_for_event_type;
+    event_handler_pair *hep;
 
     char buffer[QMP_RECEIVE_BUFFER_SIZE + 1];
     libxl__yajl_ctx *yajl_ctx;
@@ -287,6 +297,25 @@ static void qmp_handle_error_response(libxl__gc *gc, 
libxl__qmp_handler *qmp,
          libxl__json_object_get_string(resp));
 }
 
+static void qmp_handle_event(libxl__gc *gc, libxl__qmp_handler *qmp,
+                             const libxl__json_object *event)
+{
+    const char* event_type = NULL;
+    const libxl__json_object *event_o = NULL;
+    event_o = libxl__json_map_get("event", event, JSON_ANY);
+    event_type = libxl__json_object_get_string(event_o);
+    int rc;
+
+    if(qmp->wait_for_event_type &&
+       !strcmp(event_type, qmp->wait_for_event_type)) {
+       rc = qmp->hep->event_handler(qmp,
+                      libxl__json_map_get("data", event, JSON_ANY),
+                      qmp->hep->opaque);
+        qmp->hep->context->rc = rc;
+        qmp->wait_for_event_type = NULL;
+    }
+}
+
 static int qmp_handle_response(libxl__gc *gc, libxl__qmp_handler *qmp,
                                const libxl__json_object *resp)
 {
@@ -325,6 +354,7 @@ static int qmp_handle_response(libxl__gc *gc, 
libxl__qmp_handler *qmp,
         qmp_handle_error_response(gc, qmp, resp);
         return -1;
     case LIBXL__QMP_MESSAGE_TYPE_EVENT:
+        qmp_handle_event(gc, qmp, resp);
         return 0;
     case LIBXL__QMP_MESSAGE_TYPE_INVALID:
         return -1;
@@ -348,9 +378,7 @@ static libxl__qmp_handler *qmp_init_handler(libxl__gc *gc, 
uint32_t domid)
     qmp->ctx = CTX;
     qmp->domid = domid;
 
-    //TODO: Changed default timeout because drive-mirror command takes a long
-    //TODO: to return. Consider timeout to be passed as param.
-    qmp->timeout = 600;
+    qmp->timeout = 5;
 
     LIBXL_STAILQ_INIT(&qmp->callback_list);
 
@@ -627,6 +655,31 @@ static void qmp_free_handler(libxl__qmp_handler *qmp)
     free(qmp);
 }
 
+static int wait_for_event(libxl__qmp_handler *qmp, event_handler_pair *hep,
+                          int timeout)
+{
+    int ret = 0;
+    GC_INIT(qmp->ctx);
+    qmp->timeout = timeout;
+    qmp_request_context context = { .rc = 0 };
+    qmp->hep = hep;
+    qmp->wait_for_event_type = hep->event_type;
+    hep->context = &context;
+
+    while (qmp->wait_for_event_type) {
+        if ((ret = qmp_next(gc, qmp)) < 0) {
+            break;
+        }
+    }
+
+    if (!qmp->wait_for_event_type && ret == 0) {
+        ret = context.rc;
+    }
+    GC_FREE;
+
+    return ret;
+}
+
 /*
  * QMP Parameters Helpers
  */
@@ -1072,10 +1125,82 @@ int libxl__qmp_nbd_server_add(libxl__gc *gc, int domid, 
const char *disk)
     return qmp_run_command(gc, domid, "nbd-server-add", args, NULL, NULL);
 }
 
-int libxl__qmp_drive_mirror(libxl__gc *gc, int domid, const char* device, 
const char* target, const char* format)
+static int block_job_ready_handler(libxl__qmp_handler *qmp,
+                            const libxl__json_object *data, void *opaque){
+
+    GC_INIT(qmp->ctx);
+    int rc = -1;
+
+    const char *type;
+    const char *device;
+    unsigned int len;
+    unsigned int offset;
+    unsigned int speed;
+
+    const libxl__json_object *obj = NULL;
+
+    obj = libxl__json_map_get("type", data, JSON_STRING);
+    if (!obj) {
+        LOGD(ERROR, qmp->domid, "Failed to retrieve job type.");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    type = libxl__json_object_get_string(obj);
+
+    obj = libxl__json_map_get("device", data, JSON_STRING);
+    if (!obj) {
+        LOGD(ERROR, qmp->domid, "Failed to retrieve device.");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    device = libxl__json_object_get_string(obj);
+
+    obj = libxl__json_map_get("len", data, JSON_INTEGER);
+    if (!obj) {
+        LOGD(ERROR, qmp->domid, "Failed to retrieve length.");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    len = libxl__json_object_get_integer(obj);
+
+    obj = libxl__json_map_get("offset", data, JSON_INTEGER);
+    if (!obj) {
+        LOGD(ERROR, qmp->domid, "Failed to retrieve offset.");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    offset = libxl__json_object_get_integer(obj);
+
+    obj = libxl__json_map_get("speed", data, JSON_INTEGER);
+    if (!obj) {
+        LOGD(ERROR, qmp->domid, "Failed to retrieve speed.");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    speed = libxl__json_object_get_integer(obj);
+
+    LOGD(INFO, qmp->domid, "Block Job Ready: Details: Device: %s, Type: %s, 
Len: %u, Offset: %u, Speed %u\n",
+         device, type, len, offset, speed);
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl__qmp_drive_mirror(libxl__gc *gc, int domid, const char* device,
+                            const char* target, const char* format)
 {
+    libxl__qmp_handler *qmp = NULL;
     libxl__json_object *args = NULL;
-    //TODO: Allow method to receive "sync", "speed", "mode", "granurality", 
"buf-size"
+    int rc = 0;
+    /* TODO: Allow method to receive "sync", "speed", "mode", "granurality"
+     * "buf-size"
+     */
+     qmp = libxl__qmp_initialize(gc, domid);
+     if (!qmp)
+        return -1;
+
     qmp_parameters_add_string(gc, &args, "device", device);
     qmp_parameters_add_string(gc, &args, "target", target);
     qmp_parameters_add_string(gc, &args, "sync", "full");
@@ -1084,7 +1209,20 @@ int libxl__qmp_drive_mirror(libxl__gc *gc, int domid, 
const char* device, const
     qmp_parameters_add_integer(gc, &args, "granularity", 0);
     qmp_parameters_add_integer(gc, &args, "buf-size", 0);
 
-    return qmp_run_command(gc, domid, "drive-mirror", args, NULL, NULL);
+    rc = qmp_synchronous_send(qmp, "drive-mirror", args,
+                              NULL, NULL, qmp->timeout);
+
+    if ( !rc ) {
+        event_handler_pair hep =
+            {
+                .event_type = "BLOCK_JOB_READY",
+                .event_handler = block_job_ready_handler,
+            };
+
+        rc = wait_for_event(qmp, &hep, 600);
+    }
+    libxl__qmp_close(qmp);
+    return rc;
 }
 
 static int query_block_callback(libxl__qmp_handler *qmp,
-- 
2.3.2 (Apple Git-55)


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

 


Rackspace

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