Re: [Qemu-devel] [PATCH v3 1/2] contrib: add ivshmem client and server

2014-08-18 Thread David Marchand


On 08/08/2014 04:51 PM, Stefan Hajnoczi wrote:

On Fri, Aug 08, 2014 at 10:55:17AM +0200, David Marchand wrote:

Looks good, a few minor comments:


diff --git a/contrib/ivshmem-client/Makefile b/contrib/ivshmem-client/Makefile
new file mode 100644
index 000..eee97c6
--- /dev/null
+++ b/contrib/ivshmem-client/Makefile
@@ -0,0 +1,29 @@


CCed Peter Maydell for a second opinion, I'd suggest hooking up to
QEMU's top-level ./Makefile.  QEMU does not do recursive make.

The advantages of hooking up QEMU's Makefile are:

1. So that ivshmem client/server code is built by default (on supported
host platforms) and bitrot is avoided.

2. So that you don't have to duplicate rules.mak or any other build
infrastructure.



Ok, done.
But in this case, should we really keep the files in contrib/ ?
I used this directory but I am not too sure about this.

Maybe hw/misc/ivshmem/ would be better ?


The rest of your comments have been integrated in my tree.

Is it preferred to send fixes aside the original patches ? or should I 
send a squashed version ?

(I suppose the former is better as it is easier to read).


Thanks Stefan.


--
David Marchand
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [Qemu-devel] [PATCH v3 1/2] contrib: add ivshmem client and server

2014-08-18 Thread David Marchand

On 08/10/2014 05:57 AM, Gonglei wrote:

+/* can return a peer or the local client */
+peer = ivshmem_client_search_peer(client, peer_id);
+
+/* delete peer */
+if (fd == -1) {
+

Maybe the above check should be moved before getting the peer.
And the next check peer is extra.


We always need to know the peer, either for a deletion, creation or update.





+if (peer == NULL || peer == client-local) {
+debug_log(client, receive delete for invalid peer %ld,


Missing '\n' ?


Ok.




peer_id);
+return -1;
+}
+
+debug_log(client, delete peer id = %ld\n, peer_id);
+free_peer(client, peer);
+return 0;
+}
+
+/* new peer */
+if (peer == NULL) {
+peer = malloc(sizeof(*peer));


g_malloc0 ?.


Ok, replaced malloc/free with g_malloc/g_free in client and server.



+client-notif_cb = notif_cb;
+client-notif_arg = notif_arg;
+client-verbose = verbose;


Missing client-sock_fd = -1; ?


Ok.



+
+/* first, we expect our index + a fd == -1 */
+if (read_one_msg(client, client-local.id, fd)  0 ||
+client-local.id  0 || fd != -1) {

Why not fd  0 ?


Because the server will send us an id and a fd == -1 see 
ivshmem-server.c send_initial_info().





+debug_log(client, cannot read from server\n);
+close(client-sock_fd);
+client-sock_fd = -1;
+return -1;
+}
+debug_log(client, our_id=%ld\n, client-local.id);
+
+/* now, we expect shared mem fd + a -1 index, note that shm fd
+ * is not used */
+if (read_one_msg(client, tmp, fd)  0 ||
+tmp != -1 || fd  0) {
+debug_log(client, cannot read from server (2)\n);
+close(client-sock_fd);
+client-sock_fd = -1;
+return -1;

I think the error logic handle can move the end of this function, reducing
duplicated code. Something like this:

goto err;
   }
err:
debug_log(client, cannot read from server (2)\n);
 close(client-sock_fd);
 client-sock_fd = -1;
 return -1;


Ok, I also updated the server.


+int fd;
+
+if (vector  peer-vectors_count) {


Maybe if (vector = peer-vectors_count) , otherwise the
peer-vectors[] array bounds.


Oh yes, good catch.
It should not happen, at the moment, but it is wrong, indeed.


+/* send a notification to all vectors of a peer */
+int
+ivshmem_client_notify_all_vects(const struct ivshmem_client *client,
+const struct ivshmem_client_peer
*peer)
+{
+unsigned vector;
+int ret = 0;
+
+for (vector = 0; vector  peer-vectors_count; vector++) {
+if (ivshmem_client_notify(client, peer, vector)  0) {
+ret = -1;

The ret's value will be covered when multi clients failed. Do we need
store the failed status for server?.


It indicates that we could not notify *all* clients.



Thanks Gonglei.


--
David Marchand
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [Qemu-devel] [PATCH v3 1/2] contrib: add ivshmem client and server

2014-08-09 Thread Gonglei
Hi,

 Subject: [Qemu-devel] [PATCH v3 1/2] contrib: add ivshmem client and server
 
 When using ivshmem devices, notifications between guests can be sent as
 interrupts using a ivshmem-server (typical use described in documentation).
 The client is provided as a debug tool.
 
 Signed-off-by: Olivier Matz olivier.m...@6wind.com
 Signed-off-by: David Marchand david.march...@6wind.com
 ---
  contrib/ivshmem-client/Makefile |   29 +++
  contrib/ivshmem-client/ivshmem-client.c |  418
 ++
  contrib/ivshmem-client/ivshmem-client.h |  238 ++
  contrib/ivshmem-client/main.c   |  246 ++
  contrib/ivshmem-server/Makefile |   29 +++
  contrib/ivshmem-server/ivshmem-server.c |  420
 +++
  contrib/ivshmem-server/ivshmem-server.h |  185 ++
  contrib/ivshmem-server/main.c   |  296
 ++
  qemu-doc.texi   |   10 +-
  9 files changed, 1868 insertions(+), 3 deletions(-)
  create mode 100644 contrib/ivshmem-client/Makefile
  create mode 100644 contrib/ivshmem-client/ivshmem-client.c
  create mode 100644 contrib/ivshmem-client/ivshmem-client.h
  create mode 100644 contrib/ivshmem-client/main.c
  create mode 100644 contrib/ivshmem-server/Makefile
  create mode 100644 contrib/ivshmem-server/ivshmem-server.c
  create mode 100644 contrib/ivshmem-server/ivshmem-server.h
  create mode 100644 contrib/ivshmem-server/main.c
 
 diff --git a/contrib/ivshmem-client/Makefile b/contrib/ivshmem-client/Makefile
 new file mode 100644
 index 000..eee97c6
 --- /dev/null
 +++ b/contrib/ivshmem-client/Makefile
 @@ -0,0 +1,29 @@
 +# Copyright 6WIND S.A., 2014
 +#
 +# This work is licensed under the terms of the GNU GPL, version 2 or
 +# (at your option) any later version.  See the COPYING file in the
 +# top-level directory.
 +
 +S ?= $(CURDIR)
 +O ?= $(CURDIR)
 +
 +CFLAGS += -Wall -Wextra -Werror -g
 +LDFLAGS +=
 +LDLIBS += -lrt
 +
 +VPATH = $(S)
 +PROG = ivshmem-client
 +OBJS := $(O)/ivshmem-client.o
 +OBJS += $(O)/main.o
 +
 +$(O)/%.o: %.c
 + $(CC) $(CFLAGS) -o $@ -c $
 +
 +$(O)/$(PROG): $(OBJS)
 + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
 +
 +.PHONY: all
 +all: $(O)/$(PROG)
 +
 +clean:
 + rm -f $(OBJS) $(O)/$(PROG)
 diff --git a/contrib/ivshmem-client/ivshmem-client.c
 b/contrib/ivshmem-client/ivshmem-client.c
 new file mode 100644
 index 000..2166b64
 --- /dev/null
 +++ b/contrib/ivshmem-client/ivshmem-client.c
 @@ -0,0 +1,418 @@
 +/*
 + * Copyright 6WIND S.A., 2014
 + *
 + * This work is licensed under the terms of the GNU GPL, version 2 or
 + * (at your option) any later version.  See the COPYING file in the
 + * top-level directory.
 + */
 +
 +#include stdio.h
 +#include stdint.h
 +#include stdlib.h
 +#include errno.h
 +#include string.h
 +#include signal.h
 +#include unistd.h
 +#include inttypes.h
 +#include sys/queue.h
 +
 +#include sys/types.h
 +#include sys/socket.h
 +#include sys/un.h
 +
 +#include ivshmem-client.h
 +
 +/* log a message on stdout if verbose=1 */
 +#define debug_log(client, fmt, ...) do { \
 +if ((client)-verbose) { \
 +printf(fmt, ## __VA_ARGS__); \
 +}\
 +} while (0)
 +
 +/* read message from the unix socket */
 +static int
 +read_one_msg(struct ivshmem_client *client, long *index, int *fd)
 +{
 +int ret;
 +struct msghdr msg;
 +struct iovec iov[1];
 +union {
 +struct cmsghdr cmsg;
 +char control[CMSG_SPACE(sizeof(int))];
 +} msg_control;
 +struct cmsghdr *cmsg;
 +
 +iov[0].iov_base = index;
 +iov[0].iov_len = sizeof(*index);
 +
 +memset(msg, 0, sizeof(msg));
 +msg.msg_iov = iov;
 +msg.msg_iovlen = 1;
 +msg.msg_control = msg_control;
 +msg.msg_controllen = sizeof(msg_control);
 +
 +ret = recvmsg(client-sock_fd, msg, 0);
 +if (ret  0) {
 +debug_log(client, cannot read message: %s\n, strerror(errno));
 +return -1;
 +}
 +if (ret == 0) {
 +debug_log(client, lost connection to server\n);
 +return -1;
 +}
 +
 +*fd = -1;
 +
 +for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg =
 CMSG_NXTHDR(msg, cmsg)) {
 +
 +if (cmsg-cmsg_len != CMSG_LEN(sizeof(int)) ||
 +cmsg-cmsg_level != SOL_SOCKET ||
 +cmsg-cmsg_type != SCM_RIGHTS) {
 +continue;
 +}
 +
 +memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
 +}
 +
 +return 0;
 +}
 +
 +/* free a peer when the server advertise a disconnection or when the
 + * client is freed */
 +static void
 +free_peer(struct ivshmem_client *client, struct ivshmem_client_peer *peer)
 +{
 +unsigned vector;
 +
 +TAILQ_REMOVE(client-peer_list, peer, next);
 +for (vector = 0; vector  peer-vectors_count; vector++) {
 +close(peer-vectors[vector]);
 +}
 +
 +free(peer);
 +}
 +
 +/* handle message coming from server (new peer, new vectors) */
 +static int

[PATCH v3 1/2] contrib: add ivshmem client and server

2014-08-08 Thread David Marchand
When using ivshmem devices, notifications between guests can be sent as
interrupts using a ivshmem-server (typical use described in documentation).
The client is provided as a debug tool.

Signed-off-by: Olivier Matz olivier.m...@6wind.com
Signed-off-by: David Marchand david.march...@6wind.com
---
 contrib/ivshmem-client/Makefile |   29 +++
 contrib/ivshmem-client/ivshmem-client.c |  418 ++
 contrib/ivshmem-client/ivshmem-client.h |  238 ++
 contrib/ivshmem-client/main.c   |  246 ++
 contrib/ivshmem-server/Makefile |   29 +++
 contrib/ivshmem-server/ivshmem-server.c |  420 +++
 contrib/ivshmem-server/ivshmem-server.h |  185 ++
 contrib/ivshmem-server/main.c   |  296 ++
 qemu-doc.texi   |   10 +-
 9 files changed, 1868 insertions(+), 3 deletions(-)
 create mode 100644 contrib/ivshmem-client/Makefile
 create mode 100644 contrib/ivshmem-client/ivshmem-client.c
 create mode 100644 contrib/ivshmem-client/ivshmem-client.h
 create mode 100644 contrib/ivshmem-client/main.c
 create mode 100644 contrib/ivshmem-server/Makefile
 create mode 100644 contrib/ivshmem-server/ivshmem-server.c
 create mode 100644 contrib/ivshmem-server/ivshmem-server.h
 create mode 100644 contrib/ivshmem-server/main.c

diff --git a/contrib/ivshmem-client/Makefile b/contrib/ivshmem-client/Makefile
new file mode 100644
index 000..eee97c6
--- /dev/null
+++ b/contrib/ivshmem-client/Makefile
@@ -0,0 +1,29 @@
+# Copyright 6WIND S.A., 2014
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# (at your option) any later version.  See the COPYING file in the
+# top-level directory.
+
+S ?= $(CURDIR)
+O ?= $(CURDIR)
+
+CFLAGS += -Wall -Wextra -Werror -g
+LDFLAGS +=
+LDLIBS += -lrt
+
+VPATH = $(S)
+PROG = ivshmem-client
+OBJS := $(O)/ivshmem-client.o
+OBJS += $(O)/main.o
+
+$(O)/%.o: %.c
+   $(CC) $(CFLAGS) -o $@ -c $
+
+$(O)/$(PROG): $(OBJS)
+   $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+.PHONY: all
+all: $(O)/$(PROG)
+
+clean:
+   rm -f $(OBJS) $(O)/$(PROG)
diff --git a/contrib/ivshmem-client/ivshmem-client.c 
b/contrib/ivshmem-client/ivshmem-client.c
new file mode 100644
index 000..2166b64
--- /dev/null
+++ b/contrib/ivshmem-client/ivshmem-client.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright 6WIND S.A., 2014
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.  See the COPYING file in the
+ * top-level directory.
+ */
+
+#include stdio.h
+#include stdint.h
+#include stdlib.h
+#include errno.h
+#include string.h
+#include signal.h
+#include unistd.h
+#include inttypes.h
+#include sys/queue.h
+
+#include sys/types.h
+#include sys/socket.h
+#include sys/un.h
+
+#include ivshmem-client.h
+
+/* log a message on stdout if verbose=1 */
+#define debug_log(client, fmt, ...) do { \
+if ((client)-verbose) { \
+printf(fmt, ## __VA_ARGS__); \
+}\
+} while (0)
+
+/* read message from the unix socket */
+static int
+read_one_msg(struct ivshmem_client *client, long *index, int *fd)
+{
+int ret;
+struct msghdr msg;
+struct iovec iov[1];
+union {
+struct cmsghdr cmsg;
+char control[CMSG_SPACE(sizeof(int))];
+} msg_control;
+struct cmsghdr *cmsg;
+
+iov[0].iov_base = index;
+iov[0].iov_len = sizeof(*index);
+
+memset(msg, 0, sizeof(msg));
+msg.msg_iov = iov;
+msg.msg_iovlen = 1;
+msg.msg_control = msg_control;
+msg.msg_controllen = sizeof(msg_control);
+
+ret = recvmsg(client-sock_fd, msg, 0);
+if (ret  0) {
+debug_log(client, cannot read message: %s\n, strerror(errno));
+return -1;
+}
+if (ret == 0) {
+debug_log(client, lost connection to server\n);
+return -1;
+}
+
+*fd = -1;
+
+for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+
+if (cmsg-cmsg_len != CMSG_LEN(sizeof(int)) ||
+cmsg-cmsg_level != SOL_SOCKET ||
+cmsg-cmsg_type != SCM_RIGHTS) {
+continue;
+}
+
+memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
+}
+
+return 0;
+}
+
+/* free a peer when the server advertise a disconnection or when the
+ * client is freed */
+static void
+free_peer(struct ivshmem_client *client, struct ivshmem_client_peer *peer)
+{
+unsigned vector;
+
+TAILQ_REMOVE(client-peer_list, peer, next);
+for (vector = 0; vector  peer-vectors_count; vector++) {
+close(peer-vectors[vector]);
+}
+
+free(peer);
+}
+
+/* handle message coming from server (new peer, new vectors) */
+static int
+handle_server_msg(struct ivshmem_client *client)
+{
+struct ivshmem_client_peer *peer;
+long peer_id;
+int ret, fd;
+
+ret = read_one_msg(client, peer_id, fd);
+if (ret  0) {
+return -1;
+}
+
+/* can return a 

Re: [Qemu-devel] [PATCH v3 1/2] contrib: add ivshmem client and server

2014-08-08 Thread Stefan Hajnoczi
On Fri, Aug 08, 2014 at 10:55:17AM +0200, David Marchand wrote:

Looks good, a few minor comments:

 diff --git a/contrib/ivshmem-client/Makefile b/contrib/ivshmem-client/Makefile
 new file mode 100644
 index 000..eee97c6
 --- /dev/null
 +++ b/contrib/ivshmem-client/Makefile
 @@ -0,0 +1,29 @@
 +# Copyright 6WIND S.A., 2014
 +#
 +# This work is licensed under the terms of the GNU GPL, version 2 or
 +# (at your option) any later version.  See the COPYING file in the
 +# top-level directory.
 +
 +S ?= $(CURDIR)
 +O ?= $(CURDIR)
 +
 +CFLAGS += -Wall -Wextra -Werror -g
 +LDFLAGS +=
 +LDLIBS += -lrt
 +
 +VPATH = $(S)
 +PROG = ivshmem-client
 +OBJS := $(O)/ivshmem-client.o
 +OBJS += $(O)/main.o
 +
 +$(O)/%.o: %.c
 + $(CC) $(CFLAGS) -o $@ -c $
 +
 +$(O)/$(PROG): $(OBJS)
 + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
 +
 +.PHONY: all
 +all: $(O)/$(PROG)
 +
 +clean:
 + rm -f $(OBJS) $(O)/$(PROG)

CCed Peter Maydell for a second opinion, I'd suggest hooking up to
QEMU's top-level ./Makefile.  QEMU does not do recursive make.

The advantages of hooking up QEMU's Makefile are:

1. So that ivshmem client/server code is built by default (on supported
   host platforms) and bitrot is avoided.

2. So that you don't have to duplicate rules.mak or any other build
   infrastructure.

 +/**
 + * Structure storing a peer
 + *
 + * Each time a client connects to an ivshmem server, it is advertised to
 + * all connected clients through the unix socket. When our ivshmem
 + * client receives a notification, it creates a ivshmem_client_peer
 + * structure to store the infos of this peer.
 + *
 + * This structure is also used to store the information of our own
 + * client in (struct ivshmem_client)-local.
 + */
 +struct ivshmem_client_peer {
 +TAILQ_ENTRY(ivshmem_client_peer) next;/** next in list*/
 +long id;/** the id of the peer */
 +int vectors[IVSHMEM_CLIENT_MAX_VECTORS];  /** one fd per vector */
 +unsigned vectors_count; /** number of vectors */
 +};

It would be nice to follow QEMU coding style:
typedef struct IvshmemClientPeer {
...
} IvshmemClientPeer;

(Use scripts/checkpatch.pl to check coding style)

 +/* browse the queue, allowing to remove/free the current element */
 +#defineTAILQ_FOREACH_SAFE(var, var2, head, field)\
 +for ((var) = TAILQ_FIRST((head)),\
 + (var2) = ((var) ? TAILQ_NEXT((var), field) : NULL); \
 + (var);  \
 + (var) = (var2), \
 + (var2) = ((var2) ? TAILQ_NEXT((var2), field) : NULL))

Please reuse include/qemu/queue.h.  It's a copy of the BSD sys/queue.h
and it has QTAILQ_FOREACH_SAFE().

 +ret = sendmsg(sock_fd, msg, 0);
 +if (ret = 0) {
 +return -1;
 +}

This is a blocking sendmsg(2) so it could hang the server if sock_fd's
sndbuf fills up.  This shouldn't happen since the amount of data that
gets sent in the lifetime of a session is relatively small, but there is
a chance.

If hung clients should not be able to block the server then sock_fd
needs to be non-blocking.

 +struct ivshmem_server {
 +char unix_sock_path[PATH_MAX];  /** path to unix socket */
 +int sock_fd;/** unix sock file descriptor */
 +char shm_path[PATH_MAX];/** path to shm */
 +size_t shm_size;/** size of shm */
 +int shm_fd; /** shm file descriptor */
 +unsigned n_vectors; /** number of vectors */
 +long cur_id;/** id to be given to next client */
 +int verbose;/** true in verbose mode */

C99 bool is fine to use in QEMU code.  It makes the code easier to read
because you can be sure something is just true/false and not a bitmap or
integer counter.

 +/* parse the size of shm */
 +static int
 +parse_size(const char *val_str, size_t *val)

Looks similar to QEMU's util/qemu-option.c:parse_option_size().


pgpwcRy_qOcxl.pgp
Description: PGP signature