ia64/xen-unstable

changeset 7296:b67873a9e3ac

Simplify reply logic in xenstored. Maintain a linked list
of pending replies that are sent out in order.

Currently we only read new requests when the reply list is
empty. In fact there is no good reason for this restriction.
Another interesting point is that (on my test machine)
hotplug blk setup fails if xenstored_client connects to
xenstored via the unix domain socket rather than through the
kernel --- this points to some user/kernel races that are
'fixed' by the extra serialisation of the in-kernel mutexes.
It definitely needs looking into.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Oct 09 23:53:03 2005 +0100 (2005-10-09)
parents f1e8d5f64105
children b7dce4fe2488
files tools/xenstore/xenstored_core.c tools/xenstore/xenstored_core.h tools/xenstore/xenstored_domain.c tools/xenstore/xenstored_watch.c tools/xenstore/xenstored_watch.h xen/include/public/io/xs_wire.h
line diff
     1.1 --- a/tools/xenstore/xenstored_core.c	Sun Oct 09 21:29:10 2005 +0100
     1.2 +++ b/tools/xenstore/xenstored_core.c	Sun Oct 09 23:53:03 2005 +0100
     1.3 @@ -235,52 +235,50 @@ void trace(const char *fmt, ...)
     1.4  	talloc_free(str);
     1.5  }
     1.6  
     1.7 -static bool write_message(struct connection *conn)
     1.8 +static bool write_messages(struct connection *conn)
     1.9  {
    1.10  	int ret;
    1.11 -	struct buffered_data *out = conn->out;
    1.12 +	struct buffered_data *out, *tmp;
    1.13 +
    1.14 +	list_for_each_entry_safe(out, tmp, &conn->out_list, list) {
    1.15 +		if (out->inhdr) {
    1.16 +			if (verbose)
    1.17 +				xprintf("Writing msg %s (%s) out to %p\n",
    1.18 +					sockmsg_string(out->hdr.msg.type),
    1.19 +					out->buffer, conn);
    1.20 +			ret = conn->write(conn, out->hdr.raw + out->used,
    1.21 +					  sizeof(out->hdr) - out->used);
    1.22 +			if (ret < 0)
    1.23 +				return false;
    1.24  
    1.25 -	if (out->inhdr) {
    1.26 -		if (verbose)
    1.27 -			xprintf("Writing msg %s (%s) out to %p\n",
    1.28 -				sockmsg_string(out->hdr.msg.type),
    1.29 -				out->buffer, conn);
    1.30 -		ret = conn->write(conn, out->hdr.raw + out->used,
    1.31 -				  sizeof(out->hdr) - out->used);
    1.32 +			out->used += ret;
    1.33 +			if (out->used < sizeof(out->hdr))
    1.34 +				return true;
    1.35 +
    1.36 +			out->inhdr = false;
    1.37 +			out->used = 0;
    1.38 +
    1.39 +			/* Second write might block if non-zero. */
    1.40 +			if (out->hdr.msg.len && !conn->domain)
    1.41 +				return true;
    1.42 +		}
    1.43 +
    1.44 +		ret = conn->write(conn, out->buffer + out->used,
    1.45 +				  out->hdr.msg.len - out->used);
    1.46 +
    1.47  		if (ret < 0)
    1.48  			return false;
    1.49  
    1.50  		out->used += ret;
    1.51 -		if (out->used < sizeof(out->hdr))
    1.52 +		if (out->used != out->hdr.msg.len)
    1.53  			return true;
    1.54  
    1.55 -		out->inhdr = false;
    1.56 -		out->used = 0;
    1.57 +		trace_io(conn, "OUT", out);
    1.58  
    1.59 -		/* Second write might block if non-zero. */
    1.60 -		if (out->hdr.msg.len && !conn->domain)
    1.61 -			return true;
    1.62 +		list_del(&out->list);
    1.63 +		talloc_free(out);
    1.64  	}
    1.65  
    1.66 -	ret = conn->write(conn, out->buffer + out->used,
    1.67 -			  out->hdr.msg.len - out->used);
    1.68 -
    1.69 -	if (ret < 0)
    1.70 -		return false;
    1.71 -
    1.72 -	out->used += ret;
    1.73 -	if (out->used != out->hdr.msg.len)
    1.74 -		return true;
    1.75 -
    1.76 -	trace_io(conn, "OUT", out);
    1.77 -	conn->out = NULL;
    1.78 -	talloc_free(out);
    1.79 -
    1.80 -	queue_next_event(conn);
    1.81 -
    1.82 -	/* No longer busy? */
    1.83 -	if (!conn->out)
    1.84 -		conn->state = OK;
    1.85  	return true;
    1.86  }
    1.87  
    1.88 @@ -297,9 +295,9 @@ static int destroy_conn(void *_conn)
    1.89  		FD_SET(conn->fd, &set);
    1.90  		none.tv_sec = none.tv_usec = 0;
    1.91  
    1.92 -		while (conn->out
    1.93 +		while (!list_empty(&conn->out_list)
    1.94  		       && select(conn->fd+1, NULL, &set, NULL, &none) == 1)
    1.95 -			if (!write_message(conn))
    1.96 +			if (!write_messages(conn))
    1.97  				break;
    1.98  		close(conn->fd);
    1.99  	}
   1.100 @@ -326,9 +324,9 @@ static int initialize_set(fd_set *inset,
   1.101  	list_for_each_entry(i, &connections, list) {
   1.102  		if (i->domain)
   1.103  			continue;
   1.104 -		if (i->state == OK)
   1.105 +		if (list_empty(&i->out_list))
   1.106  			FD_SET(i->fd, inset);
   1.107 -		if (i->out)
   1.108 +		if (!list_empty(&i->out_list))
   1.109  			FD_SET(i->fd, outset);
   1.110  		if (i->fd > max)
   1.111  			max = i->fd;
   1.112 @@ -594,14 +592,7 @@ void send_reply(struct connection *conn,
   1.113  	bdata->hdr.msg.len = len;
   1.114  	memcpy(bdata->buffer, data, len);
   1.115  
   1.116 -	/* There might be an event going out now.  Queue behind it. */
   1.117 -	if (conn->out) {
   1.118 -		assert(conn->out->hdr.msg.type == XS_WATCH_EVENT);
   1.119 -		assert(!conn->waiting_reply);
   1.120 -		conn->waiting_reply = bdata;
   1.121 -	} else
   1.122 -		conn->out = bdata;
   1.123 -	conn->state = BUSY;
   1.124 +	list_add_tail(&bdata->list, &conn->out_list);
   1.125  }
   1.126  
   1.127  /* Some routines (write, mkdir, etc) just need a non-error return */
   1.128 @@ -1148,8 +1139,6 @@ static void consider_message(struct conn
   1.129  	enum xsd_sockmsg_type volatile type = conn->in->hdr.msg.type;
   1.130  	jmp_buf talloc_fail;
   1.131  
   1.132 -	assert(conn->state == OK);
   1.133 -
   1.134  	/* For simplicity, we kill the connection on OOM. */
   1.135  	talloc_set_fail_handler(out_of_mem, &talloc_fail);
   1.136  	if (setjmp(talloc_fail)) {
   1.137 @@ -1186,10 +1175,7 @@ end:
   1.138  static void handle_input(struct connection *conn)
   1.139  {
   1.140  	int bytes;
   1.141 -	struct buffered_data *in;
   1.142 -
   1.143 -	assert(conn->state == OK);
   1.144 -	in = conn->in;
   1.145 +	struct buffered_data *in = conn->in;
   1.146  
   1.147  	/* Not finished header yet? */
   1.148  	if (in->inhdr) {
   1.149 @@ -1237,7 +1223,7 @@ bad_client:
   1.150  
   1.151  static void handle_output(struct connection *conn)
   1.152  {
   1.153 -	if (!write_message(conn))
   1.154 +	if (!write_messages(conn))
   1.155  		talloc_free(conn);
   1.156  }
   1.157  
   1.158 @@ -1254,8 +1240,6 @@ struct connection *new_connection(connwr
   1.159  	if (!new)
   1.160  		return NULL;
   1.161  
   1.162 -	new->state = OK;
   1.163 -	new->out = new->waiting_reply = NULL;
   1.164  	new->fd = -1;
   1.165  	new->id = 0;
   1.166  	new->domain = NULL;
   1.167 @@ -1263,6 +1247,7 @@ struct connection *new_connection(connwr
   1.168  	new->write = write;
   1.169  	new->read = read;
   1.170  	new->can_write = true;
   1.171 +	INIT_LIST_HEAD(&new->out_list);
   1.172  	INIT_LIST_HEAD(&new->watches);
   1.173  
   1.174  	talloc_set_fail_handler(out_of_mem, &talloc_fail);
   1.175 @@ -1317,23 +1302,17 @@ void dump_connection(void)
   1.176  	list_for_each_entry(i, &connections, list) {
   1.177  		printf("Connection %p:\n", i);
   1.178  		printf("    state = %s\n",
   1.179 -		       i->state == OK ? "OK"
   1.180 -		       : i->state == BUSY ? "BUSY"
   1.181 -		       : "INVALID");
   1.182 +		       list_empty(&i->out_list) ? "OK" : "BUSY");
   1.183  		if (i->id)
   1.184  			printf("    id = %i\n", i->id);
   1.185  		if (!i->in->inhdr || i->in->used)
   1.186  			printf("    got %i bytes of %s\n",
   1.187  			       i->in->used, i->in->inhdr ? "header" : "data");
   1.188 +#if 0
   1.189  		if (i->out)
   1.190  			printf("    sending message %s (%s) out\n",
   1.191  			       sockmsg_string(i->out->hdr.msg.type),
   1.192  			       i->out->buffer);
   1.193 -		if (i->waiting_reply)
   1.194 -			printf("    ... and behind is queued %s (%s)\n",
   1.195 -			       sockmsg_string(i->waiting_reply->hdr.msg.type),
   1.196 -			       i->waiting_reply->buffer);
   1.197 -#if 0
   1.198  		if (i->transaction)
   1.199  			dump_transaction(i);
   1.200  		if (i->domain)
   1.201 @@ -1604,3 +1583,13 @@ int main(int argc, char *argv[])
   1.202  		max = initialize_set(&inset, &outset, *sock, *ro_sock);
   1.203  	}
   1.204  }
   1.205 +
   1.206 +/*
   1.207 + * Local variables:
   1.208 + *  c-file-style: "linux"
   1.209 + *  indent-tabs-mode: t
   1.210 + *  c-indent-level: 8
   1.211 + *  c-basic-offset: 8
   1.212 + *  tab-width: 8
   1.213 + * End:
   1.214 + */
     2.1 --- a/tools/xenstore/xenstored_core.h	Sun Oct 09 21:29:10 2005 +0100
     2.2 +++ b/tools/xenstore/xenstored_core.h	Sun Oct 09 23:53:03 2005 +0100
     2.3 @@ -31,14 +31,19 @@
     2.4  
     2.5  struct buffered_data
     2.6  {
     2.7 +	struct list_head list;
     2.8 +
     2.9  	/* Are we still doing the header? */
    2.10  	bool inhdr;
    2.11 +
    2.12  	/* How far are we? */
    2.13  	unsigned int used;
    2.14 +
    2.15  	union {
    2.16  		struct xsd_sockmsg msg;
    2.17  		char raw[sizeof(struct xsd_sockmsg)];
    2.18  	} hdr;
    2.19 +
    2.20  	/* The actual data. */
    2.21  	char *buffer;
    2.22  };
    2.23 @@ -47,14 +52,6 @@ struct connection;
    2.24  typedef int connwritefn_t(struct connection *, const void *, unsigned int);
    2.25  typedef int connreadfn_t(struct connection *, void *, unsigned int);
    2.26  
    2.27 -enum state
    2.28 -{
    2.29 -	/* Doing action, not listening */
    2.30 -	BUSY,
    2.31 -	/* Completed */
    2.32 -	OK,
    2.33 -};
    2.34 -
    2.35  struct connection
    2.36  {
    2.37  	struct list_head list;
    2.38 @@ -62,12 +59,9 @@ struct connection
    2.39  	/* The file descriptor we came in on. */
    2.40  	int fd;
    2.41  
    2.42 -	/* Who am I?  0 for socket connections. */
    2.43 +	/* Who am I? 0 for socket connections. */
    2.44  	domid_t id;
    2.45  
    2.46 -	/* Blocked on transaction?  Busy? */
    2.47 -	enum state state;
    2.48 -
    2.49  	/* Is this a read-only connection? */
    2.50  	bool can_write;
    2.51  
    2.52 @@ -75,10 +69,7 @@ struct connection
    2.53  	struct buffered_data *in;
    2.54  
    2.55  	/* Buffered output data */
    2.56 -	struct buffered_data *out;
    2.57 -
    2.58 -	/* If we had a watch fire outgoing when we needed to reply... */
    2.59 -	struct buffered_data *waiting_reply;
    2.60 +	struct list_head out_list;
    2.61  
    2.62  	/* My transaction, if any. */
    2.63  	struct transaction *transaction;
    2.64 @@ -172,3 +163,13 @@ void trace(const char *fmt, ...);
    2.65  extern int event_fd;
    2.66  
    2.67  #endif /* _XENSTORED_CORE_H */
    2.68 +
    2.69 +/*
    2.70 + * Local variables:
    2.71 + *  c-file-style: "linux"
    2.72 + *  indent-tabs-mode: t
    2.73 + *  c-indent-level: 8
    2.74 + *  c-basic-offset: 8
    2.75 + *  tab-width: 8
    2.76 + * End:
    2.77 + */
     3.1 --- a/tools/xenstore/xenstored_domain.c	Sun Oct 09 21:29:10 2005 +0100
     3.2 +++ b/tools/xenstore/xenstored_domain.c	Sun Oct 09 23:53:03 2005 +0100
     3.3 @@ -276,12 +276,14 @@ void handle_event(void)
     3.4  
     3.5  bool domain_can_read(struct connection *conn)
     3.6  {
     3.7 -	return conn->state == OK && buffer_has_input(conn->domain->input);
     3.8 +	return (list_empty(&conn->out_list) &&
     3.9 +                buffer_has_input(conn->domain->input));
    3.10  }
    3.11  
    3.12  bool domain_can_write(struct connection *conn)
    3.13  {
    3.14 -	return conn->out && buffer_has_output_room(conn->domain->output);
    3.15 +	return (!list_empty(&conn->out_list) &&
    3.16 +                buffer_has_output_room(conn->domain->output));
    3.17  }
    3.18  
    3.19  static struct domain *new_domain(void *context, domid_t domid,
     4.1 --- a/tools/xenstore/xenstored_watch.c	Sun Oct 09 21:29:10 2005 +0100
     4.2 +++ b/tools/xenstore/xenstored_watch.c	Sun Oct 09 23:53:03 2005 +0100
     4.3 @@ -32,17 +32,6 @@
     4.4  #include "xenstored_test.h"
     4.5  #include "xenstored_domain.h"
     4.6  
     4.7 -/* FIXME: time out unacked watches. */
     4.8 -struct watch_event
     4.9 -{
    4.10 -	/* The events on this watch. */
    4.11 -	struct list_head list;
    4.12 -
    4.13 -	/* Data to send (node\0token\0). */
    4.14 -	unsigned int len;
    4.15 -	char *data;
    4.16 -};
    4.17 -
    4.18  struct watch
    4.19  {
    4.20  	/* Watches on this connection */
    4.21 @@ -58,50 +47,17 @@ struct watch
    4.22  	char *node;
    4.23  };
    4.24  
    4.25 -/* Look through our watches: if any of them have an event, queue it. */
    4.26 -void queue_next_event(struct connection *conn)
    4.27 -{
    4.28 -	struct watch_event *event;
    4.29 -	struct watch *watch;
    4.30 -
    4.31 -	/* We had a reply queued already?  Send it: other end will
    4.32 -	 * discard watch. */
    4.33 -	if (conn->waiting_reply) {
    4.34 -		conn->out = conn->waiting_reply;
    4.35 -		conn->waiting_reply = NULL;
    4.36 -		return;
    4.37 -	}
    4.38 -
    4.39 -	list_for_each_entry(watch, &conn->watches, list) {
    4.40 -		event = list_top(&watch->events, struct watch_event, list);
    4.41 -		if (event) {
    4.42 -			list_del(&event->list);
    4.43 -			talloc_free(event);
    4.44 -			send_reply(conn,XS_WATCH_EVENT,event->data,event->len);
    4.45 -			break;
    4.46 -		}
    4.47 -	}
    4.48 -}
    4.49 -
    4.50 -static int destroy_watch_event(void *_event)
    4.51 -{
    4.52 -	struct watch_event *event = _event;
    4.53 -
    4.54 -	trace_destroy(event, "watch_event");
    4.55 -	return 0;
    4.56 -}
    4.57 -
    4.58  static void add_event(struct connection *conn,
    4.59  		      struct watch *watch,
    4.60  		      const char *name)
    4.61  {
    4.62 -	struct watch_event *event;
    4.63 +	/* Data to send (node\0token\0). */
    4.64 +	unsigned int len;
    4.65 +	char *data;
    4.66  
    4.67  	if (!check_event_node(name)) {
    4.68  		/* Can this conn load node, or see that it doesn't exist? */
    4.69 -		struct node *node;
    4.70 -
    4.71 -		node = get_node(conn, name, XS_PERM_READ);
    4.72 +		struct node *node = get_node(conn, name, XS_PERM_READ);
    4.73  		if (!node && errno != ENOENT)
    4.74  			return;
    4.75  	}
    4.76 @@ -112,14 +68,12 @@ static void add_event(struct connection 
    4.77  			name++;
    4.78  	}
    4.79  
    4.80 -	event = talloc(watch, struct watch_event);
    4.81 -	event->len = strlen(name) + 1 + strlen(watch->token) + 1;
    4.82 -	event->data = talloc_array(event, char, event->len);
    4.83 -	strcpy(event->data, name);
    4.84 -	strcpy(event->data + strlen(name) + 1, watch->token);
    4.85 -	talloc_set_destructor(event, destroy_watch_event);
    4.86 -	list_add_tail(&event->list, &watch->events);
    4.87 -	trace_create(event, "watch_event");
    4.88 +	len = strlen(name) + 1 + strlen(watch->token) + 1;
    4.89 +	data = talloc_array(watch, char, len);
    4.90 +	strcpy(data, name);
    4.91 +	strcpy(data + strlen(name) + 1, watch->token);
    4.92 +        send_reply(conn, XS_WATCH_EVENT, data, len);
    4.93 +	talloc_free(data);
    4.94  }
    4.95  
    4.96  /* FIXME: we fail to fire on out of memory.  Should drop connections. */
    4.97 @@ -139,11 +93,6 @@ void fire_watches(struct connection *con
    4.98  				add_event(i, watch, name);
    4.99  			else if (recurse && is_child(watch->node, name))
   4.100  				add_event(i, watch, watch->node);
   4.101 -			else
   4.102 -				continue;
   4.103 -			/* If connection not doing anything, queue this. */
   4.104 -			if (i->state == OK)
   4.105 -				queue_next_event(i);
   4.106  		}
   4.107  	}
   4.108  }
   4.109 @@ -231,13 +180,19 @@ void do_unwatch(struct connection *conn,
   4.110  void dump_watches(struct connection *conn)
   4.111  {
   4.112  	struct watch *watch;
   4.113 -	struct watch_event *event;
   4.114  
   4.115 -	list_for_each_entry(watch, &conn->watches, list) {
   4.116 +	list_for_each_entry(watch, &conn->watches, list)
   4.117  		printf("    watch on %s token %s\n",
   4.118  		       watch->node, watch->token);
   4.119 -		list_for_each_entry(event, &watch->events, list)
   4.120 -			printf("        event: %s\n", event->data);
   4.121 -	}
   4.122  }
   4.123  #endif
   4.124 +
   4.125 +/*
   4.126 + * Local variables:
   4.127 + *  c-file-style: "linux"
   4.128 + *  indent-tabs-mode: t
   4.129 + *  c-indent-level: 8
   4.130 + *  c-basic-offset: 8
   4.131 + *  tab-width: 8
   4.132 + * End:
   4.133 + */
     5.1 --- a/tools/xenstore/xenstored_watch.h	Sun Oct 09 21:29:10 2005 +0100
     5.2 +++ b/tools/xenstore/xenstored_watch.h	Sun Oct 09 23:53:03 2005 +0100
     5.3 @@ -23,17 +23,9 @@
     5.4  #include "xenstored_core.h"
     5.5  
     5.6  void do_watch(struct connection *conn, struct buffered_data *in);
     5.7 -void do_watch_ack(struct connection *conn, const char *token);
     5.8  void do_unwatch(struct connection *conn, struct buffered_data *in);
     5.9  
    5.10 -/* Is this a watch event message for this connection? */
    5.11 -bool is_watch_event(struct connection *conn, struct buffered_data *out);
    5.12 -
    5.13 -/* Look through our watches: if any of them have an event, queue it. */
    5.14 -void queue_next_event(struct connection *conn);
    5.15 -
    5.16 -/* Fire all watches: recurse means all the children are affected (ie. rm).
    5.17 - */
    5.18 +/* Fire all watches: recurse means all the children are affected (ie. rm). */
    5.19  void fire_watches(struct connection *conn, const char *name, bool recurse);
    5.20  
    5.21  void dump_watches(struct connection *conn);
     6.1 --- a/xen/include/public/io/xs_wire.h	Sun Oct 09 21:29:10 2005 +0100
     6.2 +++ b/xen/include/public/io/xs_wire.h	Sun Oct 09 23:53:03 2005 +0100
     6.3 @@ -30,23 +30,23 @@
     6.4  
     6.5  enum xsd_sockmsg_type
     6.6  {
     6.7 -	XS_DEBUG,
     6.8 -	XS_DIRECTORY,
     6.9 -	XS_READ,
    6.10 -	XS_GET_PERMS,
    6.11 -	XS_WATCH,
    6.12 -	XS_UNWATCH,
    6.13 -	XS_TRANSACTION_START,
    6.14 -	XS_TRANSACTION_END,
    6.15 -	XS_INTRODUCE,
    6.16 -	XS_RELEASE,
    6.17 -	XS_GET_DOMAIN_PATH,
    6.18 -	XS_WRITE,
    6.19 -	XS_MKDIR,
    6.20 -	XS_RM,
    6.21 -	XS_SET_PERMS,
    6.22 -	XS_WATCH_EVENT,
    6.23 -	XS_ERROR,
    6.24 +    XS_DEBUG,
    6.25 +    XS_DIRECTORY,
    6.26 +    XS_READ,
    6.27 +    XS_GET_PERMS,
    6.28 +    XS_WATCH,
    6.29 +    XS_UNWATCH,
    6.30 +    XS_TRANSACTION_START,
    6.31 +    XS_TRANSACTION_END,
    6.32 +    XS_INTRODUCE,
    6.33 +    XS_RELEASE,
    6.34 +    XS_GET_DOMAIN_PATH,
    6.35 +    XS_WRITE,
    6.36 +    XS_MKDIR,
    6.37 +    XS_RM,
    6.38 +    XS_SET_PERMS,
    6.39 +    XS_WATCH_EVENT,
    6.40 +    XS_ERROR,
    6.41  };
    6.42  
    6.43  #define XS_WRITE_NONE "NONE"
    6.44 @@ -56,38 +56,40 @@ enum xsd_sockmsg_type
    6.45  /* We hand errors as strings, for portability. */
    6.46  struct xsd_errors
    6.47  {
    6.48 -	int errnum;
    6.49 -	const char *errstring;
    6.50 +    int errnum;
    6.51 +    const char *errstring;
    6.52  };
    6.53  #define XSD_ERROR(x) { x, #x }
    6.54  static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
    6.55 -	XSD_ERROR(EINVAL),
    6.56 -	XSD_ERROR(EACCES),
    6.57 -	XSD_ERROR(EEXIST),
    6.58 -	XSD_ERROR(EISDIR),
    6.59 -	XSD_ERROR(ENOENT),
    6.60 -	XSD_ERROR(ENOMEM),
    6.61 -	XSD_ERROR(ENOSPC),
    6.62 -	XSD_ERROR(EIO),
    6.63 -	XSD_ERROR(ENOTEMPTY),
    6.64 -	XSD_ERROR(ENOSYS),
    6.65 -	XSD_ERROR(EROFS),
    6.66 -	XSD_ERROR(EBUSY),
    6.67 -	XSD_ERROR(EAGAIN),
    6.68 -	XSD_ERROR(EISCONN),
    6.69 +    XSD_ERROR(EINVAL),
    6.70 +    XSD_ERROR(EACCES),
    6.71 +    XSD_ERROR(EEXIST),
    6.72 +    XSD_ERROR(EISDIR),
    6.73 +    XSD_ERROR(ENOENT),
    6.74 +    XSD_ERROR(ENOMEM),
    6.75 +    XSD_ERROR(ENOSPC),
    6.76 +    XSD_ERROR(EIO),
    6.77 +    XSD_ERROR(ENOTEMPTY),
    6.78 +    XSD_ERROR(ENOSYS),
    6.79 +    XSD_ERROR(EROFS),
    6.80 +    XSD_ERROR(EBUSY),
    6.81 +    XSD_ERROR(EAGAIN),
    6.82 +    XSD_ERROR(EISCONN),
    6.83  };
    6.84  struct xsd_sockmsg
    6.85  {
    6.86 -	u32 type;
    6.87 -	u32 len; 		/* Length of data following this. */
    6.88 +    u32 type;  /* XS_??? */
    6.89 +    u32 req_id;/* Request identifier, echoed in daemon's response.  */
    6.90 +    u32 tx_id; /* Transaction id (0 if not related to a transaction). */
    6.91 +    u32 len;   /* Length of data following this. */
    6.92  
    6.93 -	/* Generally followed by nul-terminated string(s). */
    6.94 +    /* Generally followed by nul-terminated string(s). */
    6.95  };
    6.96  
    6.97  enum xs_watch_type
    6.98  {
    6.99 -	XS_WATCH_PATH = 0,
   6.100 -	XS_WATCH_TOKEN,
   6.101 +    XS_WATCH_PATH = 0,
   6.102 +    XS_WATCH_TOKEN,
   6.103  };
   6.104  
   6.105  #endif /* _XS_WIRE_H */