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

[Xen-devel] [PATCH v3 20/31] libxl_qmp: Introduce libxl__ev_qmp functions



Calling libxl__ev_qmp_register() will prepare a command to be sent to
QEMU and stash it in a queue to be sent later.

The actual sent will be done in a separate patch.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/libxl/libxl_internal.h         |  39 +++++++-
 tools/libxl/libxl_qmp.c              | 139 +++++++++++++++++++++++++++
 tools/libxl/libxl_types_internal.idl |  14 +++
 3 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 9271701246..16533f651e 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -202,6 +202,8 @@ typedef struct libxl__aop_occurred libxl__aop_occurred;
 typedef struct libxl__osevent_hook_nexus libxl__osevent_hook_nexus;
 typedef struct libxl__osevent_hook_nexi libxl__osevent_hook_nexi;
 typedef struct libxl__ev_qmp_state libxl__ev_qmp_state;
+typedef struct libxl__json_object libxl__json_object;
+typedef struct libxl__carefd libxl__carefd;
 
 typedef struct libxl__domain_create_state libxl__domain_create_state;
 typedef void libxl__domain_create_cb(struct libxl__egc *egc,
@@ -357,6 +359,39 @@ struct libxl__ev_child {
     LIBXL_LIST_ENTRY(struct libxl__ev_child) entry;
 };
 
+/*
+ * libxl__ev_qmp
+ */
+
+typedef struct libxl__ev_qmp libxl__ev_qmp;
+/* response: QMP response on success, or NULL on error.
+ * error_class: NONE on success, otherwise QMP error class or libxl error */
+typedef void libxl__ev_qmp_callback(libxl__egc *egc, libxl__ev_qmp *ev,
+                                    const libxl__json_object *response,
+                                    libxl__qmp_error_class error_class);
+struct libxl__ev_qmp {
+    /* read-only once registered */
+    uint32_t domid;
+    libxl__ev_qmp_callback *callback;
+    /* If !NULL, this file descriptor will be sent to the QMP server,
+     * and closed once sent. */
+    libxl__carefd *efd;
+
+    /* private */
+
+    /* id == -1: initial state or response already received and callback 
called.
+     * id > 0: id used to send a command to qemu. */
+    int id;
+    LIBXL_TAILQ_ENTRY(libxl__ev_qmp) entry;
+};
+
+_hidden void libxl__ev_qmp_init(libxl__ev_qmp *ev);
+_hidden int libxl__ev_qmp_register(libxl__gc *gc, libxl__ev_qmp *ev,
+                                   libxl__ev_qmp_callback *,
+                                   uint32_t domid,
+                                   const char *cmd, libxl__json_object *args);
+_hidden void libxl__ev_qmp_deregister(libxl__gc *gc, libxl__ev_qmp *ev);
+_hidden int libxl__ev_qmp_isregistered(const libxl__ev_qmp *ev);
 
 /*
  * evgen structures, which are the state we use for generating
@@ -1905,7 +1940,7 @@ typedef enum {
     JSON_ANY     = 255 /* this is a mask of all values above, adjust as needed 
*/
 } libxl__json_node_type;
 
-typedef struct libxl__json_object {
+struct libxl__json_object {
     libxl__json_node_type type;
     union {
         bool b;
@@ -1918,7 +1953,7 @@ typedef struct libxl__json_object {
         flexarray_t *map;
     } u;
     struct libxl__json_object *parent;
-} libxl__json_object;
+};
 
 typedef int (*libxl__json_parse_callback)(libxl__gc *gc,
                                           libxl__json_object *o,
diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index e4441f76f4..9b5eb8fd35 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -1369,15 +1369,57 @@ struct libxl__qmp_rx_buf {
     char buf[QMP_RECEIVE_BUFFER_SIZE];
 };
 
+typedef struct libxl__qmp_tx_buf libxl__qmp_tx_buf;
+struct libxl__qmp_tx_buf {
+    LIBXL_TAILQ_ENTRY(libxl__qmp_tx_buf) entry;
+    size_t len;
+    char *buf;
+    /* File descriptor to send along the command */
+    libxl__carefd *efd;
+};
+
 struct libxl__ev_qmp_state {
     libxl__carefd *cfd;
     libxl__ev_fd efd;
     uint32_t domid;
 
     LIBXL_TAILQ_HEAD(libxl__qmp_bufs, libxl__qmp_rx_buf) bufs;
+
+    unsigned int last_id_used;
+    /* Indicate that QEMU is ready to respond to command. */
+    bool ready;
+    LIBXL_TAILQ_HEAD(libxl__qmp_tx_bufs, libxl__qmp_tx_buf) tx_buf;
+
+    LIBXL_TAILQ_HEAD(libxl__ev_qmps, libxl__ev_qmp) qmp_events;
 };
 
 
+/* Prepare a QMP command to be sent */
+static int ev_qmp_queue_command(libxl__gc *gc,
+                                libxl__ev_qmp_state *qmp,
+                                const char *cmd,
+                                const libxl__json_object *args,
+                                libxl__carefd *efd)
+{
+    char *buf = NULL;
+    size_t len;
+    libxl__qmp_tx_buf *out;
+
+    buf = qmp_prepare_qmp_cmd(gc,
+                              cmd, args, ++qmp->last_id_used,
+                              &len);
+    if (!buf)
+        return ERROR_FAIL;
+
+    out = libxl__malloc(NOGC, sizeof(*out));
+    out->buf = buf;
+    out->len = len;
+    out->efd = efd;
+    LIBXL_TAILQ_INSERT_TAIL(&qmp->tx_buf, out, entry);
+
+    return 0;
+}
+
 static int ev_qmp_callback_readable(libxl__egc *egc, libxl__ev_qmp_state *qmp,
                                     int fd)
 {
@@ -1532,8 +1574,17 @@ static int ev_qmp_callback_readable(libxl__egc *egc, 
libxl__ev_qmp_state *qmp,
 static void ev_qmp_callback_error(libxl__egc *egc, libxl__ev_qmp_state *qmp)
 {
     EGC_GC;
+    libxl__ev_qmp *ev, *tev;
 
     LOGD(ERROR, qmp->domid, "Error happend with the QMP connection to QEMU");
+
+    LIBXL_TAILQ_FOREACH_SAFE(ev, &qmp->qmp_events, entry, tev) {
+        if (ev->id == -1)
+            continue;
+        /* Call every callback with error state. */
+        ev->id = -1;
+        ev->callback(egc, ev, NULL, LIBXL__QMP_ERROR_CLASS_LIBXL_ERROR);
+    }
     libxl__ev_qmp_stop(gc, qmp);
 }
 
@@ -1574,6 +1625,10 @@ static void libxl__ev_qmp_state_init(libxl__ev_qmp_state 
*qmp)
     qmp->cfd = NULL;
     libxl__ev_fd_init(&qmp->efd);
     LIBXL_TAILQ_INIT(&qmp->bufs);
+    qmp->last_id_used = 0;
+    qmp->ready = false;
+    LIBXL_TAILQ_INIT(&qmp->tx_buf);
+    LIBXL_TAILQ_INIT(&qmp->qmp_events);
 }
 
 libxl__ev_qmp_state *libxl__ev_qmp_start(libxl__gc *gc, uint32_t domid)
@@ -1650,6 +1705,8 @@ out:
 void libxl__ev_qmp_stop(libxl__gc *gc, libxl__ev_qmp_state *qmp)
 {
     libxl__qmp_rx_buf *buf, *tbuf;
+    libxl__qmp_tx_buf *tx_buf, *tx_tbuf;
+    libxl__ev_qmp *qmp_ev, *tqmp_ev;
 
     if (!qmp)
         return;
@@ -1661,6 +1718,19 @@ void libxl__ev_qmp_stop(libxl__gc *gc, 
libxl__ev_qmp_state *qmp)
     LIBXL_TAILQ_FOREACH_SAFE(buf, &qmp->bufs, entry, tbuf)
         free(buf);
     LIBXL_TAILQ_INIT(&qmp->bufs);
+    LIBXL_TAILQ_FOREACH_SAFE(tx_buf, &qmp->tx_buf, entry, tx_tbuf) {
+        free(tx_buf->buf);
+        free(tx_buf);
+    }
+    LIBXL_TAILQ_INIT(&qmp->tx_buf);
+
+    LIBXL_TAILQ_FOREACH_SAFE(qmp_ev, &qmp->qmp_events, entry, tqmp_ev) {
+        LOGD(ERROR, qmp->domid, "Event left %p", qmp_ev);
+        libxl__ev_qmp_deregister(gc, qmp_ev);
+    }
+    LIBXL_TAILQ_INIT(&qmp->qmp_events);
+
+    qmp->ready = false;
 
     libxl__ev_fd_deregister(gc, &qmp->efd);
     libxl__carefd_close(qmp->cfd);
@@ -1668,6 +1738,75 @@ void libxl__ev_qmp_stop(libxl__gc *gc, 
libxl__ev_qmp_state *qmp)
 
     CTX_UNLOCK;
 }
+
+/*
+ * Actual libxl__ev_qmp
+ */
+
+void libxl__ev_qmp_init(libxl__ev_qmp *ev)
+{
+    ev->domid = INVALID_DOMID;
+    ev->callback = NULL;
+    ev->efd = NULL;
+    ev->id = -1;
+}
+
+int libxl__ev_qmp_register(libxl__gc *gc, libxl__ev_qmp *ev,
+                           libxl__ev_qmp_callback *callback,
+                           uint32_t domid,
+                           const char *cmd, libxl__json_object *args)
+{
+    libxl__ev_qmp_state *qmp;
+    int rc;
+
+    CTX_LOCK;
+
+    LOGD(DEBUG, domid, " ev %p, cmd '%s'", ev, cmd);
+
+    /* Connect to QEMU if not already connected */
+    qmp = libxl__ev_qmp_start(gc, domid);
+    if (!qmp) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = ev_qmp_queue_command(gc, qmp, cmd, args, ev->efd);
+    if (rc)
+        goto out;
+
+    ev->domid = domid;
+    ev->callback = callback;
+    ev->id = qmp->last_id_used;
+    /* fd is in the queue, and should be closed once sent */
+    ev->efd = NULL;
+
+    LIBXL_TAILQ_INSERT_TAIL(&qmp->qmp_events, ev, entry);
+
+    rc = 0;
+
+out:
+    CTX_UNLOCK;
+    return rc;
+}
+
+void libxl__ev_qmp_deregister(libxl__gc *gc, libxl__ev_qmp *ev)
+{
+    LOGD(DEBUG, ev->domid, " ev %p", ev);
+
+    CTX_LOCK;
+
+    if (libxl__ev_qmp_isregistered(ev)) {
+        LIBXL_TAILQ_REMOVE(&CTX->qmp_ev->qmp_events, ev, entry);
+    }
+    libxl__ev_qmp_init(ev);
+
+    CTX_UNLOCK;
+}
+
+int libxl__ev_qmp_isregistered(const libxl__ev_qmp *ev)
+{
+    return ev->domid != INVALID_DOMID;
+}
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_types_internal.idl 
b/tools/libxl/libxl_types_internal.idl
index f2ff01718d..ada97615d5 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -13,6 +13,20 @@ libxl__qmp_message_type = Enumeration("qmp_message_type", [
     (5, "invalid"),
     ])
 
+libxl__qmp_error_class = Enumeration("qmp_error_class", [
+    # No error
+    (0, "NONE"),
+    # Error generated by libxl (e.g. socket closed unexpectedly, no mem, ...)
+    (1, "libxl_error"),
+    # QMP error classes described in QEMU sources code (QapiErrorClass)
+    (2, "GenericError"),
+    (3, "CommandNotFound"),
+    (4, "DeviceNotActive"),
+    (5, "DeviceNotFound"),
+    # Unrecognized QMP error class
+    (6, "Unknown"),
+    ])
+
 libxl__device_kind = Enumeration("device_kind", [
     (0, "NONE"),
     (1, "VIF"),
-- 
Anthony PERARD


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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