All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review)
@ 2015-09-15 16:07 marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 01/46] char: add qemu_chr_free() marcandre.lureau
                   ` (47 more replies)
  0 siblings, 48 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Hi,

This series is mostly about adding the client/server code from David
Marchand, code cleanups, and little improvements and fixes for
ivshmem. Finally there is some ivshmem tests (they work fine without
kvm btw).

The first two series didn't get much feedback, and the third series is
mostly untouched. The code is not complicated (hopefully), please
review, thanks!! :)

Git: https://github.com/elmarco/qemu.git ivshmem branch

v2->v3:
- add old migration fallback code
- split a few patches
- improve some commit messages
- drop a commit checking eventfd read value

v1->v2:
- add support for hugepage shm (suggested by Andrew Jones)
- add irqfd for msix notification

David Marchand (3):
  contrib: add ivshmem client and server
  docs: update ivshmem device spec
  ivshmem: add check on protocol version in QEMU

Marc-André Lureau (43):
  char: add qemu_chr_free()
  msix: add VMSTATE_MSIX_TEST
  ivhsmem: read do not accept more than sizeof(long)
  ivshmem: fix number of bytes to push to fifo
  ivshmem: factor out the incoming fifo handling
  ivshmem: remove unnecessary dup()
  ivshmem: remove superflous ivshmem_attr field
  ivshmem: remove useless doorbell field
  ivshmem: more qdev conversion
  ivshmem: remove last exit(1)
  ivshmem: limit maximum number of peers to G_MAXUINT16
  ivshmem: simplify around increase_dynamic_storage()
  ivshmem: allocate eventfds in resize_peers()
  ivshmem: remove useless ivshmem_update_irq() val argument
  ivshmem: initialize max_peer to -1
  ivshmem: remove max_peer field
  ivshmem: improve debug messages
  ivshmem: improve error
  ivshmem: print error on invalid peer id
  ivshmem: simplify a bit the code
  ivshmem: use common return
  ivshmem: use common is_power_of_2()
  ivshmem: migrate with VMStateDescription
  ivshmem: shmfd can be 0
  ivshmem: check shm isn't already initialized
  ivshmem: add device description
  ivshmem: fix pci_ivshmem_exit()
  ivshmem: replace 'guest' for 'peer' appropriately
  ivshmem: error on too many eventfd received
  ivshmem: reset mask on device reset
  ivshmem-client: check the number of vectors
  ivshmem-server: use a uint16 for client ID
  ivshmem-server: fix hugetlbfs support
  contrib: remove unnecessary strdup()
  msix: implement pba write (but read-only)
  qtest: add qtest_add_abrt_handler()
  tests: add ivshmem qtest
  ivshmem: do not keep shm_fd open
  ivshmem: make ivshmem_get_size() more generic
  ivshmem: add hostmem backend
  ivshmem: remove EventfdEntry.vector
  ivshmem: rename MSI eventfd_table
  ivshmem: use kvm irqfd for msi notifications

 Makefile                                |   8 +
 configure                               |   3 +
 contrib/ivshmem-client/ivshmem-client.c | 444 ++++++++++++++++++
 contrib/ivshmem-client/ivshmem-client.h | 213 +++++++++
 contrib/ivshmem-client/main.c           | 239 ++++++++++
 contrib/ivshmem-server/ivshmem-server.c | 478 +++++++++++++++++++
 contrib/ivshmem-server/ivshmem-server.h | 166 +++++++
 contrib/ivshmem-server/main.c           | 263 +++++++++++
 docs/specs/ivshmem_device_spec.txt      | 127 +++--
 hw/misc/ivshmem.c                       | 801 ++++++++++++++++++++++----------
 hw/pci/msix.c                           |   6 +
 include/hw/misc/ivshmem.h               |  25 +
 include/hw/pci/msix.h                   |  16 +-
 include/sysemu/char.h                   |  10 +-
 qemu-char.c                             |   9 +-
 qemu-doc.texi                           |  10 +-
 tests/Makefile                          |   3 +
 tests/ivshmem-test.c                    | 486 +++++++++++++++++++
 tests/libqtest.c                        |  37 +-
 tests/libqtest.h                        |   2 +
 20 files changed, 3050 insertions(+), 296 deletions(-)
 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/ivshmem-server.c
 create mode 100644 contrib/ivshmem-server/ivshmem-server.h
 create mode 100644 contrib/ivshmem-server/main.c
 create mode 100644 include/hw/misc/ivshmem.h
 create mode 100644 tests/ivshmem-test.c

-- 
2.4.3

^ permalink raw reply	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 01/46] char: add qemu_chr_free()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 02/46] msix: add VMSTATE_MSIX_TEST marcandre.lureau
                   ` (46 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

If a chardev is allowed to be created outside of QMP, then it must be
also possible to free it. This is useful for ivshmem that creates
chardev anonymously and must be able to free them.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 10 +++++++++-
 qemu-char.c           |  9 +++++++--
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 832b7fe..5fd0a09 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -128,11 +128,19 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename,
 /**
  * @qemu_chr_delete:
  *
- * Destroy a character backend.
+ * Destroy a character backend and remove it from the list of
+ * identified character backends.
  */
 void qemu_chr_delete(CharDriverState *chr);
 
 /**
+ * @qemu_chr_free:
+ *
+ * Destroy a character backend.
+ */
+void qemu_chr_free(CharDriverState *chr);
+
+/**
  * @qemu_chr_fe_set_echo:
  *
  * Ask the backend to override its normal echo setting.  This only really
diff --git a/qemu-char.c b/qemu-char.c
index dd83203..e26e9c5 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3840,9 +3840,8 @@ void qemu_chr_fe_release(CharDriverState *s)
     s->avail_connections++;
 }
 
-void qemu_chr_delete(CharDriverState *chr)
+void qemu_chr_free(CharDriverState *chr)
 {
-    QTAILQ_REMOVE(&chardevs, chr, next);
     if (chr->chr_close) {
         chr->chr_close(chr);
     }
@@ -3852,6 +3851,12 @@ void qemu_chr_delete(CharDriverState *chr)
     g_free(chr);
 }
 
+void qemu_chr_delete(CharDriverState *chr)
+{
+    QTAILQ_REMOVE(&chardevs, chr, next);
+    qemu_chr_free(chr);
+}
+
 ChardevInfoList *qmp_query_chardev(Error **errp)
 {
     ChardevInfoList *chr_list = NULL;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 02/46] msix: add VMSTATE_MSIX_TEST
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 01/46] char: add qemu_chr_free() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long) marcandre.lureau
                   ` (45 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

ivshmem is going to use MSIX state conditionally.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/hw/pci/msix.h | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/include/hw/pci/msix.h b/include/hw/pci/msix.h
index 954d82b..72e5f93 100644
--- a/include/hw/pci/msix.h
+++ b/include/hw/pci/msix.h
@@ -46,12 +46,16 @@ void msix_unset_vector_notifiers(PCIDevice *dev);
 
 extern const VMStateDescription vmstate_msix;
 
-#define VMSTATE_MSIX(_field, _state) {                               \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(PCIDevice),                                 \
-    .vmsd       = &vmstate_msix,                                     \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+#define VMSTATE_MSIX_TEST(_field, _state, _test) {                   \
+    .name         = (stringify(_field)),                             \
+    .size         = sizeof(PCIDevice),                               \
+    .vmsd         = &vmstate_msix,                                   \
+    .flags        = VMS_STRUCT,                                      \
+    .offset       = vmstate_offset_value(_state, _field, PCIDevice), \
+    .field_exists = (_test)                                          \
 }
 
+#define VMSTATE_MSIX(_f, _s)                                         \
+    VMSTATE_MSIX_TEST(_f, _s, NULL)
+
 #endif
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 01/46] char: add qemu_chr_free() marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 02/46] msix: add VMSTATE_MSIX_TEST marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16  9:27   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo marcandre.lureau
                   ` (44 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

ivshmem_read() only reads sizeof(long) from the input buffer.  Accepting
more could lead to fifo8 abort() on 32bit systems if fifo is not empty.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index cc76989..fb53b3f 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -272,7 +272,7 @@ static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
 
 static int ivshmem_can_receive(void * opaque)
 {
-    return 8;
+    return sizeof(long);
 }
 
 static void ivshmem_event(void *opaque, int event)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (2 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long) marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16  9:28   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling marcandre.lureau
                   ` (43 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

If the fifo has 0 bytes, and the read is of size 1, the call to
fifo8_push_all() will copy off boundary data.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index fb53b3f..2162d02 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -455,7 +455,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
         uint32_t num;
 
         IVSHMEM_DPRINTF("short read of %d bytes\n", size);
-        num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
+        num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
         fifo8_push_all(&s->incoming_fifo, buf, num);
         if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
             return;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (3 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:01   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup() marcandre.lureau
                   ` (42 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Make a new function fifo_update_and_get() that can be reused by other
functions (in next commits).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 59 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 20 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 2162d02..dd15f0e 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -441,6 +441,42 @@ static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
     return 0;
 }
 
+static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
+                                void *data, size_t len)
+{
+    const uint8_t *p;
+    uint32_t num;
+
+    assert(len <= sizeof(long)); /* limitation of the fifo */
+    if (fifo8_is_empty(&s->incoming_fifo) && size == len) {
+        memcpy(data, buf, size);
+        return true;
+    }
+
+    IVSHMEM_DPRINTF("short read of %d bytes\n", size);
+
+    num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
+    fifo8_push_all(&s->incoming_fifo, buf, num);
+
+    if (fifo8_num_used(&s->incoming_fifo) < len) {
+        assert(num == 0);
+        return false;
+    }
+
+    size -= num;
+    buf += num;
+    p = fifo8_pop_buf(&s->incoming_fifo, len, &num);
+    assert(num == len);
+
+    memcpy(data, p, len);
+
+    if (size > 0) {
+        fifo8_push_all(&s->incoming_fifo, buf, size);
+    }
+
+    return true;
+}
+
 static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 {
     IVShmemState *s = opaque;
@@ -448,26 +484,9 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     int guest_max_eventfd;
     long incoming_posn;
 
-    if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
-        memcpy(&incoming_posn, buf, size);
-    } else {
-        const uint8_t *p;
-        uint32_t num;
-
-        IVSHMEM_DPRINTF("short read of %d bytes\n", size);
-        num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
-        fifo8_push_all(&s->incoming_fifo, buf, num);
-        if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
-            return;
-        }
-        size -= num;
-        buf += num;
-        p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
-        g_assert(num == sizeof(incoming_posn));
-        memcpy(&incoming_posn, p, sizeof(incoming_posn));
-        if (size > 0) {
-            fifo8_push_all(&s->incoming_fifo, buf, size);
-        }
+    if (!fifo_update_and_get(s, buf, size,
+                             &incoming_posn, sizeof(incoming_posn))) {
+        return;
     }
 
     if (incoming_posn < -1) {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (4 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:06   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field marcandre.lureau
                   ` (41 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

qemu_chr_fe_get_msgfd() transfers ownership, there is no need to dup the
fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 21 ++++++---------------
 1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index dd15f0e..fbeb731 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -480,7 +480,7 @@ static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
 static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 {
     IVShmemState *s = opaque;
-    int incoming_fd, tmp_fd;
+    int incoming_fd;
     int guest_max_eventfd;
     long incoming_posn;
 
@@ -495,21 +495,21 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     }
 
     /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
-    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
-    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+    incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
+    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, incoming_fd);
 
     /* make sure we have enough space for this guest */
     if (incoming_posn >= s->nb_peers) {
         if (increase_dynamic_storage(s, incoming_posn) < 0) {
             error_report("increase_dynamic_storage() failed");
-            if (tmp_fd != -1) {
-                close(tmp_fd);
+            if (incoming_fd != -1) {
+                close(incoming_fd);
             }
             return;
         }
     }
 
-    if (tmp_fd == -1) {
+    if (incoming_fd == -1) {
         /* if posn is positive and unseen before then this is our posn*/
         if ((incoming_posn >= 0) &&
                             (s->peers[incoming_posn].eventfds == NULL)) {
@@ -524,15 +524,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
         }
     }
 
-    /* because of the implementation of get_msgfd, we need a dup */
-    incoming_fd = dup(tmp_fd);
-
-    if (incoming_fd == -1) {
-        error_report("could not allocate file descriptor %s", strerror(errno));
-        close(tmp_fd);
-        return;
-    }
-
     /* if the position is -1, then it's shared memory region fd */
     if (incoming_posn == -1) {
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (5 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16  9:25   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field marcandre.lureau
                   ` (40 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index fbeb731..5e4b2cc 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -85,7 +85,6 @@ typedef struct IVShmemState {
     MemoryRegion bar;
     MemoryRegion ivshmem;
     uint64_t ivshmem_size; /* size of shared memory region */
-    uint32_t ivshmem_attr;
     uint32_t ivshmem_64bit;
     int shm_fd; /* shared memory file descriptor */
 
@@ -345,7 +344,7 @@ static int check_shm_size(IVShmemState *s, int fd) {
 
 /* create the shared memory BAR when we are not using the server, so we can
  * create the BAR and map the memory immediately */
-static void create_shared_memory_BAR(IVShmemState *s, int fd) {
+static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
 
     void * ptr;
 
@@ -359,7 +358,7 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
     memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
     /* region for shared memory */
-    pci_register_bar(PCI_DEVICE(s), 2, s->ivshmem_attr, &s->bar);
+    pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
 }
 
 static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
@@ -714,6 +713,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
 {
     IVShmemState *s = IVSHMEM(dev);
     uint8_t *pci_conf;
+    uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
+        PCI_BASE_ADDRESS_MEM_PREFETCH;;
 
     if (s->sizearg == NULL)
         s->ivshmem_size = 4 << 20; /* 4 MB default */
@@ -768,10 +769,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
                      &s->ivshmem_mmio);
 
     memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size);
-    s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
-        PCI_BASE_ADDRESS_MEM_PREFETCH;
     if (s->ivshmem_64bit) {
-        s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+        attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
     }
 
     if ((s->server_chr != NULL) &&
@@ -798,7 +797,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
         /* allocate/initialize space for interrupt handling */
         s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
 
-        pci_register_bar(dev, 2, s->ivshmem_attr, &s->bar);
+        pci_register_bar(dev, 2, attr, &s->bar);
 
         s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
 
@@ -835,8 +834,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
             exit(1);
         }
 
-        create_shared_memory_BAR(s, fd);
-
+        create_shared_memory_BAR(s, fd, attr);
     }
 
     dev->config_write = ivshmem_write_config;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (6 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 13:50   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion marcandre.lureau
                   ` (39 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 5e4b2cc..1b8204e 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -71,7 +71,6 @@ typedef struct IVShmemState {
 
     uint32_t intrmask;
     uint32_t intrstatus;
-    uint32_t doorbell;
 
     CharDriverState **eventfd_chr;
     CharDriverState *server_chr;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (7 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:00   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1) marcandre.lureau
                   ` (38 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Use the latest qemu device modeling API, in particular, convert to
realize to fix the error handling; right now a botched device_add
ivhsmem command kills the VM.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 119 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 68 insertions(+), 51 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 1b8204e..3af73a5 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -319,22 +319,23 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
 
 }
 
-static int check_shm_size(IVShmemState *s, int fd) {
+static int check_shm_size(IVShmemState *s, int fd, Error **errp)
+{
     /* check that the guest isn't going to try and map more memory than the
      * the object has allocated return -1 to indicate error */
 
     struct stat buf;
 
     if (fstat(fd, &buf) < 0) {
-        error_report("exiting: fstat on fd %d failed: %s",
-                     fd, strerror(errno));
+        error_setg(errp, "exiting: fstat on fd %d failed: %s",
+                   fd, strerror(errno));
         return -1;
     }
 
     if (s->ivshmem_size > buf.st_size) {
-        error_report("Requested memory size greater"
-                     " than shared object size (%" PRIu64 " > %" PRIu64")",
-                     s->ivshmem_size, (uint64_t)buf.st_size);
+        error_setg(errp, "Requested memory size greater"
+                   " than shared object size (%" PRIu64 " > %" PRIu64")",
+                   s->ivshmem_size, (uint64_t)buf.st_size);
         return -1;
     } else {
         return 0;
@@ -343,13 +344,18 @@ static int check_shm_size(IVShmemState *s, int fd) {
 
 /* create the shared memory BAR when we are not using the server, so we can
  * create the BAR and map the memory immediately */
-static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
-
+static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
+                                    Error **errp)
+{
     void * ptr;
 
-    s->shm_fd = fd;
-
     ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (ptr == MAP_FAILED) {
+        error_setg_errno(errp, errno, "Failed to mmap shared memory");
+        return -1;
+    }
+
+    s->shm_fd = fd;
 
     memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
                                s->ivshmem_size, ptr);
@@ -358,6 +364,8 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
 
     /* region for shared memory */
     pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
+
+    return 0;
 }
 
 static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
@@ -481,6 +489,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     int incoming_fd;
     int guest_max_eventfd;
     long incoming_posn;
+    Error *err = NULL;
 
     if (!fifo_update_and_get(s, buf, size,
                              &incoming_posn, sizeof(incoming_posn))) {
@@ -524,18 +533,24 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 
     /* if the position is -1, then it's shared memory region fd */
     if (incoming_posn == -1) {
-
         void * map_ptr;
 
         s->max_peer = 0;
 
-        if (check_shm_size(s, incoming_fd) == -1) {
-            exit(1);
+        if (check_shm_size(s, incoming_fd, &err) == -1) {
+            error_report_err(err);
+            close(incoming_fd);
+            return;
         }
 
         /* mmap the region and map into the BAR2 */
         map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
                                                             incoming_fd, 0);
+        if (map_ptr == MAP_FAILED) {
+            error_report("Failed to mmap shared memory %s", strerror(errno));
+            close(incoming_fd);
+            return;
+        }
         memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
         vmstate_register_ram(&s->ivshmem, DEVICE(s));
@@ -610,7 +625,7 @@ static void ivshmem_reset(DeviceState *d)
     ivshmem_use_msix(s);
 }
 
-static uint64_t ivshmem_get_size(IVShmemState * s) {
+static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
 
     uint64_t value;
     char *ptr;
@@ -624,24 +639,23 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
             value <<= 30;
             break;
         default:
-            error_report("invalid ram size: %s", s->sizearg);
-            exit(1);
+            error_setg(errp, "invalid ram size: %s", s->sizearg);
+            return 0;
     }
 
     /* BARs must be a power of 2 */
     if (!is_power_of_two(value)) {
-        error_report("size must be power of 2");
-        exit(1);
+        error_setg(errp, "size must be power of 2");
+        return 0;
     }
 
     return value;
 }
 
-static void ivshmem_setup_msi(IVShmemState * s)
+static int ivshmem_setup_msi(IVShmemState * s)
 {
     if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
-        IVSHMEM_DPRINTF("msix initialization failed\n");
-        exit(1);
+        return -1;
     }
 
     IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
@@ -650,6 +664,7 @@ static void ivshmem_setup_msi(IVShmemState * s)
     s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
 
     ivshmem_use_msix(s);
+    return 0;
 }
 
 static void ivshmem_save(QEMUFile* f, void *opaque)
@@ -703,34 +718,37 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
 }
 
 static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
-				 uint32_t val, int len)
+                                 uint32_t val, int len)
 {
     pci_default_write_config(pci_dev, address, val, len);
 }
 
-static int pci_ivshmem_init(PCIDevice *dev)
+static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
 {
     IVShmemState *s = IVSHMEM(dev);
     uint8_t *pci_conf;
     uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
         PCI_BASE_ADDRESS_MEM_PREFETCH;;
+    Error *local_err = NULL;
 
-    if (s->sizearg == NULL)
+    if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
-    else {
-        s->ivshmem_size = ivshmem_get_size(s);
+    } else {
+        s->ivshmem_size = ivshmem_get_size(s, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
+        }
     }
 
     fifo8_create(&s->incoming_fifo, sizeof(long));
-
     register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
                                                                         dev);
-
     /* IRQFD requires MSI */
     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
         !ivshmem_has_feature(s, IVSHMEM_MSI)) {
-        error_report("ioeventfd/irqfd requires MSI");
-        exit(1);
+        error_setg(errp, "ioeventfd/irqfd requires MSI");
+        return;
     }
 
     /* check that role is reasonable */
@@ -740,8 +758,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
         } else if (strncmp(s->role, "master", 7) == 0) {
             s->role_val = IVSHMEM_MASTER;
         } else {
-            error_report("'role' must be 'peer' or 'master'");
-            exit(1);
+            error_setg(errp, "'role' must be 'peer' or 'master'");
+            return;
         }
     } else {
         s->role_val = IVSHMEM_MASTER; /* default */
@@ -778,15 +796,18 @@ static int pci_ivshmem_init(PCIDevice *dev)
          * to the ivshmem server to receive the memory region */
 
         if (s->shmobj != NULL) {
-            error_report("WARNING: do not specify both 'chardev' "
-                         "and 'shm' with ivshmem");
+            error_setg(errp, "do not specify both 'chardev' "
+                       "and 'shm' with ivshmem");
+            return;
         }
 
         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
                         s->server_chr->filename);
 
-        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
-            ivshmem_setup_msi(s);
+        if (ivshmem_has_feature(s, IVSHMEM_MSI) &&
+            ivshmem_setup_msi(s)) {
+            error_setg(errp, "msix initialization failed");
+            return;
         }
 
         /* we allocate enough space for 16 guests and grow as needed */
@@ -807,8 +828,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
         int fd;
 
         if (s->shmobj == NULL) {
-            error_report("Must specify 'chardev' or 'shm' to ivshmem");
-            exit(1);
+            error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
+            return;
         }
 
         IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
@@ -824,24 +845,19 @@ static int pci_ivshmem_init(PCIDevice *dev)
 
         } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
                         S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
-            error_report("could not open shared file");
-            exit(1);
-
+            error_setg(errp, "could not open shared file");
+            return;
         }
 
-        if (check_shm_size(s, fd) == -1) {
-            exit(1);
+        if (check_shm_size(s, fd, errp) == -1) {
+            return;
         }
 
-        create_shared_memory_BAR(s, fd, attr);
+        create_shared_memory_BAR(s, fd, attr, errp);
     }
-
-    dev->config_write = ivshmem_write_config;
-
-    return 0;
 }
 
-static void pci_ivshmem_uninit(PCIDevice *dev)
+static void pci_ivshmem_exit(PCIDevice *dev)
 {
     IVShmemState *s = IVSHMEM(dev);
 
@@ -873,8 +889,9 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-    k->init = pci_ivshmem_init;
-    k->exit = pci_ivshmem_uninit;
+    k->realize = pci_ivshmem_realize;
+    k->exit = pci_ivshmem_exit;
+    k->config_write = ivshmem_write_config;
     k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
     k->device_id = PCI_DEVICE_ID_IVSHMEM;
     k->class_id = PCI_CLASS_MEMORY_RAM;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1)
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (8 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 13:55   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16 marcandre.lureau
                   ` (37 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Failing to create a chardev shouldn't be fatal.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 3af73a5..7ba93c0 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -299,7 +299,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
 
     if (chr == NULL) {
         error_report("creating eventfd for eventfd %d failed", eventfd);
-        exit(1);
+        return NULL;
     }
     qemu_chr_fe_claim_no_fail(chr);
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (9 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1) marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:09   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage() marcandre.lureau
                   ` (36 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Limit the maximum number of peers to MAXUINT16. This is more realistic
and better matches the limit of the doorbell register.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 7ba93c0..cd2c4bc 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -34,6 +34,7 @@
 #define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
 #define PCI_DEVICE_ID_IVSHMEM   0x1110
 
+#define IVSHMEM_MAX_PEERS G_MAXUINT16
 #define IVSHMEM_IOEVENTFD   0
 #define IVSHMEM_MSI     1
 
@@ -421,8 +422,8 @@ static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
 
     int j, old_nb_alloc;
 
-    /* check for integer overflow */
-    if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
+    /* limit number of max peers */
+    if (new_min_size <= 0 || new_min_size > IVSHMEM_MAX_PEERS) {
         return -1;
     }
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (10 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16 marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:10   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 13/46] ivshmem: allocate eventfds in resize_peers() marcandre.lureau
                   ` (35 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Set the number of peers and array allocation in a single place. Rename
to better reflect the function content.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index cd2c4bc..889a199 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -417,30 +417,28 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
 
 /* this function increase the dynamic storage need to store data about other
  * guests */
-static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
+static int resize_peers(IVShmemState *s, int new_min_size)
 {
 
-    int j, old_nb_alloc;
+    int j, old_size;
 
     /* limit number of max peers */
     if (new_min_size <= 0 || new_min_size > IVSHMEM_MAX_PEERS) {
         return -1;
     }
-
-    old_nb_alloc = s->nb_peers;
-
-    if (new_min_size >= s->nb_peers) {
-        /* +1 because #new_min_size is used as last array index */
-        s->nb_peers = new_min_size + 1;
-    } else {
+    if (new_min_size <= s->nb_peers) {
         return 0;
     }
 
+    old_size = s->nb_peers;
+    s->nb_peers = new_min_size;
+
     IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+
     s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
 
     /* zero out new pointers */
-    for (j = old_nb_alloc; j < s->nb_peers; j++) {
+    for (j = old_size; j < s->nb_peers; j++) {
         s->peers[j].eventfds = NULL;
         s->peers[j].nb_eventfds = 0;
     }
@@ -508,8 +506,8 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 
     /* make sure we have enough space for this guest */
     if (incoming_posn >= s->nb_peers) {
-        if (increase_dynamic_storage(s, incoming_posn) < 0) {
-            error_report("increase_dynamic_storage() failed");
+        if (resize_peers(s, incoming_posn + 1) < 0) {
+            error_report("failed to resize peers array");
             if (incoming_fd != -1) {
                 close(incoming_fd);
             }
@@ -812,12 +810,9 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         }
 
         /* we allocate enough space for 16 guests and grow as needed */
-        s->nb_peers = 16;
+        resize_peers(s, 16);
         s->vm_id = -1;
 
-        /* allocate/initialize space for interrupt handling */
-        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
-
         pci_register_bar(dev, 2, attr, &s->bar);
 
         s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 13/46] ivshmem: allocate eventfds in resize_peers()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (11 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument marcandre.lureau
                   ` (34 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It simplifies a bit the code to allocate the array when setting the
number of peers instead of lazily when receiving the first vector.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 889a199..e890967 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -437,9 +437,8 @@ static int resize_peers(IVShmemState *s, int new_min_size)
 
     s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
 
-    /* zero out new pointers */
     for (j = old_size; j < s->nb_peers; j++) {
-        s->peers[j].eventfds = NULL;
+        s->peers[j].eventfds = g_new0(EventNotifier, s->vectors);
         s->peers[j].nb_eventfds = 0;
     }
 
@@ -517,8 +516,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 
     if (incoming_fd == -1) {
         /* if posn is positive and unseen before then this is our posn*/
-        if ((incoming_posn >= 0) &&
-                            (s->peers[incoming_posn].eventfds == NULL)) {
+        if (incoming_posn >= 0 && s->vm_id == -1) {
             /* receive our posn */
             s->vm_id = incoming_posn;
             return;
@@ -569,11 +567,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
      * guests for each VM */
     guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
 
-    if (guest_max_eventfd == 0) {
-        /* one eventfd per MSI vector */
-        s->peers[incoming_posn].eventfds = g_new(EventNotifier, s->vectors);
-    }
-
     /* this is an eventfd for a particular guest VM */
     IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
                     guest_max_eventfd, incoming_fd);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (12 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 13/46] ivshmem: allocate eventfds in resize_peers() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:13   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1 marcandre.lureau
                   ` (33 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

val isn't used in ivshmem_update_irq() function.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index e890967..3398a57 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -123,7 +123,7 @@ static inline bool is_power_of_two(uint64_t x) {
 }
 
 /* accessing registers - based on rtl8139 */
-static void ivshmem_update_irq(IVShmemState *s, int val)
+static void ivshmem_update_irq(IVShmemState *s)
 {
     PCIDevice *d = PCI_DEVICE(s);
     int isr;
@@ -144,7 +144,7 @@ static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
 
     s->intrmask = val;
 
-    ivshmem_update_irq(s, val);
+    ivshmem_update_irq(s);
 }
 
 static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
@@ -162,7 +162,7 @@ static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
 
     s->intrstatus = val;
 
-    ivshmem_update_irq(s, val);
+    ivshmem_update_irq(s);
 }
 
 static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
@@ -172,7 +172,7 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
     /* reading ISR clears all interrupts */
     s->intrstatus = 0;
 
-    ivshmem_update_irq(s, 0);
+    ivshmem_update_irq(s);
 
     return ret;
 }
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (13 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:13   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field marcandre.lureau
                   ` (32 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

There is no peer when device is initialized, do not let doorbell for
inexisting peer 0.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 3398a57..07f2182 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -532,8 +532,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     if (incoming_posn == -1) {
         void * map_ptr;
 
-        s->max_peer = 0;
-
         if (check_shm_size(s, incoming_fd, &err) == -1) {
             error_report_err(err);
             close(incoming_fd);
@@ -723,6 +721,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         PCI_BASE_ADDRESS_MEM_PREFETCH;;
     Error *local_err = NULL;
 
+    s->max_peer = -1;
+
     if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
     } else {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (14 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1 marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16  9:39   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages marcandre.lureau
                   ` (31 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

max_peer isn't really useful, it tracks the maximum received VM id, but
that quickly matches nb_peers, the size of the peers array. Since VM
come and go, there might be sparse peers so it doesn't help much in
general to have this value around.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 07f2182..cda7dce 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -90,7 +90,6 @@ typedef struct IVShmemState {
 
     Peer *peers;
     int nb_peers; /* how many guests we have space for */
-    int max_peer; /* maximum numbered peer */
 
     int vm_id;
     uint32_t vectors;
@@ -200,7 +199,7 @@ static void ivshmem_io_write(void *opaque, hwaddr addr,
 
         case DOORBELL:
             /* check that dest VM ID is reasonable */
-            if (dest > s->max_peer) {
+            if (dest >= s->nb_peers) {
                 IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
                 break;
             }
@@ -574,11 +573,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     /* increment count for particular guest */
     s->peers[incoming_posn].nb_eventfds++;
 
-    /* keep track of the maximum VM ID */
-    if (incoming_posn > s->max_peer) {
-        s->max_peer = incoming_posn;
-    }
-
     if (incoming_posn == s->vm_id) {
         s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
                    &s->peers[s->vm_id].eventfds[guest_max_eventfd],
@@ -721,8 +715,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         PCI_BASE_ADDRESS_MEM_PREFETCH;;
     Error *local_err = NULL;
 
-    s->max_peer = -1;
-
     if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
     } else {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (15 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:23   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error marcandre.lureau
                   ` (30 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Some misc improvements to ivshmem debug.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index cda7dce..084bc89 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -208,10 +208,13 @@ static void ivshmem_io_write(void *opaque, hwaddr addr,
             if (vector < s->peers[dest].nb_eventfds) {
                 IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
                 event_notifier_set(&s->peers[dest].eventfds[vector]);
+            } else {
+                IVSHMEM_DPRINTF("Invalid destination vector %d on VM %d\n",
+                                vector, dest);
             }
             break;
         default:
-            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
+            IVSHMEM_DPRINTF("Unhandled write " TARGET_FMT_plx "\n", addr);
     }
 }
 
@@ -263,9 +266,9 @@ static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
 {
     IVShmemState *s = opaque;
 
-    ivshmem_IntrStatus_write(s, *buf);
+    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x size: %d\n", *buf, size);
 
-    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
+    ivshmem_IntrStatus_write(s, *buf);
 }
 
 static int ivshmem_can_receive(void * opaque)
@@ -592,6 +595,7 @@ static void ivshmem_use_msix(IVShmemState * s)
     PCIDevice *d = PCI_DEVICE(s);
     int i;
 
+    IVSHMEM_DPRINTF("use msix\n");
     if (!msix_present(d)) {
         return;
     }
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (16 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:26   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id marcandre.lureau
                   ` (29 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The test whether the chardev is an AF_UNIX socket rejects
"-chardev socket,id=chr0,path=/tmp/foo,server,nowait -device
ivshmem,chardev=chr0", but fails to explain why.

Use an explicit error on why a chardev may be rejected.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 084bc89..52e1e63 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -301,7 +301,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
     chr = qemu_chr_open_eventfd(eventfd);
 
     if (chr == NULL) {
-        error_report("creating eventfd for eventfd %d failed", eventfd);
+        error_report("creating chardriver for eventfd %d failed", eventfd);
         return NULL;
     }
     qemu_chr_fe_claim_no_fail(chr);
@@ -778,8 +778,12 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
     }
 
-    if ((s->server_chr != NULL) &&
-                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
+    if (s->server_chr != NULL) {
+        if (strncmp(s->server_chr->filename, "unix:", 5)) {
+            error_setg(errp, "chardev is not a unix client socket");
+            return;
+        }
+
         /* if we get a UNIX socket as the parameter we will talk
          * to the ivshmem server to receive the memory region */
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (17 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:27   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code marcandre.lureau
                   ` (28 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The server shouldn't send invalid peer id, so print an error if it's the
case.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 52e1e63..1c98ec3 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -399,6 +399,7 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
         return;
     }
     if (posn < 0 || posn >= s->nb_peers) {
+        error_report("invalid peer %d", posn);
         return;
     }
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (18 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:32   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return marcandre.lureau
                   ` (27 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Use some more explicit variables to simplify the code.

nth_eventfd variable is the current eventfd to be manipulated.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 1c98ec3..a60454f 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -488,9 +488,10 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 {
     IVShmemState *s = opaque;
     int incoming_fd;
-    int guest_max_eventfd;
+    int nth_eventfd;
     long incoming_posn;
     Error *err = NULL;
+    Peer *peer;
 
     if (!fifo_update_and_get(s, buf, size,
                              &incoming_posn, sizeof(incoming_posn))) {
@@ -517,6 +518,8 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
         }
     }
 
+    peer = &s->peers[incoming_posn];
+
     if (incoming_fd == -1) {
         /* if posn is positive and unseen before then this is our posn*/
         if (incoming_posn >= 0 && s->vm_id == -1) {
@@ -564,27 +567,22 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
         return;
     }
 
-    /* each guest has an array of eventfds, and we keep track of how many
-     * guests for each VM */
-    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
+    /* get a new eventfd */
+    nth_eventfd = peer->nb_eventfds++;
 
     /* this is an eventfd for a particular guest VM */
     IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
-                    guest_max_eventfd, incoming_fd);
-    event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
-                           incoming_fd);
-
-    /* increment count for particular guest */
-    s->peers[incoming_posn].nb_eventfds++;
+                    nth_eventfd, incoming_fd);
+    event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
 
     if (incoming_posn == s->vm_id) {
-        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
-                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
-                   guest_max_eventfd);
+        s->eventfd_chr[nth_eventfd] = create_eventfd_chr_device(s,
+                   &s->peers[s->vm_id].eventfds[nth_eventfd],
+                   nth_eventfd);
     }
 
     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
-        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
+        ivshmem_add_eventfd(s, incoming_posn, nth_eventfd);
     }
 }
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (19 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 11:30   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2() marcandre.lureau
                   ` (26 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Both if branches return, move this out to common end.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index a60454f..e391396 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -525,13 +525,12 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
         if (incoming_posn >= 0 && s->vm_id == -1) {
             /* receive our posn */
             s->vm_id = incoming_posn;
-            return;
         } else {
             /* otherwise an fd == -1 means an existing guest has gone away */
             IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
             close_guest_eventfds(s, incoming_posn);
-            return;
         }
+        return;
     }
 
     /* if the position is -1, then it's shared memory region fd */
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (20 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 11:31   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 23/46] ivshmem: migrate with VMStateDescription marcandre.lureau
                   ` (25 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The common version correctly checks for 0 value case.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index e391396..f40bc98 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -117,10 +117,6 @@ static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
     return (ivs->features & (1 << feature));
 }
 
-static inline bool is_power_of_two(uint64_t x) {
-    return (x & (x - 1)) == 0;
-}
-
 /* accessing registers - based on rtl8139 */
 static void ivshmem_update_irq(IVShmemState *s)
 {
@@ -630,7 +626,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
     }
 
     /* BARs must be a power of 2 */
-    if (!is_power_of_two(value)) {
+    if (!is_power_of_2(value)) {
         error_setg(errp, "size must be power of 2");
         return 0;
     }
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 23/46] ivshmem: migrate with VMStateDescription
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (21 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0 marcandre.lureau
                   ` (24 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

load_state_old() is used to keep compatibility with version 0.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 141 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 88 insertions(+), 53 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index f40bc98..14c7d58 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -649,56 +649,6 @@ static int ivshmem_setup_msi(IVShmemState * s)
     return 0;
 }
 
-static void ivshmem_save(QEMUFile* f, void *opaque)
-{
-    IVShmemState *proxy = opaque;
-    PCIDevice *pci_dev = PCI_DEVICE(proxy);
-
-    IVSHMEM_DPRINTF("ivshmem_save\n");
-    pci_device_save(pci_dev, f);
-
-    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
-        msix_save(pci_dev, f);
-    } else {
-        qemu_put_be32(f, proxy->intrstatus);
-        qemu_put_be32(f, proxy->intrmask);
-    }
-
-}
-
-static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
-{
-    IVSHMEM_DPRINTF("ivshmem_load\n");
-
-    IVShmemState *proxy = opaque;
-    PCIDevice *pci_dev = PCI_DEVICE(proxy);
-    int ret;
-
-    if (version_id > 0) {
-        return -EINVAL;
-    }
-
-    if (proxy->role_val == IVSHMEM_PEER) {
-        error_report("'peer' devices are not migratable");
-        return -EINVAL;
-    }
-
-    ret = pci_device_load(pci_dev, f);
-    if (ret) {
-        return ret;
-    }
-
-    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
-        msix_load(pci_dev, f);
-	ivshmem_use_msix(proxy);
-    } else {
-        proxy->intrstatus = qemu_get_be32(f);
-        proxy->intrmask = qemu_get_be32(f);
-    }
-
-    return 0;
-}
-
 static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
                                  uint32_t val, int len)
 {
@@ -724,8 +674,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
     }
 
     fifo8_create(&s->incoming_fifo, sizeof(long));
-    register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
-                                                                        dev);
+
     /* IRQFD requires MSI */
     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
         !ivshmem_has_feature(s, IVSHMEM_MSI)) {
@@ -851,10 +800,95 @@ static void pci_ivshmem_exit(PCIDevice *dev)
 
     memory_region_del_subregion(&s->bar, &s->ivshmem);
     vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
-    unregister_savevm(DEVICE(dev), "ivshmem", s);
     fifo8_destroy(&s->incoming_fifo);
 }
 
+static bool test_msix(void *opaque, int version_id)
+{
+    IVShmemState *s = opaque;
+
+    return ivshmem_has_feature(s, IVSHMEM_MSI);
+}
+
+static bool test_no_msix(void *opaque, int version_id)
+{
+    return !test_msix(opaque, version_id);
+}
+
+static int ivshmem_pre_load(void *opaque)
+{
+    IVShmemState *s = opaque;
+
+    if (s->role_val == IVSHMEM_PEER) {
+        error_report("'peer' devices are not migratable");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int ivshmem_post_load(void *opaque, int version_id)
+{
+    IVShmemState *s = opaque;
+
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        ivshmem_use_msix(s);
+    }
+
+    return 0;
+}
+
+static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    IVShmemState *s = opaque;
+    PCIDevice *pdev = PCI_DEVICE(s);
+    int ret;
+
+    IVSHMEM_DPRINTF("ivshmem_load_old\n");
+
+    if (version_id != 0) {
+        return -EINVAL;
+    }
+
+    if (s->role_val == IVSHMEM_PEER) {
+        error_report("'peer' devices are not migratable");
+        return -EINVAL;
+    }
+
+    ret = pci_device_load(pdev, f);
+    if (ret) {
+        return ret;
+    }
+
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        msix_load(pdev, f);
+        ivshmem_use_msix(s);
+    } else {
+        s->intrstatus = qemu_get_be32(f);
+        s->intrmask = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription ivshmem_vmsd = {
+    .name = "ivshmem",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_load = ivshmem_pre_load,
+    .post_load = ivshmem_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
+
+        VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix),
+        VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix),
+        VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix),
+
+        VMSTATE_END_OF_LIST()
+    },
+    .load_state_old = ivshmem_load_old
+};
+
 static Property ivshmem_properties[] = {
     DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
     DEFINE_PROP_STRING("size", IVShmemState, sizearg),
@@ -880,6 +914,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_MEMORY_RAM;
     dc->reset = ivshmem_reset;
     dc->props = ivshmem_properties;
+    dc->vmsd = &ivshmem_vmsd;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 }
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (22 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 23/46] ivshmem: migrate with VMStateDescription marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 11:33   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 25/46] ivshmem: check shm isn't already initialized marcandre.lureau
                   ` (23 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

0 is a valid fd value, so change conditions and set -1 value early

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 14c7d58..c80503d 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -233,7 +233,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
 
         case IVPOSITION:
             /* return my VM ID if the memory is mapped */
-            if (s->shm_fd > 0) {
+            if (s->shm_fd >= 0) {
                 ret = s->vm_id;
             } else {
                 ret = -1;
@@ -663,6 +663,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         PCI_BASE_ADDRESS_MEM_PREFETCH;;
     Error *local_err = NULL;
 
+    s->shm_fd = -1;
+
     if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
     } else {
@@ -707,8 +709,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
 
     pci_config_set_interrupt_pin(pci_conf, 1);
 
-    s->shm_fd = 0;
-
     memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
                           "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 25/46] ivshmem: check shm isn't already initialized
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (23 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0 marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description marcandre.lureau
                   ` (22 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The server should not change the shm, and this isn't handled by qemu.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index c80503d..493e3c7 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -533,6 +533,12 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     if (incoming_posn == -1) {
         void * map_ptr;
 
+        if (s->shm_fd >= 0) {
+            error_report("shm already initialized");
+            close(incoming_fd);
+            return;
+        }
+
         if (check_shm_size(s, incoming_fd, &err) == -1) {
             error_report_err(err);
             close(incoming_fd);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (24 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 25/46] ivshmem: check shm isn't already initialized marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 11:38   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 27/46] ivshmem: fix pci_ivshmem_exit() marcandre.lureau
                   ` (21 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 493e3c7..5e96360 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -922,6 +922,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
     dc->props = ivshmem_properties;
     dc->vmsd = &ivshmem_vmsd;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->desc = "Inter-VM shared memory";
 }
 
 static const TypeInfo ivshmem_info = {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 27/46] ivshmem: fix pci_ivshmem_exit()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (25 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately marcandre.lureau
                   ` (20 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Free all objects owned by the device, making sure the device is free,
fixing hot-unplug.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 5e96360..6acdc56 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -798,15 +798,47 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
 static void pci_ivshmem_exit(PCIDevice *dev)
 {
     IVShmemState *s = IVSHMEM(dev);
+    int i;
+
+    fifo8_destroy(&s->incoming_fifo);
 
     if (s->migration_blocker) {
         migrate_del_blocker(s->migration_blocker);
         error_free(s->migration_blocker);
     }
 
-    memory_region_del_subregion(&s->bar, &s->ivshmem);
-    vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
-    fifo8_destroy(&s->incoming_fifo);
+    if (s->shm_fd >= 0) {
+        void *addr = memory_region_get_ram_ptr(&s->ivshmem);
+
+        vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
+        memory_region_del_subregion(&s->bar, &s->ivshmem);
+
+        if (munmap(addr, s->ivshmem_size) == -1) {
+            error_report("Failed to munmap shared memory %s", strerror(errno));
+        }
+    }
+
+    if (s->eventfd_chr) {
+        for (i = 0; i < s->vectors; i++) {
+            if (s->eventfd_chr[i]) {
+                qemu_chr_free(s->eventfd_chr[i]);
+            }
+        }
+        g_free(s->eventfd_chr);
+    }
+
+    if (s->peers) {
+        for (i = 0; i < s->nb_peers; i++) {
+            close_guest_eventfds(s, i);
+        }
+        g_free(s->peers);
+    }
+
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        msix_uninit_exclusive_bar(dev);
+    }
+
+    g_free(s->eventfd_table);
 }
 
 static bool test_msix(void *opaque, int version_id)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (26 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 27/46] ivshmem: fix pci_ivshmem_exit() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 11:44   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received marcandre.lureau
                   ` (19 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The terms 'guest' and 'peer' are used sometime interchangeably which may
be confusing. Instead, use 'peer' for the remote instances of ivshmem
clients, and 'guest' for the local VM.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 6acdc56..b9c78cd 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -89,7 +89,7 @@ typedef struct IVShmemState {
     int shm_fd; /* shared memory file descriptor */
 
     Peer *peers;
-    int nb_peers; /* how many guests we have space for */
+    int nb_peers; /* how many peers we have space for */
 
     int vm_id;
     uint32_t vectors;
@@ -387,9 +387,9 @@ static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
                               &s->peers[posn].eventfds[i]);
 }
 
-static void close_guest_eventfds(IVShmemState *s, int posn)
+static void close_peer_eventfds(IVShmemState *s, int posn)
 {
-    int i, guest_curr_max;
+    int i, n;
 
     if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
         return;
@@ -399,14 +399,14 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
         return;
     }
 
-    guest_curr_max = s->peers[posn].nb_eventfds;
+    n = s->peers[posn].nb_eventfds;
 
     memory_region_transaction_begin();
-    for (i = 0; i < guest_curr_max; i++) {
+    for (i = 0; i < n; i++) {
         ivshmem_del_eventfd(s, posn, i);
     }
     memory_region_transaction_commit();
-    for (i = 0; i < guest_curr_max; i++) {
+    for (i = 0; i < n; i++) {
         event_notifier_cleanup(&s->peers[posn].eventfds[i]);
     }
 
@@ -415,7 +415,7 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
 }
 
 /* this function increase the dynamic storage need to store data about other
- * guests */
+ * peers */
 static int resize_peers(IVShmemState *s, int new_min_size)
 {
 
@@ -432,7 +432,7 @@ static int resize_peers(IVShmemState *s, int new_min_size)
     old_size = s->nb_peers;
     s->nb_peers = new_min_size;
 
-    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+    IVSHMEM_DPRINTF("bumping storage to %d peers\n", s->nb_peers);
 
     s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
 
@@ -503,7 +503,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
     IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, incoming_fd);
 
-    /* make sure we have enough space for this guest */
+    /* make sure we have enough space for this peer */
     if (incoming_posn >= s->nb_peers) {
         if (resize_peers(s, incoming_posn + 1) < 0) {
             error_report("failed to resize peers array");
@@ -522,9 +522,9 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
             /* receive our posn */
             s->vm_id = incoming_posn;
         } else {
-            /* otherwise an fd == -1 means an existing guest has gone away */
+            /* otherwise an fd == -1 means an existing peer has gone away */
             IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
-            close_guest_eventfds(s, incoming_posn);
+            close_peer_eventfds(s, incoming_posn);
         }
         return;
     }
@@ -571,7 +571,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     /* get a new eventfd */
     nth_eventfd = peer->nb_eventfds++;
 
-    /* this is an eventfd for a particular guest VM */
+    /* this is an eventfd for a particular peer VM */
     IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
                     nth_eventfd, incoming_fd);
     event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
@@ -751,7 +751,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
             return;
         }
 
-        /* we allocate enough space for 16 guests and grow as needed */
+        /* we allocate enough space for 16 peers and grow as needed */
         resize_peers(s, 16);
         s->vm_id = -1;
 
@@ -829,7 +829,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
 
     if (s->peers) {
         for (i = 0; i < s->nb_peers; i++) {
-            close_guest_eventfds(s, i);
+            close_peer_eventfds(s, i);
         }
         g_free(s->peers);
     }
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (27 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 12:14   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset marcandre.lureau
                   ` (18 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The number of eventfd that can be handled per peer is limited by the
number of vectors. Return an error when receiving too many of them.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index b9c78cd..63e4c4f 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -569,6 +569,13 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     }
 
     /* get a new eventfd */
+    if (peer->nb_eventfds >= s->vectors) {
+        error_report("Too many eventfd received, device has %d vectors",
+                     s->vectors);
+        close(incoming_fd);
+        return;
+    }
+
     nth_eventfd = peer->nb_eventfds++;
 
     /* this is an eventfd for a particular peer VM */
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (28 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 12:15   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 31/46] contrib: add ivshmem client and server marcandre.lureau
                   ` (17 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The interrupt mask is a state value, it should be reset, like the value.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 63e4c4f..6c0a829 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -617,6 +617,7 @@ static void ivshmem_reset(DeviceState *d)
     IVShmemState *s = IVSHMEM(d);
 
     s->intrstatus = 0;
+    s->intrmask = 0;
     ivshmem_use_msix(s);
 }
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 31/46] contrib: add ivshmem client and server
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (29 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 32/46] ivshmem-client: check the number of vectors marcandre.lureau
                   ` (16 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: drjones, Olivier Matz, David Marchand, stefanha,
	Marc-André Lureau, cam

From: David Marchand <david.marchand@6wind.com>

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.matz@6wind.com>
Signed-off-by: David Marchand <david.marchand@6wind.com>
[fix a valgrind warning, option and server_close() segvs, extra server
headers includes]
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile                                |   8 +
 configure                               |   3 +
 contrib/ivshmem-client/ivshmem-client.c | 433 ++++++++++++++++++++++++++++++++
 contrib/ivshmem-client/ivshmem-client.h | 212 ++++++++++++++++
 contrib/ivshmem-client/main.c           | 239 ++++++++++++++++++
 contrib/ivshmem-server/ivshmem-server.c | 422 +++++++++++++++++++++++++++++++
 contrib/ivshmem-server/ivshmem-server.h | 166 ++++++++++++
 contrib/ivshmem-server/main.c           | 264 +++++++++++++++++++
 qemu-doc.texi                           |  10 +-
 9 files changed, 1754 insertions(+), 3 deletions(-)
 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/ivshmem-server.c
 create mode 100644 contrib/ivshmem-server/ivshmem-server.h
 create mode 100644 contrib/ivshmem-server/main.c

diff --git a/Makefile b/Makefile
index 9ce3972..fcdba7b 100644
--- a/Makefile
+++ b/Makefile
@@ -313,6 +313,14 @@ msi:
 	@echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)"
 endif
 
+IVSHMEM_CLIENT_OBJS=$(addprefix $(SRC_PATH)/contrib/ivshmem-client/, ivshmem-client.o main.o)
+ivshmem-client$(EXESUF): $(IVSHMEM_CLIENT_OBJS)
+	$(call LINK, $^)
+
+IVSHMEM_SERVER_OBJS=$(addprefix $(SRC_PATH)/contrib/ivshmem-server/, ivshmem-server.o main.o)
+ivshmem-server$(EXESUF): $(IVSHMEM_SERVER_OBJS) libqemuutil.a libqemustub.a
+	$(call LINK, $^)
+
 clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
diff --git a/configure b/configure
index d7c24cd..3dbcf79 100755
--- a/configure
+++ b/configure
@@ -4386,6 +4386,9 @@ if test "$want_tools" = "yes" ; then
   if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
     tools="qemu-nbd\$(EXESUF) $tools"
   fi
+  if [ "$kvm" = "yes" ] ; then
+    tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools"
+  fi
 fi
 if test "$softmmu" = yes ; then
   if test "$virtfs" != no ; then
diff --git a/contrib/ivshmem-client/ivshmem-client.c b/contrib/ivshmem-client/ivshmem-client.c
new file mode 100644
index 0000000..11c805c
--- /dev/null
+++ b/contrib/ivshmem-client/ivshmem-client.c
@@ -0,0 +1,433 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "qemu-common.h"
+#include "qemu/queue.h"
+
+#include "ivshmem-client.h"
+
+/* log a message on stdout if verbose=1 */
+#define IVSHMEM_CLIENT_DEBUG(client, fmt, ...) do { \
+        if ((client)->verbose) {         \
+            printf(fmt, ## __VA_ARGS__); \
+        }                                \
+    } while (0)
+
+/* read message from the unix socket */
+static int
+ivshmem_client_read_one_msg(IvshmemClient *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) {
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read message: %s\n",
+                             strerror(errno));
+        return -1;
+    }
+    if (ret == 0) {
+        IVSHMEM_CLIENT_DEBUG(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 advertises a disconnection or when the
+ * client is freed */
+static void
+ivshmem_client_free_peer(IvshmemClient *client, IvshmemClientPeer *peer)
+{
+    unsigned vector;
+
+    QTAILQ_REMOVE(&client->peer_list, peer, next);
+    for (vector = 0; vector < peer->vectors_count; vector++) {
+        close(peer->vectors[vector]);
+    }
+
+    g_free(peer);
+}
+
+/* handle message coming from server (new peer, new vectors) */
+static int
+ivshmem_client_handle_server_msg(IvshmemClient *client)
+{
+    IvshmemClientPeer *peer;
+    long peer_id;
+    int ret, fd;
+
+    ret = ivshmem_client_read_one_msg(client, &peer_id, &fd);
+    if (ret < 0) {
+        return -1;
+    }
+
+    /* can return a peer or the local client */
+    peer = ivshmem_client_search_peer(client, peer_id);
+
+    /* delete peer */
+    if (fd == -1) {
+
+        if (peer == NULL || peer == &client->local) {
+            IVSHMEM_CLIENT_DEBUG(client, "receive delete for invalid "
+                                 "peer %ld\n", peer_id);
+            return -1;
+        }
+
+        IVSHMEM_CLIENT_DEBUG(client, "delete peer id = %ld\n", peer_id);
+        ivshmem_client_free_peer(client, peer);
+        return 0;
+    }
+
+    /* new peer */
+    if (peer == NULL) {
+        peer = g_malloc0(sizeof(*peer));
+        peer->id = peer_id;
+        peer->vectors_count = 0;
+        QTAILQ_INSERT_TAIL(&client->peer_list, peer, next);
+        IVSHMEM_CLIENT_DEBUG(client, "new peer id = %ld\n", peer_id);
+    }
+
+    /* new vector */
+    IVSHMEM_CLIENT_DEBUG(client, "  new vector %d (fd=%d) for peer id %ld\n",
+                         peer->vectors_count, fd, peer->id);
+    peer->vectors[peer->vectors_count] = fd;
+    peer->vectors_count++;
+
+    return 0;
+}
+
+/* init a new ivshmem client */
+int
+ivshmem_client_init(IvshmemClient *client, const char *unix_sock_path,
+                    IvshmemClientNotifCb notif_cb, void *notif_arg,
+                    bool verbose)
+{
+    int ret;
+    unsigned i;
+
+    memset(client, 0, sizeof(*client));
+
+    ret = snprintf(client->unix_sock_path, sizeof(client->unix_sock_path),
+                   "%s", unix_sock_path);
+
+    if (ret < 0 || ret >= sizeof(client->unix_sock_path)) {
+        IVSHMEM_CLIENT_DEBUG(client, "could not copy unix socket path\n");
+        return -1;
+    }
+
+    for (i = 0; i < IVSHMEM_CLIENT_MAX_VECTORS; i++) {
+        client->local.vectors[i] = -1;
+    }
+
+    QTAILQ_INIT(&client->peer_list);
+    client->local.id = -1;
+
+    client->notif_cb = notif_cb;
+    client->notif_arg = notif_arg;
+    client->verbose = verbose;
+    client->shm_fd = -1;
+    client->sock_fd = -1;
+
+    return 0;
+}
+
+/* create and connect to the unix socket */
+int
+ivshmem_client_connect(IvshmemClient *client)
+{
+    struct sockaddr_un sun;
+    int fd, ret;
+    long tmp;
+
+    IVSHMEM_CLIENT_DEBUG(client, "connect to client %s\n",
+                         client->unix_sock_path);
+
+    client->sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (client->sock_fd < 0) {
+        IVSHMEM_CLIENT_DEBUG(client, "cannot create socket: %s\n",
+                             strerror(errno));
+        return -1;
+    }
+
+    sun.sun_family = AF_UNIX;
+    ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
+                   client->unix_sock_path);
+    if (ret < 0 || ret >= sizeof(sun.sun_path)) {
+        IVSHMEM_CLIENT_DEBUG(client, "could not copy unix socket path\n");
+        goto err_close;
+    }
+
+    if (connect(client->sock_fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+        IVSHMEM_CLIENT_DEBUG(client, "cannot connect to %s: %s\n", sun.sun_path,
+                             strerror(errno));
+        goto err_close;
+    }
+
+    /* first, we expect our index + a fd == -1 */
+    if (ivshmem_client_read_one_msg(client, &client->local.id, &fd) < 0 ||
+        client->local.id < 0 || fd != -1) {
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server\n");
+        goto err_close;
+    }
+    IVSHMEM_CLIENT_DEBUG(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 (ivshmem_client_read_one_msg(client, &tmp, &fd) < 0 ||
+        tmp != -1 || fd < 0) {
+        if (fd >= 0) {
+            close(fd);
+        }
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server (2)\n");
+        goto err_close;
+    }
+    client->shm_fd = fd;
+    IVSHMEM_CLIENT_DEBUG(client, "shm_fd=%d\n", fd);
+
+    return 0;
+
+err_close:
+    close(client->sock_fd);
+    client->sock_fd = -1;
+    return -1;
+}
+
+/* close connection to the server, and free all peer structures */
+void
+ivshmem_client_close(IvshmemClient *client)
+{
+    IvshmemClientPeer *peer;
+    unsigned i;
+
+    IVSHMEM_CLIENT_DEBUG(client, "close client\n");
+
+    while ((peer = QTAILQ_FIRST(&client->peer_list)) != NULL) {
+        ivshmem_client_free_peer(client, peer);
+    }
+
+    close(client->shm_fd);
+    client->shm_fd = -1;
+    close(client->sock_fd);
+    client->sock_fd = -1;
+    client->local.id = -1;
+    for (i = 0; i < IVSHMEM_CLIENT_MAX_VECTORS; i++) {
+        close(client->local.vectors[i]);
+        client->local.vectors[i] = -1;
+    }
+    client->local.vectors_count = 0;
+}
+
+/* get the fd_set according to the unix socket and peer list */
+void
+ivshmem_client_get_fds(const IvshmemClient *client, fd_set *fds, int *maxfd)
+{
+    int fd;
+    unsigned vector;
+
+    FD_SET(client->sock_fd, fds);
+    if (client->sock_fd >= *maxfd) {
+        *maxfd = client->sock_fd + 1;
+    }
+
+    for (vector = 0; vector < client->local.vectors_count; vector++) {
+        fd = client->local.vectors[vector];
+        FD_SET(fd, fds);
+        if (fd >= *maxfd) {
+            *maxfd = fd + 1;
+        }
+    }
+}
+
+/* handle events from eventfd: just print a message on notification */
+static int
+ivshmem_client_handle_event(IvshmemClient *client, const fd_set *cur, int maxfd)
+{
+    IvshmemClientPeer *peer;
+    uint64_t kick;
+    unsigned i;
+    int ret;
+
+    peer = &client->local;
+
+    for (i = 0; i < peer->vectors_count; i++) {
+        if (peer->vectors[i] >= maxfd || !FD_ISSET(peer->vectors[i], cur)) {
+            continue;
+        }
+
+        ret = read(peer->vectors[i], &kick, sizeof(kick));
+        if (ret < 0) {
+            return ret;
+        }
+        if (ret != sizeof(kick)) {
+            IVSHMEM_CLIENT_DEBUG(client, "invalid read size = %d\n", ret);
+            errno = EINVAL;
+            return -1;
+        }
+        IVSHMEM_CLIENT_DEBUG(client, "received event on fd %d vector %d: %ld\n",
+                             peer->vectors[i], i, kick);
+        if (client->notif_cb != NULL) {
+            client->notif_cb(client, peer, i, client->notif_arg);
+        }
+    }
+
+    return 0;
+}
+
+/* read and handle new messages on the given fd_set */
+int
+ivshmem_client_handle_fds(IvshmemClient *client, fd_set *fds, int maxfd)
+{
+    if (client->sock_fd < maxfd && FD_ISSET(client->sock_fd, fds) &&
+        ivshmem_client_handle_server_msg(client) < 0 && errno != EINTR) {
+        IVSHMEM_CLIENT_DEBUG(client, "ivshmem_client_handle_server_msg() "
+                             "failed\n");
+        return -1;
+    } else if (ivshmem_client_handle_event(client, fds, maxfd) < 0 &&
+               errno != EINTR) {
+        IVSHMEM_CLIENT_DEBUG(client, "ivshmem_client_handle_event() failed\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* send a notification on a vector of a peer */
+int
+ivshmem_client_notify(const IvshmemClient *client,
+                      const IvshmemClientPeer *peer, unsigned vector)
+{
+    uint64_t kick;
+    int fd;
+
+    if (vector >= peer->vectors_count) {
+        IVSHMEM_CLIENT_DEBUG(client, "invalid vector %u on peer %ld\n", vector,
+                             peer->id);
+        return -1;
+    }
+    fd = peer->vectors[vector];
+    IVSHMEM_CLIENT_DEBUG(client, "notify peer %ld on vector %d, fd %d\n",
+                         peer->id, vector, fd);
+
+    kick = 1;
+    if (write(fd, &kick, sizeof(kick)) != sizeof(kick)) {
+        fprintf(stderr, "could not write to %d: %s\n", peer->vectors[vector],
+                strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+/* send a notification to all vectors of a peer */
+int
+ivshmem_client_notify_all_vects(const IvshmemClient *client,
+                                const IvshmemClientPeer *peer)
+{
+    unsigned vector;
+    int ret = 0;
+
+    for (vector = 0; vector < peer->vectors_count; vector++) {
+        if (ivshmem_client_notify(client, peer, vector) < 0) {
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
+/* send a notification to all peers */
+int
+ivshmem_client_notify_broadcast(const IvshmemClient *client)
+{
+    IvshmemClientPeer *peer;
+    int ret = 0;
+
+    QTAILQ_FOREACH(peer, &client->peer_list, next) {
+        if (ivshmem_client_notify_all_vects(client, peer) < 0) {
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
+/* lookup peer from its id */
+IvshmemClientPeer *
+ivshmem_client_search_peer(IvshmemClient *client, long peer_id)
+{
+    IvshmemClientPeer *peer;
+
+    if (peer_id == client->local.id) {
+        return &client->local;
+    }
+
+    QTAILQ_FOREACH(peer, &client->peer_list, next) {
+        if (peer->id == peer_id) {
+            return peer;
+        }
+    }
+    return NULL;
+}
+
+/* dump our info, the list of peers their vectors on stdout */
+void
+ivshmem_client_dump(const IvshmemClient *client)
+{
+    const IvshmemClientPeer *peer;
+    unsigned vector;
+
+    /* dump local infos */
+    peer = &client->local;
+    printf("our_id = %ld\n", peer->id);
+    for (vector = 0; vector < peer->vectors_count; vector++) {
+        printf("  vector %d is enabled (fd=%d)\n", vector,
+               peer->vectors[vector]);
+    }
+
+    /* dump peers */
+    QTAILQ_FOREACH(peer, &client->peer_list, next) {
+        printf("peer_id = %ld\n", peer->id);
+
+        for (vector = 0; vector < peer->vectors_count; vector++) {
+            printf("  vector %d is enabled (fd=%d)\n", vector,
+                   peer->vectors[vector]);
+        }
+    }
+}
diff --git a/contrib/ivshmem-client/ivshmem-client.h b/contrib/ivshmem-client/ivshmem-client.h
new file mode 100644
index 0000000..284c4a3
--- /dev/null
+++ b/contrib/ivshmem-client/ivshmem-client.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#ifndef _IVSHMEM_CLIENT_H_
+#define _IVSHMEM_CLIENT_H_
+
+/**
+ * This file provides helper to implement an ivshmem client. It is used
+ * on the host to ask QEMU to send an interrupt to an ivshmem PCI device in a
+ * guest. QEMU also implements an ivshmem client similar to this one, they both
+ * connect to an ivshmem server.
+ *
+ * A standalone ivshmem client based on this file is provided for debug/test
+ * purposes.
+ */
+
+#include <limits.h>
+#include <sys/select.h>
+
+#include "qemu/queue.h"
+
+/**
+ * Maximum number of notification vectors supported by the client
+ */
+#define IVSHMEM_CLIENT_MAX_VECTORS 64
+
+/**
+ * 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 IvshmemClientPeer
+ * structure to store the infos of this peer.
+ *
+ * This structure is also used to store the information of our own
+ * client in (IvshmemClient)->local.
+ */
+typedef struct IvshmemClientPeer {
+    QTAILQ_ENTRY(IvshmemClientPeer) 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 */
+} IvshmemClientPeer;
+QTAILQ_HEAD(IvshmemClientPeerList, IvshmemClientPeer);
+
+typedef struct IvshmemClientPeerList IvshmemClientPeerList;
+typedef struct IvshmemClient IvshmemClient;
+
+/**
+ * Typedef of callback function used when our IvshmemClient receives a
+ * notification from a peer.
+ */
+typedef void (*IvshmemClientNotifCb)(
+    const IvshmemClient *client,
+    const IvshmemClientPeer *peer,
+    unsigned vect, void *arg);
+
+/**
+ * Structure describing an ivshmem client
+ *
+ * This structure stores all information related to our client: the name
+ * of the server unix socket, the list of peers advertised by the
+ * server, our own client information, and a pointer the notification
+ * callback function used when we receive a notification from a peer.
+ */
+struct IvshmemClient {
+    char unix_sock_path[PATH_MAX];      /**< path to unix sock */
+    int sock_fd;                        /**< unix sock filedesc */
+    int shm_fd;                         /**< shm file descriptor */
+
+    IvshmemClientPeerList peer_list;    /**< list of peers */
+    IvshmemClientPeer local;            /**< our own infos */
+
+    IvshmemClientNotifCb notif_cb;      /**< notification callback */
+    void *notif_arg;                    /**< notification argument */
+
+    bool verbose;                       /**< true to enable debug */
+};
+
+/**
+ * Initialize an ivshmem client
+ *
+ * @client:         A pointer to an uninitialized IvshmemClient structure
+ * @unix_sock_path: The pointer to the unix socket file name
+ * @notif_cb:       If not NULL, the pointer to the function to be called when
+ *                  our IvshmemClient receives a notification from a peer
+ * @notif_arg:      Opaque pointer given as-is to the notification callback
+ *                  function
+ * @verbose:        True to enable debug
+ *
+ * Returns:         0 on success, or a negative value on error
+ */
+int ivshmem_client_init(IvshmemClient *client, const char *unix_sock_path,
+                        IvshmemClientNotifCb notif_cb, void *notif_arg,
+                        bool verbose);
+
+/**
+ * Connect to the server
+ *
+ * Connect to the server unix socket, and read the first initial
+ * messages sent by the server, giving the ID of the client and the file
+ * descriptor of the shared memory.
+ *
+ * @client: The ivshmem client
+ *
+ * Returns: 0 on success, or a negative value on error
+ */
+int ivshmem_client_connect(IvshmemClient *client);
+
+/**
+ * Close connection to the server and free all peer structures
+ *
+ * @client: The ivshmem client
+ */
+void ivshmem_client_close(IvshmemClient *client);
+
+/**
+ * Fill a fd_set with file descriptors to be monitored
+ *
+ * This function will fill a fd_set with all file descriptors
+ * that must be polled (unix server socket and peers eventfd). The
+ * function will not initialize the fd_set, it is up to the caller
+ * to do this.
+ *
+ * @client: The ivshmem client
+ * @fds:    The fd_set to be updated
+ * @maxfd:  Must be set to the max file descriptor + 1 in fd_set. This value is
+ *          updated if this function adds a greater fd in fd_set.
+ */
+void ivshmem_client_get_fds(const IvshmemClient *client, fd_set *fds,
+                            int *maxfd);
+
+/**
+ * Read and handle new messages
+ *
+ * Given a fd_set filled by select(), handle incoming messages from
+ * server or peers.
+ *
+ * @client: The ivshmem client
+ * @fds:    The fd_set containing the file descriptors to be checked. Note
+ *          that file descriptors that are not related to our client are
+ *          ignored.
+ * @maxfd:  The maximum fd in fd_set, plus one.
+ *
+ * Returns: 0 on success, or a negative value on error
+ */
+int ivshmem_client_handle_fds(IvshmemClient *client, fd_set *fds, int maxfd);
+
+/**
+ * Send a notification to a vector of a peer
+ *
+ * @client: The ivshmem client
+ * @peer:   The peer to be notified
+ * @vector: The number of the vector
+ *
+ * Returns: 0 on success, or a negative value on error
+ */
+int ivshmem_client_notify(const IvshmemClient *client,
+                          const IvshmemClientPeer *peer, unsigned vector);
+
+/**
+ * Send a notification to all vectors of a peer
+ *
+ * @client: The ivshmem client
+ * @peer:   The peer to be notified
+ *
+ * Returns: 0 on success, or a negative value on error (at least one
+ *          notification failed)
+ */
+int ivshmem_client_notify_all_vects(const IvshmemClient *client,
+                                    const IvshmemClientPeer *peer);
+
+/**
+ * Broadcat a notification to all vectors of all peers
+ *
+ * @client: The ivshmem client
+ *
+ * Returns: 0 on success, or a negative value on error (at least one
+ *          notification failed)
+ */
+int ivshmem_client_notify_broadcast(const IvshmemClient *client);
+
+/**
+ * Search a peer from its identifier
+ *
+ * Return the peer structure from its peer_id. If the given peer_id is
+ * the local id, the function returns the local peer structure.
+ *
+ * @client:  The ivshmem client
+ * @peer_id: The identifier of the peer structure
+ *
+ * Returns:  The peer structure, or NULL if not found
+ */
+IvshmemClientPeer *
+ivshmem_client_search_peer(IvshmemClient *client, long peer_id);
+
+/**
+ * Dump information of this ivshmem client on stdout
+ *
+ * Dump the id and the vectors of the given ivshmem client and the list
+ * of its peers and their vectors on stdout.
+ *
+ * @client: The ivshmem client
+ */
+void ivshmem_client_dump(const IvshmemClient *client);
+
+#endif /* _IVSHMEM_CLIENT_H_ */
diff --git a/contrib/ivshmem-client/main.c b/contrib/ivshmem-client/main.c
new file mode 100644
index 0000000..5d85ae7
--- /dev/null
+++ b/contrib/ivshmem-client/main.c
@@ -0,0 +1,239 @@
+/*
+ * 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 "qemu-common.h"
+
+#include "ivshmem-client.h"
+
+#define IVSHMEM_CLIENT_DEFAULT_VERBOSE        0
+#define IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH "/tmp/ivshmem_socket"
+
+typedef struct IvshmemClientArgs {
+    bool verbose;
+    const char *unix_sock_path;
+} IvshmemClientArgs;
+
+/* show ivshmem_client_usage and exit with given error code */
+static void
+ivshmem_client_usage(const char *name, int code)
+{
+    fprintf(stderr, "%s [opts]\n", name);
+    fprintf(stderr, "  -h: show this help\n");
+    fprintf(stderr, "  -v: verbose mode\n");
+    fprintf(stderr, "  -S <unix_sock_path>: path to the unix socket\n"
+                    "     to connect to.\n"
+                    "     default=%s\n", IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH);
+    exit(code);
+}
+
+/* parse the program arguments, exit on error */
+static void
+ivshmem_client_parse_args(IvshmemClientArgs *args, int argc, char *argv[])
+{
+    char c;
+
+    while ((c = getopt(argc, argv,
+                       "h"  /* help */
+                       "v"  /* verbose */
+                       "S:" /* unix_sock_path */
+                      )) != -1) {
+
+        switch (c) {
+        case 'h': /* help */
+            ivshmem_client_usage(argv[0], 0);
+            break;
+
+        case 'v': /* verbose */
+            args->verbose = 1;
+            break;
+
+        case 'S': /* unix_sock_path */
+            args->unix_sock_path = strdup(optarg);
+            break;
+
+        default:
+            ivshmem_client_usage(argv[0], 1);
+            break;
+        }
+    }
+}
+
+/* show command line help */
+static void
+ivshmem_client_cmdline_help(void)
+{
+    printf("dump: dump peers (including us)\n"
+           "int <peer> <vector>: notify one vector on a peer\n"
+           "int <peer> all: notify all vectors of a peer\n"
+           "int all: notify all vectors of all peers (excepting us)\n");
+}
+
+/* read stdin and handle commands */
+static int
+ivshmem_client_handle_stdin_command(IvshmemClient *client)
+{
+    IvshmemClientPeer *peer;
+    char buf[128];
+    char *s, *token;
+    int ret;
+    int peer_id, vector;
+
+    memset(buf, 0, sizeof(buf));
+    ret = read(0, buf, sizeof(buf) - 1);
+    if (ret < 0) {
+        return -1;
+    }
+
+    s = buf;
+    while ((token = strsep(&s, "\n\r;")) != NULL) {
+        if (!strcmp(token, "")) {
+            continue;
+        }
+        if (!strcmp(token, "?")) {
+            ivshmem_client_cmdline_help();
+        }
+        if (!strcmp(token, "help")) {
+            ivshmem_client_cmdline_help();
+        } else if (!strcmp(token, "dump")) {
+            ivshmem_client_dump(client);
+        } else if (!strcmp(token, "int all")) {
+            ivshmem_client_notify_broadcast(client);
+        } else if (sscanf(token, "int %d %d", &peer_id, &vector) == 2) {
+            peer = ivshmem_client_search_peer(client, peer_id);
+            if (peer == NULL) {
+                printf("cannot find peer_id = %d\n", peer_id);
+                continue;
+            }
+            ivshmem_client_notify(client, peer, vector);
+        } else if (sscanf(token, "int %d all", &peer_id) == 1) {
+            peer = ivshmem_client_search_peer(client, peer_id);
+            if (peer == NULL) {
+                printf("cannot find peer_id = %d\n", peer_id);
+                continue;
+            }
+            ivshmem_client_notify_all_vects(client, peer);
+        } else {
+            printf("invalid command, type help\n");
+        }
+    }
+
+    printf("cmd> ");
+    fflush(stdout);
+    return 0;
+}
+
+/* listen on stdin (command line), on unix socket (notifications of new
+ * and dead peers), and on eventfd (IRQ request) */
+static int
+ivshmem_client_poll_events(IvshmemClient *client)
+{
+    fd_set fds;
+    int ret, maxfd;
+
+    while (1) {
+
+        FD_ZERO(&fds);
+        FD_SET(0, &fds); /* add stdin in fd_set */
+        maxfd = 1;
+
+        ivshmem_client_get_fds(client, &fds, &maxfd);
+
+        ret = select(maxfd, &fds, NULL, NULL, NULL);
+        if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            fprintf(stderr, "select error: %s\n", strerror(errno));
+            break;
+        }
+        if (ret == 0) {
+            continue;
+        }
+
+        if (FD_ISSET(0, &fds) &&
+            ivshmem_client_handle_stdin_command(client) < 0 && errno != EINTR) {
+            fprintf(stderr, "ivshmem_client_handle_stdin_command() failed\n");
+            break;
+        }
+
+        if (ivshmem_client_handle_fds(client, &fds, maxfd) < 0) {
+            fprintf(stderr, "ivshmem_client_handle_fds() failed\n");
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/* callback when we receive a notification (just display it) */
+static void
+ivshmem_client_notification_cb(const IvshmemClient *client,
+                               const IvshmemClientPeer *peer,
+                               unsigned vect, void *arg)
+{
+    (void)client;
+    (void)arg;
+    printf("receive notification from peer_id=%ld vector=%d\n", peer->id, vect);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct sigaction sa;
+    IvshmemClient client;
+    IvshmemClientArgs args = {
+        .verbose = IVSHMEM_CLIENT_DEFAULT_VERBOSE,
+        .unix_sock_path = IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH,
+    };
+
+    /* parse arguments, will exit on error */
+    ivshmem_client_parse_args(&args, argc, argv);
+
+    /* Ignore SIGPIPE, see this link for more info:
+     * http://www.mail-archive.com/libevent-users@monkey.org/msg01606.html */
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    if (sigemptyset(&sa.sa_mask) == -1 ||
+        sigaction(SIGPIPE, &sa, 0) == -1) {
+        perror("failed to ignore SIGPIPE; sigaction");
+        return 1;
+    }
+
+    ivshmem_client_cmdline_help();
+    printf("cmd> ");
+    fflush(stdout);
+
+    if (ivshmem_client_init(&client, args.unix_sock_path,
+                            ivshmem_client_notification_cb, NULL,
+                            args.verbose) < 0) {
+        fprintf(stderr, "cannot init client\n");
+        return 1;
+    }
+
+    while (1) {
+        if (ivshmem_client_connect(&client) < 0) {
+            fprintf(stderr, "cannot connect to server, retry in 1 second\n");
+            sleep(1);
+            continue;
+        }
+
+        fprintf(stdout, "listen on server socket %d\n", client.sock_fd);
+
+        if (ivshmem_client_poll_events(&client) == 0) {
+            continue;
+        }
+
+        /* disconnected from server, reset all peers */
+        fprintf(stdout, "disconnected from server\n");
+
+        ivshmem_client_close(&client);
+    }
+
+    return 0;
+}
diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
new file mode 100644
index 0000000..16ee583
--- /dev/null
+++ b/contrib/ivshmem-server/ivshmem-server.c
@@ -0,0 +1,422 @@
+/*
+ * 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 <sys/mman.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/eventfd.h>
+
+#include "qemu-common.h"
+#include "qemu/queue.h"
+
+#include "ivshmem-server.h"
+
+/* log a message on stdout if verbose=1 */
+#define IVSHMEM_SERVER_DEBUG(server, fmt, ...) do { \
+        if ((server)->verbose) {         \
+            printf(fmt, ## __VA_ARGS__); \
+        }                                \
+    } while (0)
+
+/** maximum size of a huge page, used by ivshmem_server_ftruncate() */
+#define IVSHMEM_SERVER_MAX_HUGEPAGE_SIZE (1024 * 1024 * 1024)
+
+/** default listen backlog (number of sockets not accepted) */
+#define IVSHMEM_SERVER_LISTEN_BACKLOG 10
+
+/* send message to a client unix socket */
+static int
+ivshmem_server_send_one_msg(int sock_fd, long peer_id, 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 = &peer_id;
+    iov[0].iov_len = sizeof(peer_id);
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+    /* if fd is specified, add it in a cmsg */
+    if (fd >= 0) {
+        memset(&msg_control, 0, sizeof(msg_control));
+        msg.msg_control = &msg_control;
+        msg.msg_controllen = sizeof(msg_control);
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+    }
+
+    ret = sendmsg(sock_fd, &msg, 0);
+    if (ret <= 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+/* free a peer when the server advertises a disconnection or when the
+ * server is freed */
+static void
+ivshmem_server_free_peer(IvshmemServer *server, IvshmemServerPeer *peer)
+{
+    unsigned vector;
+    IvshmemServerPeer *other_peer;
+
+    IVSHMEM_SERVER_DEBUG(server, "free peer %ld\n", peer->id);
+    close(peer->sock_fd);
+    QTAILQ_REMOVE(&server->peer_list, peer, next);
+
+    /* advertise the deletion to other peers */
+    QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
+        ivshmem_server_send_one_msg(other_peer->sock_fd, peer->id, -1);
+    }
+
+    for (vector = 0; vector < peer->vectors_count; vector++) {
+        close(peer->vectors[vector]);
+    }
+
+    g_free(peer);
+}
+
+/* send the peer id and the shm_fd just after a new client connection */
+static int
+ivshmem_server_send_initial_info(IvshmemServer *server, IvshmemServerPeer *peer)
+{
+    int ret;
+
+    /* send the peer id to the client */
+    ret = ivshmem_server_send_one_msg(peer->sock_fd, peer->id, -1);
+    if (ret < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot send peer id: %s\n",
+                             strerror(errno));
+        return -1;
+    }
+
+    /* send the shm_fd */
+    ret = ivshmem_server_send_one_msg(peer->sock_fd, -1, server->shm_fd);
+    if (ret < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot send shm fd: %s\n",
+                             strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+/* handle message on listening unix socket (new client connection) */
+static int
+ivshmem_server_handle_new_conn(IvshmemServer *server)
+{
+    IvshmemServerPeer *peer, *other_peer;
+    struct sockaddr_un unaddr;
+    socklen_t unaddr_len;
+    int newfd;
+    unsigned i;
+
+    /* accept the incoming connection */
+    unaddr_len = sizeof(unaddr);
+    newfd = accept4(server->sock_fd, (struct sockaddr *)&unaddr, &unaddr_len,
+                    SOCK_NONBLOCK);
+    if (newfd < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot accept() %s\n", strerror(errno));
+        return -1;
+    }
+
+    IVSHMEM_SERVER_DEBUG(server, "accept()=%d\n", newfd);
+
+    /* allocate new structure for this peer */
+    peer = g_malloc0(sizeof(*peer));
+    peer->sock_fd = newfd;
+
+    /* get an unused peer id */
+    while (ivshmem_server_search_peer(server, server->cur_id) != NULL) {
+        server->cur_id++;
+    }
+    peer->id = server->cur_id++;
+
+    /* create eventfd, one per vector */
+    peer->vectors_count = server->n_vectors;
+    for (i = 0; i < peer->vectors_count; i++) {
+        peer->vectors[i] = eventfd(0, 0);
+        if (peer->vectors[i] < 0) {
+            IVSHMEM_SERVER_DEBUG(server, "cannot create eventfd\n");
+            goto fail;
+        }
+    }
+
+    /* send peer id and shm fd */
+    if (ivshmem_server_send_initial_info(server, peer) < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot send initial info\n");
+        goto fail;
+    }
+
+    /* advertise the new peer to others */
+    QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
+        for (i = 0; i < peer->vectors_count; i++) {
+            ivshmem_server_send_one_msg(other_peer->sock_fd, peer->id,
+                                        peer->vectors[i]);
+        }
+    }
+
+    /* advertise the other peers to the new one */
+    QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
+        for (i = 0; i < peer->vectors_count; i++) {
+            ivshmem_server_send_one_msg(peer->sock_fd, other_peer->id,
+                                        other_peer->vectors[i]);
+        }
+    }
+
+    /* advertise the new peer to itself */
+    for (i = 0; i < peer->vectors_count; i++) {
+        ivshmem_server_send_one_msg(peer->sock_fd, peer->id, peer->vectors[i]);
+    }
+
+    QTAILQ_INSERT_TAIL(&server->peer_list, peer, next);
+    IVSHMEM_SERVER_DEBUG(server, "new peer id = %ld\n", peer->id);
+    return 0;
+
+fail:
+    while (i--) {
+        close(peer->vectors[i]);
+    }
+    close(newfd);
+    g_free(peer);
+    return -1;
+}
+
+/* Try to ftruncate a file to next power of 2 of shmsize.
+ * If it fails; all power of 2 above shmsize are tested until
+ * we reach the maximum huge page size. This is useful
+ * if the shm file is in a hugetlbfs that cannot be truncated to the
+ * shm_size value. */
+static int
+ivshmem_server_ftruncate(int fd, unsigned shmsize)
+{
+    int ret;
+
+    /* align shmsize to next power of 2 */
+    shmsize--;
+    shmsize |= shmsize >> 1;
+    shmsize |= shmsize >> 2;
+    shmsize |= shmsize >> 4;
+    shmsize |= shmsize >> 8;
+    shmsize |= shmsize >> 16;
+    shmsize++;
+
+    while (shmsize <= IVSHMEM_SERVER_MAX_HUGEPAGE_SIZE) {
+        ret = ftruncate(fd, shmsize);
+        if (ret == 0) {
+            return ret;
+        }
+        shmsize *= 2;
+    }
+
+    return -1;
+}
+
+/* Init a new ivshmem server */
+int
+ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
+                    const char *shm_path, size_t shm_size, unsigned n_vectors,
+                    bool verbose)
+{
+    int ret;
+
+    memset(server, 0, sizeof(*server));
+
+    ret = snprintf(server->unix_sock_path, sizeof(server->unix_sock_path),
+                   "%s", unix_sock_path);
+    if (ret < 0 || ret >= sizeof(server->unix_sock_path)) {
+        IVSHMEM_SERVER_DEBUG(server, "could not copy unix socket path\n");
+        return -1;
+    }
+    ret = snprintf(server->shm_path, sizeof(server->shm_path),
+                   "%s", shm_path);
+    if (ret < 0 || ret >= sizeof(server->shm_path)) {
+        IVSHMEM_SERVER_DEBUG(server, "could not copy shm path\n");
+        return -1;
+    }
+
+    server->shm_size = shm_size;
+    server->n_vectors = n_vectors;
+    server->verbose = verbose;
+
+    QTAILQ_INIT(&server->peer_list);
+
+    return 0;
+}
+
+/* open shm, create and bind to the unix socket */
+int
+ivshmem_server_start(IvshmemServer *server)
+{
+    struct sockaddr_un sun;
+    int shm_fd, sock_fd, ret;
+
+    /* open shm file */
+    shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
+    if (shm_fd < 0) {
+        fprintf(stderr, "cannot open shm file %s: %s\n", server->shm_path,
+                strerror(errno));
+        return -1;
+    }
+    if (ivshmem_server_ftruncate(shm_fd, server->shm_size) < 0) {
+        fprintf(stderr, "ftruncate(%s) failed: %s\n", server->shm_path,
+                strerror(errno));
+        goto err_close_shm;
+    }
+
+    IVSHMEM_SERVER_DEBUG(server, "create & bind socket %s\n",
+                         server->unix_sock_path);
+
+    /* create the unix listening socket */
+    sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock_fd < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot create socket: %s\n",
+                             strerror(errno));
+        goto err_close_shm;
+    }
+
+    sun.sun_family = AF_UNIX;
+    ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
+                   server->unix_sock_path);
+    if (ret < 0 || ret >= sizeof(sun.sun_path)) {
+        IVSHMEM_SERVER_DEBUG(server, "could not copy unix socket path\n");
+        goto err_close_sock;
+    }
+    if (bind(sock_fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot connect to %s: %s\n", sun.sun_path,
+                             strerror(errno));
+        goto err_close_sock;
+    }
+
+    if (listen(sock_fd, IVSHMEM_SERVER_LISTEN_BACKLOG) < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "listen() failed: %s\n", strerror(errno));
+        goto err_close_sock;
+    }
+
+    server->sock_fd = sock_fd;
+    server->shm_fd = shm_fd;
+
+    return 0;
+
+err_close_sock:
+    close(sock_fd);
+err_close_shm:
+    close(shm_fd);
+    return -1;
+}
+
+/* close connections to clients, the unix socket and the shm fd */
+void
+ivshmem_server_close(IvshmemServer *server)
+{
+    IvshmemServerPeer *peer, *npeer;
+
+    IVSHMEM_SERVER_DEBUG(server, "close server\n");
+
+    QTAILQ_FOREACH_SAFE(peer, &server->peer_list, next, npeer) {
+        ivshmem_server_free_peer(server, peer);
+    }
+
+    unlink(server->unix_sock_path);
+    close(server->sock_fd);
+    close(server->shm_fd);
+    server->sock_fd = -1;
+    server->shm_fd = -1;
+}
+
+/* get the fd_set according to the unix socket and the peer list */
+void
+ivshmem_server_get_fds(const IvshmemServer *server, fd_set *fds, int *maxfd)
+{
+    IvshmemServerPeer *peer;
+
+    if (server->sock_fd == -1) {
+        return;
+    }
+
+    FD_SET(server->sock_fd, fds);
+    if (server->sock_fd >= *maxfd) {
+        *maxfd = server->sock_fd + 1;
+    }
+
+    QTAILQ_FOREACH(peer, &server->peer_list, next) {
+        FD_SET(peer->sock_fd, fds);
+        if (peer->sock_fd >= *maxfd) {
+            *maxfd = peer->sock_fd + 1;
+        }
+    }
+}
+
+/* process incoming messages on the sockets in fd_set */
+int
+ivshmem_server_handle_fds(IvshmemServer *server, fd_set *fds, int maxfd)
+{
+    IvshmemServerPeer *peer, *peer_next;
+
+    if (server->sock_fd < maxfd && FD_ISSET(server->sock_fd, fds) &&
+        ivshmem_server_handle_new_conn(server) < 0 && errno != EINTR) {
+        IVSHMEM_SERVER_DEBUG(server, "ivshmem_server_handle_new_conn() "
+                             "failed\n");
+        return -1;
+    }
+
+    QTAILQ_FOREACH_SAFE(peer, &server->peer_list, next, peer_next) {
+        /* any message from a peer socket result in a close() */
+        IVSHMEM_SERVER_DEBUG(server, "peer->sock_fd=%d\n", peer->sock_fd);
+        if (peer->sock_fd < maxfd && FD_ISSET(peer->sock_fd, fds)) {
+            ivshmem_server_free_peer(server, peer);
+        }
+    }
+
+    return 0;
+}
+
+/* lookup peer from its id */
+IvshmemServerPeer *
+ivshmem_server_search_peer(IvshmemServer *server, long peer_id)
+{
+    IvshmemServerPeer *peer;
+
+    QTAILQ_FOREACH(peer, &server->peer_list, next) {
+        if (peer->id == peer_id) {
+            return peer;
+        }
+    }
+    return NULL;
+}
+
+/* dump our info, the list of peers their vectors on stdout */
+void
+ivshmem_server_dump(const IvshmemServer *server)
+{
+    const IvshmemServerPeer *peer;
+    unsigned vector;
+
+    /* dump peers */
+    QTAILQ_FOREACH(peer, &server->peer_list, next) {
+        printf("peer_id = %ld\n", peer->id);
+
+        for (vector = 0; vector < peer->vectors_count; vector++) {
+            printf("  vector %d is enabled (fd=%d)\n", vector,
+                   peer->vectors[vector]);
+        }
+    }
+}
diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
new file mode 100644
index 0000000..cd584fc
--- /dev/null
+++ b/contrib/ivshmem-server/ivshmem-server.h
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#ifndef _IVSHMEM_SERVER_H_
+#define _IVSHMEM_SERVER_H_
+
+/**
+ * The ivshmem server is a daemon that creates a unix socket in listen
+ * mode. The ivshmem clients (qemu or ivshmem-client) connect to this
+ * unix socket. For each client, the server will create some eventfd
+ * (see EVENTFD(2)), one per vector. These fd are transmitted to all
+ * clients using the SCM_RIGHTS cmsg message. Therefore, each client is
+ * able to send a notification to another client without beeing
+ * "profixied" by the server.
+ *
+ * We use this mechanism to send interruptions between guests.
+ * qemu is able to transform an event on a eventfd into a PCI MSI-x
+ * interruption in the guest.
+ *
+ * The ivshmem server is also able to share the file descriptor
+ * associated to the ivshmem shared memory.
+ */
+
+#include <limits.h>
+#include <sys/select.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "qemu/queue.h"
+
+/**
+ * Maximum number of notification vectors supported by the server
+ */
+#define IVSHMEM_SERVER_MAX_VECTORS 64
+
+/**
+ * Structure storing a peer
+ *
+ * Each time a client connects to an ivshmem server, a new
+ * IvshmemServerPeer structure is created. This peer and all its
+ * vectors are advertised to all connected clients through the connected
+ * unix sockets.
+ */
+typedef struct IvshmemServerPeer {
+    QTAILQ_ENTRY(IvshmemServerPeer) next;    /**< next in list*/
+    int sock_fd;                             /**< connected unix sock */
+    long id;                                 /**< the id of the peer */
+    int vectors[IVSHMEM_SERVER_MAX_VECTORS]; /**< one fd per vector */
+    unsigned vectors_count;                  /**< number of vectors */
+} IvshmemServerPeer;
+QTAILQ_HEAD(IvshmemServerPeerList, IvshmemServerPeer);
+
+typedef struct IvshmemServerPeerList IvshmemServerPeerList;
+
+/**
+ * Structure describing an ivshmem server
+ *
+ * This structure stores all information related to our server: the name
+ * of the server unix socket and the list of connected peers.
+ */
+typedef struct IvshmemServer {
+    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 */
+    bool verbose;                    /**< true in verbose mode */
+    IvshmemServerPeerList peer_list; /**< list of peers */
+} IvshmemServer;
+
+/**
+ * Initialize an ivshmem server
+ *
+ * @server:         A pointer to an uninitialized IvshmemServer structure
+ * @unix_sock_path: The pointer to the unix socket file name
+ * @shm_path:       Path to the shared memory. The path corresponds to a POSIX
+ *                  shm name. To use a real file, for instance in a hugetlbfs,
+ *                  it is possible to use /../../abspath/to/file.
+ * @shm_size:       Size of shared memory
+ * @n_vectors:      Number of interrupt vectors per client
+ * @verbose:        True to enable verbose mode
+ *
+ * Returns:         0 on success, or a negative value on error
+ */
+int
+ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
+                    const char *shm_path, size_t shm_size, unsigned n_vectors,
+                    bool verbose);
+
+/**
+ * Open the shm, then create and bind to the unix socket
+ *
+ * @server: The pointer to the initialized IvshmemServer structure
+ *
+ * Returns: 0 on success, or a negative value on error
+ */
+int ivshmem_server_start(IvshmemServer *server);
+
+/**
+ * Close the server
+ *
+ * Close connections to all clients, close the unix socket and the
+ * shared memory file descriptor. The structure remains initialized, so
+ * it is possible to call ivshmem_server_start() again after a call to
+ * ivshmem_server_close().
+ *
+ * @server: The ivshmem server
+ */
+void ivshmem_server_close(IvshmemServer *server);
+
+/**
+ * Fill a fd_set with file descriptors to be monitored
+ *
+ * This function will fill a fd_set with all file descriptors that must
+ * be polled (unix server socket and peers unix socket). The function
+ * will not initialize the fd_set, it is up to the caller to do it.
+ *
+ * @server: The ivshmem server
+ * @fds:    The fd_set to be updated
+ * @maxfd:  Must be set to the max file descriptor + 1 in fd_set. This value is
+ *          updated if this function adds a greater fd in fd_set.
+ */
+void
+ivshmem_server_get_fds(const IvshmemServer *server, fd_set *fds, int *maxfd);
+
+/**
+ * Read and handle new messages
+ *
+ * Given a fd_set (for instance filled by a call to select()), handle
+ * incoming messages from peers.
+ *
+ * @server: The ivshmem server
+ * @fds:    The fd_set containing the file descriptors to be checked. Note that
+ *          file descriptors that are not related to our server are ignored.
+ * @maxfd:  The maximum fd in fd_set, plus one.
+ *
+ * Returns: 0 on success, or a negative value on error
+ */
+int ivshmem_server_handle_fds(IvshmemServer *server, fd_set *fds, int maxfd);
+
+/**
+ * Search a peer from its identifier
+ *
+ * @server:  The ivshmem server
+ * @peer_id: The identifier of the peer structure
+ *
+ * Returns:  The peer structure, or NULL if not found
+ */
+IvshmemServerPeer *
+ivshmem_server_search_peer(IvshmemServer *server, long peer_id);
+
+/**
+ * Dump information of this ivshmem server and its peers on stdout
+ *
+ * @server: The ivshmem server
+ */
+void ivshmem_server_dump(const IvshmemServer *server);
+
+#endif /* _IVSHMEM_SERVER_H_ */
diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
new file mode 100644
index 0000000..84ffc4d
--- /dev/null
+++ b/contrib/ivshmem-server/main.c
@@ -0,0 +1,264 @@
+/*
+ * 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 "qemu-common.h"
+
+#include "ivshmem-server.h"
+
+#define IVSHMEM_SERVER_DEFAULT_VERBOSE        0
+#define IVSHMEM_SERVER_DEFAULT_FOREGROUND     0
+#define IVSHMEM_SERVER_DEFAULT_PID_FILE       "/var/run/ivshmem-server.pid"
+#define IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "/tmp/ivshmem_socket"
+#define IVSHMEM_SERVER_DEFAULT_SHM_PATH       "ivshmem"
+#define IVSHMEM_SERVER_DEFAULT_SHM_SIZE       (4*1024*1024)
+#define IVSHMEM_SERVER_DEFAULT_N_VECTORS      1
+
+/* used to quit on signal SIGTERM */
+static int ivshmem_server_quit;
+
+/* arguments given by the user */
+typedef struct IvshmemServerArgs {
+    bool verbose;
+    bool foreground;
+    const char *pid_file;
+    const char *unix_socket_path;
+    const char *shm_path;
+    size_t shm_size;
+    unsigned n_vectors;
+} IvshmemServerArgs;
+
+/* show ivshmem_server_usage and exit with given error code */
+static void
+ivshmem_server_usage(const char *name, int code)
+{
+    fprintf(stderr, "%s [opts]\n", name);
+    fprintf(stderr, "  -h: show this help\n");
+    fprintf(stderr, "  -v: verbose mode\n");
+    fprintf(stderr, "  -F: foreground mode (default is to daemonize)\n");
+    fprintf(stderr, "  -p <pid_file>: path to the PID file (used in daemon\n"
+                    "     mode only).\n"
+                    "     Default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
+    fprintf(stderr, "  -S <unix_socket_path>: path to the unix socket\n"
+                    "     to listen to.\n"
+                    "     Default=%s\n", IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
+    fprintf(stderr, "  -m <shm_path>: path to the shared memory.\n"
+                    "     The path corresponds to a POSIX shm name. To use a\n"
+                    "     real file, for instance in a hugetlbfs, use\n"
+                    "     /../../abspath/to/file.\n"
+                    "     default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
+    fprintf(stderr, "  -l <size>: size of shared memory in bytes. The suffix\n"
+                    "     K, M and G can be used (ex: 1K means 1024).\n"
+                    "     default=%u\n", IVSHMEM_SERVER_DEFAULT_SHM_SIZE);
+    fprintf(stderr, "  -n <n_vects>: number of vectors.\n"
+                    "     default=%u\n", IVSHMEM_SERVER_DEFAULT_N_VECTORS);
+
+    exit(code);
+}
+
+/* parse the program arguments, exit on error */
+static void
+ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
+{
+    char c;
+    unsigned long long v;
+    Error *errp = NULL;
+
+    while ((c = getopt(argc, argv,
+                       "h"  /* help */
+                       "v"  /* verbose */
+                       "F"  /* foreground */
+                       "p:" /* pid_file */
+                       "S:" /* unix_socket_path */
+                       "m:" /* shm_path */
+                       "l:" /* shm_size */
+                       "n:" /* n_vectors */
+                      )) != -1) {
+
+        switch (c) {
+        case 'h': /* help */
+            ivshmem_server_usage(argv[0], 0);
+            break;
+
+        case 'v': /* verbose */
+            args->verbose = 1;
+            break;
+
+        case 'F': /* foreground */
+            args->foreground = 1;
+            break;
+
+        case 'p': /* pid_file */
+            args->pid_file = strdup(optarg);
+            break;
+
+        case 'S': /* unix_socket_path */
+            args->unix_socket_path = strdup(optarg);
+            break;
+
+        case 'm': /* shm_path */
+            args->shm_path = strdup(optarg);
+            break;
+
+        case 'l': /* shm_size */
+            parse_option_size("shm_size", optarg, &args->shm_size, &errp);
+            if (errp) {
+                fprintf(stderr, "cannot parse shm size: %s\n",
+                        error_get_pretty(errp));
+                error_free(errp);
+                ivshmem_server_usage(argv[0], 1);
+            }
+            break;
+
+        case 'n': /* n_vectors */
+            if (parse_uint_full(optarg, &v, 0) < 0) {
+                fprintf(stderr, "cannot parse n_vectors\n");
+                ivshmem_server_usage(argv[0], 1);
+            }
+            args->n_vectors = v;
+            break;
+
+        default:
+            ivshmem_server_usage(argv[0], 1);
+            break;
+        }
+    }
+
+    if (args->n_vectors > IVSHMEM_SERVER_MAX_VECTORS) {
+        fprintf(stderr, "too many requested vectors (max is %d)\n",
+                IVSHMEM_SERVER_MAX_VECTORS);
+        ivshmem_server_usage(argv[0], 1);
+    }
+
+    if (args->verbose == 1 && args->foreground == 0) {
+        fprintf(stderr, "cannot use verbose in daemon mode\n");
+        ivshmem_server_usage(argv[0], 1);
+    }
+}
+
+/* wait for events on listening server unix socket and connected client
+ * sockets */
+static int
+ivshmem_server_poll_events(IvshmemServer *server)
+{
+    fd_set fds;
+    int ret = 0, maxfd;
+
+    while (!ivshmem_server_quit) {
+
+        FD_ZERO(&fds);
+        maxfd = 0;
+        ivshmem_server_get_fds(server, &fds, &maxfd);
+
+        ret = select(maxfd, &fds, NULL, NULL, NULL);
+
+        if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            fprintf(stderr, "select error: %s\n", strerror(errno));
+            break;
+        }
+        if (ret == 0) {
+            continue;
+        }
+
+        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
+            fprintf(stderr, "ivshmem_server_handle_fds() failed\n");
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static void
+ivshmem_server_quit_cb(int signum)
+{
+    ivshmem_server_quit = 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+    IvshmemServer server;
+    struct sigaction sa, sa_quit;
+    IvshmemServerArgs args = {
+        .verbose = IVSHMEM_SERVER_DEFAULT_VERBOSE,
+        .foreground = IVSHMEM_SERVER_DEFAULT_FOREGROUND,
+        .pid_file = IVSHMEM_SERVER_DEFAULT_PID_FILE,
+        .unix_socket_path = IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH,
+        .shm_path = IVSHMEM_SERVER_DEFAULT_SHM_PATH,
+        .shm_size = IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
+        .n_vectors = IVSHMEM_SERVER_DEFAULT_N_VECTORS,
+    };
+    int ret = 1;
+
+    /* parse arguments, will exit on error */
+    ivshmem_server_parse_args(&args, argc, argv);
+
+    /* Ignore SIGPIPE, see this link for more info:
+     * http://www.mail-archive.com/libevent-users@monkey.org/msg01606.html */
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    if (sigemptyset(&sa.sa_mask) == -1 ||
+        sigaction(SIGPIPE, &sa, 0) == -1) {
+        perror("failed to ignore SIGPIPE; sigaction");
+        goto err;
+    }
+
+    sa_quit.sa_handler = ivshmem_server_quit_cb;
+    sa_quit.sa_flags = 0;
+    if (sigemptyset(&sa_quit.sa_mask) == -1 ||
+        sigaction(SIGTERM, &sa_quit, 0) == -1) {
+        perror("failed to add SIGTERM handler; sigaction");
+        goto err;
+    }
+
+    /* init the ivshms structure */
+    if (ivshmem_server_init(&server, args.unix_socket_path, args.shm_path,
+                            args.shm_size, args.n_vectors, args.verbose) < 0) {
+        fprintf(stderr, "cannot init server\n");
+        goto err;
+    }
+
+    /* start the ivshmem server (open shm & unix socket) */
+    if (ivshmem_server_start(&server) < 0) {
+        fprintf(stderr, "cannot bind\n");
+        goto err;
+    }
+
+    /* daemonize if asked to */
+    if (!args.foreground) {
+        FILE *fp;
+
+        if (daemon(1, 1) < 0) {
+            fprintf(stderr, "cannot daemonize: %s\n", strerror(errno));
+            goto err_close;
+        }
+
+        /* write pid file */
+        fp = fopen(args.pid_file, "w");
+        if (fp == NULL) {
+            fprintf(stderr, "cannot write pid file: %s\n", strerror(errno));
+            goto err_close;
+        }
+
+        fprintf(fp, "%d\n", (int) getpid());
+        fclose(fp);
+    }
+
+    ivshmem_server_poll_events(&server);
+    fprintf(stdout, "server disconnected\n");
+    ret = 0;
+
+err_close:
+    ivshmem_server_close(&server);
+err:
+    return ret;
+}
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 7af4412..5a3d2fb 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1264,9 +1264,13 @@ is qemu.git/contrib/ivshmem-server.  An example syntax when using the shared
 memory server is:
 
 @example
-qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,chardev=<id>]
-                 [,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
-qemu-system-i386 -chardev socket,path=<path>,id=<id>
+# First start the ivshmem server once and for all
+ivshmem-server -p <pidfile> -S <path> -m <shm name> -l <shm size> -n <vectors n>
+
+# Then start your qemu instances with matching arguments
+qemu-system-i386 -device ivshmem,size=<shm size>,vectors=<vectors n>,chardev=<id>
+                 [,msi=on][,ioeventfd=on][,role=peer|master]
+                 -chardev socket,path=<path>,id=<id>
 @end example
 
 When using the server, the guest will be assigned a VM ID (>=0) that allows guests
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 32/46] ivshmem-client: check the number of vectors
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (30 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 31/46] contrib: add ivshmem client and server marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 33/46] ivshmem-server: use a uint16 for client ID marcandre.lureau
                   ` (15 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Check the number of vectors received from the server, to avoid
out of bound array access.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 contrib/ivshmem-client/ivshmem-client.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/contrib/ivshmem-client/ivshmem-client.c b/contrib/ivshmem-client/ivshmem-client.c
index 11c805c..01e24a7 100644
--- a/contrib/ivshmem-client/ivshmem-client.c
+++ b/contrib/ivshmem-client/ivshmem-client.c
@@ -128,6 +128,10 @@ ivshmem_client_handle_server_msg(IvshmemClient *client)
     /* new vector */
     IVSHMEM_CLIENT_DEBUG(client, "  new vector %d (fd=%d) for peer id %ld\n",
                          peer->vectors_count, fd, peer->id);
+    if (peer->vectors_count >= G_N_ELEMENTS(peer->vectors)) {
+        return -1;
+    }
+
     peer->vectors[peer->vectors_count] = fd;
     peer->vectors_count++;
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 33/46] ivshmem-server: use a uint16 for client ID
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (31 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 32/46] ivshmem-client: check the number of vectors marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support marcandre.lureau
                   ` (14 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

In practice, the number of VM is limited to MAXUINT16 in ivshmem, so use
the same limit on the server (removes a theorical infinite loop)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 contrib/ivshmem-server/ivshmem-server.c | 11 ++++++++++-
 contrib/ivshmem-server/ivshmem-server.h |  2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
index 16ee583..972fda2 100644
--- a/contrib/ivshmem-server/ivshmem-server.c
+++ b/contrib/ivshmem-server/ivshmem-server.c
@@ -145,9 +145,18 @@ ivshmem_server_handle_new_conn(IvshmemServer *server)
     peer->sock_fd = newfd;
 
     /* get an unused peer id */
-    while (ivshmem_server_search_peer(server, server->cur_id) != NULL) {
+    /* XXX: this could use id allocation such as Linux IDA, or simply
+     * a free-list */
+    for (i = 0; i < G_MAXUINT16; i++) {
+        if (ivshmem_server_search_peer(server, server->cur_id) == NULL) {
+            break;
+        }
         server->cur_id++;
     }
+    if (i == G_MAXUINT16) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot allocate new client id\n");
+        goto fail;
+    }
     peer->id = server->cur_id++;
 
     /* create eventfd, one per vector */
diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
index cd584fc..2176d5e 100644
--- a/contrib/ivshmem-server/ivshmem-server.h
+++ b/contrib/ivshmem-server/ivshmem-server.h
@@ -70,7 +70,7 @@ typedef struct IvshmemServer {
     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 */
+    uint16_t cur_id;                 /**< id to be given to next client */
     bool verbose;                    /**< true in verbose mode */
     IvshmemServerPeerList peer_list; /**< list of peers */
 } IvshmemServer;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (32 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 33/46] ivshmem-server: use a uint16 for client ID marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 16:07   ` Vladimir Sementsov-Ogievskiy
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 35/46] docs: update ivshmem device spec marcandre.lureau
                   ` (13 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

As pointed out on the ML by Andrew Jones, glibc no longer permits
creating POSIX shm on hugetlbfs directly. When given a hugetlbfs path,
create a shareable file there.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 contrib/ivshmem-server/ivshmem-server.c | 40 ++++++++++++++++++++++++++++++++-
 contrib/ivshmem-server/ivshmem-server.h |  3 +--
 contrib/ivshmem-server/main.c           |  5 ++---
 3 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
index 972fda2..51264b4 100644
--- a/contrib/ivshmem-server/ivshmem-server.c
+++ b/contrib/ivshmem-server/ivshmem-server.c
@@ -11,6 +11,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/eventfd.h>
+#include <sys/vfs.h>
 
 #include "qemu-common.h"
 #include "qemu/queue.h"
@@ -271,15 +272,52 @@ ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
     return 0;
 }
 
+#define HUGETLBFS_MAGIC       0x958458f6
+
+static long gethugepagesize(const char *path)
+{
+    struct statfs fs;
+    int ret;
+
+    do {
+        ret = statfs(path, &fs);
+    } while (ret != 0 && errno == EINTR);
+
+    if (ret != 0) {
+        if (errno != ENOENT) {
+            fprintf(stderr, "cannot stat shm file %s: %s\n", path,
+                    strerror(errno));
+        }
+        return -1;
+    }
+
+    if (fs.f_type != HUGETLBFS_MAGIC) {
+        return -1;
+    }
+
+    return fs.f_bsize;
+}
+
 /* open shm, create and bind to the unix socket */
 int
 ivshmem_server_start(IvshmemServer *server)
 {
     struct sockaddr_un sun;
     int shm_fd, sock_fd, ret;
+    long hpagesize;
+    gchar *filename;
 
     /* open shm file */
-    shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
+    hpagesize = gethugepagesize(server->shm_path);
+    if (hpagesize > 0) {
+        filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path);
+        shm_fd = mkstemp(filename);
+        unlink(filename);
+        g_free(filename);
+    } else {
+        shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
+    }
+
     if (shm_fd < 0) {
         fprintf(stderr, "cannot open shm file %s: %s\n", server->shm_path,
                 strerror(errno));
diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
index 2176d5e..e9b0e7a 100644
--- a/contrib/ivshmem-server/ivshmem-server.h
+++ b/contrib/ivshmem-server/ivshmem-server.h
@@ -81,8 +81,7 @@ typedef struct IvshmemServer {
  * @server:         A pointer to an uninitialized IvshmemServer structure
  * @unix_sock_path: The pointer to the unix socket file name
  * @shm_path:       Path to the shared memory. The path corresponds to a POSIX
- *                  shm name. To use a real file, for instance in a hugetlbfs,
- *                  it is possible to use /../../abspath/to/file.
+ *                  shm name or a hugetlbfs mount point.
  * @shm_size:       Size of shared memory
  * @n_vectors:      Number of interrupt vectors per client
  * @verbose:        True to enable verbose mode
diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
index 84ffc4d..cd8d9ed 100644
--- a/contrib/ivshmem-server/main.c
+++ b/contrib/ivshmem-server/main.c
@@ -47,9 +47,8 @@ ivshmem_server_usage(const char *name, int code)
                     "     to listen to.\n"
                     "     Default=%s\n", IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
     fprintf(stderr, "  -m <shm_path>: path to the shared memory.\n"
-                    "     The path corresponds to a POSIX shm name. To use a\n"
-                    "     real file, for instance in a hugetlbfs, use\n"
-                    "     /../../abspath/to/file.\n"
+                    "     The path corresponds to a POSIX shm name or a\n"
+                    "     hugetlbfs mount point.\n"
                     "     default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
     fprintf(stderr, "  -l <size>: size of shared memory in bytes. The suffix\n"
                     "     K, M and G can be used (ex: 1K means 1024).\n"
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 35/46] docs: update ivshmem device spec
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (33 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 36/46] ivshmem: add check on protocol version in QEMU marcandre.lureau
                   ` (12 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, David Marchand, stefanha

From: David Marchand <david.marchand@6wind.com>

Add some notes on the parts needed to use ivshmem devices: more specifically,
explain the purpose of an ivshmem server and the basic concept to use the
ivshmem devices in guests.
Move some parts of the documentation and re-organise it.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/specs/ivshmem_device_spec.txt | 124 +++++++++++++++++++++++++++----------
 1 file changed, 93 insertions(+), 31 deletions(-)

diff --git a/docs/specs/ivshmem_device_spec.txt b/docs/specs/ivshmem_device_spec.txt
index 667a862..12f338e 100644
--- a/docs/specs/ivshmem_device_spec.txt
+++ b/docs/specs/ivshmem_device_spec.txt
@@ -2,30 +2,103 @@
 Device Specification for Inter-VM shared memory device
 ------------------------------------------------------
 
-The Inter-VM shared memory device is designed to share a region of memory to
-userspace in multiple virtual guests.  The memory region does not belong to any
-guest, but is a POSIX memory object on the host.  Optionally, the device may
-support sending interrupts to other guests sharing the same memory region.
+The Inter-VM shared memory device is designed to share a memory region (created
+on the host via the POSIX shared memory API) between multiple QEMU processes
+running different guests. In order for all guests to be able to pick up the
+shared memory area, it is modeled by QEMU as a PCI device exposing said memory
+to the guest as a PCI BAR.
+The memory region does not belong to any guest, but is a POSIX memory object on
+the host. The host can access this shared memory if needed.
+
+The device also provides an optional communication mechanism between guests
+sharing the same memory object. More details about that in the section 'Guest to
+guest communication' section.
 
 
 The Inter-VM PCI device
 -----------------------
 
-*BARs*
+From the VM point of view, the ivshmem PCI device supports three BARs.
+
+- BAR0 is a 1 Kbyte MMIO region to support registers and interrupts when MSI is
+  not used.
+- BAR1 is used for MSI-X when it is enabled in the device.
+- BAR2 is used to access the shared memory object.
+
+It is your choice how to use the device but you must choose between two
+behaviors :
+
+- basically, if you only need the shared memory part, you will map BAR2.
+  This way, you have access to the shared memory in guest and can use it as you
+  see fit (memnic, for example, uses it in userland
+  http://dpdk.org/browse/memnic).
+
+- BAR0 and BAR1 are used to implement an optional communication mechanism
+  through interrupts in the guests. If you need an event mechanism between the
+  guests accessing the shared memory, you will most likely want to write a
+  kernel driver that will handle interrupts. See details in the section 'Guest
+  to guest communication' section.
+
+The behavior is chosen when starting your QEMU processes:
+- no communication mechanism needed, the first QEMU to start creates the shared
+  memory on the host, subsequent QEMU processes will use it.
+
+- communication mechanism needed, an ivshmem server must be started before any
+  QEMU processes, then each QEMU process connects to the server unix socket.
+
+For more details on the QEMU ivshmem parameters, see qemu-doc documentation.
+
+
+Guest to guest communication
+----------------------------
+
+This section details the communication mechanism between the guests accessing
+the ivhsmem shared memory.
 
-The device supports three BARs.  BAR0 is a 1 Kbyte MMIO region to support
-registers.  BAR1 is used for MSI-X when it is enabled in the device.  BAR2 is
-used to map the shared memory object from the host.  The size of BAR2 is
-specified when the guest is started and must be a power of 2 in size.
+*ivshmem server*
 
-*Registers*
+This server code is available in qemu.git/contrib/ivshmem-server.
 
-The device currently supports 4 registers of 32-bits each.  Registers
-are used for synchronization between guests sharing the same memory object when
-interrupts are supported (this requires using the shared memory server).
+The server must be started on the host before any guest.
+It creates a shared memory object then waits for clients to connect on a unix
+socket.
 
-The server assigns each VM an ID number and sends this ID number to the QEMU
-process when the guest starts.
+For each client (QEMU process) that connects to the server:
+- the server assigns an ID for this client and sends this ID to him as the first
+  message,
+- the server sends a fd to the shared memory object to this client,
+- the server creates a new set of host eventfds associated to the new client and
+  sends this set to all already connected clients,
+- finally, the server sends all the eventfds sets for all clients to the new
+  client.
+
+The server signals all clients when one of them disconnects.
+
+The client IDs are limited to 16 bits because of the current implementation (see
+Doorbell register in 'PCI device registers' subsection). Hence only 65536
+clients are supported.
+
+All the file descriptors (fd to the shared memory, eventfds for each client)
+are passed to clients using SCM_RIGHTS over the server unix socket.
+
+Apart from the current ivshmem implementation in QEMU, an ivshmem client has
+been provided in qemu.git/contrib/ivshmem-client for debug.
+
+*QEMU as an ivshmem client*
+
+At initialisation, when creating the ivshmem device, QEMU gets its ID from the
+server then makes it available through BAR0 IVPosition register for the VM to
+use (see 'PCI device registers' subsection).
+QEMU then uses the fd to the shared memory to map it to BAR2.
+eventfds for all other clients received from the server are stored to implement
+BAR0 Doorbell register (see 'PCI device registers' subsection).
+Finally, eventfds assigned to this QEMU process are used to send interrupts in
+this VM.
+
+*PCI device registers*
+
+From the VM point of view, the ivshmem PCI device supports 4 registers of
+32-bits each.
 
 enum ivshmem_registers {
     IntrMask = 0,
@@ -49,8 +122,8 @@ bit to 0 and unmasked by setting the first bit to 1.
 IVPosition Register: The IVPosition register is read-only and reports the
 guest's ID number.  The guest IDs are non-negative integers.  When using the
 server, since the server is a separate process, the VM ID will only be set when
-the device is ready (shared memory is received from the server and accessible via
-the device).  If the device is not ready, the IVPosition will return -1.
+the device is ready (shared memory is received from the server and accessible
+via the device).  If the device is not ready, the IVPosition will return -1.
 Applications should ensure that they have a valid VM ID before accessing the
 shared memory.
 
@@ -59,8 +132,8 @@ Doorbell register.  The doorbell register is 32-bits, logically divided into
 two 16-bit fields.  The high 16-bits are the guest ID to interrupt and the low
 16-bits are the interrupt vector to trigger.  The semantics of the value
 written to the doorbell depends on whether the device is using MSI or a regular
-pin-based interrupt.  In short, MSI uses vectors while regular interrupts set the
-status register.
+pin-based interrupt.  In short, MSI uses vectors while regular interrupts set
+the status register.
 
 Regular Interrupts
 
@@ -71,7 +144,7 @@ interrupt in the destination guest.
 
 Message Signalled Interrupts
 
-A ivshmem device may support multiple MSI vectors.  If so, the lower 16-bits
+An ivshmem device may support multiple MSI vectors.  If so, the lower 16-bits
 written to the Doorbell register must be between 0 and the maximum number of
 vectors the guest supports.  The lower 16 bits written to the doorbell is the
 MSI vector that will be raised in the destination guest.  The number of MSI
@@ -83,14 +156,3 @@ interrupt itself should be communicated via the shared memory region.  Devices
 supporting multiple MSI vectors can use different vectors to indicate different
 events have occurred.  The semantics of interrupt vectors are left to the
 user's discretion.
-
-
-Usage in the Guest
-------------------
-
-The shared memory device is intended to be used with the provided UIO driver.
-Very little configuration is needed.  The guest should map BAR0 to access the
-registers (an array of 32-bit ints allows simple writing) and map BAR2 to
-access the shared memory region itself.  The size of the shared memory region
-is specified when the guest (or shared memory server) is started.  A guest may
-map the whole shared memory region or only part of it.
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 36/46] ivshmem: add check on protocol version in QEMU
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (34 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 35/46] docs: update ivshmem device spec marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup() marcandre.lureau
                   ` (11 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, David Marchand, stefanha

From: David Marchand <david.marchand@6wind.com>

Send a protocol version as the first message from server, clients must
close communication if they don't support this protocol version.  Older
QEMUs should be fine with this change in the protocol since they
overrides their own vm_id on reception of an id associated to no
eventfd.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
[use fifo_update_and_get()]
---
 contrib/ivshmem-client/ivshmem-client.c | 13 ++++++++++---
 contrib/ivshmem-client/ivshmem-client.h |  1 +
 contrib/ivshmem-server/ivshmem-server.c |  9 +++++++++
 contrib/ivshmem-server/ivshmem-server.h |  1 +
 docs/specs/ivshmem_device_spec.txt      |  9 ++++++---
 hw/misc/ivshmem.c                       | 31 +++++++++++++++++++++++++++++--
 include/hw/misc/ivshmem.h               | 25 +++++++++++++++++++++++++
 7 files changed, 81 insertions(+), 8 deletions(-)
 create mode 100644 include/hw/misc/ivshmem.h

diff --git a/contrib/ivshmem-client/ivshmem-client.c b/contrib/ivshmem-client/ivshmem-client.c
index 01e24a7..a8477d8 100644
--- a/contrib/ivshmem-client/ivshmem-client.c
+++ b/contrib/ivshmem-client/ivshmem-client.c
@@ -205,10 +205,17 @@ ivshmem_client_connect(IvshmemClient *client)
         goto err_close;
     }
 
-    /* first, we expect our index + a fd == -1 */
+    /* first, we expect a protocol version */
+    if (ivshmem_client_read_one_msg(client, &tmp, &fd) < 0 ||
+        (tmp != IVSHMEM_PROTOCOL_VERSION) || fd != -1) {
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server\n");
+        goto err_close;
+    }
+
+    /* then, we expect our index + a fd == -1 */
     if (ivshmem_client_read_one_msg(client, &client->local.id, &fd) < 0 ||
         client->local.id < 0 || fd != -1) {
-        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server\n");
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server (2)\n");
         goto err_close;
     }
     IVSHMEM_CLIENT_DEBUG(client, "our_id=%ld\n", client->local.id);
@@ -220,7 +227,7 @@ ivshmem_client_connect(IvshmemClient *client)
         if (fd >= 0) {
             close(fd);
         }
-        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server (2)\n");
+        IVSHMEM_CLIENT_DEBUG(client, "cannot read from server (3)\n");
         goto err_close;
     }
     client->shm_fd = fd;
diff --git a/contrib/ivshmem-client/ivshmem-client.h b/contrib/ivshmem-client/ivshmem-client.h
index 284c4a3..9215f34 100644
--- a/contrib/ivshmem-client/ivshmem-client.h
+++ b/contrib/ivshmem-client/ivshmem-client.h
@@ -23,6 +23,7 @@
 #include <sys/select.h>
 
 #include "qemu/queue.h"
+#include "hw/misc/ivshmem.h"
 
 /**
  * Maximum number of notification vectors supported by the client
diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
index 51264b4..d917161 100644
--- a/contrib/ivshmem-server/ivshmem-server.c
+++ b/contrib/ivshmem-server/ivshmem-server.c
@@ -101,6 +101,15 @@ ivshmem_server_send_initial_info(IvshmemServer *server, IvshmemServerPeer *peer)
 {
     int ret;
 
+    /* send our protocol version first */
+    ret = ivshmem_server_send_one_msg(peer->sock_fd, IVSHMEM_PROTOCOL_VERSION,
+                                      -1);
+    if (ret < 0) {
+        IVSHMEM_SERVER_DEBUG(server, "cannot send version: %s\n",
+                             strerror(errno));
+        return -1;
+    }
+
     /* send the peer id to the client */
     ret = ivshmem_server_send_one_msg(peer->sock_fd, peer->id, -1);
     if (ret < 0) {
diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
index e9b0e7a..65b3c2d 100644
--- a/contrib/ivshmem-server/ivshmem-server.h
+++ b/contrib/ivshmem-server/ivshmem-server.h
@@ -32,6 +32,7 @@
 #include <stdbool.h>
 
 #include "qemu/queue.h"
+#include "hw/misc/ivshmem.h"
 
 /**
  * Maximum number of notification vectors supported by the server
diff --git a/docs/specs/ivshmem_device_spec.txt b/docs/specs/ivshmem_device_spec.txt
index 12f338e..3435116 100644
--- a/docs/specs/ivshmem_device_spec.txt
+++ b/docs/specs/ivshmem_device_spec.txt
@@ -64,6 +64,8 @@ It creates a shared memory object then waits for clients to connect on a unix
 socket.
 
 For each client (QEMU process) that connects to the server:
+- the server sends a protocol version, if client does not support it, the client
+  closes the communication,
 - the server assigns an ID for this client and sends this ID to him as the first
   message,
 - the server sends a fd to the shared memory object to this client,
@@ -86,9 +88,10 @@ been provided in qemu.git/contrib/ivshmem-client for debug.
 
 *QEMU as an ivshmem client*
 
-At initialisation, when creating the ivshmem device, QEMU gets its ID from the
-server then makes it available through BAR0 IVPosition register for the VM to
-use (see 'PCI device registers' subsection).
+At initialisation, when creating the ivshmem device, QEMU first receives a
+protocol version and closes communication with server if it does not match.
+Then, QEMU gets its ID from the server then makes it available through BAR0
+IVPosition register for the VM to use (see 'PCI device registers' subsection).
 QEMU then uses the fd to the shared memory to map it to BAR2.
 eventfds for all other clients received from the server are stored to implement
 BAR0 Doorbell register (see 'PCI device registers' subsection).
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 6c0a829..4adcac5 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -27,6 +27,8 @@
 #include "qemu/fifo8.h"
 #include "sysemu/char.h"
 
+#include "hw/misc/ivshmem.h"
+
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <limits.h>
@@ -594,6 +596,31 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     }
 }
 
+static void ivshmem_check_version(void *opaque, const uint8_t * buf, int size)
+{
+    IVShmemState *s = opaque;
+    int tmp;
+    long version;
+
+    if (!fifo_update_and_get(s, buf, size,
+                             &version, sizeof(version))) {
+        return;
+    }
+
+    tmp = qemu_chr_fe_get_msgfd(s->server_chr);
+    if (tmp != -1 || version != IVSHMEM_PROTOCOL_VERSION) {
+        fprintf(stderr, "incompatible version, you are connecting to a ivshmem-"
+                "server using a different protocol please check your setup\n");
+        qemu_chr_delete(s->server_chr);
+        s->server_chr = NULL;
+        return;
+    }
+
+    IVSHMEM_DPRINTF("version check ok, switch to real chardev handler\n");
+    qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+                          ivshmem_event, s);
+}
+
 /* Select the MSI-X vectors used by device.
  * ivshmem maps events to vectors statically, so
  * we just enable all vectors on init and after reset. */
@@ -767,8 +794,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
 
         s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
 
-        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
-                     ivshmem_event, s);
+        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
+                              ivshmem_check_version, ivshmem_event, s);
     } else {
         /* just map the file immediately, we're not using a server */
         int fd;
diff --git a/include/hw/misc/ivshmem.h b/include/hw/misc/ivshmem.h
new file mode 100644
index 0000000..433ef53
--- /dev/null
+++ b/include/hw/misc/ivshmem.h
@@ -0,0 +1,25 @@
+
+/*
+ * Inter-VM Shared Memory PCI device.
+ *
+ * Author:
+ *      Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based On: cirrus_vga.c
+ *          Copyright (c) 2004 Fabrice Bellard
+ *          Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ *      and rtl8139.c
+ *          Copyright (c) 2006 Igor Kovalenko
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#ifndef IVSHMEM_H
+#define IVSHMEM_H
+
+#define IVSHMEM_PROTOCOL_VERSION 0
+
+#endif /* IVSHMEM_H */
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (35 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 36/46] ivshmem: add check on protocol version in QEMU marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-17  9:01   ` Vladimir Sementsov-Ogievskiy
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 38/46] msix: implement pba write (but read-only) marcandre.lureau
                   ` (10 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

getopt() optarg points to argv memory, no need to dup those values,
fixes small leaks detected by clang-analyzer.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 contrib/ivshmem-client/main.c | 2 +-
 contrib/ivshmem-server/main.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/contrib/ivshmem-client/main.c b/contrib/ivshmem-client/main.c
index 5d85ae7..bd7cbfc 100644
--- a/contrib/ivshmem-client/main.c
+++ b/contrib/ivshmem-client/main.c
@@ -53,7 +53,7 @@ ivshmem_client_parse_args(IvshmemClientArgs *args, int argc, char *argv[])
             break;
 
         case 'S': /* unix_sock_path */
-            args->unix_sock_path = strdup(optarg);
+            args->unix_sock_path = optarg;
             break;
 
         default:
diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
index cd8d9ed..71e87ea 100644
--- a/contrib/ivshmem-server/main.c
+++ b/contrib/ivshmem-server/main.c
@@ -92,15 +92,15 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
             break;
 
         case 'p': /* pid_file */
-            args->pid_file = strdup(optarg);
+            args->pid_file = optarg;
             break;
 
         case 'S': /* unix_socket_path */
-            args->unix_socket_path = strdup(optarg);
+            args->unix_socket_path = optarg;
             break;
 
         case 'm': /* shm_path */
-            args->shm_path = strdup(optarg);
+            args->shm_path = optarg;
             break;
 
         case 'l': /* shm_size */
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 38/46] msix: implement pba write (but read-only)
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (36 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 39/46] qtest: add qtest_add_abrt_handler() marcandre.lureau
                   ` (9 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

qpci_msix_pending() writes on pba region, causing qemu to SEGV:

  Program received signal SIGSEGV, Segmentation fault.
  [Switching to Thread 0x7ffff7fba8c0 (LWP 25882)]
  0x0000000000000000 in ?? ()
  (gdb) bt
  #0  0x0000000000000000 in  ()
  #1  0x00005555556556c5 in memory_region_oldmmio_write_accessor (mr=0x5555579f3f80, addr=0, value=0x7fffffffbf68, size=4, shift=0, mask=4294967295, attrs=...) at /home/elmarco/src/qemu/memory.c:434
  #2  0x00005555556558e1 in access_with_adjusted_size (addr=0, value=0x7fffffffbf68, size=4, access_size_min=1, access_size_max=4, access=0x55555565563e <memory_region_oldmmio_write_accessor>, mr=0x5555579f3f80, attrs=...) at /home/elmarco/src/qemu/memory.c:506
  #3  0x00005555556581eb in memory_region_dispatch_write (mr=0x5555579f3f80, addr=0, data=0, size=4, attrs=...) at /home/elmarco/src/qemu/memory.c:1176
  #4  0x000055555560b6f9 in address_space_rw (as=0x555555eff4e0 <address_space_memory>, addr=3759147008, attrs=..., buf=0x7fffffffc1b0 "", len=4, is_write=true) at /home/elmarco/src/qemu/exec.c:2439
  #5  0x000055555560baa2 in cpu_physical_memory_rw (addr=3759147008, buf=0x7fffffffc1b0 "", len=4, is_write=1) at /home/elmarco/src/qemu/exec.c:2534
  #6  0x000055555564c005 in cpu_physical_memory_write (addr=3759147008, buf=0x7fffffffc1b0, len=4) at /home/elmarco/src/qemu/include/exec/cpu-common.h:80
  #7  0x000055555564cd9c in qtest_process_command (chr=0x55555642b890, words=0x5555578de4b0) at /home/elmarco/src/qemu/qtest.c:378
  #8  0x000055555564db77 in qtest_process_inbuf (chr=0x55555642b890, inbuf=0x55555641b340) at /home/elmarco/src/qemu/qtest.c:569
  #9  0x000055555564dc07 in qtest_read (opaque=0x55555642b890, buf=0x7fffffffc2e0 "writel 0xe0100800 0x0\n", size=22) at /home/elmarco/src/qemu/qtest.c:581
  #10 0x000055555574ce3e in qemu_chr_be_write (s=0x55555642b890, buf=0x7fffffffc2e0 "writel 0xe0100800 0x0\n", len=22) at qemu-char.c:306
  #11 0x0000555555751263 in tcp_chr_read (chan=0x55555642bcf0, cond=G_IO_IN, opaque=0x55555642b890) at qemu-char.c:2876
  #12 0x00007ffff64c9a8a in g_main_context_dispatch (context=0x55555641c400) at gmain.c:3122

(without this patch, this can be reproduced with the ivshmem qtest)

Implement an empty mmio write to avoid the crash.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/pci/msix.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 2fdada4..64c93d8 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -200,8 +200,14 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr,
     return pci_get_long(dev->msix_pba + addr);
 }
 
+static void msix_pba_mmio_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+}
+
 static const MemoryRegionOps msix_pba_mmio_ops = {
     .read = msix_pba_mmio_read,
+    .write = msix_pba_mmio_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
     .valid = {
         .min_access_size = 4,
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 39/46] qtest: add qtest_add_abrt_handler()
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (37 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 38/46] msix: implement pba write (but read-only) marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest marcandre.lureau
                   ` (8 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Allow a test to add abort handlers, use GHook for all handlers.

There is currently no way to remove a handler, but it could be
later added if needed.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/libqtest.c | 37 ++++++++++++++++++++++++-------------
 tests/libqtest.h |  2 ++
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index e5188e0..4a3a6ad 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -49,6 +49,7 @@ struct QTestState
     struct sigaction sigact_old; /* restored on exit */
 };
 
+static GHookList abrt_hooks;
 static GList *qtest_instances;
 static struct sigaction sigact_old;
 
@@ -112,10 +113,7 @@ static void kill_qemu(QTestState *s)
 
 static void sigabrt_handler(int signo)
 {
-    GList *elem;
-    for (elem = qtest_instances; elem; elem = elem->next) {
-        kill_qemu(elem->data);
-    }
+    g_hook_list_invoke(&abrt_hooks, FALSE);
 }
 
 static void setup_sigabrt_handler(void)
@@ -136,6 +134,23 @@ static void cleanup_sigabrt_handler(void)
     sigaction(SIGABRT, &sigact_old, NULL);
 }
 
+void qtest_add_abrt_handler(void (*fn), const void *data)
+{
+    GHook *hook;
+
+    /* Only install SIGABRT handler once */
+    if (!abrt_hooks.is_setup) {
+        g_hook_list_init(&abrt_hooks, sizeof(GHook));
+        setup_sigabrt_handler();
+    }
+
+    hook = g_hook_alloc(&abrt_hooks);
+    hook->func = fn;
+    hook->data = (void *)data;
+
+    g_hook_prepend(&abrt_hooks, hook);
+}
+
 QTestState *qtest_init(const char *extra_args)
 {
     QTestState *s;
@@ -156,12 +171,7 @@ QTestState *qtest_init(const char *extra_args)
     sock = init_socket(socket_path);
     qmpsock = init_socket(qmp_socket_path);
 
-    /* Only install SIGABRT handler once */
-    if (!qtest_instances) {
-        setup_sigabrt_handler();
-    }
-
-    qtest_instances = g_list_prepend(qtest_instances, s);
+    qtest_add_abrt_handler(kill_qemu, s);
 
     s->qemu_pid = fork();
     if (s->qemu_pid == 0) {
@@ -209,13 +219,14 @@ QTestState *qtest_init(const char *extra_args)
 
 void qtest_quit(QTestState *s)
 {
+    qtest_instances = g_list_remove(qtest_instances, s);
+    g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s));
+
     /* Uninstall SIGABRT handler on last instance */
-    if (qtest_instances && !qtest_instances->next) {
+    if (!qtest_instances) {
         cleanup_sigabrt_handler();
     }
 
-    qtest_instances = g_list_remove(qtest_instances, s);
-
     kill_qemu(s);
     close(s->fd);
     close(s->qmp_fd);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ec42031..f02c07c 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -427,6 +427,8 @@ void qtest_add_data_func(const char *str, const void *data, void (*fn));
         g_free(path); \
     } while (0)
 
+void qtest_add_abrt_handler(void (*fn), const void *data);
+
 /**
  * qtest_start:
  * @args: other arguments to pass to QEMU
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (38 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 39/46] qtest: add qtest_add_abrt_handler() marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:44   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open marcandre.lureau
                   ` (7 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Marc-André Lureau, drjones, cam, Andreas Färber, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Adds 4 ivshmemtests:
- single qemu instance and basic IO
- pair of instances, check memory sharing
- pair of instances with server, and MSIX
- hot plug/unplug

A temporary shm is created as well as a directory to place server
socket, both should be clear on exit and abort.

Cc: Cam Macdonell <cam@cs.ualberta.ca>
CC: Andreas Färber <afaerber@suse.de>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile       |   3 +
 tests/ivshmem-test.c | 474 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 477 insertions(+)
 create mode 100644 tests/ivshmem-test.c

diff --git a/tests/Makefile b/tests/Makefile
index 34c6136..e7a50e7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -142,6 +142,8 @@ gcov-files-pci-y += hw/display/virtio-gpu-pci.c
 gcov-files-pci-$(CONFIG_VIRTIO_VGA) += hw/display/virtio-vga.c
 check-qtest-pci-y += tests/intel-hda-test$(EXESUF)
 gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c
+check-qtest-pci-$(CONFIG_LINUX) += tests/ivshmem-test$(EXESUF)
+gcov-files-pci-y += hw/misc/ivshmem.c
 
 check-qtest-i386-y = tests/endianness-test$(EXESUF)
 check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -416,6 +418,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
 tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y)
 
 ifeq ($(CONFIG_POSIX),y)
 LIBS += -lutil
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
new file mode 100644
index 0000000..03f44c1
--- /dev/null
+++ b/tests/ivshmem-test.c
@@ -0,0 +1,474 @@
+/*
+ * QTest testcase for ivshmem
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include "contrib/ivshmem-server/ivshmem-server.h"
+#include "libqos/pci-pc.h"
+#include "libqtest.h"
+#include "qemu/osdep.h"
+#include <stdlib.h>
+
+#if GLIB_CHECK_VERSION(2, 32, 0)
+#define HAVE_THREAD_NEW
+#endif
+
+#define TMPSHMSIZE (1 << 20)
+static char *tmpshm;
+static void *tmpshmem;
+static char *tmpdir;
+static char *tmpserver;
+
+static void save_fn(QPCIDevice *dev, int devfn, void *data)
+{
+    QPCIDevice **pdev = (QPCIDevice **) data;
+
+    *pdev = dev;
+}
+
+static QPCIDevice *get_device(void)
+{
+    QPCIDevice *dev;
+    QPCIBus *pcibus;
+
+    pcibus = qpci_init_pc();
+    qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
+    g_assert(dev != NULL);
+
+    return dev;
+}
+
+typedef struct _IVState {
+    QTestState *qtest;
+    void *reg_base, *mem_base;
+    QPCIDevice *dev;
+} IVState;
+
+#define REG(name, len, val)                                     \
+    static inline unsigned in_##name(IVState *s)                \
+    {                                                           \
+        QTestState *qtest = global_qtest;                       \
+        unsigned res;                                           \
+        global_qtest = s->qtest;                                \
+        res = qpci_io_read##len(s->dev, s->reg_base+(val));     \
+        g_test_message("*%s -> %x\n", #name, res);              \
+        global_qtest = qtest;                                   \
+        return res;                                             \
+    }                                                           \
+    static inline void out_##name(IVState *s, unsigned v)       \
+    {                                                           \
+        QTestState *qtest = global_qtest;                       \
+        global_qtest = s->qtest;                                \
+        g_test_message("%x -> *%s\n", v, #name);                \
+        qpci_io_write##len(s->dev, s->reg_base+(val), v);       \
+        global_qtest = qtest;                                   \
+    }
+
+REG(IntrMask, l, 0)
+REG(IntrStatus, l, 4)
+REG(IVPosition, l, 8)
+REG(DoorBell, l, 12)
+
+#if 0
+static void info_qtree(void)
+{
+    QDict *response;
+
+    response = qmp("{'execute': 'human-monitor-command',"
+                   " 'arguments': {"
+                   "   'command-line': 'info qtree'"
+                   "}}");
+    g_assert(response);
+    g_debug(qdict_get_try_str(response, "return"));
+    QDECREF(response);
+}
+#endif
+
+static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
+{
+    uint64_t barsize;
+
+    s->qtest = qtest_start(cmd);
+
+    s->dev = get_device();
+
+    /* FIXME: other bar order fails, mappings changes */
+    s->mem_base = qpci_iomap(s->dev, 2, &barsize);
+    g_assert_nonnull(s->mem_base);
+    g_assert_cmpuint(barsize, ==, TMPSHMSIZE);
+
+    if (msix) {
+        qpci_msix_enable(s->dev);
+    }
+
+    s->reg_base = qpci_iomap(s->dev, 0, &barsize);
+    g_assert_nonnull(s->reg_base);
+    g_assert_cmpuint(barsize, ==, 256);
+
+    qpci_device_enable(s->dev);
+}
+
+static void setup_vm(IVState *s)
+{
+    char *cmd = g_strdup_printf("-device ivshmem,shm=%s,size=1M", tmpshm);
+
+    setup_vm_cmd(s, cmd, false);
+
+    g_free(cmd);
+}
+
+static void test_ivshmem_single(void)
+{
+    IVState state, *s;
+    uint32_t data[1024];
+    int i;
+
+    setup_vm(&state);
+    s = &state;
+
+    /* valid io */
+    out_IntrMask(s, 0);
+    in_IntrStatus(s);
+    in_IVPosition(s);
+
+    out_IntrMask(s, 0xffffffff);
+    g_assert_cmpuint(in_IntrMask(s), ==, 0xffffffff);
+    out_IntrStatus(s, 1);
+    /* XXX: intercept IRQ, not seen in resp */
+    g_assert_cmpuint(in_IntrStatus(s), ==, 1);
+
+    /* invalid io */
+    out_IVPosition(s, 1);
+    out_DoorBell(s, 8 << 16);
+
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        data[i] = i;
+    }
+    qtest_memwrite(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data));
+
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        g_assert_cmpuint(((uint32_t *)tmpshmem)[i], ==, i);
+    }
+
+    memset(data, 0, sizeof(data));
+
+    qtest_memread(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data));
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        g_assert_cmpuint(data[i], ==, i);
+    }
+
+    qtest_quit(s->qtest);
+}
+
+static void test_ivshmem_pair(void)
+{
+    IVState state1, state2, *s1, *s2;
+    char *data;
+    int i;
+
+    setup_vm(&state1);
+    s1 = &state1;
+    setup_vm(&state2);
+    s2 = &state2;
+
+    data = g_malloc0(TMPSHMSIZE);
+
+    /* host write, guest 1 & 2 read */
+    memset(tmpshmem, 0x42, TMPSHMSIZE);
+    qtest_memread(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x42);
+    }
+    qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x42);
+    }
+
+    /* guest 1 write, guest 2 read */
+    memset(data, 0x43, TMPSHMSIZE);
+    qtest_memwrite(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE);
+    memset(data, 0, TMPSHMSIZE);
+    qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x43);
+    }
+
+    /* guest 2 write, guest 1 read */
+    memset(data, 0x44, TMPSHMSIZE);
+    qtest_memwrite(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
+    memset(data, 0, TMPSHMSIZE);
+    qtest_memread(s1->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
+    for (i = 0; i < TMPSHMSIZE; i++) {
+        g_assert_cmpuint(data[i], ==, 0x44);
+    }
+
+    qtest_quit(s1->qtest);
+    qtest_quit(s2->qtest);
+    g_free(data);
+}
+
+typedef struct ServerThread {
+    GThread *thread;
+    IvshmemServer *server;
+    int pipe[2]; /* to handle quit */
+} ServerThread;
+
+static void *server_thread(void *data)
+{
+    ServerThread *t = data;
+    IvshmemServer *server = t->server;
+
+    while (true) {
+        fd_set fds;
+        int maxfd, ret;
+
+        FD_ZERO(&fds);
+        FD_SET(t->pipe[0], &fds);
+        maxfd = t->pipe[0] + 1;
+
+        ivshmem_server_get_fds(server, &fds, &maxfd);
+
+        ret = select(maxfd, &fds, NULL, NULL, NULL);
+
+        if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+
+            g_critical("select error: %s\n", strerror(errno));
+            break;
+        }
+        if (ret == 0) {
+            continue;
+        }
+
+        if (FD_ISSET(t->pipe[0], &fds)) {
+            break;
+        }
+
+        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
+            g_critical("ivshmem_server_handle_fds() failed\n");
+            break;
+        }
+    }
+
+    return NULL;
+}
+
+static void setup_vm_with_server(IVState *s, int nvectors)
+{
+    char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
+                                "-device ivshmem,size=1M,chardev=chr0,vectors=%d",
+                                tmpserver, nvectors);
+
+    setup_vm_cmd(s, cmd, true);
+
+    g_free(cmd);
+}
+
+static GThread *thread_new(const gchar *name, GThreadFunc func, gpointer data)
+{
+    GThread *thread = NULL;
+    GError *error = NULL;
+#ifdef HAVE_THREAD_NEW
+    thread = g_thread_try_new(name, func, data, &error);
+#else
+    thread = g_thread_create(func, data, TRUE, &error);
+#endif
+    g_assert_no_error(error);
+    return thread;
+}
+
+static void test_ivshmem_server(void)
+{
+    IVState state1, state2, *s1, *s2;
+    ServerThread thread;
+    IvshmemServer server;
+    int ret, vm1, vm2;
+    int nvectors = 2;
+
+    memset(tmpshmem, 0x42, TMPSHMSIZE);
+    ret = ivshmem_server_init(&server, tmpserver, tmpshm,
+                              TMPSHMSIZE, nvectors,
+                              getenv("QTEST_LOG") != NULL);
+    g_assert_cmpint(ret, ==, 0);
+
+    ret = ivshmem_server_start(&server);
+    g_assert_cmpint(ret, ==, 0);
+
+    setup_vm_with_server(&state1, nvectors);
+    s1 = &state1;
+    setup_vm_with_server(&state2, nvectors);
+    s2 = &state2;
+
+    g_assert_cmpuint(in_IVPosition(s1), ==, 0xffffffff);
+    g_assert_cmpuint(in_IVPosition(s2), ==, 0xffffffff);
+
+    g_assert_cmpuint(qtest_readb(s1->qtest, (uintptr_t)s1->mem_base), ==, 0x00);
+
+    thread.server = &server;
+    ret = pipe(thread.pipe);
+    g_assert_cmpint(ret, ==, 0);
+    thread.thread = thread_new("ivshmem-server", server_thread, &thread);
+
+    /* waiting until mapping is done */
+    while (true) {
+        g_usleep(1000);
+
+        if (qtest_readb(s1->qtest, (uintptr_t)s1->mem_base) == 0x42 &&
+            qtest_readb(s2->qtest, (uintptr_t)s2->mem_base) == 0x42) {
+            break;
+        }
+    }
+
+    /* check got different VM ids */
+    vm1 = in_IVPosition(s1);
+    vm2 = in_IVPosition(s2);
+    g_assert_cmpuint(vm1, !=, vm2);
+
+    global_qtest = s1->qtest;
+    ret = qpci_msix_table_size(s1->dev);
+    g_assert_cmpuint(ret, ==, nvectors);
+
+    /* ping vm2 -> vm1 */
+    ret = qpci_msix_pending(s1->dev, 0);
+    g_assert_cmpuint(ret, ==, 0);
+    out_DoorBell(s2, vm1 << 16);
+    g_usleep(10000);
+    ret = qpci_msix_pending(s1->dev, 0);
+    g_assert_cmpuint(ret, !=, 0);
+
+    /* ping vm1 -> vm2 */
+    global_qtest = s2->qtest;
+    ret = qpci_msix_pending(s2->dev, 0);
+    g_assert_cmpuint(ret, ==, 0);
+    out_DoorBell(s1, vm2 << 16);
+    g_usleep(10000);
+    ret = qpci_msix_pending(s2->dev, 0);
+    g_assert_cmpuint(ret, !=, 0);
+
+    /* remove vm2 */
+    qtest_quit(s2->qtest);
+    /* XXX wait enough time for vm1 to be notified */
+    g_usleep(1000);
+
+    qtest_quit(s1->qtest);
+
+    write(thread.pipe[1], "q", 1);
+    g_thread_join(thread.thread);
+
+    ivshmem_server_close(&server);
+    close(thread.pipe[1]);
+    close(thread.pipe[0]);
+}
+
+#define PCI_SLOT_HP             0x06
+
+static void test_ivshmem_hotplug(void)
+{
+    gchar *opts;
+
+    qtest_start("");
+
+    opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm);
+
+    qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts);
+    qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
+
+    qtest_end();
+    g_free(opts);
+}
+
+static void cleanup(void)
+{
+    if (tmpshmem) {
+        munmap(tmpshmem, TMPSHMSIZE);
+        tmpshmem = NULL;
+    }
+
+    if (tmpshm) {
+        shm_unlink(tmpshm);
+        g_free(tmpshm);
+        tmpshm = NULL;
+    }
+
+    if (tmpserver) {
+        g_unlink(tmpserver);
+        g_free(tmpserver);
+        tmpserver = NULL;
+    }
+
+    if (tmpdir) {
+        g_rmdir(tmpdir);
+        tmpdir = NULL;
+    }
+}
+
+static void abrt_handler(void *data)
+{
+    cleanup();
+}
+
+static gchar *mktempshm(int size, int *fd)
+{
+    while (true) {
+        gchar *name;
+
+        name = g_strdup_printf("/qtest-%u-%u", getpid(), g_random_int());
+        *fd = shm_open(name, O_CREAT|O_RDWR|O_EXCL,
+                       S_IRWXU|S_IRWXG|S_IRWXO);
+        if (*fd > 0) {
+            g_assert(ftruncate(*fd, size) == 0);
+            return name;
+        }
+
+        g_free(name);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int ret, fd;
+    static gchar dir[] = "/tmp/ivshmem-test.XXXXXX";
+
+#if !GLIB_CHECK_VERSION(2, 31, 0)
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+#endif
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_abrt_handler(abrt_handler, NULL);
+    /* shm */
+    tmpshm = mktempshm(TMPSHMSIZE, &fd);
+    tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    g_assert(tmpshmem != MAP_FAILED);
+    /* server */
+    if (g_mkdtemp_full(dir, 0700) == NULL) {
+        g_error("g_mkdtemp_full: %s", g_strerror(errno));
+    }
+    tmpdir = dir;
+    tmpserver = g_strconcat(tmpdir, "/server", NULL);
+
+    qtest_add_func("/ivshmem/single", test_ivshmem_single);
+    qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
+    qtest_add_func("/ivshmem/server", test_ivshmem_server);
+    qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
+
+    ret = g_test_run();
+
+    cleanup();
+    return ret;
+}
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (39 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-22 14:36   ` Claudio Fontana
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic marcandre.lureau
                   ` (6 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Remove shm_fd from device state, closing it as early as possible to avoid leaks.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 4adcac5..f9ac955 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -88,7 +88,6 @@ typedef struct IVShmemState {
     MemoryRegion ivshmem;
     uint64_t ivshmem_size; /* size of shared memory region */
     uint32_t ivshmem_64bit;
-    int shm_fd; /* shared memory file descriptor */
 
     Peer *peers;
     int nb_peers; /* how many peers we have space for */
@@ -235,7 +234,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
 
         case IVPOSITION:
             /* return my VM ID if the memory is mapped */
-            if (s->shm_fd >= 0) {
+            if (memory_region_is_mapped(&s->ivshmem)) {
                 ret = s->vm_id;
             } else {
                 ret = -1;
@@ -356,8 +355,6 @@ static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
         return -1;
     }
 
-    s->shm_fd = fd;
-
     memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
                                s->ivshmem_size, ptr);
     vmstate_register_ram(&s->ivshmem, DEVICE(s));
@@ -535,7 +532,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     if (incoming_posn == -1) {
         void * map_ptr;
 
-        if (s->shm_fd >= 0) {
+        if (memory_region_is_mapped(&s->ivshmem)) {
             error_report("shm already initialized");
             close(incoming_fd);
             return;
@@ -564,9 +561,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 
         memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
-        /* only store the fd if it is successfully mapped */
-        s->shm_fd = incoming_fd;
-
+        close(incoming_fd);
         return;
     }
 
@@ -827,6 +822,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         }
 
         create_shared_memory_BAR(s, fd, attr, errp);
+        close(fd);
     }
 }
 
@@ -842,7 +838,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
         error_free(s->migration_blocker);
     }
 
-    if (s->shm_fd >= 0) {
+    if (memory_region_is_mapped(&s->ivshmem)) {
         void *addr = memory_region_get_ram_ptr(&s->ivshmem);
 
         vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (40 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open marcandre.lureau
@ 2015-09-15 16:07 ` marcandre.lureau
  2015-09-16 15:23   ` Vladimir Sementsov-Ogievskiy
  2015-09-16 15:24   ` Vladimir Sementsov-Ogievskiy
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend marcandre.lureau
                   ` (5 subsequent siblings)
  47 siblings, 2 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Use a more explicit function name parse_mem_size(). I guess such
function could be common (or exists already somewhere).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index f9ac955..5fb2123 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -643,12 +643,12 @@ static void ivshmem_reset(DeviceState *d)
     ivshmem_use_msix(s);
 }
 
-static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
-
+static uint64_t parse_mem_size(const char *sizearg, Error **errp)
+{
     uint64_t value;
     char *ptr;
 
-    value = strtoull(s->sizearg, &ptr, 10);
+    value = strtoull(sizearg, &ptr, 10);
     switch (*ptr) {
         case 0: case 'M': case 'm':
             value <<= 20;
@@ -657,7 +657,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
             value <<= 30;
             break;
         default:
-            error_setg(errp, "invalid ram size: %s", s->sizearg);
+            error_setg(errp, "invalid ram size: %s", sizearg);
             return 0;
     }
 
@@ -704,7 +704,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
     if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
     } else {
-        s->ivshmem_size = ivshmem_get_size(s, &local_err);
+        s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
             return;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (41 preceding siblings ...)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic marcandre.lureau
@ 2015-09-15 16:08 ` marcandre.lureau
  2015-09-22 14:49   ` Claudio Fontana
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector marcandre.lureau
                   ` (4 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Instead of handling allocation, teach ivshmem to use a memory backend.
This allows to use hugetlbfs backed memory now.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c    | 84 ++++++++++++++++++++++++++++++++++++++++------------
 tests/ivshmem-test.c | 12 ++++++++
 2 files changed, 77 insertions(+), 19 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 5fb2123..ac90f0a 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -26,6 +26,8 @@
 #include "qemu/event_notifier.h"
 #include "qemu/fifo8.h"
 #include "sysemu/char.h"
+#include "sysemu/hostmem.h"
+#include "qapi/visitor.h"
 
 #include "hw/misc/ivshmem.h"
 
@@ -57,6 +59,8 @@
 #define IVSHMEM(obj) \
     OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
 
+#define IVSHMEM_MEMDEV_PROP "memdev"
+
 typedef struct Peer {
     int nb_eventfds;
     EventNotifier *eventfds;
@@ -72,6 +76,7 @@ typedef struct IVShmemState {
     PCIDevice parent_obj;
     /*< public >*/
 
+    HostMemoryBackend *hostmem;
     uint32_t intrmask;
     uint32_t intrstatus;
 
@@ -699,9 +704,22 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         PCI_BASE_ADDRESS_MEM_PREFETCH;;
     Error *local_err = NULL;
 
-    s->shm_fd = -1;
+    if (!!s->server_chr + !!s->shmobj + !!s->hostmem != 1) {
+        error_setg(errp, "You must specify either a shmobj, a chardev"
+                   " or a hostmem");
+        return;
+    }
+
+    if (s->hostmem) {
+        MemoryRegion *mr;
 
-    if (s->sizearg == NULL) {
+        if (s->sizearg) {
+            g_warning("size argument ignored with hostmem");
+        }
+
+        mr = host_memory_backend_get_memory(s->hostmem, errp);
+        s->ivshmem_size = memory_region_size(mr);
+    } else if (s->sizearg == NULL) {
         s->ivshmem_size = 4 << 20; /* 4 MB default */
     } else {
         s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
@@ -757,7 +775,16 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
     }
 
-    if (s->server_chr != NULL) {
+    if (s->hostmem != NULL) {
+        MemoryRegion *mr;
+
+        IVSHMEM_DPRINTF("using hostmem\n");
+
+        mr = host_memory_backend_get_memory(MEMORY_BACKEND(s->hostmem), errp);
+        vmstate_register_ram(mr, DEVICE(s));
+        memory_region_add_subregion(&s->bar, 0, mr);
+        pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
+    } else if (s->server_chr != NULL) {
         if (strncmp(s->server_chr->filename, "unix:", 5)) {
             error_setg(errp, "chardev is not a unix client socket");
             return;
@@ -766,12 +793,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         /* if we get a UNIX socket as the parameter we will talk
          * to the ivshmem server to receive the memory region */
 
-        if (s->shmobj != NULL) {
-            error_setg(errp, "do not specify both 'chardev' "
-                       "and 'shm' with ivshmem");
-            return;
-        }
-
         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
                         s->server_chr->filename);
 
@@ -795,11 +816,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
         /* just map the file immediately, we're not using a server */
         int fd;
 
-        if (s->shmobj == NULL) {
-            error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
-            return;
-        }
-
         IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
 
         /* try opening with O_EXCL and if it succeeds zero the memory
@@ -839,14 +855,17 @@ static void pci_ivshmem_exit(PCIDevice *dev)
     }
 
     if (memory_region_is_mapped(&s->ivshmem)) {
-        void *addr = memory_region_get_ram_ptr(&s->ivshmem);
+        if (!s->hostmem) {
+            void *addr = memory_region_get_ram_ptr(&s->ivshmem);
+
+            if (munmap(addr, s->ivshmem_size) == -1) {
+                error_report("Failed to munmap shared memory %s",
+                             strerror(errno));
+            }
+        }
 
         vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
         memory_region_del_subregion(&s->bar, &s->ivshmem);
-
-        if (munmap(addr, s->ivshmem_size) == -1) {
-            error_report("Failed to munmap shared memory %s", strerror(errno));
-        }
     }
 
     if (s->eventfd_chr) {
@@ -988,10 +1007,37 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
     dc->desc = "Inter-VM shared memory";
 }
 
+static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
+                                         Object *val, Error **errp)
+{
+    MemoryRegion *mr;
+
+    mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), errp);
+    if (memory_region_is_mapped(mr)) {
+        char *path = object_get_canonical_path_component(val);
+        error_setg(errp, "can't use already busy memdev: %s", path);
+        g_free(path);
+    } else {
+        qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
+    }
+}
+
+static void ivshmem_init(Object *obj)
+{
+    IVShmemState *s = IVSHMEM(obj);
+
+    object_property_add_link(obj, IVSHMEM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
+                             (Object **)&s->hostmem,
+                             ivshmem_check_memdev_is_busy,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
+}
+
 static const TypeInfo ivshmem_info = {
     .name          = TYPE_IVSHMEM,
     .parent        = TYPE_PCI_DEVICE,
     .instance_size = sizeof(IVShmemState),
+    .instance_init = ivshmem_init,
     .class_init    = ivshmem_class_init,
 };
 
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 03f44c1..920b9fa 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -390,6 +390,17 @@ static void test_ivshmem_hotplug(void)
     g_free(opts);
 }
 
+static void test_ivshmem_memdev(void)
+{
+    IVState state;
+
+    /* just for the sake of checking memory-backend property */
+    setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
+                 " -device ivshmem,memdev=mb1", false);
+
+    qtest_quit(state.qtest);
+}
+
 static void cleanup(void)
 {
     if (tmpshmem) {
@@ -466,6 +477,7 @@ int main(int argc, char **argv)
     qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
     qtest_add_func("/ivshmem/server", test_ivshmem_server);
     qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
+    qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev);
 
     ret = g_test_run();
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (42 preceding siblings ...)
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend marcandre.lureau
@ 2015-09-15 16:08 ` marcandre.lureau
  2015-09-22 14:59   ` Claudio Fontana
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 45/46] ivshmem: rename MSI eventfd_table marcandre.lureau
                   ` (3 subsequent siblings)
  47 siblings, 1 reply; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

No need to store an extra int for the vector number when it can be
computed easily by looking at the position in the array.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index ac90f0a..976fbea 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -68,7 +68,6 @@ typedef struct Peer {
 
 typedef struct EventfdEntry {
     PCIDevice *pdev;
-    int vector;
 } EventfdEntry;
 
 typedef struct IVShmemState {
@@ -287,9 +286,11 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
 
     EventfdEntry *entry = opaque;
     PCIDevice *pdev = entry->pdev;
+    IVShmemState *s = IVSHMEM(pdev);
+    int vector = entry - s->eventfd_table;
 
-    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
-    msix_notify(pdev, entry->vector);
+    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
+    msix_notify(pdev, vector);
 }
 
 static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
@@ -311,7 +312,6 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
     /* if MSI is supported we need multiple interrupts */
     if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
         s->eventfd_table[vector].pdev = PCI_DEVICE(s);
-        s->eventfd_table[vector].vector = vector;
 
         qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
                       ivshmem_event, &s->eventfd_table[vector]);
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 45/46] ivshmem: rename MSI eventfd_table
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (43 preceding siblings ...)
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector marcandre.lureau
@ 2015-09-15 16:08 ` marcandre.lureau
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 46/46] ivshmem: use kvm irqfd for msi notifications marcandre.lureau
                   ` (2 subsequent siblings)
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The array is used to have vector specific data, so use a more
descriptive name.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 976fbea..f4a2ea2 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -66,9 +66,9 @@ typedef struct Peer {
     EventNotifier *eventfds;
 } Peer;
 
-typedef struct EventfdEntry {
+typedef struct MSIVector {
     PCIDevice *pdev;
-} EventfdEntry;
+} MSIVector;
 
 typedef struct IVShmemState {
     /*< private >*/
@@ -99,7 +99,7 @@ typedef struct IVShmemState {
     int vm_id;
     uint32_t vectors;
     uint32_t features;
-    EventfdEntry *eventfd_table;
+    MSIVector *msi_vectors;
 
     Error *migration_blocker;
 
@@ -284,10 +284,10 @@ static void ivshmem_event(void *opaque, int event)
 
 static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
 
-    EventfdEntry *entry = opaque;
+    MSIVector *entry = opaque;
     PCIDevice *pdev = entry->pdev;
     IVShmemState *s = IVSHMEM(pdev);
-    int vector = entry - s->eventfd_table;
+    int vector = entry - s->msi_vectors;
 
     IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
     msix_notify(pdev, vector);
@@ -311,10 +311,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
 
     /* if MSI is supported we need multiple interrupts */
     if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
-        s->eventfd_table[vector].pdev = PCI_DEVICE(s);
+        s->msi_vectors[vector].pdev = PCI_DEVICE(s);
 
         qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
-                      ivshmem_event, &s->eventfd_table[vector]);
+                      ivshmem_event, &s->msi_vectors[vector]);
     } else {
         qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
                       ivshmem_event, s);
@@ -684,7 +684,7 @@ static int ivshmem_setup_msi(IVShmemState * s)
     IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
 
     /* allocate QEMU char devices for receiving interrupts */
-    s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
+    s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
 
     ivshmem_use_msix(s);
     return 0;
@@ -888,7 +888,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
         msix_uninit_exclusive_bar(dev);
     }
 
-    g_free(s->eventfd_table);
+    g_free(s->msi_vectors);
 }
 
 static bool test_msix(void *opaque, int version_id)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* [Qemu-devel] [PATCH v3 46/46] ivshmem: use kvm irqfd for msi notifications
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (44 preceding siblings ...)
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 45/46] ivshmem: rename MSI eventfd_table marcandre.lureau
@ 2015-09-15 16:08 ` marcandre.lureau
  2015-09-16 12:47 ` [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) Claudio Fontana
  2015-09-16 16:52 ` Vladimir Sementsov-Ogievskiy
  47 siblings, 0 replies; 109+ messages in thread
From: marcandre.lureau @ 2015-09-15 16:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, drjones, cam, stefanha

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Use irqfd for improving context switch when notifying the guest.
If the host doesn't support kvm irqfd, regular msi notifications are
still supported.

Note: the ivshmem implementation doesn't allow switching between MSI and
IO interrupts, this patch doesn't either.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 169 insertions(+), 6 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index f4a2ea2..fa4193e 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -19,6 +19,7 @@
 #include "hw/hw.h"
 #include "hw/i386/pc.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "sysemu/kvm.h"
 #include "migration/migration.h"
@@ -68,6 +69,7 @@ typedef struct Peer {
 
 typedef struct MSIVector {
     PCIDevice *pdev;
+    int virq;
 } MSIVector;
 
 typedef struct IVShmemState {
@@ -293,13 +295,73 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
     msix_notify(pdev, vector);
 }
 
+static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
+                                 MSIMessage msg)
+{
+    IVShmemState *s = IVSHMEM(dev);
+    EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
+    MSIVector *v = &s->msi_vectors[vector];
+    int ret;
+
+    IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector);
+
+    ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq);
+}
+
+static void ivshmem_vector_mask(PCIDevice *dev, unsigned vector)
+{
+    IVShmemState *s = IVSHMEM(dev);
+    EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
+    int ret;
+
+    IVSHMEM_DPRINTF("vector mask %p %d\n", dev, vector);
+
+    ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n,
+                                                s->msi_vectors[vector].virq);
+    if (ret != 0) {
+        error_report("remove_irqfd_notifier_gsi failed");
+    }
+}
+
+static void ivshmem_vector_poll(PCIDevice *dev,
+                                unsigned int vector_start,
+                                unsigned int vector_end)
+{
+    IVShmemState *s = IVSHMEM(dev);
+    unsigned int vector;
+
+    IVSHMEM_DPRINTF("vector poll %p %d-%d\n", dev, vector_start, vector_end);
+
+    vector_end = MIN(vector_end, s->vectors);
+
+    for (vector = vector_start; vector < vector_end; vector++) {
+        EventNotifier *notifier = &s->peers[s->vm_id].eventfds[vector];
+
+        if (!msix_is_masked(dev, vector)) {
+            continue;
+        }
+
+        if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }
+    }
+}
+
 static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
                                                   int vector)
 {
     /* create a event character device based on the passed eventfd */
     IVShmemState *s = opaque;
-    CharDriverState * chr;
+    PCIDevice *pdev = PCI_DEVICE(s);
     int eventfd = event_notifier_get_fd(n);
+    CharDriverState *chr;
+
+    s->msi_vectors[vector].pdev = pdev;
 
     chr = qemu_chr_open_eventfd(eventfd);
 
@@ -484,6 +546,53 @@ static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
     return true;
 }
 
+static int ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector)
+{
+    PCIDevice *pdev = PCI_DEVICE(s);
+    MSIMessage msg = msix_get_message(pdev, vector);
+    int ret;
+
+    IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector);
+
+    if (s->msi_vectors[vector].pdev != NULL) {
+        return 0;
+    }
+
+    ret = kvm_irqchip_add_msi_route(kvm_state, msg); /*  */
+    if (ret < 0) {
+        error_report("ivshmem: kvm_irqchip_add_msi_route failed");
+        return -1;
+    }
+
+    s->msi_vectors[vector].virq = ret;
+    s->msi_vectors[vector].pdev = pdev;
+
+    return 0;
+}
+
+static void setup_interrupt(IVShmemState *s, int vector)
+{
+    EventNotifier *n = &s->peers[s->vm_id].eventfds[vector];
+    bool with_irqfd = kvm_msi_via_irqfd_enabled() &&
+        ivshmem_has_feature(s, IVSHMEM_MSI);
+    PCIDevice *pdev = PCI_DEVICE(s);
+
+    IVSHMEM_DPRINTF("setting up interrupt for vector: %d\n", vector);
+
+    if (!with_irqfd) {
+        s->eventfd_chr[vector] = create_eventfd_chr_device(s, n, vector);
+    } else if (msix_enabled(pdev)) {
+        if (ivshmem_add_kvm_msi_virq(s, vector) < 0) {
+            return;
+        }
+
+        if (!msix_is_masked(pdev, vector)) {
+            kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL,
+                                               s->msi_vectors[vector].virq);
+        }
+    }
+}
+
 static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 {
     IVShmemState *s = opaque;
@@ -584,11 +693,10 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
                     nth_eventfd, incoming_fd);
     event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
+    fcntl_setfl(incoming_fd, O_NONBLOCK); /* msix/irqfd poll non block */
 
     if (incoming_posn == s->vm_id) {
-        s->eventfd_chr[nth_eventfd] = create_eventfd_chr_device(s,
-                   &s->peers[s->vm_id].eventfds[nth_eventfd],
-                   nth_eventfd);
+        setup_interrupt(s, nth_eventfd);
     }
 
     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
@@ -690,10 +798,65 @@ static int ivshmem_setup_msi(IVShmemState * s)
     return 0;
 }
 
-static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
+static void ivshmem_enable_irqfd(IVShmemState *s)
+{
+    PCIDevice *pdev = PCI_DEVICE(s);
+    int i;
+
+    for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
+        ivshmem_add_kvm_msi_virq(s, i);
+    }
+
+    if (msix_set_vector_notifiers(pdev,
+                                  ivshmem_vector_unmask,
+                                  ivshmem_vector_mask,
+                                  ivshmem_vector_poll)) {
+        error_report("ivshmem: msix_set_vector_notifiers failed");
+    }
+}
+
+static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
+{
+    IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
+
+    if (s->msi_vectors[vector].pdev == NULL) {
+        return;
+    }
+
+    /* it was cleaned when masked in the frontend. */
+    kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
+
+    s->msi_vectors[vector].pdev = NULL;
+}
+
+static void ivshmem_disable_irqfd(IVShmemState *s)
+{
+    PCIDevice *pdev = PCI_DEVICE(s);
+    int i;
+
+    for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
+        ivshmem_remove_kvm_msi_virq(s, i);
+    }
+
+    msix_unset_vector_notifiers(pdev);
+}
+
+static void ivshmem_write_config(PCIDevice *pdev, uint32_t address,
                                  uint32_t val, int len)
 {
-    pci_default_write_config(pci_dev, address, val, len);
+    IVShmemState *s = IVSHMEM(pdev);
+    int is_enabled, was_enabled = msix_enabled(pdev);
+
+    pci_default_write_config(pdev, address, val, len);
+    is_enabled = msix_enabled(pdev);
+
+    if (kvm_msi_via_irqfd_enabled() && s->vm_id != -1) {
+        if (!was_enabled && is_enabled) {
+            ivshmem_enable_irqfd(s);
+        } else if (was_enabled && !is_enabled) {
+            ivshmem_disable_irqfd(s);
+        }
+    }
 }
 
 static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field marcandre.lureau
@ 2015-09-16  9:25   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16  9:25 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

only a small nitpick below on extra ";" character.


On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index fbeb731..5e4b2cc 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -85,7 +85,6 @@ typedef struct IVShmemState {
>      MemoryRegion bar;
>      MemoryRegion ivshmem;
>      uint64_t ivshmem_size; /* size of shared memory region */
> -    uint32_t ivshmem_attr;
>      uint32_t ivshmem_64bit;
>      int shm_fd; /* shared memory file descriptor */
>  
> @@ -345,7 +344,7 @@ static int check_shm_size(IVShmemState *s, int fd) {
>  
>  /* create the shared memory BAR when we are not using the server, so we can
>   * create the BAR and map the memory immediately */
> -static void create_shared_memory_BAR(IVShmemState *s, int fd) {
> +static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
>  
>      void * ptr;
>  
> @@ -359,7 +358,7 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
>      memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
>  
>      /* region for shared memory */
> -    pci_register_bar(PCI_DEVICE(s), 2, s->ivshmem_attr, &s->bar);
> +    pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
>  }
>  
>  static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
> @@ -714,6 +713,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>  {
>      IVShmemState *s = IVSHMEM(dev);
>      uint8_t *pci_conf;
> +    uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
> +        PCI_BASE_ADDRESS_MEM_PREFETCH;;

nit: unwanted extra ;

>  
>      if (s->sizearg == NULL)
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
> @@ -768,10 +769,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>                       &s->ivshmem_mmio);
>  
>      memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size);
> -    s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
> -        PCI_BASE_ADDRESS_MEM_PREFETCH;
>      if (s->ivshmem_64bit) {
> -        s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
> +        attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
>      }
>  
>      if ((s->server_chr != NULL) &&
> @@ -798,7 +797,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
>          /* allocate/initialize space for interrupt handling */
>          s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
>  
> -        pci_register_bar(dev, 2, s->ivshmem_attr, &s->bar);
> +        pci_register_bar(dev, 2, attr, &s->bar);
>  
>          s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
>  
> @@ -835,8 +834,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
>              exit(1);
>          }
>  
> -        create_shared_memory_BAR(s, fd);
> -
> +        create_shared_memory_BAR(s, fd, attr);
>      }
>  
>      dev->config_write = ivshmem_write_config;
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long) marcandre.lureau
@ 2015-09-16  9:27   ` Claudio Fontana
  2015-09-16  9:33     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16  9:27 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> ivshmem_read() only reads sizeof(long) from the input buffer.  Accepting
> more could lead to fifo8 abort() on 32bit systems if fifo is not empty.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index cc76989..fb53b3f 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -272,7 +272,7 @@ static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
>  
>  static int ivshmem_can_receive(void * opaque)
>  {
> -    return 8;
> +    return sizeof(long);
>  }
>  

Is the right fix this one, or should ivshmem_read() not rely on sizeof(long)?

>  static void ivshmem_event(void *opaque, int event)
> 

Ciao,

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo marcandre.lureau
@ 2015-09-16  9:28   ` Claudio Fontana
  2015-09-23 10:17     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16  9:28 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> If the fifo has 0 bytes, and the read is of size 1, the call to
> fifo8_push_all() will copy off boundary data.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index fb53b3f..2162d02 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -455,7 +455,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>          uint32_t num;
>  
>          IVSHMEM_DPRINTF("short read of %d bytes\n", size);
> -        num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
> +        num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
>          fifo8_push_all(&s->incoming_fifo, buf, num);
>          if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
>              return;
> 

(should we rely on sizeof(long) here?)

Ciao,

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-16  9:27   ` Claudio Fontana
@ 2015-09-16  9:33     ` Marc-André Lureau
  2015-09-16 11:27       ` Claudio Fontana
  0 siblings, 1 reply; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16  9:33 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

Hi

----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > ivshmem_read() only reads sizeof(long) from the input buffer.  Accepting
> > more could lead to fifo8 abort() on 32bit systems if fifo is not empty.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index cc76989..fb53b3f 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -272,7 +272,7 @@ static void ivshmem_receive(void *opaque, const uint8_t
> > *buf, int size)
> >  
> >  static int ivshmem_can_receive(void * opaque)
> >  {
> > -    return 8;
> > +    return sizeof(long);
> >  }
> >  
> 
> Is the right fix this one, or should ivshmem_read() not rely on sizeof(long)?


See my answer to Paolo:
http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg05341.html

> 
> >  static void ivshmem_event(void *opaque, int event)
> > 
> 
> Ciao,
> 
> Claudio
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field marcandre.lureau
@ 2015-09-16  9:39   ` Claudio Fontana
  2015-09-16  9:40     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16  9:39 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> max_peer isn't really useful, it tracks the maximum received VM id, but
> that quickly matches nb_peers, the size of the peers array. Since VM
> come and go, there might be sparse peers so it doesn't help much in
> general to have this value around.

Does this max_peer provide any value if VMs _don't_ come and go?
Not that I see any.

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 10 +---------
>  1 file changed, 1 insertion(+), 9 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 07f2182..cda7dce 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -90,7 +90,6 @@ typedef struct IVShmemState {
>  
>      Peer *peers;
>      int nb_peers; /* how many guests we have space for */
> -    int max_peer; /* maximum numbered peer */
>  
>      int vm_id;
>      uint32_t vectors;
> @@ -200,7 +199,7 @@ static void ivshmem_io_write(void *opaque, hwaddr addr,
>  
>          case DOORBELL:
>              /* check that dest VM ID is reasonable */
> -            if (dest > s->max_peer) {
> +            if (dest >= s->nb_peers) {
>                  IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
>                  break;
>              }
> @@ -574,11 +573,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      /* increment count for particular guest */
>      s->peers[incoming_posn].nb_eventfds++;
>  
> -    /* keep track of the maximum VM ID */
> -    if (incoming_posn > s->max_peer) {
> -        s->max_peer = incoming_posn;
> -    }
> -
>      if (incoming_posn == s->vm_id) {
>          s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
>                     &s->peers[s->vm_id].eventfds[guest_max_eventfd],
> @@ -721,8 +715,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
>      Error *local_err = NULL;
>  
> -    s->max_peer = -1;
> -
>      if (s->sizearg == NULL) {
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
>      } else {
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field
  2015-09-16  9:39   ` Claudio Fontana
@ 2015-09-16  9:40     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16  9:40 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

Hi

----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > max_peer isn't really useful, it tracks the maximum received VM id, but
> > that quickly matches nb_peers, the size of the peers array. Since VM
> > come and go, there might be sparse peers so it doesn't help much in
> > general to have this value around.
> 
> Does this max_peer provide any value if VMs _don't_ come and go?
> Not that I see any.

I don't see any either.

> 
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 10 +---------
> >  1 file changed, 1 insertion(+), 9 deletions(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index 07f2182..cda7dce 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -90,7 +90,6 @@ typedef struct IVShmemState {
> >  
> >      Peer *peers;
> >      int nb_peers; /* how many guests we have space for */
> > -    int max_peer; /* maximum numbered peer */
> >  
> >      int vm_id;
> >      uint32_t vectors;
> > @@ -200,7 +199,7 @@ static void ivshmem_io_write(void *opaque, hwaddr addr,
> >  
> >          case DOORBELL:
> >              /* check that dest VM ID is reasonable */
> > -            if (dest > s->max_peer) {
> > +            if (dest >= s->nb_peers) {
> >                  IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
> >                  break;
> >              }
> > @@ -574,11 +573,6 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >      /* increment count for particular guest */
> >      s->peers[incoming_posn].nb_eventfds++;
> >  
> > -    /* keep track of the maximum VM ID */
> > -    if (incoming_posn > s->max_peer) {
> > -        s->max_peer = incoming_posn;
> > -    }
> > -
> >      if (incoming_posn == s->vm_id) {
> >          s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
> >                     &s->peers[s->vm_id].eventfds[guest_max_eventfd],
> > @@ -721,8 +715,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error
> > **errp)
> >          PCI_BASE_ADDRESS_MEM_PREFETCH;;
> >      Error *local_err = NULL;
> >  
> > -    s->max_peer = -1;
> > -
> >      if (s->sizearg == NULL) {
> >          s->ivshmem_size = 4 << 20; /* 4 MB default */
> >      } else {
> > 
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-16  9:33     ` Marc-André Lureau
@ 2015-09-16 11:27       ` Claudio Fontana
  2015-09-16 12:03         ` Marc-André Lureau
  2015-09-16 12:51         ` Paolo Bonzini
  0 siblings, 2 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:27 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

On 16.09.2015 11:33, Marc-André Lureau wrote:
> Hi
> 
> ----- Original Message -----
>> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>
>>> ivshmem_read() only reads sizeof(long) from the input buffer.  Accepting
>>> more could lead to fifo8 abort() on 32bit systems if fifo is not empty.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  hw/misc/ivshmem.c | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>>> index cc76989..fb53b3f 100644
>>> --- a/hw/misc/ivshmem.c
>>> +++ b/hw/misc/ivshmem.c
>>> @@ -272,7 +272,7 @@ static void ivshmem_receive(void *opaque, const uint8_t
>>> *buf, int size)
>>>  
>>>  static int ivshmem_can_receive(void * opaque)
>>>  {
>>> -    return 8;
>>> +    return sizeof(long);
>>>  }
>>>  
>>
>> Is the right fix this one, or should ivshmem_read() not rely on sizeof(long)?
> 
> 
> See my answer to Paolo:
> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg05341.html

Sorry for not noticing the previous discussion..

Still it would seem more sensible to say explicitly how big the field is I think,
especially if we want to make it possible to have independent server implementations of this...

This field is used to communicate directly with another process on the host right?
Should we not mandate the communication interface quite precisely, in order to allow independent server development?
I'll push it further: do we need to consider endianness? It's the same host I know, but is the meaning of the field endian-independant, or fully expressed?

Ciao,

CLaudio

 
>>
>>>  static void ivshmem_event(void *opaque, int event)
>>>
>>
>> Ciao,
>>
>> Claudio
>>
>>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return marcandre.lureau
@ 2015-09-16 11:30   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:30 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Both if branches return, move this out to common end.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index a60454f..e391396 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -525,13 +525,12 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>          if (incoming_posn >= 0 && s->vm_id == -1) {
>              /* receive our posn */
>              s->vm_id = incoming_posn;
> -            return;
>          } else {
>              /* otherwise an fd == -1 means an existing guest has gone away */
>              IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
>              close_guest_eventfds(s, incoming_posn);
> -            return;
>          }
> +        return;
>      }
>  
>      /* if the position is -1, then it's shared memory region fd */
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2()
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2() marcandre.lureau
@ 2015-09-16 11:31   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:31 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The common version correctly checks for 0 value case.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index e391396..f40bc98 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -117,10 +117,6 @@ static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
>      return (ivs->features & (1 << feature));
>  }
>  
> -static inline bool is_power_of_two(uint64_t x) {
> -    return (x & (x - 1)) == 0;
> -}
> -
>  /* accessing registers - based on rtl8139 */
>  static void ivshmem_update_irq(IVShmemState *s)
>  {
> @@ -630,7 +626,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
>      }
>  
>      /* BARs must be a power of 2 */
> -    if (!is_power_of_two(value)) {
> +    if (!is_power_of_2(value)) {
>          error_setg(errp, "size must be power of 2");
>          return 0;
>      }
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0 marcandre.lureau
@ 2015-09-16 11:33   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:33 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> 0 is a valid fd value, so change conditions and set -1 value early
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 14c7d58..c80503d 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -233,7 +233,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
>  
>          case IVPOSITION:
>              /* return my VM ID if the memory is mapped */
> -            if (s->shm_fd > 0) {
> +            if (s->shm_fd >= 0) {
>                  ret = s->vm_id;
>              } else {
>                  ret = -1;
> @@ -663,6 +663,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
>      Error *local_err = NULL;
>  
> +    s->shm_fd = -1;
> +
>      if (s->sizearg == NULL) {
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
>      } else {
> @@ -707,8 +709,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>  
>      pci_config_set_interrupt_pin(pci_conf, 1);
>  
> -    s->shm_fd = 0;
> -
>      memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
>                            "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
>  
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description marcandre.lureau
@ 2015-09-16 11:38   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:38 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 493e3c7..5e96360 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -922,6 +922,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
>      dc->props = ivshmem_properties;
>      dc->vmsd = &ivshmem_vmsd;
>      set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->desc = "Inter-VM shared memory";
>  }
>  
>  static const TypeInfo ivshmem_info = {
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately marcandre.lureau
@ 2015-09-16 11:44   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 11:44 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The terms 'guest' and 'peer' are used sometime interchangeably which may
> be confusing. Instead, use 'peer' for the remote instances of ivshmem
> clients, and 'guest' for the local VM.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 28 ++++++++++++++--------------
>  1 file changed, 14 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 6acdc56..b9c78cd 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -89,7 +89,7 @@ typedef struct IVShmemState {
>      int shm_fd; /* shared memory file descriptor */
>  
>      Peer *peers;
> -    int nb_peers; /* how many guests we have space for */
> +    int nb_peers; /* how many peers we have space for */
>  
>      int vm_id;
>      uint32_t vectors;
> @@ -387,9 +387,9 @@ static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
>                                &s->peers[posn].eventfds[i]);
>  }
>  
> -static void close_guest_eventfds(IVShmemState *s, int posn)
> +static void close_peer_eventfds(IVShmemState *s, int posn)
>  {
> -    int i, guest_curr_max;
> +    int i, n;
>  
>      if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
>          return;
> @@ -399,14 +399,14 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
>          return;
>      }
>  
> -    guest_curr_max = s->peers[posn].nb_eventfds;
> +    n = s->peers[posn].nb_eventfds;
>  
>      memory_region_transaction_begin();
> -    for (i = 0; i < guest_curr_max; i++) {
> +    for (i = 0; i < n; i++) {
>          ivshmem_del_eventfd(s, posn, i);
>      }
>      memory_region_transaction_commit();
> -    for (i = 0; i < guest_curr_max; i++) {
> +    for (i = 0; i < n; i++) {
>          event_notifier_cleanup(&s->peers[posn].eventfds[i]);
>      }
>  
> @@ -415,7 +415,7 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
>  }
>  
>  /* this function increase the dynamic storage need to store data about other
> - * guests */
> + * peers */
>  static int resize_peers(IVShmemState *s, int new_min_size)
>  {
>  
> @@ -432,7 +432,7 @@ static int resize_peers(IVShmemState *s, int new_min_size)
>      old_size = s->nb_peers;
>      s->nb_peers = new_min_size;
>  
> -    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
> +    IVSHMEM_DPRINTF("bumping storage to %d peers\n", s->nb_peers);
>  
>      s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
>  
> @@ -503,7 +503,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
>      IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, incoming_fd);
>  
> -    /* make sure we have enough space for this guest */
> +    /* make sure we have enough space for this peer */
>      if (incoming_posn >= s->nb_peers) {
>          if (resize_peers(s, incoming_posn + 1) < 0) {
>              error_report("failed to resize peers array");
> @@ -522,9 +522,9 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>              /* receive our posn */
>              s->vm_id = incoming_posn;
>          } else {
> -            /* otherwise an fd == -1 means an existing guest has gone away */
> +            /* otherwise an fd == -1 means an existing peer has gone away */
>              IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
> -            close_guest_eventfds(s, incoming_posn);
> +            close_peer_eventfds(s, incoming_posn);
>          }
>          return;
>      }
> @@ -571,7 +571,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      /* get a new eventfd */
>      nth_eventfd = peer->nb_eventfds++;
>  
> -    /* this is an eventfd for a particular guest VM */
> +    /* this is an eventfd for a particular peer VM */
>      IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
>                      nth_eventfd, incoming_fd);
>      event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
> @@ -751,7 +751,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>              return;
>          }
>  
> -        /* we allocate enough space for 16 guests and grow as needed */
> +        /* we allocate enough space for 16 peers and grow as needed */
>          resize_peers(s, 16);
>          s->vm_id = -1;
>  
> @@ -829,7 +829,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
>  
>      if (s->peers) {
>          for (i = 0; i < s->nb_peers; i++) {
> -            close_guest_eventfds(s, i);
> +            close_peer_eventfds(s, i);
>          }
>          g_free(s->peers);
>      }
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-16 11:27       ` Claudio Fontana
@ 2015-09-16 12:03         ` Marc-André Lureau
  2015-09-16 12:51         ` Paolo Bonzini
  1 sibling, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16 12:03 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha



----- Original Message -----
> On 16.09.2015 11:33, Marc-André Lureau wrote:
> > ----- Original Message -----
> >> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> >>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >>>
> >>> ivshmem_read() only reads sizeof(long) from the input buffer.  Accepting
> >>> more could lead to fifo8 abort() on 32bit systems if fifo is not empty.
> >>>
> >>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >>> ---
> >>>  hw/misc/ivshmem.c | 2 +-
> >>>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>>
> >>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> >>> index cc76989..fb53b3f 100644
> >>> --- a/hw/misc/ivshmem.c
> >>> +++ b/hw/misc/ivshmem.c
> >>> @@ -272,7 +272,7 @@ static void ivshmem_receive(void *opaque, const
> >>> uint8_t
> >>> *buf, int size)
> >>>  
> >>>  static int ivshmem_can_receive(void * opaque)
> >>>  {
> >>> -    return 8;
> >>> +    return sizeof(long);
> >>>  }
> >>>  
> >>
> >> Is the right fix this one, or should ivshmem_read() not rely on
> >> sizeof(long)?
> > 
> > 
> > See my answer to Paolo:
> > http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg05341.html
> 
> Sorry for not noticing the previous discussion..
> 
> Still it would seem more sensible to say explicitly how big the field is I
> think,
> especially if we want to make it possible to have independent server
> implementations of this...
> 
> This field is used to communicate directly with another process on the host
> right?
> Should we not mandate the communication interface quite precisely, in order
> to allow independent server development?
> I'll push it further: do we need to consider endianness? It's the same host I
> know, but is the meaning of the field endian-independant, or fully
> expressed?

I am not aware of any specification, so following implementation it is 'long' integer in native endianness

I agree we could document and change the protocol, but this will likely break it and could be done in a different patch series.

thanks

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received marcandre.lureau
@ 2015-09-16 12:14   ` Claudio Fontana
  2015-09-23 10:47     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 12:14 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The number of eventfd that can be handled per peer is limited by the
> number of vectors. Return an error when receiving too many of them.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index b9c78cd..63e4c4f 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -569,6 +569,13 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      }
>  
>      /* get a new eventfd */
> +    if (peer->nb_eventfds >= s->vectors) {
> +        error_report("Too many eventfd received, device has %d vectors",
> +                     s->vectors);
> +        close(incoming_fd);
> +        return;
> +    }
> +
>      nth_eventfd = peer->nb_eventfds++;
>  
>      /* this is an eventfd for a particular peer VM */
> 

can the device still operate if we detect these errors at ivshmem_read time?

I am referring also to the other checks happening in ivshmem_read doing

if ([something fails]) {
    error_report("abcabc");
    /* close(), ... */
    return;
}

Can the device stop operating if these conditions happen?
If so, do we have to put the device into a non-operating state, where all read/writes are ignored? Should there be a ivshmem status flag for ERROR?
Should we exit(1)?

note: I don't know what the "proper" behavior should be, but I am concerned about the runtime stability of the software which uses the device.


Ciao,

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset marcandre.lureau
@ 2015-09-16 12:15   ` Claudio Fontana
  2015-09-23 10:48     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 12:15 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The interrupt mask is a state value, it should be reset, like the value.

probably you wanted to say "it should be reset, like the interrupt status".

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 63e4c4f..6c0a829 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -617,6 +617,7 @@ static void ivshmem_reset(DeviceState *d)
>      IVShmemState *s = IVSHMEM(d);
>  
>      s->intrstatus = 0;
> +    s->intrmask = 0;
>      ivshmem_use_msix(s);
>  }
>  
> 

Ciao

CLaudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review)
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (45 preceding siblings ...)
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 46/46] ivshmem: use kvm irqfd for msi notifications marcandre.lureau
@ 2015-09-16 12:47 ` Claudio Fontana
  2015-09-16 16:52 ` Vladimir Sementsov-Ogievskiy
  47 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 12:47 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

Hi Marc Andre',

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Hi,
> 
> This series is mostly about adding the client/server code from David
> Marchand, code cleanups, and little improvements and fixes for
> ivshmem. Finally there is some ivshmem tests (they work fine without
> kvm btw).
> 
> The first two series didn't get much feedback, and the third series is
> mostly untouched. The code is not complicated (hopefully), please
> review, thanks!! :)

I'll give it a shot.

Ciao

Claudio

> 
> Git: https://github.com/elmarco/qemu.git ivshmem branch
> 
> v2->v3:
> - add old migration fallback code
> - split a few patches
> - improve some commit messages
> - drop a commit checking eventfd read value
> 
> v1->v2:
> - add support for hugepage shm (suggested by Andrew Jones)
> - add irqfd for msix notification
> 
> David Marchand (3):
>   contrib: add ivshmem client and server
>   docs: update ivshmem device spec
>   ivshmem: add check on protocol version in QEMU
> 
> Marc-André Lureau (43):
>   char: add qemu_chr_free()
>   msix: add VMSTATE_MSIX_TEST
>   ivhsmem: read do not accept more than sizeof(long)
>   ivshmem: fix number of bytes to push to fifo
>   ivshmem: factor out the incoming fifo handling
>   ivshmem: remove unnecessary dup()
>   ivshmem: remove superflous ivshmem_attr field
>   ivshmem: remove useless doorbell field
>   ivshmem: more qdev conversion
>   ivshmem: remove last exit(1)
>   ivshmem: limit maximum number of peers to G_MAXUINT16
>   ivshmem: simplify around increase_dynamic_storage()
>   ivshmem: allocate eventfds in resize_peers()
>   ivshmem: remove useless ivshmem_update_irq() val argument
>   ivshmem: initialize max_peer to -1
>   ivshmem: remove max_peer field
>   ivshmem: improve debug messages
>   ivshmem: improve error
>   ivshmem: print error on invalid peer id
>   ivshmem: simplify a bit the code
>   ivshmem: use common return
>   ivshmem: use common is_power_of_2()
>   ivshmem: migrate with VMStateDescription
>   ivshmem: shmfd can be 0
>   ivshmem: check shm isn't already initialized
>   ivshmem: add device description
>   ivshmem: fix pci_ivshmem_exit()
>   ivshmem: replace 'guest' for 'peer' appropriately
>   ivshmem: error on too many eventfd received
>   ivshmem: reset mask on device reset
>   ivshmem-client: check the number of vectors
>   ivshmem-server: use a uint16 for client ID
>   ivshmem-server: fix hugetlbfs support
>   contrib: remove unnecessary strdup()
>   msix: implement pba write (but read-only)
>   qtest: add qtest_add_abrt_handler()
>   tests: add ivshmem qtest
>   ivshmem: do not keep shm_fd open
>   ivshmem: make ivshmem_get_size() more generic
>   ivshmem: add hostmem backend
>   ivshmem: remove EventfdEntry.vector
>   ivshmem: rename MSI eventfd_table
>   ivshmem: use kvm irqfd for msi notifications
> 
>  Makefile                                |   8 +
>  configure                               |   3 +
>  contrib/ivshmem-client/ivshmem-client.c | 444 ++++++++++++++++++
>  contrib/ivshmem-client/ivshmem-client.h | 213 +++++++++
>  contrib/ivshmem-client/main.c           | 239 ++++++++++
>  contrib/ivshmem-server/ivshmem-server.c | 478 +++++++++++++++++++
>  contrib/ivshmem-server/ivshmem-server.h | 166 +++++++
>  contrib/ivshmem-server/main.c           | 263 +++++++++++
>  docs/specs/ivshmem_device_spec.txt      | 127 +++--
>  hw/misc/ivshmem.c                       | 801 ++++++++++++++++++++++----------
>  hw/pci/msix.c                           |   6 +
>  include/hw/misc/ivshmem.h               |  25 +
>  include/hw/pci/msix.h                   |  16 +-
>  include/sysemu/char.h                   |  10 +-
>  qemu-char.c                             |   9 +-
>  qemu-doc.texi                           |  10 +-
>  tests/Makefile                          |   3 +
>  tests/ivshmem-test.c                    | 486 +++++++++++++++++++
>  tests/libqtest.c                        |  37 +-
>  tests/libqtest.h                        |   2 +
>  20 files changed, 3050 insertions(+), 296 deletions(-)
>  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/ivshmem-server.c
>  create mode 100644 contrib/ivshmem-server/ivshmem-server.h
>  create mode 100644 contrib/ivshmem-server/main.c
>  create mode 100644 include/hw/misc/ivshmem.h
>  create mode 100644 tests/ivshmem-test.c
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-16 11:27       ` Claudio Fontana
  2015-09-16 12:03         ` Marc-André Lureau
@ 2015-09-16 12:51         ` Paolo Bonzini
  2015-09-16 13:05           ` Claudio Fontana
  1 sibling, 1 reply; 109+ messages in thread
From: Paolo Bonzini @ 2015-09-16 12:51 UTC (permalink / raw)
  To: Claudio Fontana, Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha



On 16/09/2015 13:27, Claudio Fontana wrote:
>> > See my answer to Paolo:
>> > http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg05341.html
> Sorry for not noticing the previous discussion..
> 
> Still it would seem more sensible to say explicitly how big the field is I think,
> especially if we want to make it possible to have independent server implementations of this...

There was another question that went unanswered:

> Does anyone care about ivshmem on 32-bit hosts?

And I might even double down with "does anyone care about ivshmem on
big-endian hosts?"

Just defining the protocol to be "64-bit little-endian" would be nice,
even if it would break those 2 people that respectively used ivshmem on
32-bit Intel and big-endian PPC.  (And maybe also the one guy who used
it on 32-bit big-endian PPC!).

Paolo

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long)
  2015-09-16 12:51         ` Paolo Bonzini
@ 2015-09-16 13:05           ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-16 13:05 UTC (permalink / raw)
  To: Paolo Bonzini, Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

On 16.09.2015 14:51, Paolo Bonzini wrote:
> 
> 
> On 16/09/2015 13:27, Claudio Fontana wrote:
>>>> See my answer to Paolo:
>>>> http://lists.nongnu.org/archive/html/qemu-devel/2015-07/msg05341.html
>> Sorry for not noticing the previous discussion..
>>
>> Still it would seem more sensible to say explicitly how big the field is I think,
>> especially if we want to make it possible to have independent server implementations of this...
> 
> There was another question that went unanswered:
> 
>> Does anyone care about ivshmem on 32-bit hosts?
> 
> And I might even double down with "does anyone care about ivshmem on
> big-endian hosts?"
> 
> Just defining the protocol to be "64-bit little-endian" would be nice,
> even if it would break those 2 people that respectively used ivshmem on
> 32-bit Intel and big-endian PPC.  (And maybe also the one guy who used
> it on 32-bit big-endian PPC!).
> 
> Paolo

Defining in general the protocol to be 64-bit and little endian is better than not defining it at all I think.

For the two guys that use ivshmem on 32-bit Intel and big-endian PPC, please speak now!
If there is indeed some use we could use some form of versioning I presume.

There is regrettably no version register I could find in the current ivshmem implementation (is there something in the patch series I have missed?)

Incidentally, (but please ignore this comment for the purpose of this series)
I was thinking that if the device would provide a little bit more,
like a separate BAR3 as a read-only shared memory area,

and even (should I dare?) some form of simple multicast use case, like a peer negotiation and notification mechanism,

that would make it even a bit more useful. But this is for another time..

Ciao,

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic marcandre.lureau
@ 2015-09-16 15:23   ` Vladimir Sementsov-Ogievskiy
  2015-09-16 15:24   ` Vladimir Sementsov-Ogievskiy
  1 sibling, 0 replies; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-16 15:23 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

Hi!

On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Use a more explicit function name parse_mem_size(). I guess such
> function could be common (or exists already somewhere).

include/qemu-common.h : strtosz() may be used here

>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   hw/misc/ivshmem.c | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index f9ac955..5fb2123 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -643,12 +643,12 @@ static void ivshmem_reset(DeviceState *d)
>       ivshmem_use_msix(s);
>   }
>   
> -static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
> -
> +static uint64_t parse_mem_size(const char *sizearg, Error **errp)
> +{
>       uint64_t value;
>       char *ptr;
>   
> -    value = strtoull(s->sizearg, &ptr, 10);
> +    value = strtoull(sizearg, &ptr, 10);
>       switch (*ptr) {
>           case 0: case 'M': case 'm':
>               value <<= 20;
> @@ -657,7 +657,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
>               value <<= 30;
>               break;
>           default:
> -            error_setg(errp, "invalid ram size: %s", s->sizearg);
> +            error_setg(errp, "invalid ram size: %s", sizearg);
>               return 0;
>       }
>   
> @@ -704,7 +704,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>       if (s->sizearg == NULL) {
>           s->ivshmem_size = 4 << 20; /* 4 MB default */
>       } else {
> -        s->ivshmem_size = ivshmem_get_size(s, &local_err);
> +        s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
>           if (local_err) {
>               error_propagate(errp, local_err);
>               return;


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic marcandre.lureau
  2015-09-16 15:23   ` Vladimir Sementsov-Ogievskiy
@ 2015-09-16 15:24   ` Vladimir Sementsov-Ogievskiy
  2015-09-16 15:26     ` Marc-André Lureau
  1 sibling, 1 reply; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-16 15:24 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

Hi!

On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Use a more explicit function name parse_mem_size(). I guess such
> function could be common (or exists already somewhere).

strtosz() from include/qemu-common.h is appropriate

>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   hw/misc/ivshmem.c | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index f9ac955..5fb2123 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -643,12 +643,12 @@ static void ivshmem_reset(DeviceState *d)
>       ivshmem_use_msix(s);
>   }
>   
> -static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
> -
> +static uint64_t parse_mem_size(const char *sizearg, Error **errp)
> +{
>       uint64_t value;
>       char *ptr;
>   
> -    value = strtoull(s->sizearg, &ptr, 10);
> +    value = strtoull(sizearg, &ptr, 10);
>       switch (*ptr) {
>           case 0: case 'M': case 'm':
>               value <<= 20;
> @@ -657,7 +657,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
>               value <<= 30;
>               break;
>           default:
> -            error_setg(errp, "invalid ram size: %s", s->sizearg);
> +            error_setg(errp, "invalid ram size: %s", sizearg);
>               return 0;
>       }
>   
> @@ -704,7 +704,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>       if (s->sizearg == NULL) {
>           s->ivshmem_size = 4 << 20; /* 4 MB default */
>       } else {
> -        s->ivshmem_size = ivshmem_get_size(s, &local_err);
> +        s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
>           if (local_err) {
>               error_propagate(errp, local_err);
>               return;


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic
  2015-09-16 15:24   ` Vladimir Sementsov-Ogievskiy
@ 2015-09-16 15:26     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16 15:26 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

Hi

----- Original Message -----
> Hi!
> 
> On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Use a more explicit function name parse_mem_size(). I guess such
> > function could be common (or exists already somewhere).
> 
> strtosz() from include/qemu-common.h is appropriate

thanks, that's what I was looking for!

cheers

> 
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >   hw/misc/ivshmem.c | 10 +++++-----
> >   1 file changed, 5 insertions(+), 5 deletions(-)
> >
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index f9ac955..5fb2123 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -643,12 +643,12 @@ static void ivshmem_reset(DeviceState *d)
> >       ivshmem_use_msix(s);
> >   }
> >   
> > -static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
> > -
> > +static uint64_t parse_mem_size(const char *sizearg, Error **errp)
> > +{
> >       uint64_t value;
> >       char *ptr;
> >   
> > -    value = strtoull(s->sizearg, &ptr, 10);
> > +    value = strtoull(sizearg, &ptr, 10);
> >       switch (*ptr) {
> >           case 0: case 'M': case 'm':
> >               value <<= 20;
> > @@ -657,7 +657,7 @@ static uint64_t ivshmem_get_size(IVShmemState * s,
> > Error **errp) {
> >               value <<= 30;
> >               break;
> >           default:
> > -            error_setg(errp, "invalid ram size: %s", s->sizearg);
> > +            error_setg(errp, "invalid ram size: %s", sizearg);
> >               return 0;
> >       }
> >   
> > @@ -704,7 +704,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error
> > **errp)
> >       if (s->sizearg == NULL) {
> >           s->ivshmem_size = 4 << 20; /* 4 MB default */
> >       } else {
> > -        s->ivshmem_size = ivshmem_get_size(s, &local_err);
> > +        s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
> >           if (local_err) {
> >               error_propagate(errp, local_err);
> >               return;
> 
> 
> --
> Best regards,
> Vladimir
> * now, @virtuozzo.com instead of @parallels.com. Sorry for this
> inconvenience.
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support marcandre.lureau
@ 2015-09-16 16:07   ` Vladimir Sementsov-Ogievskiy
  2015-09-16 16:14     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-16 16:07 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> As pointed out on the ML by Andrew Jones, glibc no longer permits
> creating POSIX shm on hugetlbfs directly. When given a hugetlbfs path,
> create a shareable file there.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   contrib/ivshmem-server/ivshmem-server.c | 40 ++++++++++++++++++++++++++++++++-
>   contrib/ivshmem-server/ivshmem-server.h |  3 +--
>   contrib/ivshmem-server/main.c           |  5 ++---
>   3 files changed, 42 insertions(+), 6 deletions(-)
>
> diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
> index 972fda2..51264b4 100644
> --- a/contrib/ivshmem-server/ivshmem-server.c
> +++ b/contrib/ivshmem-server/ivshmem-server.c
> @@ -11,6 +11,7 @@
>   #include <sys/socket.h>
>   #include <sys/un.h>
>   #include <sys/eventfd.h>
> +#include <sys/vfs.h>
>   
>   #include "qemu-common.h"
>   #include "qemu/queue.h"
> @@ -271,15 +272,52 @@ ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
>       return 0;
>   }
>   
> +#define HUGETLBFS_MAGIC       0x958458f6
> +
> +static long gethugepagesize(const char *path)
> +{
> +    struct statfs fs;
> +    int ret;
> +
> +    do {
> +        ret = statfs(path, &fs);
> +    } while (ret != 0 && errno == EINTR);
> +
> +    if (ret != 0) {
> +        if (errno != ENOENT) {
> +            fprintf(stderr, "cannot stat shm file %s: %s\n", path,
> +                    strerror(errno));
> +        }
> +        return -1;
> +    }
> +
> +    if (fs.f_type != HUGETLBFS_MAGIC) {

should it be silent?

> +        return -1;
> +    }
> +
> +    return fs.f_bsize;
> +}
> +
>   /* open shm, create and bind to the unix socket */
>   int
>   ivshmem_server_start(IvshmemServer *server)
>   {
>       struct sockaddr_un sun;
>       int shm_fd, sock_fd, ret;
> +    long hpagesize;
> +    gchar *filename;
>   
>       /* open shm file */
> -    shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
> +    hpagesize = gethugepagesize(server->shm_path);
> +    if (hpagesize > 0) {

filename is used only in this block, it may be defined here.

> +        filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path);
> +        shm_fd = mkstemp(filename);
> +        unlink(filename);
> +        g_free(filename);
> +    } else {
> +        shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
> +    }
> +
>       if (shm_fd < 0) {
>           fprintf(stderr, "cannot open shm file %s: %s\n", server->shm_path,
>                   strerror(errno));
> diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
> index 2176d5e..e9b0e7a 100644
> --- a/contrib/ivshmem-server/ivshmem-server.h
> +++ b/contrib/ivshmem-server/ivshmem-server.h
> @@ -81,8 +81,7 @@ typedef struct IvshmemServer {
>    * @server:         A pointer to an uninitialized IvshmemServer structure
>    * @unix_sock_path: The pointer to the unix socket file name
>    * @shm_path:       Path to the shared memory. The path corresponds to a POSIX
> - *                  shm name. To use a real file, for instance in a hugetlbfs,
> - *                  it is possible to use /../../abspath/to/file.
> + *                  shm name or a hugetlbfs mount point.
>    * @shm_size:       Size of shared memory
>    * @n_vectors:      Number of interrupt vectors per client
>    * @verbose:        True to enable verbose mode
> diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
> index 84ffc4d..cd8d9ed 100644
> --- a/contrib/ivshmem-server/main.c
> +++ b/contrib/ivshmem-server/main.c
> @@ -47,9 +47,8 @@ ivshmem_server_usage(const char *name, int code)
>                       "     to listen to.\n"
>                       "     Default=%s\n", IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
>       fprintf(stderr, "  -m <shm_path>: path to the shared memory.\n"
> -                    "     The path corresponds to a POSIX shm name. To use a\n"
> -                    "     real file, for instance in a hugetlbfs, use\n"
> -                    "     /../../abspath/to/file.\n"
> +                    "     The path corresponds to a POSIX shm name or a\n"
> +                    "     hugetlbfs mount point.\n"
>                       "     default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
>       fprintf(stderr, "  -l <size>: size of shared memory in bytes. The suffix\n"
>                       "     K, M and G can be used (ex: 1K means 1024).\n"


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support
  2015-09-16 16:07   ` Vladimir Sementsov-Ogievskiy
@ 2015-09-16 16:14     ` Marc-André Lureau
  2015-09-17  8:52       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 1 reply; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16 16:14 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha



----- Original Message -----
> On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > As pointed out on the ML by Andrew Jones, glibc no longer permits
> > creating POSIX shm on hugetlbfs directly. When given a hugetlbfs path,
> > create a shareable file there.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >   contrib/ivshmem-server/ivshmem-server.c | 40
> >   ++++++++++++++++++++++++++++++++-
> >   contrib/ivshmem-server/ivshmem-server.h |  3 +--
> >   contrib/ivshmem-server/main.c           |  5 ++---
> >   3 files changed, 42 insertions(+), 6 deletions(-)
> >
> > diff --git a/contrib/ivshmem-server/ivshmem-server.c
> > b/contrib/ivshmem-server/ivshmem-server.c
> > index 972fda2..51264b4 100644
> > --- a/contrib/ivshmem-server/ivshmem-server.c
> > +++ b/contrib/ivshmem-server/ivshmem-server.c
> > @@ -11,6 +11,7 @@
> >   #include <sys/socket.h>
> >   #include <sys/un.h>
> >   #include <sys/eventfd.h>
> > +#include <sys/vfs.h>
> >   
> >   #include "qemu-common.h"
> >   #include "qemu/queue.h"
> > @@ -271,15 +272,52 @@ ivshmem_server_init(IvshmemServer *server, const char
> > *unix_sock_path,
> >       return 0;
> >   }
> >   
> > +#define HUGETLBFS_MAGIC       0x958458f6
> > +
> > +static long gethugepagesize(const char *path)
> > +{
> > +    struct statfs fs;
> > +    int ret;
> > +
> > +    do {
> > +        ret = statfs(path, &fs);
> > +    } while (ret != 0 && errno == EINTR);
> > +
> > +    if (ret != 0) {
> > +        if (errno != ENOENT) {
> > +            fprintf(stderr, "cannot stat shm file %s: %s\n", path,
> > +                    strerror(errno));
> > +        }
> > +        return -1;
> > +    }
> > +
> > +    if (fs.f_type != HUGETLBFS_MAGIC) {
> 
> should it be silent?

Well, the same given path may be shm name or a hugefs. I guess we could use a different argument instead and make sure that it is hugefs. At the minimum, I understand we may want a warning here.

> > +        return -1;
> > +    }
> > +
> > +    return fs.f_bsize;
> > +}
> > +
> >   /* open shm, create and bind to the unix socket */
> >   int
> >   ivshmem_server_start(IvshmemServer *server)
> >   {
> >       struct sockaddr_un sun;
> >       int shm_fd, sock_fd, ret;
> > +    long hpagesize;
> > +    gchar *filename;
> >   
> >       /* open shm file */
> > -    shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
> > +    hpagesize = gethugepagesize(server->shm_path);
> > +    if (hpagesize > 0) {
> 
> filename is used only in this block, it may be defined here.

ok

> 
> > +        filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path);
> > +        shm_fd = mkstemp(filename);
> > +        unlink(filename);
> > +        g_free(filename);
> > +    } else {
> > +        shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
> > +    }
> > +
> >       if (shm_fd < 0) {
> >           fprintf(stderr, "cannot open shm file %s: %s\n",
> >           server->shm_path,
> >                   strerror(errno));
> > diff --git a/contrib/ivshmem-server/ivshmem-server.h
> > b/contrib/ivshmem-server/ivshmem-server.h
> > index 2176d5e..e9b0e7a 100644
> > --- a/contrib/ivshmem-server/ivshmem-server.h
> > +++ b/contrib/ivshmem-server/ivshmem-server.h
> > @@ -81,8 +81,7 @@ typedef struct IvshmemServer {
> >    * @server:         A pointer to an uninitialized IvshmemServer structure
> >    * @unix_sock_path: The pointer to the unix socket file name
> >    * @shm_path:       Path to the shared memory. The path corresponds to a
> >    POSIX
> > - *                  shm name. To use a real file, for instance in a
> > hugetlbfs,
> > - *                  it is possible to use /../../abspath/to/file.
> > + *                  shm name or a hugetlbfs mount point.
> >    * @shm_size:       Size of shared memory
> >    * @n_vectors:      Number of interrupt vectors per client
> >    * @verbose:        True to enable verbose mode
> > diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
> > index 84ffc4d..cd8d9ed 100644
> > --- a/contrib/ivshmem-server/main.c
> > +++ b/contrib/ivshmem-server/main.c
> > @@ -47,9 +47,8 @@ ivshmem_server_usage(const char *name, int code)
> >                       "     to listen to.\n"
> >                       "     Default=%s\n",
> >                       IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
> >       fprintf(stderr, "  -m <shm_path>: path to the shared memory.\n"
> > -                    "     The path corresponds to a POSIX shm name. To use
> > a\n"
> > -                    "     real file, for instance in a hugetlbfs, use\n"
> > -                    "     /../../abspath/to/file.\n"
> > +                    "     The path corresponds to a POSIX shm name or a\n"
> > +                    "     hugetlbfs mount point.\n"
> >                       "     default=%s\n",
> >                       IVSHMEM_SERVER_DEFAULT_SHM_PATH);
> >       fprintf(stderr, "  -l <size>: size of shared memory in bytes. The
> >       suffix\n"
> >                       "     K, M and G can be used (ex: 1K means 1024).\n"
> 
> 
> --
> Best regards,
> Vladimir
> * now, @virtuozzo.com instead of @parallels.com. Sorry for this
> inconvenience.
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review)
  2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
                   ` (46 preceding siblings ...)
  2015-09-16 12:47 ` [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) Claudio Fontana
@ 2015-09-16 16:52 ` Vladimir Sementsov-Ogievskiy
  2015-09-16 20:34   ` Marc-André Lureau
  47 siblings, 1 reply; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-16 16:52 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

Hi Marc-André,

I have one question relative to these series:

Are there any plans of continuing development of ivshmem guest driver, 
including it to kernel tree, etc?

On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Hi,
>
> This series is mostly about adding the client/server code from David
> Marchand, code cleanups, and little improvements and fixes for
> ivshmem. Finally there is some ivshmem tests (they work fine without
> kvm btw).
>
> The first two series didn't get much feedback, and the third series is
> mostly untouched. The code is not complicated (hopefully), please
> review, thanks!! :)
>
> Git: https://github.com/elmarco/qemu.git ivshmem branch
>
> v2->v3:
> - add old migration fallback code
> - split a few patches
> - improve some commit messages
> - drop a commit checking eventfd read value
>
> v1->v2:
> - add support for hugepage shm (suggested by Andrew Jones)
> - add irqfd for msix notification
>
> David Marchand (3):
>    contrib: add ivshmem client and server
>    docs: update ivshmem device spec
>    ivshmem: add check on protocol version in QEMU
>
> Marc-André Lureau (43):
>    char: add qemu_chr_free()
>    msix: add VMSTATE_MSIX_TEST
>    ivhsmem: read do not accept more than sizeof(long)
>    ivshmem: fix number of bytes to push to fifo
>    ivshmem: factor out the incoming fifo handling
>    ivshmem: remove unnecessary dup()
>    ivshmem: remove superflous ivshmem_attr field
>    ivshmem: remove useless doorbell field
>    ivshmem: more qdev conversion
>    ivshmem: remove last exit(1)
>    ivshmem: limit maximum number of peers to G_MAXUINT16
>    ivshmem: simplify around increase_dynamic_storage()
>    ivshmem: allocate eventfds in resize_peers()
>    ivshmem: remove useless ivshmem_update_irq() val argument
>    ivshmem: initialize max_peer to -1
>    ivshmem: remove max_peer field
>    ivshmem: improve debug messages
>    ivshmem: improve error
>    ivshmem: print error on invalid peer id
>    ivshmem: simplify a bit the code
>    ivshmem: use common return
>    ivshmem: use common is_power_of_2()
>    ivshmem: migrate with VMStateDescription
>    ivshmem: shmfd can be 0
>    ivshmem: check shm isn't already initialized
>    ivshmem: add device description
>    ivshmem: fix pci_ivshmem_exit()
>    ivshmem: replace 'guest' for 'peer' appropriately
>    ivshmem: error on too many eventfd received
>    ivshmem: reset mask on device reset
>    ivshmem-client: check the number of vectors
>    ivshmem-server: use a uint16 for client ID
>    ivshmem-server: fix hugetlbfs support
>    contrib: remove unnecessary strdup()
>    msix: implement pba write (but read-only)
>    qtest: add qtest_add_abrt_handler()
>    tests: add ivshmem qtest
>    ivshmem: do not keep shm_fd open
>    ivshmem: make ivshmem_get_size() more generic
>    ivshmem: add hostmem backend
>    ivshmem: remove EventfdEntry.vector
>    ivshmem: rename MSI eventfd_table
>    ivshmem: use kvm irqfd for msi notifications
>
>   Makefile                                |   8 +
>   configure                               |   3 +
>   contrib/ivshmem-client/ivshmem-client.c | 444 ++++++++++++++++++
>   contrib/ivshmem-client/ivshmem-client.h | 213 +++++++++
>   contrib/ivshmem-client/main.c           | 239 ++++++++++
>   contrib/ivshmem-server/ivshmem-server.c | 478 +++++++++++++++++++
>   contrib/ivshmem-server/ivshmem-server.h | 166 +++++++
>   contrib/ivshmem-server/main.c           | 263 +++++++++++
>   docs/specs/ivshmem_device_spec.txt      | 127 +++--
>   hw/misc/ivshmem.c                       | 801 ++++++++++++++++++++++----------
>   hw/pci/msix.c                           |   6 +
>   include/hw/misc/ivshmem.h               |  25 +
>   include/hw/pci/msix.h                   |  16 +-
>   include/sysemu/char.h                   |  10 +-
>   qemu-char.c                             |   9 +-
>   qemu-doc.texi                           |  10 +-
>   tests/Makefile                          |   3 +
>   tests/ivshmem-test.c                    | 486 +++++++++++++++++++
>   tests/libqtest.c                        |  37 +-
>   tests/libqtest.h                        |   2 +
>   20 files changed, 3050 insertions(+), 296 deletions(-)
>   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/ivshmem-server.c
>   create mode 100644 contrib/ivshmem-server/ivshmem-server.h
>   create mode 100644 contrib/ivshmem-server/main.c
>   create mode 100644 include/hw/misc/ivshmem.h
>   create mode 100644 tests/ivshmem-test.c
>

Hi

-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review)
  2015-09-16 16:52 ` Vladimir Sementsov-Ogievskiy
@ 2015-09-16 20:34   ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-16 20:34 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Wed, Sep 16, 2015 at 6:52 PM, Vladimir Sementsov-Ogievskiy
<vsementsov@virtuozzo.com> wrote:
> Are there any plans of continuing development of ivshmem guest driver,
> including it to kernel tree, etc?

I have no further plans yet.

regards

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support
  2015-09-16 16:14     ` Marc-André Lureau
@ 2015-09-17  8:52       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-17  8:52 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

On 16.09.2015 19:14, Marc-André Lureau wrote:
>
> ----- Original Message -----
>> On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
>>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>
>>> As pointed out on the ML by Andrew Jones, glibc no longer permits
>>> creating POSIX shm on hugetlbfs directly. When given a hugetlbfs path,
>>> create a shareable file there.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>    contrib/ivshmem-server/ivshmem-server.c | 40
>>>    ++++++++++++++++++++++++++++++++-
>>>    contrib/ivshmem-server/ivshmem-server.h |  3 +--
>>>    contrib/ivshmem-server/main.c           |  5 ++---
>>>    3 files changed, 42 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/contrib/ivshmem-server/ivshmem-server.c
>>> b/contrib/ivshmem-server/ivshmem-server.c
>>> index 972fda2..51264b4 100644
>>> --- a/contrib/ivshmem-server/ivshmem-server.c
>>> +++ b/contrib/ivshmem-server/ivshmem-server.c
>>> @@ -11,6 +11,7 @@
>>>    #include <sys/socket.h>
>>>    #include <sys/un.h>
>>>    #include <sys/eventfd.h>
>>> +#include <sys/vfs.h>
>>>    
>>>    #include "qemu-common.h"
>>>    #include "qemu/queue.h"
>>> @@ -271,15 +272,52 @@ ivshmem_server_init(IvshmemServer *server, const char
>>> *unix_sock_path,
>>>        return 0;
>>>    }
>>>    
>>> +#define HUGETLBFS_MAGIC       0x958458f6
>>> +
>>> +static long gethugepagesize(const char *path)
>>> +{
>>> +    struct statfs fs;
>>> +    int ret;
>>> +
>>> +    do {
>>> +        ret = statfs(path, &fs);
>>> +    } while (ret != 0 && errno == EINTR);
>>> +
>>> +    if (ret != 0) {
>>> +        if (errno != ENOENT) {
>>> +            fprintf(stderr, "cannot stat shm file %s: %s\n", path,
>>> +                    strerror(errno));
>>> +        }
>>> +        return -1;
>>> +    }
>>> +
>>> +    if (fs.f_type != HUGETLBFS_MAGIC) {
>> should it be silent?
> Well, the same given path may be shm name or a hugefs. I guess we could use a different argument instead and make sure that it is hugefs. At the minimum, I understand we may want a warning here.
>
>>> +        return -1;
>>> +    }
>>> +
>>> +    return fs.f_bsize;
>>> +}
>>> +
>>>    /* open shm, create and bind to the unix socket */
>>>    int
>>>    ivshmem_server_start(IvshmemServer *server)
>>>    {
>>>        struct sockaddr_un sun;
>>>        int shm_fd, sock_fd, ret;
>>> +    long hpagesize;
>>> +    gchar *filename;
>>>    
>>>        /* open shm file */
>>> -    shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
>>> +    hpagesize = gethugepagesize(server->shm_path);
>>> +    if (hpagesize > 0) {
>> filename is used only in this block, it may be defined here.
> ok
>
>>> +        filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path);
>>> +        shm_fd = mkstemp(filename);
>>> +        unlink(filename);
>>> +        g_free(filename);
>>> +    } else {
>>> +        shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
>>> +    }
>>> +
>>>        if (shm_fd < 0) {
>>>            fprintf(stderr, "cannot open shm file %s: %s\n",
>>>            server->shm_path,
>>>                    strerror(errno));
>>> diff --git a/contrib/ivshmem-server/ivshmem-server.h
>>> b/contrib/ivshmem-server/ivshmem-server.h
>>> index 2176d5e..e9b0e7a 100644
>>> --- a/contrib/ivshmem-server/ivshmem-server.h
>>> +++ b/contrib/ivshmem-server/ivshmem-server.h
>>> @@ -81,8 +81,7 @@ typedef struct IvshmemServer {
>>>     * @server:         A pointer to an uninitialized IvshmemServer structure
>>>     * @unix_sock_path: The pointer to the unix socket file name
>>>     * @shm_path:       Path to the shared memory. The path corresponds to a
>>>     POSIX
>>> - *                  shm name. To use a real file, for instance in a
>>> hugetlbfs,
>>> - *                  it is possible to use /../../abspath/to/file.
>>> + *                  shm name or a hugetlbfs mount point.
>>>     * @shm_size:       Size of shared memory
>>>     * @n_vectors:      Number of interrupt vectors per client
>>>     * @verbose:        True to enable verbose mode
>>> diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
>>> index 84ffc4d..cd8d9ed 100644
>>> --- a/contrib/ivshmem-server/main.c
>>> +++ b/contrib/ivshmem-server/main.c
>>> @@ -47,9 +47,8 @@ ivshmem_server_usage(const char *name, int code)
>>>                        "     to listen to.\n"
>>>                        "     Default=%s\n",
>>>                        IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
>>>        fprintf(stderr, "  -m <shm_path>: path to the shared memory.\n"
>>> -                    "     The path corresponds to a POSIX shm name. To use
>>> a\n"
>>> -                    "     real file, for instance in a hugetlbfs, use\n"
>>> -                    "     /../../abspath/to/file.\n"
>>> +                    "     The path corresponds to a POSIX shm name or a\n"
>>> +                    "     hugetlbfs mount point.\n"
>>>                        "     default=%s\n",
>>>                        IVSHMEM_SERVER_DEFAULT_SHM_PATH);
>>>        fprintf(stderr, "  -l <size>: size of shared memory in bytes. The
>>>        suffix\n"
>>>                        "     K, M and G can be used (ex: 1K means 1024).\n"
>>
>> --
>> Best regards,
>> Vladimir
>> * now, @virtuozzo.com instead of @parallels.com. Sorry for this
>> inconvenience.
>>
>>
with these tiny fixes:

Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>



-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup()
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup() marcandre.lureau
@ 2015-09-17  9:01   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 109+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-09-17  9:01 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 19:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> getopt() optarg points to argv memory, no need to dup those values,
> fixes small leaks detected by clang-analyzer.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   contrib/ivshmem-client/main.c | 2 +-
>   contrib/ivshmem-server/main.c | 6 +++---
>   2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/contrib/ivshmem-client/main.c b/contrib/ivshmem-client/main.c
> index 5d85ae7..bd7cbfc 100644
> --- a/contrib/ivshmem-client/main.c
> +++ b/contrib/ivshmem-client/main.c
> @@ -53,7 +53,7 @@ ivshmem_client_parse_args(IvshmemClientArgs *args, int argc, char *argv[])
>               break;
>   
>           case 'S': /* unix_sock_path */
> -            args->unix_sock_path = strdup(optarg);
> +            args->unix_sock_path = optarg;
>               break;
>   
>           default:
> diff --git a/contrib/ivshmem-server/main.c b/contrib/ivshmem-server/main.c
> index cd8d9ed..71e87ea 100644
> --- a/contrib/ivshmem-server/main.c
> +++ b/contrib/ivshmem-server/main.c
> @@ -92,15 +92,15 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
>               break;
>   
>           case 'p': /* pid_file */
> -            args->pid_file = strdup(optarg);
> +            args->pid_file = optarg;
>               break;
>   
>           case 'S': /* unix_socket_path */
> -            args->unix_socket_path = strdup(optarg);
> +            args->unix_socket_path = optarg;
>               break;
>   
>           case 'm': /* shm_path */
> -            args->shm_path = strdup(optarg);
> +            args->shm_path = optarg;
>               break;
>   
>           case 'l': /* shm_size */

Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field marcandre.lureau
@ 2015-09-22 13:50   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 13:50 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 5e4b2cc..1b8204e 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -71,7 +71,6 @@ typedef struct IVShmemState {
>  
>      uint32_t intrmask;
>      uint32_t intrstatus;
> -    uint32_t doorbell;
>  
>      CharDriverState **eventfd_chr;
>      CharDriverState *server_chr;
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1)
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1) marcandre.lureau
@ 2015-09-22 13:55   ` Claudio Fontana
  2015-09-22 13:58     ` Claudio Fontana
  2015-09-22 14:00     ` Marc-André Lureau
  0 siblings, 2 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 13:55 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Failing to create a chardev shouldn't be fatal.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 3af73a5..7ba93c0 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -299,7 +299,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>  
>      if (chr == NULL) {
>          error_report("creating eventfd for eventfd %d failed", eventfd);
> -        exit(1);
> +        return NULL;
>      }
>      qemu_chr_fe_claim_no_fail(chr);
>  
> 

I took a look at the eventfd_chr array in the IVShmemState,
and I noticed that it's allocated with malloc at some point for receiving interrupts
with g_malloc0 in pci_ivshmem_init, but it's never freed in pci_ivshmem_uninit.

Is there such a change somewhere in the patchset I have missed?

Have you checked that the resources allocated during pci_ivshmem_init are released on pci_ivshmem_uninit?

Ciao

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1)
  2015-09-22 13:55   ` Claudio Fontana
@ 2015-09-22 13:58     ` Claudio Fontana
  2015-09-22 14:00     ` Marc-André Lureau
  1 sibling, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 13:58 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 22.09.2015 15:55, Claudio Fontana wrote:
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> Failing to create a chardev shouldn't be fatal.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  hw/misc/ivshmem.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>> index 3af73a5..7ba93c0 100644
>> --- a/hw/misc/ivshmem.c
>> +++ b/hw/misc/ivshmem.c
>> @@ -299,7 +299,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>>  
>>      if (chr == NULL) {
>>          error_report("creating eventfd for eventfd %d failed", eventfd);
>> -        exit(1);
>> +        return NULL;
>>      }
>>      qemu_chr_fe_claim_no_fail(chr);
>>  
>>
> 
> I took a look at the eventfd_chr array in the IVShmemState,
> and I noticed that it's allocated with malloc at some point for receiving interrupts
> with g_malloc0 in pci_ivshmem_init, but it's never freed in pci_ivshmem_uninit.
> 
> Is there such a change somewhere in the patchset I have missed?
> 
> Have you checked that the resources allocated during pci_ivshmem_init are released on pci_ivshmem_uninit?

With your patchset applied, that would be _realize and _exit,
as changed by patch

[PATCH v3 09/46] ivshmem: more qdev conversion

Ciao,CLaudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion marcandre.lureau
@ 2015-09-22 14:00   ` Claudio Fontana
  2015-09-23 10:22     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:00 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Use the latest qemu device modeling API, in particular, convert to
> realize to fix the error handling; right now a botched device_add
> ivhsmem command kills the VM.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 119 +++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 68 insertions(+), 51 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 1b8204e..3af73a5 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -319,22 +319,23 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>  
>  }
>  
> -static int check_shm_size(IVShmemState *s, int fd) {
> +static int check_shm_size(IVShmemState *s, int fd, Error **errp)
> +{
>      /* check that the guest isn't going to try and map more memory than the
>       * the object has allocated return -1 to indicate error */
>  
>      struct stat buf;
>  
>      if (fstat(fd, &buf) < 0) {
> -        error_report("exiting: fstat on fd %d failed: %s",
> -                     fd, strerror(errno));
> +        error_setg(errp, "exiting: fstat on fd %d failed: %s",
> +                   fd, strerror(errno));
>          return -1;
>      }
>  
>      if (s->ivshmem_size > buf.st_size) {
> -        error_report("Requested memory size greater"
> -                     " than shared object size (%" PRIu64 " > %" PRIu64")",
> -                     s->ivshmem_size, (uint64_t)buf.st_size);
> +        error_setg(errp, "Requested memory size greater"
> +                   " than shared object size (%" PRIu64 " > %" PRIu64")",
> +                   s->ivshmem_size, (uint64_t)buf.st_size);
>          return -1;
>      } else {
>          return 0;
> @@ -343,13 +344,18 @@ static int check_shm_size(IVShmemState *s, int fd) {
>  
>  /* create the shared memory BAR when we are not using the server, so we can
>   * create the BAR and map the memory immediately */
> -static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
> -
> +static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
> +                                    Error **errp)
> +{
>      void * ptr;
>  
> -    s->shm_fd = fd;
> -
>      ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
> +    if (ptr == MAP_FAILED) {
> +        error_setg_errno(errp, errno, "Failed to mmap shared memory");
> +        return -1;
> +    }
> +
> +    s->shm_fd = fd;
>  
>      memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
>                                 s->ivshmem_size, ptr);
> @@ -358,6 +364,8 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
>  
>      /* region for shared memory */
>      pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
> +
> +    return 0;
>  }
>  
>  static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
> @@ -481,6 +489,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      int incoming_fd;
>      int guest_max_eventfd;
>      long incoming_posn;
> +    Error *err = NULL;
>  
>      if (!fifo_update_and_get(s, buf, size,
>                               &incoming_posn, sizeof(incoming_posn))) {
> @@ -524,18 +533,24 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  
>      /* if the position is -1, then it's shared memory region fd */
>      if (incoming_posn == -1) {
> -
>          void * map_ptr;
>  
>          s->max_peer = 0;
>  
> -        if (check_shm_size(s, incoming_fd) == -1) {
> -            exit(1);
> +        if (check_shm_size(s, incoming_fd, &err) == -1) {
> +            error_report_err(err);
> +            close(incoming_fd);
> +            return;
>          }
>  
>          /* mmap the region and map into the BAR2 */
>          map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
>                                                              incoming_fd, 0);
> +        if (map_ptr == MAP_FAILED) {
> +            error_report("Failed to mmap shared memory %s", strerror(errno));
> +            close(incoming_fd);
> +            return;
> +        }
>          memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
>                                     "ivshmem.bar2", s->ivshmem_size, map_ptr);
>          vmstate_register_ram(&s->ivshmem, DEVICE(s));
> @@ -610,7 +625,7 @@ static void ivshmem_reset(DeviceState *d)
>      ivshmem_use_msix(s);
>  }
>  
> -static uint64_t ivshmem_get_size(IVShmemState * s) {
> +static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
>  
>      uint64_t value;
>      char *ptr;
> @@ -624,24 +639,23 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
>              value <<= 30;
>              break;
>          default:
> -            error_report("invalid ram size: %s", s->sizearg);
> -            exit(1);
> +            error_setg(errp, "invalid ram size: %s", s->sizearg);
> +            return 0;
>      }
>  
>      /* BARs must be a power of 2 */
>      if (!is_power_of_two(value)) {
> -        error_report("size must be power of 2");
> -        exit(1);
> +        error_setg(errp, "size must be power of 2");
> +        return 0;
>      }
>  
>      return value;
>  }
>  
> -static void ivshmem_setup_msi(IVShmemState * s)
> +static int ivshmem_setup_msi(IVShmemState * s)
>  {
>      if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
> -        IVSHMEM_DPRINTF("msix initialization failed\n");
> -        exit(1);
> +        return -1;
>      }
>  
>      IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
> @@ -650,6 +664,7 @@ static void ivshmem_setup_msi(IVShmemState * s)
>      s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
>  
>      ivshmem_use_msix(s);
> +    return 0;
>  }
>  
>  static void ivshmem_save(QEMUFile* f, void *opaque)
> @@ -703,34 +718,37 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
>  }
>  
>  static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
> -				 uint32_t val, int len)
> +                                 uint32_t val, int len)
>  {
>      pci_default_write_config(pci_dev, address, val, len);
>  }
>  
> -static int pci_ivshmem_init(PCIDevice *dev)
> +static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>  {
>      IVShmemState *s = IVSHMEM(dev);
>      uint8_t *pci_conf;
>      uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
> +    Error *local_err = NULL;
>  
> -    if (s->sizearg == NULL)
> +    if (s->sizearg == NULL) {
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
> -    else {
> -        s->ivshmem_size = ivshmem_get_size(s);
> +    } else {
> +        s->ivshmem_size = ivshmem_get_size(s, &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err);
> +            return;
> +        }
>      }
>  
>      fifo8_create(&s->incoming_fifo, sizeof(long));
> -
>      register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
>                                                                          dev);
> -
>      /* IRQFD requires MSI */
>      if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
>          !ivshmem_has_feature(s, IVSHMEM_MSI)) {
> -        error_report("ioeventfd/irqfd requires MSI");
> -        exit(1);
> +        error_setg(errp, "ioeventfd/irqfd requires MSI");
> +        return;
>      }
>  
>      /* check that role is reasonable */
> @@ -740,8 +758,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>          } else if (strncmp(s->role, "master", 7) == 0) {
>              s->role_val = IVSHMEM_MASTER;
>          } else {
> -            error_report("'role' must be 'peer' or 'master'");
> -            exit(1);
> +            error_setg(errp, "'role' must be 'peer' or 'master'");
> +            return;
>          }
>      } else {
>          s->role_val = IVSHMEM_MASTER; /* default */
> @@ -778,15 +796,18 @@ static int pci_ivshmem_init(PCIDevice *dev)
>           * to the ivshmem server to receive the memory region */
>  
>          if (s->shmobj != NULL) {
> -            error_report("WARNING: do not specify both 'chardev' "
> -                         "and 'shm' with ivshmem");
> +            error_setg(errp, "do not specify both 'chardev' "
> +                       "and 'shm' with ivshmem");
> +            return;
>          }
>  
>          IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
>                          s->server_chr->filename);
>  
> -        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
> -            ivshmem_setup_msi(s);
> +        if (ivshmem_has_feature(s, IVSHMEM_MSI) &&
> +            ivshmem_setup_msi(s)) {
> +            error_setg(errp, "msix initialization failed");
> +            return;
>          }
>  
>          /* we allocate enough space for 16 guests and grow as needed */
> @@ -807,8 +828,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>          int fd;
>  
>          if (s->shmobj == NULL) {
> -            error_report("Must specify 'chardev' or 'shm' to ivshmem");
> -            exit(1);
> +            error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
> +            return;
>          }
>  
>          IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
> @@ -824,24 +845,19 @@ static int pci_ivshmem_init(PCIDevice *dev)
>  
>          } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
>                          S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
> -            error_report("could not open shared file");
> -            exit(1);
> -
> +            error_setg(errp, "could not open shared file");
> +            return;
>          }
>  
> -        if (check_shm_size(s, fd) == -1) {
> -            exit(1);
> +        if (check_shm_size(s, fd, errp) == -1) {
> +            return;
>          }
>  
> -        create_shared_memory_BAR(s, fd, attr);
> +        create_shared_memory_BAR(s, fd, attr, errp);
>      }
> -
> -    dev->config_write = ivshmem_write_config;
> -
> -    return 0;
>  }
>  
> -static void pci_ivshmem_uninit(PCIDevice *dev)
> +static void pci_ivshmem_exit(PCIDevice *dev)
>  {
>      IVShmemState *s = IVSHMEM(dev);
>  
> @@ -873,8 +889,9 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
>      DeviceClass *dc = DEVICE_CLASS(klass);
>      PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>  
> -    k->init = pci_ivshmem_init;
> -    k->exit = pci_ivshmem_uninit;
> +    k->realize = pci_ivshmem_realize;
> +    k->exit = pci_ivshmem_exit;
> +    k->config_write = ivshmem_write_config;
>      k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
>      k->device_id = PCI_DEVICE_ID_IVSHMEM;
>      k->class_id = PCI_CLASS_MEMORY_RAM;
> 


As mentioned, have you checked this for leaking resources between _realize and _exit? Or do I misunderstand the interface?

Ciao,

Claudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1)
  2015-09-22 13:55   ` Claudio Fontana
  2015-09-22 13:58     ` Claudio Fontana
@ 2015-09-22 14:00     ` Marc-André Lureau
  1 sibling, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-22 14:00 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha


Hi

----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > Failing to create a chardev shouldn't be fatal.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index 3af73a5..7ba93c0 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -299,7 +299,7 @@ static CharDriverState* create_eventfd_chr_device(void
> > * opaque, EventNotifier *
> >  
> >      if (chr == NULL) {
> >          error_report("creating eventfd for eventfd %d failed", eventfd);
> > -        exit(1);
> > +        return NULL;
> >      }
> >      qemu_chr_fe_claim_no_fail(chr);
> >  
> > 
> 
> I took a look at the eventfd_chr array in the IVShmemState,
> and I noticed that it's allocated with malloc at some point for receiving
> interrupts
> with g_malloc0 in pci_ivshmem_init, but it's never freed in
> pci_ivshmem_uninit.
> 
> Is there such a change somewhere in the patchset I have missed?
> 
> Have you checked that the resources allocated during pci_ivshmem_init are
> released on pci_ivshmem_uninit?

Yes, see other patches such as "ivshmem: more qdev conversion" & "ivshmem: fix pci_ivshmem_exit()"

thanks

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling marcandre.lureau
@ 2015-09-22 14:01   ` Claudio Fontana
  2015-09-23 10:18     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:01 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Make a new function fifo_update_and_get() that can be reused by other
> functions (in next commits).
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 59 ++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 39 insertions(+), 20 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 2162d02..dd15f0e 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -441,6 +441,42 @@ static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
>      return 0;
>  }
>  
> +static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
> +                                void *data, size_t len)
> +{
> +    const uint8_t *p;
> +    uint32_t num;
> +
> +    assert(len <= sizeof(long)); /* limitation of the fifo */
> +    if (fifo8_is_empty(&s->incoming_fifo) && size == len) {
> +        memcpy(data, buf, size);
> +        return true;
> +    }
> +
> +    IVSHMEM_DPRINTF("short read of %d bytes\n", size);
> +
> +    num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
> +    fifo8_push_all(&s->incoming_fifo, buf, num);
> +
> +    if (fifo8_num_used(&s->incoming_fifo) < len) {
> +        assert(num == 0);
> +        return false;
> +    }
> +
> +    size -= num;
> +    buf += num;
> +    p = fifo8_pop_buf(&s->incoming_fifo, len, &num);
> +    assert(num == len);
> +
> +    memcpy(data, p, len);
> +
> +    if (size > 0) {
> +        fifo8_push_all(&s->incoming_fifo, buf, size);
> +    }
> +
> +    return true;
> +}
> +
>  static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  {
>      IVShmemState *s = opaque;
> @@ -448,26 +484,9 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      int guest_max_eventfd;
>      long incoming_posn;
>  
> -    if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
> -        memcpy(&incoming_posn, buf, size);
> -    } else {
> -        const uint8_t *p;
> -        uint32_t num;
> -
> -        IVSHMEM_DPRINTF("short read of %d bytes\n", size);
> -        num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
> -        fifo8_push_all(&s->incoming_fifo, buf, num);
> -        if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
> -            return;
> -        }
> -        size -= num;
> -        buf += num;
> -        p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
> -        g_assert(num == sizeof(incoming_posn));
> -        memcpy(&incoming_posn, p, sizeof(incoming_posn));
> -        if (size > 0) {
> -            fifo8_push_all(&s->incoming_fifo, buf, size);
> -        }
> +    if (!fifo_update_and_get(s, buf, size,
> +                             &incoming_posn, sizeof(incoming_posn))) {
> +        return;
>      }
>  
>      if (incoming_posn < -1) {
> 


Fine in principle, I have that reservation about using sizeof(long) as part of the interface.

Ciao

C.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup()
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup() marcandre.lureau
@ 2015-09-22 14:06   ` Claudio Fontana
  2015-09-22 15:29     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:06 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> qemu_chr_fe_get_msgfd() transfers ownership, there is no need to dup the
> fd.
> 

Are you sure? (tested?)
There is a specific comment that the dup is done because of the get_msgfds implementation,
I checked tcp_get_msgfds and it closes unused fds, is this ok?

static int tcp_get_msgfds(...)
{
...
/* Close unused fds */
for (i = to_copy, i < s->read_msgfds_num; i++) {
    close(s->read_msgfds[i]);
}
...

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 21 ++++++---------------
>  1 file changed, 6 insertions(+), 15 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index dd15f0e..fbeb731 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -480,7 +480,7 @@ static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
>  static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  {
>      IVShmemState *s = opaque;
> -    int incoming_fd, tmp_fd;
> +    int incoming_fd;
>      int guest_max_eventfd;
>      long incoming_posn;
>  
> @@ -495,21 +495,21 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      }
>  
>      /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
> -    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
> -    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
> +    incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
> +    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, incoming_fd);
>  
>      /* make sure we have enough space for this guest */
>      if (incoming_posn >= s->nb_peers) {
>          if (increase_dynamic_storage(s, incoming_posn) < 0) {
>              error_report("increase_dynamic_storage() failed");
> -            if (tmp_fd != -1) {
> -                close(tmp_fd);
> +            if (incoming_fd != -1) {
> +                close(incoming_fd);
>              }
>              return;
>          }
>      }
>  
> -    if (tmp_fd == -1) {
> +    if (incoming_fd == -1) {
>          /* if posn is positive and unseen before then this is our posn*/
>          if ((incoming_posn >= 0) &&
>                              (s->peers[incoming_posn].eventfds == NULL)) {
> @@ -524,15 +524,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>          }
>      }
>  
> -    /* because of the implementation of get_msgfd, we need a dup */
> -    incoming_fd = dup(tmp_fd);
> -
> -    if (incoming_fd == -1) {
> -        error_report("could not allocate file descriptor %s", strerror(errno));
> -        close(tmp_fd);
> -        return;
> -    }
> -
>      /* if the position is -1, then it's shared memory region fd */
>      if (incoming_posn == -1) {
>  
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16 marcandre.lureau
@ 2015-09-22 14:09   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:09 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Limit the maximum number of peers to MAXUINT16. This is more realistic
> and better matches the limit of the doorbell register.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 7ba93c0..cd2c4bc 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -34,6 +34,7 @@
>  #define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
>  #define PCI_DEVICE_ID_IVSHMEM   0x1110
>  
> +#define IVSHMEM_MAX_PEERS G_MAXUINT16
>  #define IVSHMEM_IOEVENTFD   0
>  #define IVSHMEM_MSI     1
>  
> @@ -421,8 +422,8 @@ static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
>  
>      int j, old_nb_alloc;
>  
> -    /* check for integer overflow */
> -    if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
> +    /* limit number of max peers */
> +    if (new_min_size <= 0 || new_min_size > IVSHMEM_MAX_PEERS) {
>          return -1;
>      }
>  
> 
Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>


-- 
Claudio Fontana
Server Virtualization Architect
Huawei Technologies Duesseldorf GmbH
Riesstraße 25 - 80992 München

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage()
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage() marcandre.lureau
@ 2015-09-22 14:10   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:10 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Set the number of peers and array allocation in a single place. Rename
> to better reflect the function content.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 27 +++++++++++----------------
>  1 file changed, 11 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index cd2c4bc..889a199 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -417,30 +417,28 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
>  
>  /* this function increase the dynamic storage need to store data about other
>   * guests */
> -static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
> +static int resize_peers(IVShmemState *s, int new_min_size)
>  {
>  
> -    int j, old_nb_alloc;
> +    int j, old_size;
>  
>      /* limit number of max peers */
>      if (new_min_size <= 0 || new_min_size > IVSHMEM_MAX_PEERS) {
>          return -1;
>      }
> -
> -    old_nb_alloc = s->nb_peers;
> -
> -    if (new_min_size >= s->nb_peers) {
> -        /* +1 because #new_min_size is used as last array index */
> -        s->nb_peers = new_min_size + 1;
> -    } else {
> +    if (new_min_size <= s->nb_peers) {
>          return 0;
>      }
>  
> +    old_size = s->nb_peers;
> +    s->nb_peers = new_min_size;
> +
>      IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
> +
>      s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
>  
>      /* zero out new pointers */
> -    for (j = old_nb_alloc; j < s->nb_peers; j++) {
> +    for (j = old_size; j < s->nb_peers; j++) {
>          s->peers[j].eventfds = NULL;
>          s->peers[j].nb_eventfds = 0;
>      }
> @@ -508,8 +506,8 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  
>      /* make sure we have enough space for this guest */
>      if (incoming_posn >= s->nb_peers) {
> -        if (increase_dynamic_storage(s, incoming_posn) < 0) {
> -            error_report("increase_dynamic_storage() failed");
> +        if (resize_peers(s, incoming_posn + 1) < 0) {
> +            error_report("failed to resize peers array");
>              if (incoming_fd != -1) {
>                  close(incoming_fd);
>              }
> @@ -812,12 +810,9 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          }
>  
>          /* we allocate enough space for 16 guests and grow as needed */
> -        s->nb_peers = 16;
> +        resize_peers(s, 16);
>          s->vm_id = -1;
>  
> -        /* allocate/initialize space for interrupt handling */
> -        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
> -
>          pci_register_bar(dev, 2, attr, &s->bar);
>  
>          s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument marcandre.lureau
@ 2015-09-22 14:13   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:13 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> val isn't used in ivshmem_update_irq() function.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index e890967..3398a57 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -123,7 +123,7 @@ static inline bool is_power_of_two(uint64_t x) {
>  }
>  
>  /* accessing registers - based on rtl8139 */
> -static void ivshmem_update_irq(IVShmemState *s, int val)
> +static void ivshmem_update_irq(IVShmemState *s)
>  {
>      PCIDevice *d = PCI_DEVICE(s);
>      int isr;
> @@ -144,7 +144,7 @@ static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
>  
>      s->intrmask = val;
>  
> -    ivshmem_update_irq(s, val);
> +    ivshmem_update_irq(s);
>  }
>  
>  static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
> @@ -162,7 +162,7 @@ static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
>  
>      s->intrstatus = val;
>  
> -    ivshmem_update_irq(s, val);
> +    ivshmem_update_irq(s);
>  }
>  
>  static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
> @@ -172,7 +172,7 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
>      /* reading ISR clears all interrupts */
>      s->intrstatus = 0;
>  
> -    ivshmem_update_irq(s, 0);
> +    ivshmem_update_irq(s);
>  
>      return ret;
>  }
> 


Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1 marcandre.lureau
@ 2015-09-22 14:13   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:13 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> There is no peer when device is initialized, do not let doorbell for
> inexisting peer 0.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 3398a57..07f2182 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -532,8 +532,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      if (incoming_posn == -1) {
>          void * map_ptr;
>  
> -        s->max_peer = 0;
> -
>          if (check_shm_size(s, incoming_fd, &err) == -1) {
>              error_report_err(err);
>              close(incoming_fd);
> @@ -723,6 +721,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
>      Error *local_err = NULL;
>  
> +    s->max_peer = -1;
> +
>      if (s->sizearg == NULL) {
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
>      } else {
> 

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages marcandre.lureau
@ 2015-09-22 14:23   ` Claudio Fontana
  2015-09-23 10:29     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:23 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Some misc improvements to ivshmem debug.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index cda7dce..084bc89 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -208,10 +208,13 @@ static void ivshmem_io_write(void *opaque, hwaddr addr,
>              if (vector < s->peers[dest].nb_eventfds) {
>                  IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
>                  event_notifier_set(&s->peers[dest].eventfds[vector]);
> +            } else {
> +                IVSHMEM_DPRINTF("Invalid destination vector %d on VM %d\n",
> +                                vector, dest);
>              }
>              break;
>          default:
> -            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
> +            IVSHMEM_DPRINTF("Unhandled write " TARGET_FMT_plx "\n", addr);
>      }
>  }
>  
> @@ -263,9 +266,9 @@ static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
>  {
>      IVShmemState *s = opaque;
>  
> -    ivshmem_IntrStatus_write(s, *buf);
> +    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x size: %d\n", *buf, size);
>  
> -    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
> +    ivshmem_IntrStatus_write(s, *buf);
>  }
>  
>  static int ivshmem_can_receive(void * opaque)
> @@ -592,6 +595,7 @@ static void ivshmem_use_msix(IVShmemState * s)
>      PCIDevice *d = PCI_DEVICE(s);
>      int i;
>  
> +    IVSHMEM_DPRINTF("use msix\n");
>      if (!msix_present(d)) {
>          return;
>      }
> 

This MSI-X use vs not use is a bit confusing to me.
I see that the use of MSI is controlled mainly by IVSHMEM_MSI (Property "msi"),
but then there are if (msix_present()) checks spread around.

Could this printf be a bit more clear, possibly adding other DPRINTFs as necessary?

Is your IVSHMEM_DPRINTF("use msix\n"); actually intended to mean ("using MSIX\n")? But then why is the check for if (!msix_present(d)) only afterwards?

Ciao,

Claudio 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error marcandre.lureau
@ 2015-09-22 14:26   ` Claudio Fontana
  2015-09-23 10:30     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:26 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

Subject: ivshmem: improve error

Seems an interrupted sentence...

... improve error handling? improve error messages?

Ciao

Claudio

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The test whether the chardev is an AF_UNIX socket rejects
> "-chardev socket,id=chr0,path=/tmp/foo,server,nowait -device
> ivshmem,chardev=chr0", but fails to explain why.
> 
> Use an explicit error on why a chardev may be rejected.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 084bc89..52e1e63 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -301,7 +301,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>      chr = qemu_chr_open_eventfd(eventfd);
>  
>      if (chr == NULL) {
> -        error_report("creating eventfd for eventfd %d failed", eventfd);
> +        error_report("creating chardriver for eventfd %d failed", eventfd);
>          return NULL;
>      }
>      qemu_chr_fe_claim_no_fail(chr);
> @@ -778,8 +778,12 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
>      }
>  
> -    if ((s->server_chr != NULL) &&
> -                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
> +    if (s->server_chr != NULL) {
> +        if (strncmp(s->server_chr->filename, "unix:", 5)) {
> +            error_setg(errp, "chardev is not a unix client socket");
> +            return;
> +        }
> +
>          /* if we get a UNIX socket as the parameter we will talk
>           * to the ivshmem server to receive the memory region */
>  
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id marcandre.lureau
@ 2015-09-22 14:27   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:27 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The server shouldn't send invalid peer id, so print an error if it's the
> case.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 52e1e63..1c98ec3 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -399,6 +399,7 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
>          return;
>      }
>      if (posn < 0 || posn >= s->nb_peers) {
> +        error_report("invalid peer %d", posn);
>          return;
>      }
>  
> 


Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code marcandre.lureau
@ 2015-09-22 14:32   ` Claudio Fontana
  2015-09-22 14:56     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:32 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Use some more explicit variables to simplify the code.
> 
> nth_eventfd variable is the current eventfd to be manipulated.

well maybe a silly question, but then why not call it current_eventfd?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 1c98ec3..a60454f 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -488,9 +488,10 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  {
>      IVShmemState *s = opaque;
>      int incoming_fd;
> -    int guest_max_eventfd;
> +    int nth_eventfd;
>      long incoming_posn;
>      Error *err = NULL;
> +    Peer *peer;
>  
>      if (!fifo_update_and_get(s, buf, size,
>                               &incoming_posn, sizeof(incoming_posn))) {
> @@ -517,6 +518,8 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>          }
>      }
>  
> +    peer = &s->peers[incoming_posn];
> +
>      if (incoming_fd == -1) {
>          /* if posn is positive and unseen before then this is our posn*/
>          if (incoming_posn >= 0 && s->vm_id == -1) {
> @@ -564,27 +567,22 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>          return;
>      }
>  
> -    /* each guest has an array of eventfds, and we keep track of how many
> -     * guests for each VM */

you removed a few comments, do they no longer apply?
If so do they need to be replaced with better ones mentioning how it works in contrast with the previous?

> -    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
> +    /* get a new eventfd */
> +    nth_eventfd = peer->nb_eventfds++;
>  
>      /* this is an eventfd for a particular guest VM */
>      IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
> -                    guest_max_eventfd, incoming_fd);
> -    event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
> -                           incoming_fd);
> -
> -    /* increment count for particular guest */
> -    s->peers[incoming_posn].nb_eventfds++;
> +                    nth_eventfd, incoming_fd);
> +    event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
>  
>      if (incoming_posn == s->vm_id) {
> -        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
> -                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
> -                   guest_max_eventfd);
> +        s->eventfd_chr[nth_eventfd] = create_eventfd_chr_device(s,
> +                   &s->peers[s->vm_id].eventfds[nth_eventfd],
> +                   nth_eventfd);
>      }
>  
>      if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
> -        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
> +        ivshmem_add_eventfd(s, incoming_posn, nth_eventfd);
>      }
>  }
>  
> 

Ciao
C.

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open marcandre.lureau
@ 2015-09-22 14:36   ` Claudio Fontana
  2015-09-22 14:59     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:36 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Remove shm_fd from device state, closing it as early as possible to avoid leaks.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c | 14 +++++---------
>  1 file changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 4adcac5..f9ac955 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -88,7 +88,6 @@ typedef struct IVShmemState {
>      MemoryRegion ivshmem;
>      uint64_t ivshmem_size; /* size of shared memory region */
>      uint32_t ivshmem_64bit;
> -    int shm_fd; /* shared memory file descriptor */

is it in no way useful during debugging to have access to this field?
Or is it easily available elsewhere?

Ciao C.

>  
>      Peer *peers;
>      int nb_peers; /* how many peers we have space for */
> @@ -235,7 +234,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
>  
>          case IVPOSITION:
>              /* return my VM ID if the memory is mapped */
> -            if (s->shm_fd >= 0) {
> +            if (memory_region_is_mapped(&s->ivshmem)) {
>                  ret = s->vm_id;
>              } else {
>                  ret = -1;
> @@ -356,8 +355,6 @@ static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
>          return -1;
>      }
>  
> -    s->shm_fd = fd;
> -
>      memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
>                                 s->ivshmem_size, ptr);
>      vmstate_register_ram(&s->ivshmem, DEVICE(s));
> @@ -535,7 +532,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>      if (incoming_posn == -1) {
>          void * map_ptr;
>  
> -        if (s->shm_fd >= 0) {
> +        if (memory_region_is_mapped(&s->ivshmem)) {
>              error_report("shm already initialized");
>              close(incoming_fd);
>              return;
> @@ -564,9 +561,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>  
>          memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
>  
> -        /* only store the fd if it is successfully mapped */
> -        s->shm_fd = incoming_fd;
> -
> +        close(incoming_fd);
>          return;
>      }
>  
> @@ -827,6 +822,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          }
>  
>          create_shared_memory_BAR(s, fd, attr, errp);
> +        close(fd);
>      }
>  }
>  
> @@ -842,7 +838,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
>          error_free(s->migration_blocker);
>      }
>  
> -    if (s->shm_fd >= 0) {
> +    if (memory_region_is_mapped(&s->ivshmem)) {
>          void *addr = memory_region_get_ram_ptr(&s->ivshmem);
>  
>          vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest
  2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest marcandre.lureau
@ 2015-09-22 14:44   ` Claudio Fontana
  2015-09-23 11:24     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:44 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, Andreas Färber, stefanha

On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Adds 4 ivshmemtests:
> - single qemu instance and basic IO
> - pair of instances, check memory sharing
> - pair of instances with server, and MSIX
> - hot plug/unplug
> 
> A temporary shm is created as well as a directory to place server
> socket, both should be clear on exit and abort.
> 
> Cc: Cam Macdonell <cam@cs.ualberta.ca>
> CC: Andreas Färber <afaerber@suse.de>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  tests/Makefile       |   3 +
>  tests/ivshmem-test.c | 474 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 477 insertions(+)
>  create mode 100644 tests/ivshmem-test.c
> 
> diff --git a/tests/Makefile b/tests/Makefile
> index 34c6136..e7a50e7 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -142,6 +142,8 @@ gcov-files-pci-y += hw/display/virtio-gpu-pci.c
>  gcov-files-pci-$(CONFIG_VIRTIO_VGA) += hw/display/virtio-vga.c
>  check-qtest-pci-y += tests/intel-hda-test$(EXESUF)
>  gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c
> +check-qtest-pci-$(CONFIG_LINUX) += tests/ivshmem-test$(EXESUF)
> +gcov-files-pci-y += hw/misc/ivshmem.c
>  
>  check-qtest-i386-y = tests/endianness-test$(EXESUF)
>  check-qtest-i386-y += tests/fdc-test$(EXESUF)
> @@ -416,6 +418,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o
>  tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
>  tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
>  tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a
> +tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y)
>  
>  ifeq ($(CONFIG_POSIX),y)
>  LIBS += -lutil
> diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
> new file mode 100644
> index 0000000..03f44c1
> --- /dev/null
> +++ b/tests/ivshmem-test.c
> @@ -0,0 +1,474 @@
> +/*
> + * QTest testcase for ivshmem
> + *
> + * Copyright (c) 2015 Red Hat, Inc.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <glib.h>
> +#include <glib/gstdio.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include "contrib/ivshmem-server/ivshmem-server.h"
> +#include "libqos/pci-pc.h"
> +#include "libqtest.h"
> +#include "qemu/osdep.h"
> +#include <stdlib.h>
> +
> +#if GLIB_CHECK_VERSION(2, 32, 0)
> +#define HAVE_THREAD_NEW
> +#endif
> +
> +#define TMPSHMSIZE (1 << 20)
> +static char *tmpshm;
> +static void *tmpshmem;
> +static char *tmpdir;
> +static char *tmpserver;
> +
> +static void save_fn(QPCIDevice *dev, int devfn, void *data)
> +{
> +    QPCIDevice **pdev = (QPCIDevice **) data;
> +
> +    *pdev = dev;
> +}
> +
> +static QPCIDevice *get_device(void)
> +{
> +    QPCIDevice *dev;
> +    QPCIBus *pcibus;
> +
> +    pcibus = qpci_init_pc();
> +    qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
> +    g_assert(dev != NULL);
> +
> +    return dev;
> +}
> +
> +typedef struct _IVState {
> +    QTestState *qtest;
> +    void *reg_base, *mem_base;
> +    QPCIDevice *dev;
> +} IVState;
> +
> +#define REG(name, len, val)                                     \
> +    static inline unsigned in_##name(IVState *s)                \
> +    {                                                           \
> +        QTestState *qtest = global_qtest;                       \
> +        unsigned res;                                           \
> +        global_qtest = s->qtest;                                \
> +        res = qpci_io_read##len(s->dev, s->reg_base+(val));     \
> +        g_test_message("*%s -> %x\n", #name, res);              \
> +        global_qtest = qtest;                                   \
> +        return res;                                             \
> +    }                                                           \
> +    static inline void out_##name(IVState *s, unsigned v)       \
> +    {                                                           \
> +        QTestState *qtest = global_qtest;                       \
> +        global_qtest = s->qtest;                                \
> +        g_test_message("%x -> *%s\n", v, #name);                \
> +        qpci_io_write##len(s->dev, s->reg_base+(val), v);       \
> +        global_qtest = qtest;                                   \
> +    }
> +
> +REG(IntrMask, l, 0)
> +REG(IntrStatus, l, 4)
> +REG(IVPosition, l, 8)
> +REG(DoorBell, l, 12)

I find this kind of macro use an aberration, but it is common use in QEMU (unfortunately), and becoming worse.

If somebody else wants to step in and add his own tag on this I would feel like less of an accomplice in this crime.

Ciao,

Claudio

> +
> +#if 0
> +static void info_qtree(void)
> +{
> +    QDict *response;
> +
> +    response = qmp("{'execute': 'human-monitor-command',"
> +                   " 'arguments': {"
> +                   "   'command-line': 'info qtree'"
> +                   "}}");
> +    g_assert(response);
> +    g_debug(qdict_get_try_str(response, "return"));
> +    QDECREF(response);
> +}
> +#endif
> +
> +static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
> +{
> +    uint64_t barsize;
> +
> +    s->qtest = qtest_start(cmd);
> +
> +    s->dev = get_device();
> +
> +    /* FIXME: other bar order fails, mappings changes */
> +    s->mem_base = qpci_iomap(s->dev, 2, &barsize);
> +    g_assert_nonnull(s->mem_base);
> +    g_assert_cmpuint(barsize, ==, TMPSHMSIZE);
> +
> +    if (msix) {
> +        qpci_msix_enable(s->dev);
> +    }
> +
> +    s->reg_base = qpci_iomap(s->dev, 0, &barsize);
> +    g_assert_nonnull(s->reg_base);
> +    g_assert_cmpuint(barsize, ==, 256);
> +
> +    qpci_device_enable(s->dev);
> +}
> +
> +static void setup_vm(IVState *s)
> +{
> +    char *cmd = g_strdup_printf("-device ivshmem,shm=%s,size=1M", tmpshm);
> +
> +    setup_vm_cmd(s, cmd, false);
> +
> +    g_free(cmd);
> +}
> +
> +static void test_ivshmem_single(void)
> +{
> +    IVState state, *s;
> +    uint32_t data[1024];
> +    int i;
> +
> +    setup_vm(&state);
> +    s = &state;
> +
> +    /* valid io */
> +    out_IntrMask(s, 0);
> +    in_IntrStatus(s);
> +    in_IVPosition(s);
> +
> +    out_IntrMask(s, 0xffffffff);
> +    g_assert_cmpuint(in_IntrMask(s), ==, 0xffffffff);
> +    out_IntrStatus(s, 1);
> +    /* XXX: intercept IRQ, not seen in resp */
> +    g_assert_cmpuint(in_IntrStatus(s), ==, 1);
> +
> +    /* invalid io */
> +    out_IVPosition(s, 1);
> +    out_DoorBell(s, 8 << 16);
> +
> +    for (i = 0; i < G_N_ELEMENTS(data); i++) {
> +        data[i] = i;
> +    }
> +    qtest_memwrite(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data));
> +
> +    for (i = 0; i < G_N_ELEMENTS(data); i++) {
> +        g_assert_cmpuint(((uint32_t *)tmpshmem)[i], ==, i);
> +    }
> +
> +    memset(data, 0, sizeof(data));
> +
> +    qtest_memread(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data));
> +    for (i = 0; i < G_N_ELEMENTS(data); i++) {
> +        g_assert_cmpuint(data[i], ==, i);
> +    }
> +
> +    qtest_quit(s->qtest);
> +}
> +
> +static void test_ivshmem_pair(void)
> +{
> +    IVState state1, state2, *s1, *s2;
> +    char *data;
> +    int i;
> +
> +    setup_vm(&state1);
> +    s1 = &state1;
> +    setup_vm(&state2);
> +    s2 = &state2;
> +
> +    data = g_malloc0(TMPSHMSIZE);
> +
> +    /* host write, guest 1 & 2 read */
> +    memset(tmpshmem, 0x42, TMPSHMSIZE);
> +    qtest_memread(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE);
> +    for (i = 0; i < TMPSHMSIZE; i++) {
> +        g_assert_cmpuint(data[i], ==, 0x42);
> +    }
> +    qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
> +    for (i = 0; i < TMPSHMSIZE; i++) {
> +        g_assert_cmpuint(data[i], ==, 0x42);
> +    }
> +
> +    /* guest 1 write, guest 2 read */
> +    memset(data, 0x43, TMPSHMSIZE);
> +    qtest_memwrite(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE);
> +    memset(data, 0, TMPSHMSIZE);
> +    qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
> +    for (i = 0; i < TMPSHMSIZE; i++) {
> +        g_assert_cmpuint(data[i], ==, 0x43);
> +    }
> +
> +    /* guest 2 write, guest 1 read */
> +    memset(data, 0x44, TMPSHMSIZE);
> +    qtest_memwrite(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
> +    memset(data, 0, TMPSHMSIZE);
> +    qtest_memread(s1->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE);
> +    for (i = 0; i < TMPSHMSIZE; i++) {
> +        g_assert_cmpuint(data[i], ==, 0x44);
> +    }
> +
> +    qtest_quit(s1->qtest);
> +    qtest_quit(s2->qtest);
> +    g_free(data);
> +}
> +
> +typedef struct ServerThread {
> +    GThread *thread;
> +    IvshmemServer *server;
> +    int pipe[2]; /* to handle quit */
> +} ServerThread;
> +
> +static void *server_thread(void *data)
> +{
> +    ServerThread *t = data;
> +    IvshmemServer *server = t->server;
> +
> +    while (true) {
> +        fd_set fds;
> +        int maxfd, ret;
> +
> +        FD_ZERO(&fds);
> +        FD_SET(t->pipe[0], &fds);
> +        maxfd = t->pipe[0] + 1;
> +
> +        ivshmem_server_get_fds(server, &fds, &maxfd);
> +
> +        ret = select(maxfd, &fds, NULL, NULL, NULL);
> +
> +        if (ret < 0) {
> +            if (errno == EINTR) {
> +                continue;
> +            }
> +
> +            g_critical("select error: %s\n", strerror(errno));
> +            break;
> +        }
> +        if (ret == 0) {
> +            continue;
> +        }
> +
> +        if (FD_ISSET(t->pipe[0], &fds)) {
> +            break;
> +        }
> +
> +        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
> +            g_critical("ivshmem_server_handle_fds() failed\n");
> +            break;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +static void setup_vm_with_server(IVState *s, int nvectors)
> +{
> +    char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
> +                                "-device ivshmem,size=1M,chardev=chr0,vectors=%d",
> +                                tmpserver, nvectors);
> +
> +    setup_vm_cmd(s, cmd, true);
> +
> +    g_free(cmd);
> +}
> +
> +static GThread *thread_new(const gchar *name, GThreadFunc func, gpointer data)
> +{
> +    GThread *thread = NULL;
> +    GError *error = NULL;
> +#ifdef HAVE_THREAD_NEW
> +    thread = g_thread_try_new(name, func, data, &error);
> +#else
> +    thread = g_thread_create(func, data, TRUE, &error);
> +#endif
> +    g_assert_no_error(error);
> +    return thread;
> +}
> +
> +static void test_ivshmem_server(void)
> +{
> +    IVState state1, state2, *s1, *s2;
> +    ServerThread thread;
> +    IvshmemServer server;
> +    int ret, vm1, vm2;
> +    int nvectors = 2;
> +
> +    memset(tmpshmem, 0x42, TMPSHMSIZE);
> +    ret = ivshmem_server_init(&server, tmpserver, tmpshm,
> +                              TMPSHMSIZE, nvectors,
> +                              getenv("QTEST_LOG") != NULL);
> +    g_assert_cmpint(ret, ==, 0);
> +
> +    ret = ivshmem_server_start(&server);
> +    g_assert_cmpint(ret, ==, 0);
> +
> +    setup_vm_with_server(&state1, nvectors);
> +    s1 = &state1;
> +    setup_vm_with_server(&state2, nvectors);
> +    s2 = &state2;
> +
> +    g_assert_cmpuint(in_IVPosition(s1), ==, 0xffffffff);
> +    g_assert_cmpuint(in_IVPosition(s2), ==, 0xffffffff);
> +
> +    g_assert_cmpuint(qtest_readb(s1->qtest, (uintptr_t)s1->mem_base), ==, 0x00);
> +
> +    thread.server = &server;
> +    ret = pipe(thread.pipe);
> +    g_assert_cmpint(ret, ==, 0);
> +    thread.thread = thread_new("ivshmem-server", server_thread, &thread);
> +
> +    /* waiting until mapping is done */
> +    while (true) {
> +        g_usleep(1000);
> +
> +        if (qtest_readb(s1->qtest, (uintptr_t)s1->mem_base) == 0x42 &&
> +            qtest_readb(s2->qtest, (uintptr_t)s2->mem_base) == 0x42) {
> +            break;
> +        }
> +    }
> +
> +    /* check got different VM ids */
> +    vm1 = in_IVPosition(s1);
> +    vm2 = in_IVPosition(s2);
> +    g_assert_cmpuint(vm1, !=, vm2);
> +
> +    global_qtest = s1->qtest;
> +    ret = qpci_msix_table_size(s1->dev);
> +    g_assert_cmpuint(ret, ==, nvectors);
> +
> +    /* ping vm2 -> vm1 */
> +    ret = qpci_msix_pending(s1->dev, 0);
> +    g_assert_cmpuint(ret, ==, 0);
> +    out_DoorBell(s2, vm1 << 16);
> +    g_usleep(10000);
> +    ret = qpci_msix_pending(s1->dev, 0);
> +    g_assert_cmpuint(ret, !=, 0);
> +
> +    /* ping vm1 -> vm2 */
> +    global_qtest = s2->qtest;
> +    ret = qpci_msix_pending(s2->dev, 0);
> +    g_assert_cmpuint(ret, ==, 0);
> +    out_DoorBell(s1, vm2 << 16);
> +    g_usleep(10000);
> +    ret = qpci_msix_pending(s2->dev, 0);
> +    g_assert_cmpuint(ret, !=, 0);
> +
> +    /* remove vm2 */
> +    qtest_quit(s2->qtest);
> +    /* XXX wait enough time for vm1 to be notified */
> +    g_usleep(1000);
> +
> +    qtest_quit(s1->qtest);
> +
> +    write(thread.pipe[1], "q", 1);
> +    g_thread_join(thread.thread);
> +
> +    ivshmem_server_close(&server);
> +    close(thread.pipe[1]);
> +    close(thread.pipe[0]);
> +}
> +
> +#define PCI_SLOT_HP             0x06
> +
> +static void test_ivshmem_hotplug(void)
> +{
> +    gchar *opts;
> +
> +    qtest_start("");
> +
> +    opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm);
> +
> +    qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts);
> +    qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
> +
> +    qtest_end();
> +    g_free(opts);
> +}
> +
> +static void cleanup(void)
> +{
> +    if (tmpshmem) {
> +        munmap(tmpshmem, TMPSHMSIZE);
> +        tmpshmem = NULL;
> +    }
> +
> +    if (tmpshm) {
> +        shm_unlink(tmpshm);
> +        g_free(tmpshm);
> +        tmpshm = NULL;
> +    }
> +
> +    if (tmpserver) {
> +        g_unlink(tmpserver);
> +        g_free(tmpserver);
> +        tmpserver = NULL;
> +    }
> +
> +    if (tmpdir) {
> +        g_rmdir(tmpdir);
> +        tmpdir = NULL;
> +    }
> +}
> +
> +static void abrt_handler(void *data)
> +{
> +    cleanup();
> +}
> +
> +static gchar *mktempshm(int size, int *fd)
> +{
> +    while (true) {
> +        gchar *name;
> +
> +        name = g_strdup_printf("/qtest-%u-%u", getpid(), g_random_int());
> +        *fd = shm_open(name, O_CREAT|O_RDWR|O_EXCL,
> +                       S_IRWXU|S_IRWXG|S_IRWXO);
> +        if (*fd > 0) {
> +            g_assert(ftruncate(*fd, size) == 0);
> +            return name;
> +        }
> +
> +        g_free(name);
> +    }
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    int ret, fd;
> +    static gchar dir[] = "/tmp/ivshmem-test.XXXXXX";
> +
> +#if !GLIB_CHECK_VERSION(2, 31, 0)
> +    if (!g_thread_supported()) {
> +        g_thread_init(NULL);
> +    }
> +#endif
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    qtest_add_abrt_handler(abrt_handler, NULL);
> +    /* shm */
> +    tmpshm = mktempshm(TMPSHMSIZE, &fd);
> +    tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
> +    g_assert(tmpshmem != MAP_FAILED);
> +    /* server */
> +    if (g_mkdtemp_full(dir, 0700) == NULL) {
> +        g_error("g_mkdtemp_full: %s", g_strerror(errno));
> +    }
> +    tmpdir = dir;
> +    tmpserver = g_strconcat(tmpdir, "/server", NULL);
> +
> +    qtest_add_func("/ivshmem/single", test_ivshmem_single);
> +    qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
> +    qtest_add_func("/ivshmem/server", test_ivshmem_server);
> +    qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
> +
> +    ret = g_test_run();
> +
> +    cleanup();
> +    return ret;
> +}
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend marcandre.lureau
@ 2015-09-22 14:49   ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:49 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:08, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Instead of handling allocation, teach ivshmem to use a memory backend.
> This allows to use hugetlbfs backed memory now.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/misc/ivshmem.c    | 84 ++++++++++++++++++++++++++++++++++++++++------------
>  tests/ivshmem-test.c | 12 ++++++++
>  2 files changed, 77 insertions(+), 19 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index 5fb2123..ac90f0a 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -26,6 +26,8 @@
>  #include "qemu/event_notifier.h"
>  #include "qemu/fifo8.h"
>  #include "sysemu/char.h"
> +#include "sysemu/hostmem.h"
> +#include "qapi/visitor.h"
>  
>  #include "hw/misc/ivshmem.h"
>  
> @@ -57,6 +59,8 @@
>  #define IVSHMEM(obj) \
>      OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
>  
> +#define IVSHMEM_MEMDEV_PROP "memdev"
> +
>  typedef struct Peer {
>      int nb_eventfds;
>      EventNotifier *eventfds;
> @@ -72,6 +76,7 @@ typedef struct IVShmemState {
>      PCIDevice parent_obj;
>      /*< public >*/
>  
> +    HostMemoryBackend *hostmem;
>      uint32_t intrmask;
>      uint32_t intrstatus;
>  
> @@ -699,9 +704,22 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
>      Error *local_err = NULL;
>  
> -    s->shm_fd = -1;
> +    if (!!s->server_chr + !!s->shmobj + !!s->hostmem != 1) {
> +        error_setg(errp, "You must specify either a shmobj, a chardev"
> +                   " or a hostmem");
> +        return;
> +    }
> +
> +    if (s->hostmem) {
> +        MemoryRegion *mr;
>  
> -    if (s->sizearg == NULL) {
> +        if (s->sizearg) {
> +            g_warning("size argument ignored with hostmem");
> +        }
> +
> +        mr = host_memory_backend_get_memory(s->hostmem, errp);
> +        s->ivshmem_size = memory_region_size(mr);
> +    } else if (s->sizearg == NULL) {
>          s->ivshmem_size = 4 << 20; /* 4 MB default */
>      } else {
>          s->ivshmem_size = parse_mem_size(s->sizearg, &local_err);
> @@ -757,7 +775,16 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
>      }
>  
> -    if (s->server_chr != NULL) {
> +    if (s->hostmem != NULL) {
> +        MemoryRegion *mr;
> +
> +        IVSHMEM_DPRINTF("using hostmem\n");
> +
> +        mr = host_memory_backend_get_memory(MEMORY_BACKEND(s->hostmem), errp);
> +        vmstate_register_ram(mr, DEVICE(s));
> +        memory_region_add_subregion(&s->bar, 0, mr);
> +        pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
> +    } else if (s->server_chr != NULL) {
>          if (strncmp(s->server_chr->filename, "unix:", 5)) {
>              error_setg(errp, "chardev is not a unix client socket");
>              return;
> @@ -766,12 +793,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          /* if we get a UNIX socket as the parameter we will talk
>           * to the ivshmem server to receive the memory region */
>  
> -        if (s->shmobj != NULL) {
> -            error_setg(errp, "do not specify both 'chardev' "
> -                       "and 'shm' with ivshmem");
> -            return;
> -        }
> -
>          IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
>                          s->server_chr->filename);
>  
> @@ -795,11 +816,6 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>          /* just map the file immediately, we're not using a server */
>          int fd;
>  
> -        if (s->shmobj == NULL) {
> -            error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
> -            return;
> -        }
> -
>          IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
>  
>          /* try opening with O_EXCL and if it succeeds zero the memory
> @@ -839,14 +855,17 @@ static void pci_ivshmem_exit(PCIDevice *dev)
>      }
>  
>      if (memory_region_is_mapped(&s->ivshmem)) {
> -        void *addr = memory_region_get_ram_ptr(&s->ivshmem);
> +        if (!s->hostmem) {
> +            void *addr = memory_region_get_ram_ptr(&s->ivshmem);
> +
> +            if (munmap(addr, s->ivshmem_size) == -1) {
> +                error_report("Failed to munmap shared memory %s",
> +                             strerror(errno));
> +            }
> +        }
>  
>          vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
>          memory_region_del_subregion(&s->bar, &s->ivshmem);
> -
> -        if (munmap(addr, s->ivshmem_size) == -1) {
> -            error_report("Failed to munmap shared memory %s", strerror(errno));
> -        }
>      }
>  
>      if (s->eventfd_chr) {
> @@ -988,10 +1007,37 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
>      dc->desc = "Inter-VM shared memory";
>  }
>  
> +static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
> +                                         Object *val, Error **errp)
> +{
> +    MemoryRegion *mr;
> +
> +    mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), errp);
> +    if (memory_region_is_mapped(mr)) {
> +        char *path = object_get_canonical_path_component(val);
> +        error_setg(errp, "can't use already busy memdev: %s", path);
> +        g_free(path);
> +    } else {
> +        qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
> +    }
> +}
> +
> +static void ivshmem_init(Object *obj)
> +{
> +    IVShmemState *s = IVSHMEM(obj);
> +
> +    object_property_add_link(obj, IVSHMEM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
> +                             (Object **)&s->hostmem,
> +                             ivshmem_check_memdev_is_busy,
> +                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
> +                             &error_abort);
> +}
> +
>  static const TypeInfo ivshmem_info = {
>      .name          = TYPE_IVSHMEM,
>      .parent        = TYPE_PCI_DEVICE,
>      .instance_size = sizeof(IVShmemState),
> +    .instance_init = ivshmem_init,
>      .class_init    = ivshmem_class_init,
>  };
>  
> diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
> index 03f44c1..920b9fa 100644
> --- a/tests/ivshmem-test.c
> +++ b/tests/ivshmem-test.c
> @@ -390,6 +390,17 @@ static void test_ivshmem_hotplug(void)
>      g_free(opts);
>  }
>  
> +static void test_ivshmem_memdev(void)
> +{
> +    IVState state;
> +
> +    /* just for the sake of checking memory-backend property */
> +    setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
> +                 " -device ivshmem,memdev=mb1", false);
> +
> +    qtest_quit(state.qtest);
> +}
> +
>  static void cleanup(void)
>  {
>      if (tmpshmem) {
> @@ -466,6 +477,7 @@ int main(int argc, char **argv)
>      qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
>      qtest_add_func("/ivshmem/server", test_ivshmem_server);
>      qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug);
> +    qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev);
>  
>      ret = g_test_run();
>  
> 

seems good to me..

Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code
  2015-09-22 14:32   ` Claudio Fontana
@ 2015-09-22 14:56     ` Marc-André Lureau
  2015-09-23 12:18       ` Claudio Fontana
  0 siblings, 1 reply; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-22 14:56 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha



----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > Use some more explicit variables to simplify the code.
> > 
> > nth_eventfd variable is the current eventfd to be manipulated.
> 
> well maybe a silly question, but then why not call it current_eventfd?

Either way, ok.

current_eventfd is the nth eventfd to be added :)

> 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 26 ++++++++++++--------------
> >  1 file changed, 12 insertions(+), 14 deletions(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index 1c98ec3..a60454f 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -488,9 +488,10 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >  {
> >      IVShmemState *s = opaque;
> >      int incoming_fd;
> > -    int guest_max_eventfd;
> > +    int nth_eventfd;
> >      long incoming_posn;
> >      Error *err = NULL;
> > +    Peer *peer;
> >  
> >      if (!fifo_update_and_get(s, buf, size,
> >                               &incoming_posn, sizeof(incoming_posn))) {
> > @@ -517,6 +518,8 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >          }
> >      }
> >  
> > +    peer = &s->peers[incoming_posn];
> > +
> >      if (incoming_fd == -1) {
> >          /* if posn is positive and unseen before then this is our posn*/
> >          if (incoming_posn >= 0 && s->vm_id == -1) {
> > @@ -564,27 +567,22 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >          return;
> >      }
> >  
> > -    /* each guest has an array of eventfds, and we keep track of how many
> > -     * guests for each VM */
> 
> you removed a few comments, do they no longer apply?
> If so do they need to be replaced with better ones mentioning how it works in
> contrast with the previous?

That comment didn't make much sense to me, especially the second part,
what about:

"each peer has an associated array of eventfds, and we keep track of how many eventfd received so far"

> 
> > -    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
> > +    /* get a new eventfd */
> > +    nth_eventfd = peer->nb_eventfds++;
> >  
> >      /* this is an eventfd for a particular guest VM */
> >      IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
> > -                    guest_max_eventfd, incoming_fd);
> > -
> > event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
> > -                           incoming_fd);
> > -
> > -    /* increment count for particular guest */
> > -    s->peers[incoming_posn].nb_eventfds++;
> > +                    nth_eventfd, incoming_fd);
> > +    event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
> >  
> >      if (incoming_posn == s->vm_id) {
> > -        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
> > -                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
> > -                   guest_max_eventfd);
> > +        s->eventfd_chr[nth_eventfd] = create_eventfd_chr_device(s,
> > +                   &s->peers[s->vm_id].eventfds[nth_eventfd],
> > +                   nth_eventfd);
> >      }
> >  
> >      if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
> > -        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
> > +        ivshmem_add_eventfd(s, incoming_posn, nth_eventfd);
> >      }
> >  }
> >  
> > 
> 
> Ciao
> C.
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open
  2015-09-22 14:36   ` Claudio Fontana
@ 2015-09-22 14:59     ` Marc-André Lureau
  2015-09-23 12:20       ` Claudio Fontana
  0 siblings, 1 reply; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-22 14:59 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

Hi

----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > Remove shm_fd from device state, closing it as early as possible to avoid
> > leaks.
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 14 +++++---------
> >  1 file changed, 5 insertions(+), 9 deletions(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index 4adcac5..f9ac955 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -88,7 +88,6 @@ typedef struct IVShmemState {
> >      MemoryRegion ivshmem;
> >      uint64_t ivshmem_size; /* size of shared memory region */
> >      uint32_t ivshmem_64bit;
> > -    int shm_fd; /* shared memory file descriptor */
> 
> is it in no way useful during debugging to have access to this field?
> Or is it easily available elsewhere?

How would it be useful during debugging? Once the memory is mapped there isn't much you can do with it, it's just keeping a fd open, isn't it?

> 
> Ciao C.
> 
> >  
> >      Peer *peers;
> >      int nb_peers; /* how many peers we have space for */
> > @@ -235,7 +234,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr
> > addr,
> >  
> >          case IVPOSITION:
> >              /* return my VM ID if the memory is mapped */
> > -            if (s->shm_fd >= 0) {
> > +            if (memory_region_is_mapped(&s->ivshmem)) {
> >                  ret = s->vm_id;
> >              } else {
> >                  ret = -1;
> > @@ -356,8 +355,6 @@ static int create_shared_memory_BAR(IVShmemState *s,
> > int fd, uint8_t attr,
> >          return -1;
> >      }
> >  
> > -    s->shm_fd = fd;
> > -
> >      memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
> >                                 s->ivshmem_size, ptr);
> >      vmstate_register_ram(&s->ivshmem, DEVICE(s));
> > @@ -535,7 +532,7 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >      if (incoming_posn == -1) {
> >          void * map_ptr;
> >  
> > -        if (s->shm_fd >= 0) {
> > +        if (memory_region_is_mapped(&s->ivshmem)) {
> >              error_report("shm already initialized");
> >              close(incoming_fd);
> >              return;
> > @@ -564,9 +561,7 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >  
> >          memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
> >  
> > -        /* only store the fd if it is successfully mapped */
> > -        s->shm_fd = incoming_fd;
> > -
> > +        close(incoming_fd);
> >          return;
> >      }
> >  
> > @@ -827,6 +822,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error
> > **errp)
> >          }
> >  
> >          create_shared_memory_BAR(s, fd, attr, errp);
> > +        close(fd);
> >      }
> >  }
> >  
> > @@ -842,7 +838,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
> >          error_free(s->migration_blocker);
> >      }
> >  
> > -    if (s->shm_fd >= 0) {
> > +    if (memory_region_is_mapped(&s->ivshmem)) {
> >          void *addr = memory_region_get_ram_ptr(&s->ivshmem);
> >  
> >          vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
> > 
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector
  2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector marcandre.lureau
@ 2015-09-22 14:59   ` Claudio Fontana
  2015-09-22 15:18     ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-22 14:59 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: drjones, cam, stefanha

On 15.09.2015 18:08, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> No need to store an extra int for the vector number when it can be
> computed easily by looking at the position in the array.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

This one does not seem particularly valuable to me.. btw isn't it slightly easier to debug with the vector in the structure?

> ---
>  hw/misc/ivshmem.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> index ac90f0a..976fbea 100644
> --- a/hw/misc/ivshmem.c
> +++ b/hw/misc/ivshmem.c
> @@ -68,7 +68,6 @@ typedef struct Peer {
>  
>  typedef struct EventfdEntry {
>      PCIDevice *pdev;
> -    int vector;
>  } EventfdEntry;
>  
>  typedef struct IVShmemState {
> @@ -287,9 +286,11 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
>  
>      EventfdEntry *entry = opaque;
>      PCIDevice *pdev = entry->pdev;
> +    IVShmemState *s = IVSHMEM(pdev);
> +    int vector = entry - s->eventfd_table;
>  
> -    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
> -    msix_notify(pdev, entry->vector);
> +    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector);
> +    msix_notify(pdev, vector);
>  }
>  
>  static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
> @@ -311,7 +312,6 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>      /* if MSI is supported we need multiple interrupts */
>      if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
>          s->eventfd_table[vector].pdev = PCI_DEVICE(s);
> -        s->eventfd_table[vector].vector = vector;
>  
>          qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
>                        ivshmem_event, &s->eventfd_table[vector]);
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector
  2015-09-22 14:59   ` Claudio Fontana
@ 2015-09-22 15:18     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-22 15:18 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Tue, Sep 22, 2015 at 4:59 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> This one does not seem particularly valuable to me.. btw isn't it slightly easier to debug with the vector in the structure?

Yeah, it's just is a bit superflous to me store the vector index in
all the elements.

You get the vector index calculated and printed in debug, so I failed
to see what it removes for debugging.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup()
  2015-09-22 14:06   ` Claudio Fontana
@ 2015-09-22 15:29     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-22 15:29 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

Hi

----- Original Message -----
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > qemu_chr_fe_get_msgfd() transfers ownership, there is no need to dup the
> > fd.
> > 
> 
> Are you sure? (tested?)
> There is a specific comment that the dup is done because of the get_msgfds
> implementation,
> I checked tcp_get_msgfds and it closes unused fds, is this ok?
> 
> static int tcp_get_msgfds(...)
> {
> ...
> /* Close unused fds */
> for (i = to_copy, i < s->read_msgfds_num; i++) {
>     close(s->read_msgfds[i]);
> }
> ...

Yes, it closes the remaining fds. But for the others, the one it got, there is no need for an extra dup() since the ownership is transfered.

> 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  hw/misc/ivshmem.c | 21 ++++++---------------
> >  1 file changed, 6 insertions(+), 15 deletions(-)
> > 
> > diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
> > index dd15f0e..fbeb731 100644
> > --- a/hw/misc/ivshmem.c
> > +++ b/hw/misc/ivshmem.c
> > @@ -480,7 +480,7 @@ static bool fifo_update_and_get(IVShmemState *s, const
> > uint8_t *buf, int size,
> >  static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
> >  {
> >      IVShmemState *s = opaque;
> > -    int incoming_fd, tmp_fd;
> > +    int incoming_fd;
> >      int guest_max_eventfd;
> >      long incoming_posn;
> >  
> > @@ -495,21 +495,21 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >      }
> >  
> >      /* pick off s->server_chr->msgfd and store it, posn should accompany
> >      msg */
> > -    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
> > -    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
> > +    incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
> > +    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn,
> > incoming_fd);
> >  
> >      /* make sure we have enough space for this guest */
> >      if (incoming_posn >= s->nb_peers) {
> >          if (increase_dynamic_storage(s, incoming_posn) < 0) {
> >              error_report("increase_dynamic_storage() failed");
> > -            if (tmp_fd != -1) {
> > -                close(tmp_fd);
> > +            if (incoming_fd != -1) {
> > +                close(incoming_fd);
> >              }
> >              return;
> >          }
> >      }
> >  
> > -    if (tmp_fd == -1) {
> > +    if (incoming_fd == -1) {
> >          /* if posn is positive and unseen before then this is our posn*/
> >          if ((incoming_posn >= 0) &&
> >                              (s->peers[incoming_posn].eventfds == NULL)) {
> > @@ -524,15 +524,6 @@ static void ivshmem_read(void *opaque, const uint8_t
> > *buf, int size)
> >          }
> >      }
> >  
> > -    /* because of the implementation of get_msgfd, we need a dup */
> > -    incoming_fd = dup(tmp_fd);
> > -
> > -    if (incoming_fd == -1) {
> > -        error_report("could not allocate file descriptor %s",
> > strerror(errno));
> > -        close(tmp_fd);
> > -        return;
> > -    }
> > -
> >      /* if the position is -1, then it's shared memory region fd */
> >      if (incoming_posn == -1) {
> >  
> > 
> 
> 

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo
  2015-09-16  9:28   ` Claudio Fontana
@ 2015-09-23 10:17     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:17 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Wed, Sep 16, 2015 at 11:28 AM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> (should we rely on sizeof(long) here?)

This is unrelated to the fix (MIN/MAX). I will add a patch to change
the protocol.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling
  2015-09-22 14:01   ` Claudio Fontana
@ 2015-09-23 10:18     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:18 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Tue, Sep 22, 2015 at 4:01 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> Make a new function fifo_update_and_get() that can be reused by other
>> functions (in next commits).
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  hw/misc/ivshmem.c | 59 ++++++++++++++++++++++++++++++++++++-------------------
>>  1 file changed, 39 insertions(+), 20 deletions(-)
>>
>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>> index 2162d02..dd15f0e 100644
>> --- a/hw/misc/ivshmem.c
>> +++ b/hw/misc/ivshmem.c
>> @@ -441,6 +441,42 @@ static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
>>      return 0;
>>  }
>>
>> +static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
>> +                                void *data, size_t len)
>> +{
>> +    const uint8_t *p;
>> +    uint32_t num;
>> +
>> +    assert(len <= sizeof(long)); /* limitation of the fifo */
>> +    if (fifo8_is_empty(&s->incoming_fifo) && size == len) {
>> +        memcpy(data, buf, size);
>> +        return true;
>> +    }
>> +
>> +    IVSHMEM_DPRINTF("short read of %d bytes\n", size);
>> +
>> +    num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
>> +    fifo8_push_all(&s->incoming_fifo, buf, num);
>> +
>> +    if (fifo8_num_used(&s->incoming_fifo) < len) {
>> +        assert(num == 0);
>> +        return false;
>> +    }
>> +
>> +    size -= num;
>> +    buf += num;
>> +    p = fifo8_pop_buf(&s->incoming_fifo, len, &num);
>> +    assert(num == len);
>> +
>> +    memcpy(data, p, len);
>> +
>> +    if (size > 0) {
>> +        fifo8_push_all(&s->incoming_fifo, buf, size);
>> +    }
>> +
>> +    return true;
>> +}
>> +
>>  static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>>  {
>>      IVShmemState *s = opaque;
>> @@ -448,26 +484,9 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>>      int guest_max_eventfd;
>>      long incoming_posn;
>>
>> -    if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
>> -        memcpy(&incoming_posn, buf, size);
>> -    } else {
>> -        const uint8_t *p;
>> -        uint32_t num;
>> -
>> -        IVSHMEM_DPRINTF("short read of %d bytes\n", size);
>> -        num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
>> -        fifo8_push_all(&s->incoming_fifo, buf, num);
>> -        if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
>> -            return;
>> -        }
>> -        size -= num;
>> -        buf += num;
>> -        p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
>> -        g_assert(num == sizeof(incoming_posn));
>> -        memcpy(&incoming_posn, p, sizeof(incoming_posn));
>> -        if (size > 0) {
>> -            fifo8_push_all(&s->incoming_fifo, buf, size);
>> -        }
>> +    if (!fifo_update_and_get(s, buf, size,
>> +                             &incoming_posn, sizeof(incoming_posn))) {
>> +        return;
>>      }
>>
>>      if (incoming_posn < -1) {
>>
>
>
> Fine in principle, I have that reservation about using sizeof(long) as part of the interface.


This will be treated in a seperate patch.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion
  2015-09-22 14:00   ` Claudio Fontana
@ 2015-09-23 10:22     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:22 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

On Tue, Sep 22, 2015 at 4:00 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> Use the latest qemu device modeling API, in particular, convert to
>> realize to fix the error handling; right now a botched device_add
>> ivhsmem command kills the VM.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  hw/misc/ivshmem.c | 119 +++++++++++++++++++++++++++++++-----------------------
>>  1 file changed, 68 insertions(+), 51 deletions(-)
>>
>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>> index 1b8204e..3af73a5 100644
>> --- a/hw/misc/ivshmem.c
>> +++ b/hw/misc/ivshmem.c
>> @@ -319,22 +319,23 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
>>
>>  }
>>
>> -static int check_shm_size(IVShmemState *s, int fd) {
>> +static int check_shm_size(IVShmemState *s, int fd, Error **errp)
>> +{
>>      /* check that the guest isn't going to try and map more memory than the
>>       * the object has allocated return -1 to indicate error */
>>
>>      struct stat buf;
>>
>>      if (fstat(fd, &buf) < 0) {
>> -        error_report("exiting: fstat on fd %d failed: %s",
>> -                     fd, strerror(errno));
>> +        error_setg(errp, "exiting: fstat on fd %d failed: %s",
>> +                   fd, strerror(errno));
>>          return -1;
>>      }
>>
>>      if (s->ivshmem_size > buf.st_size) {
>> -        error_report("Requested memory size greater"
>> -                     " than shared object size (%" PRIu64 " > %" PRIu64")",
>> -                     s->ivshmem_size, (uint64_t)buf.st_size);
>> +        error_setg(errp, "Requested memory size greater"
>> +                   " than shared object size (%" PRIu64 " > %" PRIu64")",
>> +                   s->ivshmem_size, (uint64_t)buf.st_size);
>>          return -1;
>>      } else {
>>          return 0;
>> @@ -343,13 +344,18 @@ static int check_shm_size(IVShmemState *s, int fd) {
>>
>>  /* create the shared memory BAR when we are not using the server, so we can
>>   * create the BAR and map the memory immediately */
>> -static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
>> -
>> +static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
>> +                                    Error **errp)
>> +{
>>      void * ptr;
>>
>> -    s->shm_fd = fd;
>> -
>>      ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
>> +    if (ptr == MAP_FAILED) {
>> +        error_setg_errno(errp, errno, "Failed to mmap shared memory");
>> +        return -1;
>> +    }
>> +
>> +    s->shm_fd = fd;
>>
>>      memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
>>                                 s->ivshmem_size, ptr);
>> @@ -358,6 +364,8 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr) {
>>
>>      /* region for shared memory */
>>      pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
>> +
>> +    return 0;
>>  }
>>
>>  static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
>> @@ -481,6 +489,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>>      int incoming_fd;
>>      int guest_max_eventfd;
>>      long incoming_posn;
>> +    Error *err = NULL;
>>
>>      if (!fifo_update_and_get(s, buf, size,
>>                               &incoming_posn, sizeof(incoming_posn))) {
>> @@ -524,18 +533,24 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>>
>>      /* if the position is -1, then it's shared memory region fd */
>>      if (incoming_posn == -1) {
>> -
>>          void * map_ptr;
>>
>>          s->max_peer = 0;
>>
>> -        if (check_shm_size(s, incoming_fd) == -1) {
>> -            exit(1);
>> +        if (check_shm_size(s, incoming_fd, &err) == -1) {
>> +            error_report_err(err);
>> +            close(incoming_fd);
>> +            return;
>>          }
>>
>>          /* mmap the region and map into the BAR2 */
>>          map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
>>                                                              incoming_fd, 0);
>> +        if (map_ptr == MAP_FAILED) {
>> +            error_report("Failed to mmap shared memory %s", strerror(errno));
>> +            close(incoming_fd);
>> +            return;
>> +        }
>>          memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
>>                                     "ivshmem.bar2", s->ivshmem_size, map_ptr);
>>          vmstate_register_ram(&s->ivshmem, DEVICE(s));
>> @@ -610,7 +625,7 @@ static void ivshmem_reset(DeviceState *d)
>>      ivshmem_use_msix(s);
>>  }
>>
>> -static uint64_t ivshmem_get_size(IVShmemState * s) {
>> +static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
>>
>>      uint64_t value;
>>      char *ptr;
>> @@ -624,24 +639,23 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
>>              value <<= 30;
>>              break;
>>          default:
>> -            error_report("invalid ram size: %s", s->sizearg);
>> -            exit(1);
>> +            error_setg(errp, "invalid ram size: %s", s->sizearg);
>> +            return 0;
>>      }
>>
>>      /* BARs must be a power of 2 */
>>      if (!is_power_of_two(value)) {
>> -        error_report("size must be power of 2");
>> -        exit(1);
>> +        error_setg(errp, "size must be power of 2");
>> +        return 0;
>>      }
>>
>>      return value;
>>  }
>>
>> -static void ivshmem_setup_msi(IVShmemState * s)
>> +static int ivshmem_setup_msi(IVShmemState * s)
>>  {
>>      if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
>> -        IVSHMEM_DPRINTF("msix initialization failed\n");
>> -        exit(1);
>> +        return -1;
>>      }
>>
>>      IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
>> @@ -650,6 +664,7 @@ static void ivshmem_setup_msi(IVShmemState * s)
>>      s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
>>
>>      ivshmem_use_msix(s);
>> +    return 0;
>>  }
>>
>>  static void ivshmem_save(QEMUFile* f, void *opaque)
>> @@ -703,34 +718,37 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
>>  }
>>
>>  static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
>> -                              uint32_t val, int len)
>> +                                 uint32_t val, int len)
>>  {
>>      pci_default_write_config(pci_dev, address, val, len);
>>  }
>>
>> -static int pci_ivshmem_init(PCIDevice *dev)
>> +static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
>>  {
>>      IVShmemState *s = IVSHMEM(dev);
>>      uint8_t *pci_conf;
>>      uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
>>          PCI_BASE_ADDRESS_MEM_PREFETCH;;
>> +    Error *local_err = NULL;
>>
>> -    if (s->sizearg == NULL)
>> +    if (s->sizearg == NULL) {
>>          s->ivshmem_size = 4 << 20; /* 4 MB default */
>> -    else {
>> -        s->ivshmem_size = ivshmem_get_size(s);
>> +    } else {
>> +        s->ivshmem_size = ivshmem_get_size(s, &local_err);
>> +        if (local_err) {
>> +            error_propagate(errp, local_err);
>> +            return;
>> +        }
>>      }
>>
>>      fifo8_create(&s->incoming_fifo, sizeof(long));
>> -
>>      register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
>>                                                                          dev);
>> -
>>      /* IRQFD requires MSI */
>>      if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
>>          !ivshmem_has_feature(s, IVSHMEM_MSI)) {
>> -        error_report("ioeventfd/irqfd requires MSI");
>> -        exit(1);
>> +        error_setg(errp, "ioeventfd/irqfd requires MSI");
>> +        return;
>>      }
>>
>>      /* check that role is reasonable */
>> @@ -740,8 +758,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>>          } else if (strncmp(s->role, "master", 7) == 0) {
>>              s->role_val = IVSHMEM_MASTER;
>>          } else {
>> -            error_report("'role' must be 'peer' or 'master'");
>> -            exit(1);
>> +            error_setg(errp, "'role' must be 'peer' or 'master'");
>> +            return;
>>          }
>>      } else {
>>          s->role_val = IVSHMEM_MASTER; /* default */
>> @@ -778,15 +796,18 @@ static int pci_ivshmem_init(PCIDevice *dev)
>>           * to the ivshmem server to receive the memory region */
>>
>>          if (s->shmobj != NULL) {
>> -            error_report("WARNING: do not specify both 'chardev' "
>> -                         "and 'shm' with ivshmem");
>> +            error_setg(errp, "do not specify both 'chardev' "
>> +                       "and 'shm' with ivshmem");
>> +            return;
>>          }
>>
>>          IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
>>                          s->server_chr->filename);
>>
>> -        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
>> -            ivshmem_setup_msi(s);
>> +        if (ivshmem_has_feature(s, IVSHMEM_MSI) &&
>> +            ivshmem_setup_msi(s)) {
>> +            error_setg(errp, "msix initialization failed");
>> +            return;
>>          }
>>
>>          /* we allocate enough space for 16 guests and grow as needed */
>> @@ -807,8 +828,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
>>          int fd;
>>
>>          if (s->shmobj == NULL) {
>> -            error_report("Must specify 'chardev' or 'shm' to ivshmem");
>> -            exit(1);
>> +            error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
>> +            return;
>>          }
>>
>>          IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
>> @@ -824,24 +845,19 @@ static int pci_ivshmem_init(PCIDevice *dev)
>>
>>          } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
>>                          S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
>> -            error_report("could not open shared file");
>> -            exit(1);
>> -
>> +            error_setg(errp, "could not open shared file");
>> +            return;
>>          }
>>
>> -        if (check_shm_size(s, fd) == -1) {
>> -            exit(1);
>> +        if (check_shm_size(s, fd, errp) == -1) {
>> +            return;
>>          }
>>
>> -        create_shared_memory_BAR(s, fd, attr);
>> +        create_shared_memory_BAR(s, fd, attr, errp);
>>      }
>> -
>> -    dev->config_write = ivshmem_write_config;
>> -
>> -    return 0;
>>  }
>>
>> -static void pci_ivshmem_uninit(PCIDevice *dev)
>> +static void pci_ivshmem_exit(PCIDevice *dev)
>>  {
>>      IVShmemState *s = IVSHMEM(dev);
>>
>> @@ -873,8 +889,9 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
>>      DeviceClass *dc = DEVICE_CLASS(klass);
>>      PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>>
>> -    k->init = pci_ivshmem_init;
>> -    k->exit = pci_ivshmem_uninit;
>> +    k->realize = pci_ivshmem_realize;
>> +    k->exit = pci_ivshmem_exit;
>> +    k->config_write = ivshmem_write_config;
>>      k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
>>      k->device_id = PCI_DEVICE_ID_IVSHMEM;
>>      k->class_id = PCI_CLASS_MEMORY_RAM;
>>
>
>
> As mentioned, have you checked this for leaking resources between _realize and _exit? Or do I misunderstand the interface?


Yes, see "ivshmem: fix pci_ivshmem_exit()" patch.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages
  2015-09-22 14:23   ` Claudio Fontana
@ 2015-09-23 10:29     ` Marc-André Lureau
  2015-09-23 12:10       ` Claudio Fontana
  0 siblings, 1 reply; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:29 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

On Tue, Sep 22, 2015 at 4:23 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> This MSI-X use vs not use is a bit confusing to me.
> I see that the use of MSI is controlled mainly by IVSHMEM_MSI (Property "msi"),
> but then there are if (msix_present()) checks spread around.
>
> Could this printf be a bit more clear, possibly adding other DPRINTFs as necessary?
>
> Is your IVSHMEM_DPRINTF("use msix\n"); actually intended to mean ("using MSIX\n")? But then why is the check for if (!msix_present(d)) only afterwards?


I don't remember precisely why it's there, only I probably wanted to
trace the entering of function ivshmem_use_msix().

Let's change it for IVSHMEM_DPRINTF("use msix, present: %d\n",
msix_present(d)); ok?

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error
  2015-09-22 14:26   ` Claudio Fontana
@ 2015-09-23 10:30     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:30 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

On Tue, Sep 22, 2015 at 4:26 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> Seems an interrupted sentence...
>
> ... improve error handling? improve error messages?


ack

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received
  2015-09-16 12:14   ` Claudio Fontana
@ 2015-09-23 10:47     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:47 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Wed, Sep 16, 2015 at 2:14 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> The number of eventfd that can be handled per peer is limited by the
>> number of vectors. Return an error when receiving too many of them.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  hw/misc/ivshmem.c | 7 +++++++
>>  1 file changed, 7 insertions(+)
>>
>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>> index b9c78cd..63e4c4f 100644
>> --- a/hw/misc/ivshmem.c
>> +++ b/hw/misc/ivshmem.c
>> @@ -569,6 +569,13 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
>>      }
>>
>>      /* get a new eventfd */
>> +    if (peer->nb_eventfds >= s->vectors) {
>> +        error_report("Too many eventfd received, device has %d vectors",
>> +                     s->vectors);
>> +        close(incoming_fd);
>> +        return;
>> +    }
>> +
>>      nth_eventfd = peer->nb_eventfds++;
>>
>>      /* this is an eventfd for a particular peer VM */
>>
>
> can the device still operate if we detect these errors at ivshmem_read time?
>
> I am referring also to the other checks happening in ivshmem_read doing
>
> if ([something fails]) {
>     error_report("abcabc");
>     /* close(), ... */
>     return;
> }
>
> Can the device stop operating if these conditions happen?

Yes, it simply closes the "new" incoming_fd. So if the server sends
extra eventfd for peers that we can't handle, we won't be able to
notify those peers. But the rest of the peers and function is still
working.

This is btw, what the current code is doing (only the variable is
called tmp_fd before I removed it in "remove unnecessary dup()" patch)

> If so, do we have to put the device into a non-operating state, where all read/writes are ignored? Should there be a ivshmem status flag for ERROR?
> Should we exit(1)?
>
> note: I don't know what the "proper" behavior should be, but I am concerned about the runtime stability of the software which uses the device.

It's likely a misconfiguration. So having error reported seems like a
sane and enough thing to do.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset
  2015-09-16 12:15   ` Claudio Fontana
@ 2015-09-23 10:48     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 10:48 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Wed, Sep 16, 2015 at 2:15 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> probably you wanted to say "it should be reset, like the interrupt status".


yes, thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest
  2015-09-22 14:44   ` Claudio Fontana
@ 2015-09-23 11:24     ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 11:24 UTC (permalink / raw)
  To: Claudio Fontana
  Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi, Andreas Färber

Hi

On Tue, Sep 22, 2015 at 4:44 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
> I find this kind of macro use an aberration, but it is common use in QEMU (unfortunately), and becoming worse.
>
> If somebody else wants to step in and add his own tag on this I would feel like less of an accomplice in this crime.

That won't be necessary, I replaced it with regular functions for v4

thanks


-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages
  2015-09-23 10:29     ` Marc-André Lureau
@ 2015-09-23 12:10       ` Claudio Fontana
  2015-09-23 15:45         ` Marc-André Lureau
  0 siblings, 1 reply; 109+ messages in thread
From: Claudio Fontana @ 2015-09-23 12:10 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

On 23.09.2015 12:29, Marc-André Lureau wrote:
> On Tue, Sep 22, 2015 at 4:23 PM, Claudio Fontana
> <claudio.fontana@huawei.com> wrote:
>> This MSI-X use vs not use is a bit confusing to me.
>> I see that the use of MSI is controlled mainly by IVSHMEM_MSI (Property "msi"),
>> but then there are if (msix_present()) checks spread around.
>>
>> Could this printf be a bit more clear, possibly adding other DPRINTFs as necessary?
>>
>> Is your IVSHMEM_DPRINTF("use msix\n"); actually intended to mean ("using MSIX\n")? But then why is the check for if (!msix_present(d)) only afterwards?
> 
> 
> I don't remember precisely why it's there, only I probably wanted to
> trace the entering of function ivshmem_use_msix().
> 
> Let's change it for IVSHMEM_DPRINTF("use msix, present: %d\n",
> msix_present(d)); ok?
> 

what about something like

IVSHMEM_DPRINTF("%susing MSI-X\n", msix_present(d) ? "" : "not ");

or just

if (!msix_present(d) {
   IVSHMEM_DPRINTF("not using MSI-X");
   return;
}

IVSHMEM_DPRINTF("using MSI-X");

Ciao

CLaudio

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code
  2015-09-22 14:56     ` Marc-André Lureau
@ 2015-09-23 12:18       ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-23 12:18 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

On 22.09.2015 16:56, Marc-André Lureau wrote:
> 
> 
> ----- Original Message -----
>> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>
>>> Use some more explicit variables to simplify the code.
>>>
>>> nth_eventfd variable is the current eventfd to be manipulated.
>>
>> well maybe a silly question, but then why not call it current_eventfd?
> 
> Either way, ok.
> 
> current_eventfd is the nth eventfd to be added :)
> 
>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  hw/misc/ivshmem.c | 26 ++++++++++++--------------
>>>  1 file changed, 12 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>>> index 1c98ec3..a60454f 100644
>>> --- a/hw/misc/ivshmem.c
>>> +++ b/hw/misc/ivshmem.c
>>> @@ -488,9 +488,10 @@ static void ivshmem_read(void *opaque, const uint8_t
>>> *buf, int size)
>>>  {
>>>      IVShmemState *s = opaque;
>>>      int incoming_fd;
>>> -    int guest_max_eventfd;
>>> +    int nth_eventfd;
>>>      long incoming_posn;
>>>      Error *err = NULL;
>>> +    Peer *peer;
>>>  
>>>      if (!fifo_update_and_get(s, buf, size,
>>>                               &incoming_posn, sizeof(incoming_posn))) {
>>> @@ -517,6 +518,8 @@ static void ivshmem_read(void *opaque, const uint8_t
>>> *buf, int size)
>>>          }
>>>      }
>>>  
>>> +    peer = &s->peers[incoming_posn];
>>> +
>>>      if (incoming_fd == -1) {
>>>          /* if posn is positive and unseen before then this is our posn*/
>>>          if (incoming_posn >= 0 && s->vm_id == -1) {
>>> @@ -564,27 +567,22 @@ static void ivshmem_read(void *opaque, const uint8_t
>>> *buf, int size)
>>>          return;
>>>      }
>>>  
>>> -    /* each guest has an array of eventfds, and we keep track of how many
>>> -     * guests for each VM */
>>
>> you removed a few comments, do they no longer apply?
>> If so do they need to be replaced with better ones mentioning how it works in
>> contrast with the previous?
> 
> That comment didn't make much sense to me, especially the second part,
> what about:
> 
> "each peer has an associated array of eventfds, and we keep track of how many eventfd received so far"

ok, "... of how many eventfds have been received so far".

> 
>>
>>> -    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
>>> +    /* get a new eventfd */
>>> +    nth_eventfd = peer->nb_eventfds++;
>>>  
>>>      /* this is an eventfd for a particular guest VM */
>>>      IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
>>> -                    guest_max_eventfd, incoming_fd);
>>> -
>>> event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
>>> -                           incoming_fd);
>>> -
>>> -    /* increment count for particular guest */
>>> -    s->peers[incoming_posn].nb_eventfds++;
>>> +                    nth_eventfd, incoming_fd);
>>> +    event_notifier_init_fd(&peer->eventfds[nth_eventfd], incoming_fd);
>>>  
>>>      if (incoming_posn == s->vm_id) {
>>> -        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
>>> -                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
>>> -                   guest_max_eventfd);
>>> +        s->eventfd_chr[nth_eventfd] = create_eventfd_chr_device(s,
>>> +                   &s->peers[s->vm_id].eventfds[nth_eventfd],
>>> +                   nth_eventfd);
>>>      }
>>>  
>>>      if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
>>> -        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
>>> +        ivshmem_add_eventfd(s, incoming_posn, nth_eventfd);
>>>      }
>>>  }
>>>  
>>>
>>
>> Ciao
>> C.
>>
>>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open
  2015-09-22 14:59     ` Marc-André Lureau
@ 2015-09-23 12:20       ` Claudio Fontana
  0 siblings, 0 replies; 109+ messages in thread
From: Claudio Fontana @ 2015-09-23 12:20 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: marcandre lureau, drjones, cam, qemu-devel, stefanha

On 22.09.2015 16:59, Marc-André Lureau wrote:
> Hi
> 
> ----- Original Message -----
>> On 15.09.2015 18:07, marcandre.lureau@redhat.com wrote:
>>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>
>>> Remove shm_fd from device state, closing it as early as possible to avoid
>>> leaks.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  hw/misc/ivshmem.c | 14 +++++---------
>>>  1 file changed, 5 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
>>> index 4adcac5..f9ac955 100644
>>> --- a/hw/misc/ivshmem.c
>>> +++ b/hw/misc/ivshmem.c
>>> @@ -88,7 +88,6 @@ typedef struct IVShmemState {
>>>      MemoryRegion ivshmem;
>>>      uint64_t ivshmem_size; /* size of shared memory region */
>>>      uint32_t ivshmem_64bit;
>>> -    int shm_fd; /* shared memory file descriptor */
>>
>> is it in no way useful during debugging to have access to this field?
>> Or is it easily available elsewhere?
> 
> How would it be useful during debugging? Once the memory is mapped there isn't much you can do with it, it's just keeping a fd open, isn't it?

all right.

> 
>>
>> Ciao C.
>>
>>>  
>>>      Peer *peers;
>>>      int nb_peers; /* how many peers we have space for */
>>> @@ -235,7 +234,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr
>>> addr,
>>>  
>>>          case IVPOSITION:
>>>              /* return my VM ID if the memory is mapped */
>>> -            if (s->shm_fd >= 0) {
>>> +            if (memory_region_is_mapped(&s->ivshmem)) {
>>>                  ret = s->vm_id;
>>>              } else {
>>>                  ret = -1;
>>> @@ -356,8 +355,6 @@ static int create_shared_memory_BAR(IVShmemState *s,
>>> int fd, uint8_t attr,
>>>          return -1;
>>>      }
>>>  
>>> -    s->shm_fd = fd;
>>> -
>>>      memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
>>>                                 s->ivshmem_size, ptr);
>>>      vmstate_register_ram(&s->ivshmem, DEVICE(s));
>>> @@ -535,7 +532,7 @@ static void ivshmem_read(void *opaque, const uint8_t
>>> *buf, int size)
>>>      if (incoming_posn == -1) {
>>>          void * map_ptr;
>>>  
>>> -        if (s->shm_fd >= 0) {
>>> +        if (memory_region_is_mapped(&s->ivshmem)) {
>>>              error_report("shm already initialized");
>>>              close(incoming_fd);
>>>              return;
>>> @@ -564,9 +561,7 @@ static void ivshmem_read(void *opaque, const uint8_t
>>> *buf, int size)
>>>  
>>>          memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
>>>  
>>> -        /* only store the fd if it is successfully mapped */
>>> -        s->shm_fd = incoming_fd;
>>> -
>>> +        close(incoming_fd);
>>>          return;
>>>      }
>>>  
>>> @@ -827,6 +822,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error
>>> **errp)
>>>          }
>>>  
>>>          create_shared_memory_BAR(s, fd, attr, errp);
>>> +        close(fd);
>>>      }
>>>  }
>>>  
>>> @@ -842,7 +838,7 @@ static void pci_ivshmem_exit(PCIDevice *dev)
>>>          error_free(s->migration_blocker);
>>>      }
>>>  
>>> -    if (s->shm_fd >= 0) {
>>> +    if (memory_region_is_mapped(&s->ivshmem)) {
>>>          void *addr = memory_region_get_ram_ptr(&s->ivshmem);
>>>  
>>>          vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
>>>

^ permalink raw reply	[flat|nested] 109+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages
  2015-09-23 12:10       ` Claudio Fontana
@ 2015-09-23 15:45         ` Marc-André Lureau
  0 siblings, 0 replies; 109+ messages in thread
From: Marc-André Lureau @ 2015-09-23 15:45 UTC (permalink / raw)
  To: Claudio Fontana; +Cc: Andrew Jones, cam, QEMU, Stefan Hajnoczi

Hi

On Wed, Sep 23, 2015 at 2:10 PM, Claudio Fontana
<claudio.fontana@huawei.com> wrote:
>> Let's change it for IVSHMEM_DPRINTF("use msix, present: %d\n",
>> msix_present(d)); ok?
>>
>
> what about something like
>
> IVSHMEM_DPRINTF("%susing MSI-X\n", msix_present(d) ? "" : "not ");
>
> or just
>
> if (!msix_present(d) {
>    IVSHMEM_DPRINTF("not using MSI-X");
>    return;
> }
>
> IVSHMEM_DPRINTF("using MSI-X");

I find it more confusing. ivshmem_use_msix() is the place where
msix_vector_use() is called. However, ivshmem_has_feature(s,
IVSHMEM_MSI) may be true or not. Only MSIX is effectively enabled if
the guest has MSIX, which is what msix_present(d) says. So I would
rather keep the last debug Iine I proposed (again this is just for
debugging, when compiling with IVSHMEM_DEBUG, not a message that a
user will ever see).

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 109+ messages in thread

end of thread, other threads:[~2015-09-23 15:45 UTC | newest]

Thread overview: 109+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-15 16:07 [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 01/46] char: add qemu_chr_free() marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 02/46] msix: add VMSTATE_MSIX_TEST marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 03/46] ivhsmem: read do not accept more than sizeof(long) marcandre.lureau
2015-09-16  9:27   ` Claudio Fontana
2015-09-16  9:33     ` Marc-André Lureau
2015-09-16 11:27       ` Claudio Fontana
2015-09-16 12:03         ` Marc-André Lureau
2015-09-16 12:51         ` Paolo Bonzini
2015-09-16 13:05           ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 04/46] ivshmem: fix number of bytes to push to fifo marcandre.lureau
2015-09-16  9:28   ` Claudio Fontana
2015-09-23 10:17     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 05/46] ivshmem: factor out the incoming fifo handling marcandre.lureau
2015-09-22 14:01   ` Claudio Fontana
2015-09-23 10:18     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 06/46] ivshmem: remove unnecessary dup() marcandre.lureau
2015-09-22 14:06   ` Claudio Fontana
2015-09-22 15:29     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 07/46] ivshmem: remove superflous ivshmem_attr field marcandre.lureau
2015-09-16  9:25   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 08/46] ivshmem: remove useless doorbell field marcandre.lureau
2015-09-22 13:50   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 09/46] ivshmem: more qdev conversion marcandre.lureau
2015-09-22 14:00   ` Claudio Fontana
2015-09-23 10:22     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 10/46] ivshmem: remove last exit(1) marcandre.lureau
2015-09-22 13:55   ` Claudio Fontana
2015-09-22 13:58     ` Claudio Fontana
2015-09-22 14:00     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 11/46] ivshmem: limit maximum number of peers to G_MAXUINT16 marcandre.lureau
2015-09-22 14:09   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 12/46] ivshmem: simplify around increase_dynamic_storage() marcandre.lureau
2015-09-22 14:10   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 13/46] ivshmem: allocate eventfds in resize_peers() marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 14/46] ivshmem: remove useless ivshmem_update_irq() val argument marcandre.lureau
2015-09-22 14:13   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 15/46] ivshmem: initialize max_peer to -1 marcandre.lureau
2015-09-22 14:13   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 16/46] ivshmem: remove max_peer field marcandre.lureau
2015-09-16  9:39   ` Claudio Fontana
2015-09-16  9:40     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 17/46] ivshmem: improve debug messages marcandre.lureau
2015-09-22 14:23   ` Claudio Fontana
2015-09-23 10:29     ` Marc-André Lureau
2015-09-23 12:10       ` Claudio Fontana
2015-09-23 15:45         ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 18/46] ivshmem: improve error marcandre.lureau
2015-09-22 14:26   ` Claudio Fontana
2015-09-23 10:30     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 19/46] ivshmem: print error on invalid peer id marcandre.lureau
2015-09-22 14:27   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 20/46] ivshmem: simplify a bit the code marcandre.lureau
2015-09-22 14:32   ` Claudio Fontana
2015-09-22 14:56     ` Marc-André Lureau
2015-09-23 12:18       ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 21/46] ivshmem: use common return marcandre.lureau
2015-09-16 11:30   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 22/46] ivshmem: use common is_power_of_2() marcandre.lureau
2015-09-16 11:31   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 23/46] ivshmem: migrate with VMStateDescription marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 24/46] ivshmem: shmfd can be 0 marcandre.lureau
2015-09-16 11:33   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 25/46] ivshmem: check shm isn't already initialized marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 26/46] ivshmem: add device description marcandre.lureau
2015-09-16 11:38   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 27/46] ivshmem: fix pci_ivshmem_exit() marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 28/46] ivshmem: replace 'guest' for 'peer' appropriately marcandre.lureau
2015-09-16 11:44   ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 29/46] ivshmem: error on too many eventfd received marcandre.lureau
2015-09-16 12:14   ` Claudio Fontana
2015-09-23 10:47     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 30/46] ivshmem: reset mask on device reset marcandre.lureau
2015-09-16 12:15   ` Claudio Fontana
2015-09-23 10:48     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 31/46] contrib: add ivshmem client and server marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 32/46] ivshmem-client: check the number of vectors marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 33/46] ivshmem-server: use a uint16 for client ID marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 34/46] ivshmem-server: fix hugetlbfs support marcandre.lureau
2015-09-16 16:07   ` Vladimir Sementsov-Ogievskiy
2015-09-16 16:14     ` Marc-André Lureau
2015-09-17  8:52       ` Vladimir Sementsov-Ogievskiy
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 35/46] docs: update ivshmem device spec marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 36/46] ivshmem: add check on protocol version in QEMU marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 37/46] contrib: remove unnecessary strdup() marcandre.lureau
2015-09-17  9:01   ` Vladimir Sementsov-Ogievskiy
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 38/46] msix: implement pba write (but read-only) marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 39/46] qtest: add qtest_add_abrt_handler() marcandre.lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 40/46] tests: add ivshmem qtest marcandre.lureau
2015-09-22 14:44   ` Claudio Fontana
2015-09-23 11:24     ` Marc-André Lureau
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 41/46] ivshmem: do not keep shm_fd open marcandre.lureau
2015-09-22 14:36   ` Claudio Fontana
2015-09-22 14:59     ` Marc-André Lureau
2015-09-23 12:20       ` Claudio Fontana
2015-09-15 16:07 ` [Qemu-devel] [PATCH v3 42/46] ivshmem: make ivshmem_get_size() more generic marcandre.lureau
2015-09-16 15:23   ` Vladimir Sementsov-Ogievskiy
2015-09-16 15:24   ` Vladimir Sementsov-Ogievskiy
2015-09-16 15:26     ` Marc-André Lureau
2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 43/46] ivshmem: add hostmem backend marcandre.lureau
2015-09-22 14:49   ` Claudio Fontana
2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 44/46] ivshmem: remove EventfdEntry.vector marcandre.lureau
2015-09-22 14:59   ` Claudio Fontana
2015-09-22 15:18     ` Marc-André Lureau
2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 45/46] ivshmem: rename MSI eventfd_table marcandre.lureau
2015-09-15 16:08 ` [Qemu-devel] [PATCH v3 46/46] ivshmem: use kvm irqfd for msi notifications marcandre.lureau
2015-09-16 12:47 ` [Qemu-devel] [PATCH v3 00/46] ivshmem improvements (please review) Claudio Fontana
2015-09-16 16:52 ` Vladimir Sementsov-Ogievskiy
2015-09-16 20:34   ` Marc-André Lureau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.