@@ -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;
@@ -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
@@ -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 */
@@ -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
@@ -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 */