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

[PATCH v11 23/27] tools/xenstore: add read connection state for live update



Add the needed functions for reading connection state for live update.

As the connection is identified by a unique connection id in the state
records we need to add this to struct connection. Add a new function
to return the connection based on a connection id.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
Reviewed-by: Julien Grall <jgrall@xxxxxxxxxx>
---
V2:
- fixed condition in introduce_domain() (Julien Grall)

V4:
- set pending data msg type to XS_INVALID (Julien Grall)
- add buffered read data (Julien Grall)

V5:
- really read buffered read data (Julien Grall)
- drop conn parameter from introduce_domain() (Paul Durrant)
- split pending write data into individual buffers

V6:
- rename "first" to "partial" (Paul Durrant)

V7:
- use local port from connection data

V8:
- remove dom0 special handling
---
 tools/xenstore/xenstored_control.c |   1 +
 tools/xenstore/xenstored_core.c    | 102 ++++++++++++++++++++++++++++-
 tools/xenstore/xenstored_core.h    |  10 +++
 tools/xenstore/xenstored_domain.c  |  60 +++++++++++++----
 tools/xenstore/xenstored_domain.h  |   2 +
 5 files changed, 162 insertions(+), 13 deletions(-)

diff --git a/tools/xenstore/xenstored_control.c 
b/tools/xenstore/xenstored_control.c
index 497e1f2a63..d6454d4e77 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -539,6 +539,7 @@ void lu_read_state(void)
                        read_state_global(ctx, head + 1);
                        break;
                case XS_STATE_TYPE_CONN:
+                       read_state_connection(ctx, head + 1);
                        break;
                case XS_STATE_TYPE_WATCH:
                        break;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 71c0f8617b..4175b871ee 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -1575,12 +1575,35 @@ struct connection *new_connection(connwritefn_t *write, 
connreadfn_t *read)
        return new;
 }
 
+struct connection *get_connection_by_id(unsigned int conn_id)
+{
+       struct connection *conn;
+
+       list_for_each_entry(conn, &connections, list)
+               if (conn->conn_id == conn_id)
+                       return conn;
+
+       return NULL;
+}
+
 #ifdef NO_SOCKETS
 static void accept_connection(int sock)
 {
 }
+
+int writefd(struct connection *conn, const void *data, unsigned int len)
+{
+       errno = EBADF;
+       return -1;
+}
+
+int readfd(struct connection *conn, void *data, unsigned int len)
+{
+       errno = EBADF;
+       return -1;
+}
 #else
-static int writefd(struct connection *conn, const void *data, unsigned int len)
+int writefd(struct connection *conn, const void *data, unsigned int len)
 {
        int rc;
 
@@ -1596,7 +1619,7 @@ static int writefd(struct connection *conn, const void 
*data, unsigned int len)
        return rc;
 }
 
-static int readfd(struct connection *conn, void *data, unsigned int len)
+int readfd(struct connection *conn, void *data, unsigned int len)
 {
        int rc;
 
@@ -2514,6 +2537,81 @@ void read_state_global(const void *ctx, const void 
*state)
        domain_init(glb->evtchn_fd);
 }
 
+static void add_buffered_data(struct buffered_data *bdata,
+                             struct connection *conn, const uint8_t *data,
+                             unsigned int len)
+{
+       bdata->hdr.msg.len = len;
+       if (len <= DEFAULT_BUFFER_SIZE)
+               bdata->buffer = bdata->default_buffer;
+       else
+               bdata->buffer = talloc_array(bdata, char, len);
+       if (!bdata->buffer)
+               barf("error restoring buffered data");
+
+       memcpy(bdata->buffer, data, len);
+
+       /* Queue for later transmission. */
+       list_add_tail(&bdata->list, &conn->out_list);
+}
+
+void read_state_buffered_data(const void *ctx, struct connection *conn,
+                             const struct xs_state_connection *sc)
+{
+       struct buffered_data *bdata;
+       const uint8_t *data;
+       unsigned int len;
+       bool partial = sc->data_resp_len;
+
+       if (sc->data_in_len) {
+               bdata = new_buffer(conn);
+               if (!bdata)
+                       barf("error restoring read data");
+               if (sc->data_in_len < sizeof(bdata->hdr)) {
+                       bdata->inhdr = true;
+                       memcpy(&bdata->hdr, sc->data, sc->data_in_len);
+                       bdata->used = sc->data_in_len;
+               } else {
+                       bdata->inhdr = false;
+                       memcpy(&bdata->hdr, sc->data, sizeof(bdata->hdr));
+                       if (bdata->hdr.msg.len <= DEFAULT_BUFFER_SIZE)
+                               bdata->buffer = bdata->default_buffer;
+                       else
+                               bdata->buffer = talloc_array(bdata, char,
+                                                       bdata->hdr.msg.len);
+                       if (!bdata->buffer)
+                               barf("Error allocating in buffer");
+                       bdata->used = sc->data_in_len - sizeof(bdata->hdr);
+                       memcpy(bdata->buffer, sc->data + sizeof(bdata->hdr),
+                              bdata->used);
+               }
+
+               conn->in = bdata;
+       }
+
+       for (data = sc->data + sc->data_in_len;
+            data < sc->data + sc->data_in_len + sc->data_out_len;
+            data += len) {
+               bdata = new_buffer(conn);
+               if (!bdata)
+                       barf("error restoring buffered data");
+               if (partial) {
+                       bdata->inhdr = false;
+                       /* Make trace look nice. */
+                       bdata->hdr.msg.type = XS_INVALID;
+                       len = sc->data_resp_len;
+                       add_buffered_data(bdata, conn, data, len);
+                       partial = false;
+                       continue;
+               }
+
+               memcpy(&bdata->hdr, data, sizeof(bdata->hdr));
+               data += sizeof(bdata->hdr);
+               len = bdata->hdr.msg.len;
+               add_buffered_data(bdata, conn, data, len);
+       }
+}
+
 /*
  * Local variables:
  *  mode: C
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index ac9fe1559e..dcb3ad3e4b 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -135,6 +135,9 @@ struct connection
        /* Methods for communicating over this connection: write can be NULL */
        connwritefn_t *write;
        connreadfn_t *read;
+
+       /* Support for live update: connection id. */
+       unsigned int conn_id;
 };
 extern struct list_head connections;
 
@@ -195,6 +198,7 @@ struct node *read_node(struct connection *conn, const void 
*ctx,
                       const char *name);
 
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
+struct connection *get_connection_by_id(unsigned int conn_id);
 void check_store(void);
 void corrupt(struct connection *conn, const char *fmt, ...);
 enum xs_perm_type perm_for_conn(struct connection *conn,
@@ -250,6 +254,10 @@ void finish_daemonize(void);
 /* Open a pipe for signal handling */
 void init_pipe(int reopen_log_pipe[2]);
 
+int writefd(struct connection *conn, const void *data, unsigned int len);
+int readfd(struct connection *conn, void *data, unsigned int len);
+
+extern struct interface_funcs socket_funcs;
 extern xengnttab_handle **xgt_handle;
 
 int remember_string(struct hashtable *hash, const char *str);
@@ -266,6 +274,8 @@ const char *dump_state_node_perms(FILE *fp, struct 
xs_state_node *sn,
                                  unsigned int n_perms);
 
 void read_state_global(const void *ctx, const void *state);
+void read_state_buffered_data(const void *ctx, struct connection *conn,
+                             const struct xs_state_connection *sc);
 
 #endif /* _XENSTORED_CORE_H */
 
diff --git a/tools/xenstore/xenstored_domain.c 
b/tools/xenstore/xenstored_domain.c
index 775546757b..6934f1bc89 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -355,7 +355,7 @@ static struct domain *find_or_alloc_domain(const void *ctx, 
unsigned int domid)
        return domain ? : alloc_domain(ctx, domid);
 }
 
-static int new_domain(struct domain *domain, int port)
+static int new_domain(struct domain *domain, int port, bool restore)
 {
        int rc;
 
@@ -369,11 +369,16 @@ static int new_domain(struct domain *domain, int port)
 
        wrl_domain_new(domain);
 
-       /* Tell kernel we're interested in this event. */
-       rc = xenevtchn_bind_interdomain(xce_handle, domain->domid, port);
-       if (rc == -1)
-               return errno;
-       domain->port = rc;
+       if (restore)
+               domain->port = port;
+       else {
+               /* Tell kernel we're interested in this event. */
+               rc = xenevtchn_bind_interdomain(xce_handle, domain->domid,
+                                               port);
+               if (rc == -1)
+                       return errno;
+               domain->port = rc;
+       }
 
        domain->introduced = true;
 
@@ -423,7 +428,7 @@ static void domain_conn_reset(struct domain *domain)
 
 static struct domain *introduce_domain(const void *ctx,
                                       unsigned int domid,
-                                      evtchn_port_t port)
+                                      evtchn_port_t port, bool restore)
 {
        struct domain *domain;
        int rc;
@@ -439,7 +444,7 @@ static struct domain *introduce_domain(const void *ctx,
                                             : map_interface(domid);
                if (!interface)
                        return NULL;
-               if (new_domain(domain, port)) {
+               if (new_domain(domain, port, restore)) {
                        rc = errno;
                        if (is_master_domain)
                                unmap_xenbus(interface);
@@ -453,7 +458,7 @@ static struct domain *introduce_domain(const void *ctx,
                /* Now domain belongs to its connection. */
                talloc_steal(domain->conn, domain);
 
-               if (!is_master_domain)
+               if (!is_master_domain && !restore)
                        fire_watches(NULL, ctx, "@introduceDomain", NULL,
                                     false, NULL);
        } else {
@@ -486,7 +491,7 @@ int do_introduce(struct connection *conn, struct 
buffered_data *in)
        if (port <= 0)
                return EINVAL;
 
-       domain = introduce_domain(in, domid, port);
+       domain = introduce_domain(in, domid, port, false);
        if (!domain)
                return errno;
 
@@ -715,7 +720,7 @@ void dom0_init(void)
        if (port == -1)
                barf_perror("Failed to initialize dom0 port");
 
-       dom0 = introduce_domain(NULL, xenbus_master_domid(), port);
+       dom0 = introduce_domain(NULL, xenbus_master_domid(), port, false);
        if (!dom0)
                barf_perror("Failed to initialize dom0");
 
@@ -1261,6 +1266,39 @@ const char *dump_state_special_nodes(FILE *fp)
        return ret;
 }
 
+void read_state_connection(const void *ctx, const void *state)
+{
+       const struct xs_state_connection *sc = state;
+       struct connection *conn;
+       struct domain *domain, *tdomain;
+
+       if (sc->conn_type == XS_STATE_CONN_TYPE_SOCKET) {
+               conn = new_connection(writefd, readfd);
+               if (!conn)
+                       barf("error restoring connection");
+               conn->fd = sc->spec.socket_fd;
+       } else {
+               domain = introduce_domain(ctx, sc->spec.ring.domid,
+                                         sc->spec.ring.evtchn, true);
+               if (!domain)
+                       barf("domain allocation error");
+
+               if (sc->spec.ring.tdomid != DOMID_INVALID) {
+                       tdomain = find_or_alloc_domain(ctx,
+                                                      sc->spec.ring.tdomid);
+                       if (!tdomain)
+                               barf("target domain allocation error");
+                       talloc_reference(domain->conn, tdomain->conn);
+                       domain->conn->target = tdomain->conn;
+               }
+               conn = domain->conn;
+       }
+
+       conn->conn_id = sc->conn_id;
+
+       read_state_buffered_data(ctx, conn, sc);
+}
+
 /*
  * Local variables:
  *  mode: C
diff --git a/tools/xenstore/xenstored_domain.h 
b/tools/xenstore/xenstored_domain.h
index b20269b038..8f3b4e0f8b 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -101,4 +101,6 @@ void wrl_apply_debit_trans_commit(struct connection *conn);
 const char *dump_state_connections(FILE *fp, struct connection *conn);
 const char *dump_state_special_nodes(FILE *fp);
 
+void read_state_connection(const void *ctx, const void *state);
+
 #endif /* _XENSTORED_DOMAIN_H */
-- 
2.26.2




 


Rackspace

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