All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS
@ 2016-01-12 11:43 Daniel P. Berrange
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
                   ` (23 more replies)
  0 siblings, 24 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

This is a formal posting of patches that were previously
previewed at:

  FYI: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg00829.html

The primary goal of this series of patches is to support TLS on the
migration data channel. The bulk of the work in this series though,
is converting the various QEMUFile implementations to be baed on the
new QIOChannel framework.

At the end of this current series there is just one remaining impl
of QEMUFileOps that is not based on QIOChannel - the one in savevm.c
that is using BlockDriverState. It would be possible to create a
QIOChannel wrapper around BlockDriverState too, at which point all
QEMUFile impls would be QIOChannel based. This would then let us
cut out the QEMUFileOps driver callbacks entirely and thus simply
code even more. This patch series is already too large, so I left
that for now.

The first 6 patchs are some basic clean ups to QEMUFile code

The 7th patch introduces the QIOChannel based QEMUFile impl

Patches 8-14 convert the various migration protocols to use
the QIOChannel based QEMUFile impl.

Patches 15-18 remove the now unused QEMUFile impls that do
not use QIOChanel

Patches 19, 21 and 22 does some more cleanup

Patch 20 achieves the original stated primary goal of adding
TLS encryption to the TCP migration backend.

Overall we have a net win of deleting 500 lines of code,
despite adding more features, which is always nice.

I testing unix, tcp, exec migrations. I don't have the ability
to test RDMA migration, and that's the patch I'm also least
confident about code quality of, so would appreciated some
independant testing of that one in particular.


Daniel P. Berrange (22):
  s390: use FILE instead of QEMUFile for creating text file
  migration: remove use of qemu_bufopen from vmstate tests
  migration: ensure qemu_fflush() always writes full data amount
  migration: split migration hooks out of QEMUFileOps
  migration: introduce set_blocking function in QEMUFileOps
  migration: force QEMUFile to blocking mode for outgoing migration
  migration: introduce a new QEMUFile impl based on QIOChannel
  migration: convert post-copy to use QIOChannelBuffer
  migration: convert unix socket protocol to use QIOChannel
  migration: convert tcp socket protocol to use QIOChannel
  migration: convert fd socket protocol to use QIOChannel
  migration: convert exec socket protocol to use QIOChannel
  migration: convert RDMA to use QIOChannel interface
  migration: convert savevm to use QIOChannel for writing to files
  migration: delete QEMUFile buffer implementation
  migration: delete QEMUSizedBuffer struct
  migration: delete QEMUFile sockets implementation
  migration: delete QEMUFile stdio implementation
  migration: move definition of struct QEMUFile back into qemu-file.c
  migration: support TLS encryption with TCP migration backend
  migration: remove support for non-iovec based write handlers
  migration: remove qemu_get_fd method from QEMUFile

 docs/migration.txt             |   4 +-
 hw/s390x/s390-skeys.c          |  19 +-
 include/migration/qemu-file.h  |  57 ++---
 include/qemu/typedefs.h        |   1 -
 include/sysemu/sysemu.h        |   2 +-
 migration/Makefile.objs        |   6 +-
 migration/exec.c               |  48 +++--
 migration/fd.c                 |  57 +++--
 migration/migration.c          |  24 +--
 migration/qemu-file-buf.c      | 463 -----------------------------------------
 migration/qemu-file-channel.c  | 201 ++++++++++++++++++
 migration/qemu-file-internal.h |  53 -----
 migration/qemu-file-stdio.c    | 195 -----------------
 migration/qemu-file-unix.c     | 324 ----------------------------
 migration/qemu-file.c          | 110 +++++-----
 migration/rdma.c               | 256 ++++++++++++++---------
 migration/savevm.c             |  57 ++---
 migration/tcp.c                | 372 +++++++++++++++++++++++++++++----
 migration/unix.c               | 103 +++++----
 qemu-options.hx                |   7 +-
 tests/Makefile                 |   6 +-
 tests/test-vmstate.c           |  55 ++---
 22 files changed, 975 insertions(+), 1445 deletions(-)
 delete mode 100644 migration/qemu-file-buf.c
 create mode 100644 migration/qemu-file-channel.c
 delete mode 100644 migration/qemu-file-internal.h
 delete mode 100644 migration/qemu-file-stdio.c
 delete mode 100644 migration/qemu-file-unix.c

-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
@ 2016-01-12 11:43 ` Daniel P. Berrange
  2016-01-12 11:58   ` Cornelia Huck
  2016-02-12 17:19   ` Dr. David Alan Gilbert
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests Daniel P. Berrange
                   ` (22 subsequent siblings)
  23 siblings, 2 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

The s390 skeys monitor command needs to write out a plain text
file. Currently it is using the QEMUFile class for this. There
is no real benefit to this, and the downside is that it needs to
snprintf via an intermediate buffer. Switching to regular FILE
objects simplifies the code.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 hw/s390x/s390-skeys.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 539ef6d..637ccf5 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -45,15 +45,11 @@ void s390_skeys_init(void)
     qdev_init_nofail(DEVICE(obj));
 }
 
-static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
+static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn,
                        uint64_t count, Error **errp)
 {
     uint64_t curpage = startgfn;
     uint64_t maxpage = curpage + count - 1;
-    const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
-                      " ch=%d, reserved=%d\n";
-    char buf[128];
-    int len;
 
     for (; curpage <= maxpage; curpage++) {
         uint8_t acc = (*keys & 0xF0) >> 4;
@@ -62,10 +58,9 @@ static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
         int ch = (*keys & 0x02);
         int res = (*keys & 0x01);
 
-        len = snprintf(buf, sizeof(buf), fmt, curpage,
-                       *keys, acc, fp, ref, ch, res);
-        assert(len < sizeof(buf));
-        qemu_put_buffer(f, (uint8_t *)buf, len);
+        fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
+                " ch=%d, reserved=%d\n",
+                curpage, *keys, acc, fp, ref, ch, res);
         keys++;
     }
 }
@@ -115,7 +110,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
     vaddr cur_gfn = 0;
     uint8_t *buf;
     int ret;
-    QEMUFile *f;
+    FILE *f;
 
     /* Quick check to see if guest is using storage keys*/
     if (!skeyclass->skeys_enabled(ss)) {
@@ -124,7 +119,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
         return;
     }
 
-    f = qemu_fopen(filename, "wb");
+    f = fopen(filename, "wb");
     if (!f) {
         error_setg_file_open(errp, errno, filename);
         return;
@@ -161,7 +156,7 @@ out_free:
     error_propagate(errp, lerr);
     g_free(buf);
 out:
-    qemu_fclose(f);
+    fclose(f);
 }
 
 static void qemu_s390_skeys_init(Object *obj)
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
@ 2016-01-12 11:43 ` Daniel P. Berrange
  2016-01-28 17:45   ` Dr. David Alan Gilbert
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount Daniel P. Berrange
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Some of the test-vmstate.c test cases use a temporary file
while others use a memory buffer. To facilitate the future
removal of the qemu_bufopen() function, convert all the tests
to use a temporary file.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 tests/Makefile       |  2 +-
 tests/test-vmstate.c | 44 +++++++++++++-------------------------------
 2 files changed, 14 insertions(+), 32 deletions(-)

diff --git a/tests/Makefile b/tests/Makefile
index b7352f1..5a1b25f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -422,7 +422,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
 	hw/core/fw-path-provider.o \
 	$(test-qapi-obj-y)
 tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
-	migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \
+	migration/vmstate.o migration/qemu-file.o \
         migration/qemu-file-unix.o qjson.o \
 	$(test-qom-obj-y)
 tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 4d13bd0..0f943d5 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -43,11 +43,6 @@ void yield_until_fd_readable(int fd)
     select(fd + 1, &fds, NULL, NULL, NULL);
 }
 
-/*
- * Some tests use 'open_test_file' to work on a real fd, some use
- * an in memory file (QEMUSizedBuffer+qemu_bufopen); we could pick one
- * but this way we test both.
- */
 
 /* Duplicate temp_fd and seek to the beginning of the file */
 static QEMUFile *open_test_file(bool write)
@@ -60,20 +55,6 @@ static QEMUFile *open_test_file(bool write)
     return qemu_fdopen(fd, write ? "wb" : "rb");
 }
 
-/*
- * Check that the contents of the memory-buffered file f match
- * the given size/data.
- */
-static void check_mem_file(QEMUFile *f, void *data, size_t size)
-{
-    uint8_t *result = g_malloc(size);
-    const QEMUSizedBuffer *qsb = qemu_buf_get(f);
-    g_assert_cmpint(qsb_get_length(qsb), ==, size);
-    g_assert_cmpint(qsb_get_buffer(qsb, 0, size, result), ==, size);
-    g_assert_cmpint(memcmp(result, data, size), ==, 0);
-    g_free(result);
-}
-
 #define SUCCESS(val) \
     g_assert_cmpint((val), ==, 0)
 
@@ -391,7 +372,7 @@ static const VMStateDescription vmstate_skipping = {
 
 static void test_save_noskip(void)
 {
-    QEMUFile *fsave = qemu_bufopen("w", NULL);
+    QEMUFile *fsave = open_test_file(true);
     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
                        .skip_c_e = false };
     vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
@@ -405,13 +386,14 @@ static void test_save_noskip(void)
         0, 0, 0, 5,             /* e */
         0, 0, 0, 0, 0, 0, 0, 6, /* f */
     };
-    check_mem_file(fsave, expected, sizeof(expected));
+
     qemu_fclose(fsave);
+    compare_vmstate(expected, sizeof(expected));
 }
 
 static void test_save_skip(void)
 {
-    QEMUFile *fsave = qemu_bufopen("w", NULL);
+    QEMUFile *fsave = open_test_file(true);
     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
                        .skip_c_e = true };
     vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
@@ -423,13 +405,14 @@ static void test_save_skip(void)
         0, 0, 0, 0, 0, 0, 0, 4, /* d */
         0, 0, 0, 0, 0, 0, 0, 6, /* f */
     };
-    check_mem_file(fsave, expected, sizeof(expected));
 
     qemu_fclose(fsave);
+    compare_vmstate(expected, sizeof(expected));
 }
 
 static void test_load_noskip(void)
 {
+    QEMUFile *fsave = open_test_file(true);
     uint8_t buf[] = {
         0, 0, 0, 10,             /* a */
         0, 0, 0, 20,             /* b */
@@ -439,10 +422,10 @@ static void test_load_noskip(void)
         0, 0, 0, 0, 0, 0, 0, 60, /* f */
         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
     };
+    qemu_put_buffer(fsave, buf, sizeof(buf));
+    qemu_fclose(fsave);
 
-    QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
-    g_assert(qsb);
-    QEMUFile *loading = qemu_bufopen("r", qsb);
+    QEMUFile *loading = open_test_file(false);
     TestStruct obj = { .skip_c_e = false };
     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
     g_assert(!qemu_file_get_error(loading));
@@ -453,11 +436,11 @@ static void test_load_noskip(void)
     g_assert_cmpint(obj.e, ==, 50);
     g_assert_cmpint(obj.f, ==, 60);
     qemu_fclose(loading);
-    qsb_free(qsb);
 }
 
 static void test_load_skip(void)
 {
+    QEMUFile *fsave = open_test_file(true);
     uint8_t buf[] = {
         0, 0, 0, 10,             /* a */
         0, 0, 0, 20,             /* b */
@@ -465,10 +448,10 @@ static void test_load_skip(void)
         0, 0, 0, 0, 0, 0, 0, 60, /* f */
         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
     };
+    qemu_put_buffer(fsave, buf, sizeof(buf));
+    qemu_fclose(fsave);
 
-    QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
-    g_assert(qsb);
-    QEMUFile *loading = qemu_bufopen("r", qsb);
+    QEMUFile *loading = open_test_file(false);
     TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
     g_assert(!qemu_file_get_error(loading));
@@ -479,7 +462,6 @@ static void test_load_skip(void)
     g_assert_cmpint(obj.e, ==, 500);
     g_assert_cmpint(obj.f, ==, 60);
     qemu_fclose(loading);
-    qsb_free(qsb);
 }
 
 int main(int argc, char **argv)
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests Daniel P. Berrange
@ 2016-01-12 11:43 ` Daniel P. Berrange
  2016-01-28 17:53   ` Dr. David Alan Gilbert
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps Daniel P. Berrange
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

The QEMUFile writev_buffer / put_buffer functions are expected
to write out the full set of requested data, blocking until
complete. The qemu_fflush() caller does not expect to deal with
partial writes. Clarify the function comments and add a sanity
check to the code to catch mistaken implementations.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  6 ++++--
 migration/qemu-file.c         | 16 ++++++++++++----
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index b5d08d2..5debe8c 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -29,7 +29,8 @@
 
 /* This function writes a chunk of data to a file at the given position.
  * The pos argument can be ignored if the file is only being used for
- * streaming.  The handler should try to write all of the data it can.
+ * streaming.  The handler must write all of the data or return a negative
+ * errno value.
  */
 typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
                                         int64_t pos, size_t size);
@@ -55,7 +56,8 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
 typedef int (QEMUFileGetFD)(void *opaque);
 
 /*
- * This function writes an iovec to file.
+ * This function writes an iovec to file. The handler must write all
+ * of the data or return a negative errno value.
  */
 typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
                                            int iovcnt, int64_t pos);
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 0bbd257..f89e64e 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -107,11 +107,13 @@ bool qemu_file_is_writable(QEMUFile *f)
  * Flushes QEMUFile buffer
  *
  * If there is writev_buffer QEMUFileOps it uses it otherwise uses
- * put_buffer ops.
+ * put_buffer ops. This will flush all pending data. If data was
+ * only partially flushed, it will set an error state.
  */
 void qemu_fflush(QEMUFile *f)
 {
     ssize_t ret = 0;
+    ssize_t expect = 0;
 
     if (!qemu_file_is_writable(f)) {
         return;
@@ -119,21 +121,27 @@ void qemu_fflush(QEMUFile *f)
 
     if (f->ops->writev_buffer) {
         if (f->iovcnt > 0) {
+            expect = iov_size(f->iov, f->iovcnt);
             ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
         }
     } else {
         if (f->buf_index > 0) {
+            expect = f->buf_index;
             ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
         }
     }
+
     if (ret >= 0) {
         f->pos += ret;
     }
-    f->buf_index = 0;
-    f->iovcnt = 0;
-    if (ret < 0) {
+    /* We expect the QEMUFile write impl to send the full
+     * data set we requested, so sanity check that.
+     */
+    if (ret < 0 || ret != expect) {
         qemu_file_set_error(f, ret);
     }
+    f->buf_index = 0;
+    f->iovcnt = 0;
 }
 
 void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (2 preceding siblings ...)
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount Daniel P. Berrange
@ 2016-01-12 11:43 ` Daniel P. Berrange
  2016-01-28 17:57   ` Dr. David Alan Gilbert
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps Daniel P. Berrange
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

The QEMUFileOps struct contains the I/O subsystem callbacks
and the migration stage hooks. Split the hooks out into a
separate QEMUFileHooks struct to make it easier to refactor
the I/O side of QEMUFile without affecting the hooks.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h  | 10 +++++++---
 migration/qemu-file-internal.h |  1 +
 migration/qemu-file.c          | 24 +++++++++++++++---------
 migration/rdma.c               |  8 ++++++++
 4 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 5debe8c..ddffc6a 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -109,13 +109,16 @@ typedef struct QEMUFileOps {
     QEMUFileCloseFunc *close;
     QEMUFileGetFD *get_fd;
     QEMUFileWritevBufferFunc *writev_buffer;
+    QEMURetPathFunc *get_return_path;
+    QEMUFileShutdownFunc *shut_down;
+} QEMUFileOps;
+
+typedef struct QEMUFileHooks {
     QEMURamHookFunc *before_ram_iterate;
     QEMURamHookFunc *after_ram_iterate;
     QEMURamHookFunc *hook_ram_load;
     QEMURamSaveFunc *save_page;
-    QEMURetPathFunc *get_return_path;
-    QEMUFileShutdownFunc *shut_down;
-} QEMUFileOps;
+} QEMUFileHooks;
 
 struct QEMUSizedBuffer {
     struct iovec *iov;
@@ -130,6 +133,7 @@ QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd, const char *mode);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
 QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
+void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
 int qemu_get_fd(QEMUFile *f);
 int qemu_fclose(QEMUFile *f);
 int64_t qemu_ftell(QEMUFile *f);
diff --git a/migration/qemu-file-internal.h b/migration/qemu-file-internal.h
index d95e853..8fdfa95 100644
--- a/migration/qemu-file-internal.h
+++ b/migration/qemu-file-internal.h
@@ -33,6 +33,7 @@
 
 struct QEMUFile {
     const QEMUFileOps *ops;
+    const QEMUFileHooks *hooks;
     void *opaque;
 
     int64_t bytes_xfer;
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index f89e64e..337cb4c 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -79,6 +79,12 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
     return f;
 }
 
+
+void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
+{
+    f->hooks = hooks;
+}
+
 /*
  * Get last error for stream f
  *
@@ -148,8 +154,8 @@ void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
 {
     int ret = 0;
 
-    if (f->ops->before_ram_iterate) {
-        ret = f->ops->before_ram_iterate(f, f->opaque, flags, NULL);
+    if (f->hooks && f->hooks->before_ram_iterate) {
+        ret = f->hooks->before_ram_iterate(f, f->opaque, flags, NULL);
         if (ret < 0) {
             qemu_file_set_error(f, ret);
         }
@@ -160,8 +166,8 @@ void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
 {
     int ret = 0;
 
-    if (f->ops->after_ram_iterate) {
-        ret = f->ops->after_ram_iterate(f, f->opaque, flags, NULL);
+    if (f->hooks && f->hooks->after_ram_iterate) {
+        ret = f->hooks->after_ram_iterate(f, f->opaque, flags, NULL);
         if (ret < 0) {
             qemu_file_set_error(f, ret);
         }
@@ -172,8 +178,8 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data)
 {
     int ret = -EINVAL;
 
-    if (f->ops->hook_ram_load) {
-        ret = f->ops->hook_ram_load(f, f->opaque, flags, data);
+    if (f->hooks && f->hooks->hook_ram_load) {
+        ret = f->hooks->hook_ram_load(f, f->opaque, flags, data);
         if (ret < 0) {
             qemu_file_set_error(f, ret);
         }
@@ -192,9 +198,9 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
                              ram_addr_t offset, size_t size,
                              uint64_t *bytes_sent)
 {
-    if (f->ops->save_page) {
-        int ret = f->ops->save_page(f, f->opaque, block_offset,
-                                    offset, size, bytes_sent);
+    if (f->hooks && f->hooks->save_page) {
+        int ret = f->hooks->save_page(f, f->opaque, block_offset,
+                                      offset, size, bytes_sent);
 
         if (ret != RAM_SAVE_CONTROL_DELAYED) {
             if (bytes_sent && *bytes_sent > 0) {
diff --git a/migration/rdma.c b/migration/rdma.c
index dcabb91..bffbfaf 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -3380,12 +3380,18 @@ static const QEMUFileOps rdma_read_ops = {
     .get_buffer    = qemu_rdma_get_buffer,
     .get_fd        = qemu_rdma_get_fd,
     .close         = qemu_rdma_close,
+};
+
+static const QEMUFileHooks rdma_read_hooks = {
     .hook_ram_load = rdma_load_hook,
 };
 
 static const QEMUFileOps rdma_write_ops = {
     .put_buffer         = qemu_rdma_put_buffer,
     .close              = qemu_rdma_close,
+};
+
+static const QEMUFileHooks rdma_write_hooks = {
     .before_ram_iterate = qemu_rdma_registration_start,
     .after_ram_iterate  = qemu_rdma_registration_stop,
     .save_page          = qemu_rdma_save_page,
@@ -3404,8 +3410,10 @@ static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
 
     if (mode[0] == 'w') {
         r->file = qemu_fopen_ops(r, &rdma_write_ops);
+        qemu_file_set_hooks(r->file, &rdma_write_hooks);
     } else {
         r->file = qemu_fopen_ops(r, &rdma_read_ops);
+        qemu_file_set_hooks(r->file, &rdma_read_hooks);
     }
 
     return r->file;
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (3 preceding siblings ...)
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps Daniel P. Berrange
@ 2016-01-12 11:43 ` Daniel P. Berrange
  2016-01-28 18:00   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration Daniel P. Berrange
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Remove the assumption that every QEMUFile implementation has
a file descriptor available by introducing a new function
in QEMUFileOps to change the blocking state of a QEMUFile.

If not set, it will fallback to the original code using
the get_fd method.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  5 +++++
 migration/migration.c         |  4 +---
 migration/qemu-file.c         | 10 +++++++---
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index ddffc6a..072bb38 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -55,6 +55,10 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
  */
 typedef int (QEMUFileGetFD)(void *opaque);
 
+/* Called to change the blocking mode of the file
+ */
+typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
+
 /*
  * This function writes an iovec to file. The handler must write all
  * of the data or return a negative errno value.
@@ -108,6 +112,7 @@ typedef struct QEMUFileOps {
     QEMUFileGetBufferFunc *get_buffer;
     QEMUFileCloseFunc *close;
     QEMUFileGetFD *get_fd;
+    QEMUFileSetBlocking *set_blocking;
     QEMUFileWritevBufferFunc *writev_buffer;
     QEMURetPathFunc *get_return_path;
     QEMUFileShutdownFunc *shut_down;
diff --git a/migration/migration.c b/migration/migration.c
index c842499..c964a8d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -408,11 +408,9 @@ static void process_incoming_migration_co(void *opaque)
 void process_incoming_migration(QEMUFile *f)
 {
     Coroutine *co = qemu_coroutine_create(process_incoming_migration_co);
-    int fd = qemu_get_fd(f);
 
-    assert(fd != -1);
     migrate_decompress_threads_create();
-    qemu_set_nonblock(fd);
+    qemu_file_set_blocking(f, false);
     qemu_coroutine_enter(co, f);
 }
 
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 337cb4c..fc5977e 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -683,9 +683,13 @@ size_t qemu_get_counted_string(QEMUFile *f, char buf[256])
  */
 void qemu_file_set_blocking(QEMUFile *f, bool block)
 {
-    if (block) {
-        qemu_set_block(qemu_get_fd(f));
+    if (f->ops->set_blocking) {
+        f->ops->set_blocking(f->opaque, block);
     } else {
-        qemu_set_nonblock(qemu_get_fd(f));
+        if (block) {
+            qemu_set_block(qemu_get_fd(f));
+        } else {
+            qemu_set_nonblock(qemu_get_fd(f));
+        }
     }
 }
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (4 preceding siblings ...)
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-01-28 18:17   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel Daniel P. Berrange
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Instead of relying on the default QEMUFile I/O blocking flag
state, explicitly turn on blocking I/O for outgoing migration
since it takes place in a background thread.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/migration.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/migration/migration.c b/migration/migration.c
index c964a8d..715f069 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1732,6 +1732,7 @@ void migrate_fd_connect(MigrationState *s)
     s->expected_downtime = max_downtime/1000000;
     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
 
+    qemu_file_set_blocking(s->file, true);
     qemu_file_set_rate_limit(s->file,
                              s->bandwidth_limit / XFER_LIMIT_RATIO);
 
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (5 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 17:06   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer Daniel P. Berrange
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Introduce a new QEMUFile implementation that is based on
the QIOChannel objects. This impl is different from existing
impls in that there is no file descriptor that can be made
available, as some channels may be based on higher level
protocols such as TLS.

Although the QIOChannel based implementation can trivially
provide a bi-directional stream, initially we have separate
functions for opening input & output directions to fit with
the expectation of the current QEMUFile interface.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |   4 +
 migration/Makefile.objs       |   1 +
 migration/qemu-file-channel.c | 201 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 migration/qemu-file-channel.c

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 072bb38..cb79311 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -23,7 +23,9 @@
  */
 #ifndef QEMU_FILE_H
 #define QEMU_FILE_H 1
+#include "qemu-common.h"
 #include "exec/cpu-common.h"
+#include "io/channel.h"
 
 #include <stdint.h>
 
@@ -136,6 +138,8 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
 QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd, const char *mode);
+QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
+QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
 QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
 void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 0cac6d7..b357e2f 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,6 +1,7 @@
 common-obj-y += migration.o tcp.o
 common-obj-y += vmstate.o
 common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
+common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
 common-obj-$(CONFIG_RDMA) += rdma.o
diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
new file mode 100644
index 0000000..09a7170
--- /dev/null
+++ b/migration/qemu-file-channel.c
@@ -0,0 +1,201 @@
+/*
+ * QEMUFile backend for QIOChannel objects
+ *
+ * Copyright (c) 2015 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "migration/qemu-file.h"
+#include "io/channel-socket.h"
+#include "qemu/iov.h"
+
+
+/**
+ * @skip: number of bytes to advance head of @iov
+ * @iov: pointer to iov array, updated on success
+ * @iovcnt: number of elements in @iov, updated on success
+ * @oldiov: pointer single element to hold old info from @iov
+ *
+ * This will update @iov so that its head is advanced
+ * by @skip bytes. To do this, zero or more complete
+ * elements of @iov will be skipped over. The new head
+ * of @iov will then have its base & len updated to
+ * skip the remaining number of bytes. @oldiov will
+ * hold the original data from the new head of @iov.
+ */
+static void channel_skip_iov(size_t skip,
+                             struct iovec **iov,
+                             int *iovcnt,
+                             struct iovec *oldiov)
+{
+    ssize_t done = 0;
+    size_t i;
+    for (i = 0; i < *iovcnt; i++) {
+        if ((*iov)[i].iov_len <= skip) {
+            done += (*iov)[i].iov_len;
+            skip -= (*iov)[i].iov_len;
+        } else {
+            done += skip;
+            oldiov->iov_base = (*iov)[i].iov_base;
+            oldiov->iov_len = (*iov)[i].iov_len;
+            (*iov)[i].iov_len -= skip;
+            (*iov)[i].iov_base += skip;
+            *iov = *iov + i;
+            *iovcnt = *iovcnt - i;
+            break;
+        }
+    }
+}
+
+static ssize_t channel_writev_buffer(void *opaque,
+                                     struct iovec *iov,
+                                     int iovcnt,
+                                     int64_t pos)
+{
+    QIOChannel *ioc = QIO_CHANNEL(opaque);
+    ssize_t done = 0;
+    ssize_t want = iov_size(iov, iovcnt);
+    struct iovec oldiov = { NULL, 0 };
+
+    while (done < want) {
+        ssize_t len;
+        struct iovec *cur = iov;
+        int curcnt = iovcnt;
+
+        channel_skip_iov(done, &cur, &curcnt, &oldiov);
+
+        len = qio_channel_writev(ioc, cur, curcnt, NULL);
+        if (oldiov.iov_base) {
+            /* Restore original caller's info in @iov */
+            cur[0].iov_base = oldiov.iov_base;
+            cur[0].iov_len = oldiov.iov_len;
+            oldiov.iov_base = NULL;
+            oldiov.iov_len = 0;
+        }
+        if (len == QIO_CHANNEL_ERR_BLOCK) {
+            qio_channel_wait(ioc, G_IO_OUT);
+            continue;
+        }
+        if (len < 0) {
+            /* XXX handle Error objects */
+            return -EIO;
+        }
+
+        done += len;
+    }
+    return done;
+}
+
+
+static ssize_t channel_get_buffer(void *opaque,
+                                  uint8_t *buf,
+                                  int64_t pos,
+                                  size_t size)
+{
+    QIOChannel *ioc = QIO_CHANNEL(opaque);
+    ssize_t ret;
+
+ reread:
+    ret = qio_channel_read(ioc, (char *)buf, size, NULL);
+    if (ret < 0) {
+        if (ret == QIO_CHANNEL_ERR_BLOCK) {
+            qio_channel_yield(ioc, G_IO_IN);
+            goto reread;
+        } else {
+            /* XXX handle Error * object */
+            return -EIO;
+        }
+    }
+    return ret;
+}
+
+
+static int channel_close(void *opaque)
+{
+    QIOChannel *ioc = QIO_CHANNEL(opaque);
+    qio_channel_close(ioc, NULL);
+    object_unref(OBJECT(ioc));
+    return 0;
+}
+
+
+static int channel_shutdown(void *opaque,
+                            bool rd,
+                            bool wr)
+{
+    QIOChannel *ioc = QIO_CHANNEL(opaque);
+
+    if (qio_channel_has_feature(ioc,
+                                QIO_CHANNEL_FEATURE_SHUTDOWN)) {
+        QIOChannelShutdown mode;
+        if (rd && wr) {
+            mode = QIO_CHANNEL_SHUTDOWN_BOTH;
+        } else if (rd) {
+            mode = QIO_CHANNEL_SHUTDOWN_READ;
+        } else {
+            mode = QIO_CHANNEL_SHUTDOWN_WRITE;
+        }
+        if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
+            /* XXX handler Error * object */
+            return -EIO;
+        }
+    }
+    return 0;
+}
+
+
+static int channel_set_blocking(void *opaque,
+                                bool enabled)
+{
+    QIOChannel *ioc = QIO_CHANNEL(opaque);
+
+    if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+
+static const QEMUFileOps channel_input_ops = {
+    .get_buffer = channel_get_buffer,
+    .close = channel_close,
+    .shut_down = channel_shutdown,
+    .set_blocking = channel_set_blocking,
+};
+
+
+static const QEMUFileOps channel_output_ops = {
+    .writev_buffer = channel_writev_buffer,
+    .close = channel_close,
+    .shut_down = channel_shutdown,
+    .set_blocking = channel_set_blocking,
+};
+
+
+QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
+{
+    object_ref(OBJECT(ioc));
+    return qemu_fopen_ops(ioc, &channel_input_ops);
+}
+
+QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
+{
+    object_ref(OBJECT(ioc));
+    return qemu_fopen_ops(ioc, &channel_output_ops);
+}
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (6 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-01-25 19:38   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel Daniel P. Berrange
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

The post-copy code does some I/O to/from an intermediate
in-memory buffer rather than direct to the underlying
I/O channel. Switch this code to use QIOChannelBuffer
instead of QEMUSizedBuffer.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 docs/migration.txt      |  4 ++--
 include/sysemu/sysemu.h |  2 +-
 migration/migration.c   | 15 +++++++--------
 migration/savevm.c      | 41 +++++++++++++----------------------------
 4 files changed, 23 insertions(+), 39 deletions(-)

diff --git a/docs/migration.txt b/docs/migration.txt
index fda8d61..11703de 100644
--- a/docs/migration.txt
+++ b/docs/migration.txt
@@ -403,8 +403,8 @@ listen thread:                     --- page -- page -- page -- page -- page --
 
 On receipt of CMD_PACKAGED (1)
    All the data associated with the package - the ( ... ) section in the
-diagram - is read into memory (into a QEMUSizedBuffer), and the main thread
-recurses into qemu_loadvm_state_main to process the contents of the package (2)
+diagram - is read into memory, and the main thread recurses into
+qemu_loadvm_state_main to process the contents of the package (2)
 which contains commands (3,6) and devices (4...)
 
 On receipt of 'postcopy listen' - 3 -(i.e. the 1st command in the package)
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 3bb8897..0f59912 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -120,7 +120,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
                               uint16_t len, uint8_t *data);
 void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
 void qemu_savevm_send_open_return_path(QEMUFile *f);
-int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
+int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len);
 void qemu_savevm_send_postcopy_advise(QEMUFile *f);
 void qemu_savevm_send_postcopy_listen(QEMUFile *f);
 void qemu_savevm_send_postcopy_run(QEMUFile *f);
diff --git a/migration/migration.c b/migration/migration.c
index 715f069..e921b20 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -33,6 +33,7 @@
 #include "qom/cpu.h"
 #include "exec/memory.h"
 #include "exec/address-spaces.h"
+#include "io/channel-buffer.h"
 
 #define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
 
@@ -1401,7 +1402,8 @@ static int await_return_path_close_on_source(MigrationState *ms)
 static int postcopy_start(MigrationState *ms, bool *old_vm_running)
 {
     int ret;
-    const QEMUSizedBuffer *qsb;
+    QIOChannelBuffer *bioc;
+    QEMUFile *fb;
     int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
     migrate_set_state(ms, MIGRATION_STATUS_ACTIVE,
                       MIGRATION_STATUS_POSTCOPY_ACTIVE);
@@ -1456,11 +1458,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
      * So we wrap the device state up in a package with a length at the start;
      * to do this we use a qemu_buf to hold the whole of the device state.
      */
-    QEMUFile *fb = qemu_bufopen("w", NULL);
-    if (!fb) {
-        error_report("Failed to create buffered file");
-        goto fail;
-    }
+    bioc = qio_channel_buffer_new(4096);
+    fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc));
+    object_unref(OBJECT(bioc));
 
     /*
      * Make sure the receiver can get incoming pages before we send the rest
@@ -1474,10 +1474,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
     qemu_savevm_send_postcopy_run(fb);
 
     /* <><> end of stuff going into the package */
-    qsb = qemu_buf_get(fb);
 
     /* Now send that blob */
-    if (qemu_savevm_send_packaged(ms->file, qsb)) {
+    if (qemu_savevm_send_packaged(ms->file, bioc->data, bioc->usage)) {
         goto fail_closefb;
     }
     qemu_fclose(fb);
diff --git a/migration/savevm.c b/migration/savevm.c
index 0ad1b93..f2e1880 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -50,6 +50,7 @@
 #include "qemu/iov.h"
 #include "block/snapshot.h"
 #include "block/qapi.h"
+#include "io/channel-buffer.h"
 
 
 #ifndef ETH_P_RARP
@@ -760,10 +761,8 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
  *    0 on success
  *    -ve on error
  */
-int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
+int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len)
 {
-    size_t cur_iov;
-    size_t len = qsb_get_length(qsb);
     uint32_t tmp;
 
     if (len > MAX_VM_CMD_PACKAGED_SIZE) {
@@ -777,18 +776,7 @@ int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
     trace_qemu_savevm_send_packaged();
     qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
 
-    /* all the data follows (concatinating the iov's) */
-    for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
-        /* The iov entries are partially filled */
-        size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
-        len -= towrite;
-
-        if (!towrite) {
-            break;
-        }
-
-        qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
-    }
+    qemu_put_buffer(f, (const uint8_t *)buf, len);
 
     return 0;
 }
@@ -1548,9 +1536,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
 static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
 {
     int ret;
-    uint8_t *buffer;
     uint32_t length;
-    QEMUSizedBuffer *qsb;
+    QIOChannelBuffer *bioc;
 
     length = qemu_get_be32(mis->from_src_file);
     trace_loadvm_handle_cmd_packaged(length);
@@ -1559,28 +1546,26 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
         error_report("Unreasonably large packaged state: %u", length);
         return -1;
     }
-    buffer = g_malloc0(length);
-    ret = qemu_get_buffer(mis->from_src_file, buffer, (int)length);
+
+    bioc = qio_channel_buffer_new(length);
+    ret = qemu_get_buffer(mis->from_src_file,
+                          (uint8_t *)bioc->data,
+                          (int)length);
     if (ret != length) {
-        g_free(buffer);
+        object_unref(OBJECT(bioc));
         error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%d\n",
                 ret, length);
         return (ret < 0) ? ret : -EAGAIN;
     }
+    bioc->usage += length;
     trace_loadvm_handle_cmd_packaged_received(ret);
 
-    /* Setup a dummy QEMUFile that actually reads from the buffer */
-    qsb = qsb_create(buffer, length);
-    g_free(buffer); /* Because qsb_create copies */
-    if (!qsb) {
-        error_report("Unable to create qsb");
-    }
-    QEMUFile *packf = qemu_bufopen("r", qsb);
+    QEMUFile *packf = qemu_fopen_channel_input(QIO_CHANNEL(bioc));
 
     ret = qemu_loadvm_state_main(packf, mis);
     trace_loadvm_handle_cmd_packaged_main(ret);
     qemu_fclose(packf);
-    qsb_free(qsb);
+    object_unref(OBJECT(bioc));
 
     return ret;
 }
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (7 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 18:02   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 10/22] migration: convert tcp " Daniel P. Berrange
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Convert the unix socket migration protocol driver to use
QIOChannel and QEMUFileChannel, instead of plain sockets
APIs. It can be unconditionally built, since the socket
impl of QIOChannel will report a suitable error on platforms
where UNIX sockets are unavailable.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/Makefile.objs |   4 +-
 migration/migration.c   |   4 ++
 migration/unix.c        | 103 +++++++++++++++++++++++++++++++-----------------
 3 files changed, 72 insertions(+), 39 deletions(-)

diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index b357e2f..a5f8a03 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,11 +1,11 @@
-common-obj-y += migration.o tcp.o
+common-obj-y += migration.o tcp.o unix.o
 common-obj-y += vmstate.o
 common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
 common-obj-$(CONFIG_RDMA) += rdma.o
-common-obj-$(CONFIG_POSIX) += exec.o unix.o fd.o
+common-obj-$(CONFIG_POSIX) += exec.o fd.o
 
 common-obj-y += block.o
 
diff --git a/migration/migration.c b/migration/migration.c
index e921b20..1c5f12e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -312,8 +312,10 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
 #if !defined(WIN32)
     } else if (strstart(uri, "exec:", &p)) {
         exec_start_incoming_migration(p, errp);
+#endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_incoming_migration(p, errp);
+#if !defined(WIN32)
     } else if (strstart(uri, "fd:", &p)) {
         fd_start_incoming_migration(p, errp);
 #endif
@@ -1017,8 +1019,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 #if !defined(WIN32)
     } else if (strstart(uri, "exec:", &p)) {
         exec_start_outgoing_migration(s, p, &local_err);
+#endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_outgoing_migration(s, p, &local_err);
+#if !defined(WIN32)
     } else if (strstart(uri, "fd:", &p)) {
         fd_start_outgoing_migration(s, p, &local_err);
 #endif
diff --git a/migration/unix.c b/migration/unix.c
index b591813..4674640 100644
--- a/migration/unix.c
+++ b/migration/unix.c
@@ -1,10 +1,11 @@
 /*
  * QEMU live migration via Unix Domain Sockets
  *
- * Copyright Red Hat, Inc. 2009
+ * Copyright Red Hat, Inc. 2009-2015
  *
  * Authors:
  *  Chris Lalancette <clalance@redhat.com>
+ *  Daniel P. Berrange <berrange@redhat.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
@@ -17,11 +18,9 @@
 
 #include "qemu-common.h"
 #include "qemu/error-report.h"
-#include "qemu/sockets.h"
-#include "qemu/main-loop.h"
 #include "migration/migration.h"
 #include "migration/qemu-file.h"
-#include "block/block.h"
+#include "io/channel-socket.h"
 
 //#define DEBUG_MIGRATION_UNIX
 
@@ -33,71 +32,101 @@
     do { } while (0)
 #endif
 
-static void unix_wait_for_connect(int fd, Error *err, void *opaque)
+
+static SocketAddress *unix_build_address(const char *path)
+{
+    SocketAddress *saddr;
+
+    saddr = g_new0(SocketAddress, 1);
+    saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+    saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+    saddr->u.q_unix->path = g_strdup(path);
+
+    return saddr;
+}
+
+
+static void unix_outgoing_migration(Object *src,
+                                    Error *err,
+                                    gpointer opaque)
 {
     MigrationState *s = opaque;
+    QIOChannel *sioc = QIO_CHANNEL(src);
 
-    if (fd < 0) {
+    if (err) {
         DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
         s->file = NULL;
         migrate_fd_error(s);
     } else {
         DPRINTF("migrate connect success\n");
-        s->file = qemu_fopen_socket(fd, "wb");
+        s->file = qemu_fopen_channel_output(sioc);
         migrate_fd_connect(s);
     }
+    object_unref(src);
 }
 
+
 void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp)
 {
-    unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
+    SocketAddress *saddr = unix_build_address(path);
+    QIOChannelSocket *sioc;
+    sioc = qio_channel_socket_new();
+    qio_channel_socket_connect_async(sioc,
+                                     saddr,
+                                     unix_outgoing_migration,
+                                     s,
+                                     NULL);
+    qapi_free_SocketAddress(saddr);
 }
 
-static void unix_accept_incoming_migration(void *opaque)
+
+static gboolean unix_accept_incoming_migration(QIOChannel *ioc,
+                                               GIOCondition condition,
+                                               gpointer opaque)
 {
-    struct sockaddr_un addr;
-    socklen_t addrlen = sizeof(addr);
-    int s = (intptr_t)opaque;
     QEMUFile *f;
-    int c, err;
-
-    do {
-        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
-        err = errno;
-    } while (c < 0 && err == EINTR);
-    qemu_set_fd_handler(s, NULL, NULL, NULL);
-    close(s);
+    QIOChannelSocket *cioc;
+    Error *err = NULL;
 
-    DPRINTF("accepted migration\n");
-
-    if (c < 0) {
+    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+                                     &err);
+    if (!cioc) {
         error_report("could not accept migration connection (%s)",
-                     strerror(err));
-        return;
-    }
-
-    f = qemu_fopen_socket(c, "rb");
-    if (f == NULL) {
-        error_report("could not qemu_fopen socket");
+                     error_get_pretty(err));
         goto out;
     }
 
+    DPRINTF("accepted migration\n");
+
+    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
+    object_unref(OBJECT(cioc));
+
     process_incoming_migration(f);
-    return;
 
 out:
-    close(c);
+    /* Close listening socket as its no longer needed */
+    qio_channel_close(ioc, NULL);
+    return FALSE;
 }
 
+
 void unix_start_incoming_migration(const char *path, Error **errp)
 {
-    int s;
+    SocketAddress *saddr = unix_build_address(path);
+    QIOChannelSocket *listen_ioc;
 
-    s = unix_listen(path, NULL, 0, errp);
-    if (s < 0) {
+    listen_ioc = qio_channel_socket_new();
+    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
+        object_unref(OBJECT(listen_ioc));
+        qapi_free_SocketAddress(saddr);
         return;
     }
 
-    qemu_set_fd_handler(s, unix_accept_incoming_migration, NULL,
-                        (void *)(intptr_t)s);
+    qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
+                          G_IO_IN,
+                          unix_accept_incoming_migration,
+                          listen_ioc,
+                          (GDestroyNotify)object_unref);
+
+    qapi_free_SocketAddress(saddr);
 }
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 10/22] migration: convert tcp socket protocol to use QIOChannel
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (8 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 18:19   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 11/22] migration: convert fd " Daniel P. Berrange
                   ` (13 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Convert the tcp socket migration protocol driver to use
QIOChannel and QEMUFileChannel, instead of plain sockets
APIs.

While this now looks pretty similar to the migration/unix.c
file from the previous patch, it was decided not to merge
the two, because when TLS is added to the TCP impl later,
this file diverge from unix.c once again.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/tcp.c | 119 ++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 82 insertions(+), 37 deletions(-)

diff --git a/migration/tcp.c b/migration/tcp.c
index ae89172..ac73977 100644
--- a/migration/tcp.c
+++ b/migration/tcp.c
@@ -2,9 +2,11 @@
  * QEMU live migration
  *
  * Copyright IBM, Corp. 2008
+ * Copyright Red Hat, Inc. 2015
  *
  * Authors:
  *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Daniel P. Berrange <berrange@redhat.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
@@ -17,11 +19,9 @@
 
 #include "qemu-common.h"
 #include "qemu/error-report.h"
-#include "qemu/sockets.h"
 #include "migration/migration.h"
 #include "migration/qemu-file.h"
-#include "block/block.h"
-#include "qemu/main-loop.h"
+#include "io/channel-socket.h"
 
 //#define DEBUG_MIGRATION_TCP
 
@@ -33,71 +33,116 @@
     do { } while (0)
 #endif
 
-static void tcp_wait_for_connect(int fd, Error *err, void *opaque)
+
+static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
+{
+    InetSocketAddress *iaddr = inet_parse(host_port, errp);
+    SocketAddress *saddr;
+
+    if (!iaddr) {
+        return NULL;
+    }
+
+    saddr = g_new0(SocketAddress, 1);
+    saddr->type = SOCKET_ADDRESS_KIND_INET;
+    saddr->u.inet = iaddr;
+
+    return saddr;
+}
+
+
+static void tcp_outgoing_migration(Object *src,
+                                   Error *err,
+                                   gpointer opaque)
 {
     MigrationState *s = opaque;
+    QIOChannel *sioc = QIO_CHANNEL(src);
 
-    if (fd < 0) {
+    if (err) {
         DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
         s->file = NULL;
         migrate_fd_error(s);
     } else {
         DPRINTF("migrate connect success\n");
-        s->file = qemu_fopen_socket(fd, "wb");
+        s->file = qemu_fopen_channel_output(sioc);
         migrate_fd_connect(s);
     }
+    object_unref(src);
 }
 
-void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
+
+void tcp_start_outgoing_migration(MigrationState *s,
+                                  const char *host_port,
+                                  Error **errp)
 {
-    inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
+    SocketAddress *saddr = tcp_build_address(host_port, errp);
+    QIOChannelSocket *sioc;
+
+    if (!saddr) {
+        return;
+    }
+
+    sioc = qio_channel_socket_new();
+    qio_channel_socket_connect_async(sioc,
+                                     saddr,
+                                     tcp_outgoing_migration,
+                                     s,
+                                     NULL);
+    qapi_free_SocketAddress(saddr);
 }
 
-static void tcp_accept_incoming_migration(void *opaque)
+
+static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
+                                              GIOCondition condition,
+                                              gpointer opaque)
 {
-    struct sockaddr_in addr;
-    socklen_t addrlen = sizeof(addr);
-    int s = (intptr_t)opaque;
     QEMUFile *f;
-    int c, err;
+    QIOChannelSocket *cioc;
+    Error *err = NULL;
 
-    do {
-        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
-        err = socket_error();
-    } while (c < 0 && err == EINTR);
-    qemu_set_fd_handler(s, NULL, NULL, NULL);
-    closesocket(s);
-
-    DPRINTF("accepted migration\n");
-
-    if (c < 0) {
+    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+                                     &err);
+    if (!cioc) {
         error_report("could not accept migration connection (%s)",
-                     strerror(err));
-        return;
-    }
-
-    f = qemu_fopen_socket(c, "rb");
-    if (f == NULL) {
-        error_report("could not qemu_fopen socket");
+                     error_get_pretty(err));
         goto out;
     }
 
+    DPRINTF("accepted migration\n");
+
+    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
+    object_unref(OBJECT(cioc));
+
     process_incoming_migration(f);
-    return;
 
 out:
-    closesocket(c);
+    /* Close listening socket as its no longer needed */
+    qio_channel_close(ioc, NULL);
+    return FALSE;
 }
 
+
 void tcp_start_incoming_migration(const char *host_port, Error **errp)
 {
-    int s;
+    SocketAddress *saddr = tcp_build_address(host_port, errp);
+    QIOChannelSocket *listen_ioc;
 
-    s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
-    if (s < 0) {
+    if (!saddr) {
         return;
     }
 
-    qemu_set_fd_handler(s, tcp_accept_incoming_migration, NULL,
-                        (void *)(intptr_t)s);
+    listen_ioc = qio_channel_socket_new();
+    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
+        object_unref(OBJECT(listen_ioc));
+        qapi_free_SocketAddress(saddr);
+        return;
+    }
+
+    qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
+                          G_IO_IN,
+                          tcp_accept_incoming_migration,
+                          listen_ioc,
+                          (GDestroyNotify)object_unref);
+
+    qapi_free_SocketAddress(saddr);
 }
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 11/22] migration: convert fd socket protocol to use QIOChannel
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (9 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 10/22] migration: convert tcp " Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 18:46   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 12/22] migration: convert exec " Daniel P. Berrange
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Convert the fd socket migration protocol driver to use
QIOChannel and QEMUFileChannel, instead of plain sockets
APIs. It can be unconditionally built because the
QIOChannel APIs it uses will take care to report suitable
error messages if needed.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/Makefile.objs |  4 ++--
 migration/fd.c          | 57 ++++++++++++++++++++++++++++++++-----------------
 migration/migration.c   |  4 ----
 3 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index a5f8a03..64f95cd 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,11 +1,11 @@
-common-obj-y += migration.o tcp.o unix.o
+common-obj-y += migration.o tcp.o unix.o fd.o
 common-obj-y += vmstate.o
 common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
 common-obj-$(CONFIG_RDMA) += rdma.o
-common-obj-$(CONFIG_POSIX) += exec.o fd.o
+common-obj-$(CONFIG_POSIX) += exec.o
 
 common-obj-y += block.o
 
diff --git a/migration/fd.c b/migration/fd.c
index 3e4bed0..8d48e0d 100644
--- a/migration/fd.c
+++ b/migration/fd.c
@@ -20,6 +20,8 @@
 #include "monitor/monitor.h"
 #include "migration/qemu-file.h"
 #include "block/block.h"
+#include "io/channel-file.h"
+#include "io/channel-socket.h"
 
 //#define DEBUG_MIGRATION_FD
 
@@ -33,56 +35,71 @@
 
 static bool fd_is_socket(int fd)
 {
-    struct stat stat;
-    int ret = fstat(fd, &stat);
-    if (ret == -1) {
-        /* When in doubt say no */
-        return false;
-    }
-    return S_ISSOCK(stat.st_mode);
+    int optval;
+    socklen_t optlen;
+    optlen = sizeof(optval);
+    return getsockopt(fd,
+                      SOL_SOCKET,
+                      SO_TYPE,
+                      (char *)&optval,
+                      &optlen) == 0;
 }
 
 void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
 {
+    QIOChannel *ioc;
     int fd = monitor_get_fd(cur_mon, fdname, errp);
     if (fd == -1) {
         return;
     }
 
     if (fd_is_socket(fd)) {
-        s->file = qemu_fopen_socket(fd, "wb");
+        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
+        if (!ioc) {
+            close(fd);
+            return;
+        }
     } else {
-        s->file = qemu_fdopen(fd, "wb");
+        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
     }
+    s->file = qemu_fopen_channel_output(ioc);
 
     migrate_fd_connect(s);
 }
 
-static void fd_accept_incoming_migration(void *opaque)
+static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
+                                             GIOCondition condition,
+                                             gpointer opaque)
 {
     QEMUFile *f = opaque;
-
-    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
     process_incoming_migration(f);
+    return FALSE;
 }
 
 void fd_start_incoming_migration(const char *infd, Error **errp)
 {
-    int fd;
     QEMUFile *f;
+    QIOChannel *ioc;
+    int fd;
 
     DPRINTF("Attempting to start an incoming migration via fd\n");
 
     fd = strtol(infd, NULL, 0);
     if (fd_is_socket(fd)) {
-        f = qemu_fopen_socket(fd, "rb");
+        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
+        if (!ioc) {
+            close(fd);
+            return;
+        }
     } else {
-        f = qemu_fdopen(fd, "rb");
-    }
-    if(f == NULL) {
-        error_setg_errno(errp, errno, "failed to open the source descriptor");
-        return;
+        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
     }
+    f = qemu_fopen_channel_input(ioc);
+    object_unref(OBJECT(ioc));
 
-    qemu_set_fd_handler(fd, fd_accept_incoming_migration, NULL, f);
+    qio_channel_add_watch(ioc,
+                          G_IO_IN,
+                          fd_accept_incoming_migration,
+                          f,
+                          NULL);
 }
diff --git a/migration/migration.c b/migration/migration.c
index 1c5f12e..211879e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -315,10 +315,8 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
 #endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_incoming_migration(p, errp);
-#if !defined(WIN32)
     } else if (strstart(uri, "fd:", &p)) {
         fd_start_incoming_migration(p, errp);
-#endif
     } else {
         error_setg(errp, "unknown migration protocol: %s", uri);
     }
@@ -1022,10 +1020,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 #endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_outgoing_migration(s, p, &local_err);
-#if !defined(WIN32)
     } else if (strstart(uri, "fd:", &p)) {
         fd_start_outgoing_migration(s, p, &local_err);
-#endif
     } else {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri",
                    "a valid migration protocol");
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 12/22] migration: convert exec socket protocol to use QIOChannel
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (10 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 11/22] migration: convert fd " Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 18:53   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface Daniel P. Berrange
                   ` (11 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Convert the exec socket migration protocol driver to use
QIOChannel and QEMUFileChannel, instead of the stdio
popen APIs. It can be unconditionally built because the
QIOChannelCommand class can report suitable error messages
on platforms which can't fork processes.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/Makefile.objs |  3 +--
 migration/exec.c        | 48 ++++++++++++++++++++++++++++++------------------
 migration/migration.c   |  4 ----
 3 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 64f95cd..3c90c44 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,11 +1,10 @@
-common-obj-y += migration.o tcp.o unix.o fd.o
+common-obj-y += migration.o tcp.o unix.o fd.o exec.o
 common-obj-y += vmstate.o
 common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
 common-obj-$(CONFIG_RDMA) += rdma.o
-common-obj-$(CONFIG_POSIX) += exec.o
 
 common-obj-y += block.o
 
diff --git a/migration/exec.c b/migration/exec.c
index 8406d2b..6159aba 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -15,14 +15,8 @@
  * GNU GPL, version 2 or (at your option) any later version.
  */
 
-#include "qemu-common.h"
-#include "qemu/sockets.h"
-#include "qemu/main-loop.h"
 #include "migration/migration.h"
-#include "migration/qemu-file.h"
-#include "block/block.h"
-#include <sys/types.h>
-#include <sys/wait.h>
+#include "io/channel-command.h"
 
 //#define DEBUG_MIGRATION_EXEC
 
@@ -36,34 +30,52 @@
 
 void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
 {
-    s->file = qemu_popen_cmd(command, "w");
-    if (s->file == NULL) {
-        error_setg_errno(errp, errno, "failed to popen the migration target");
+    QIOChannel *ioc;
+    const char *argv[] = { "/bin/sh", "-c", command, NULL };
+
+    DPRINTF("Attempting to start an outgoing migration\n");
+    ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
+                                                    O_WRONLY,
+                                                    errp));
+    if (!ioc) {
         return;
     }
 
+    s->file = qemu_fopen_channel_output(ioc);
+    object_unref(OBJECT(ioc));
+
     migrate_fd_connect(s);
 }
 
-static void exec_accept_incoming_migration(void *opaque)
+static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
+                                               GIOCondition condition,
+                                               gpointer opaque)
 {
     QEMUFile *f = opaque;
-
-    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
     process_incoming_migration(f);
+    return FALSE;
 }
 
 void exec_start_incoming_migration(const char *command, Error **errp)
 {
     QEMUFile *f;
+    QIOChannel *ioc;
+    const char *argv[] = { "/bin/sh", "-c", command, NULL };
 
     DPRINTF("Attempting to start an incoming migration\n");
-    f = qemu_popen_cmd(command, "r");
-    if(f == NULL) {
-        error_setg_errno(errp, errno, "failed to popen the migration source");
+    ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
+                                                    O_RDONLY,
+                                                    errp));
+    if (!ioc) {
         return;
     }
 
-    qemu_set_fd_handler(qemu_get_fd(f), exec_accept_incoming_migration, NULL,
-                        f);
+    f = qemu_fopen_channel_input(ioc);
+    object_unref(OBJECT(ioc));
+
+    qio_channel_add_watch(ioc,
+                          G_IO_IN,
+                          exec_accept_incoming_migration,
+                          f,
+                          NULL);
 }
diff --git a/migration/migration.c b/migration/migration.c
index 211879e..2d2079d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -309,10 +309,8 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
     } else if (strstart(uri, "rdma:", &p)) {
         rdma_start_incoming_migration(p, errp);
 #endif
-#if !defined(WIN32)
     } else if (strstart(uri, "exec:", &p)) {
         exec_start_incoming_migration(p, errp);
-#endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_incoming_migration(p, errp);
     } else if (strstart(uri, "fd:", &p)) {
@@ -1014,10 +1012,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
     } else if (strstart(uri, "rdma:", &p)) {
         rdma_start_outgoing_migration(s, p, &local_err);
 #endif
-#if !defined(WIN32)
     } else if (strstart(uri, "exec:", &p)) {
         exec_start_outgoing_migration(s, p, &local_err);
-#endif
     } else if (strstart(uri, "unix:", &p)) {
         unix_start_outgoing_migration(s, p, &local_err);
     } else if (strstart(uri, "fd:", &p)) {
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (11 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 12/22] migration: convert exec " Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-02 20:01   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files Daniel P. Berrange
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

This converts the RDMA code to provide a subclass of
QIOChannel that uses RDMA for the data transport.

The RDMA code would be much better off it it could
be split up in a generic RDMA layer, a QIOChannel
impl based on RMDA, and then the RMDA migration
glue. This is left as a future exercise for the brave.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/rdma.c | 260 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 161 insertions(+), 99 deletions(-)

diff --git a/migration/rdma.c b/migration/rdma.c
index bffbfaf..3e961cb 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -374,14 +374,19 @@ typedef struct RDMAContext {
     GHashTable *blockmap;
 } RDMAContext;
 
-/*
- * Interface to the rest of the migration call stack.
- */
-typedef struct QEMUFileRDMA {
+#define TYPE_QIO_CHANNEL_RDMA "qio-channel-rdma"
+#define QIO_CHANNEL_RDMA(obj)                                     \
+    OBJECT_CHECK(QIOChannelRDMA, (obj), TYPE_QIO_CHANNEL_RDMA)
+
+typedef struct QIOChannelRDMA QIOChannelRDMA;
+
+
+struct QIOChannelRDMA {
+    QIOChannel parent;
     RDMAContext *rdma;
+    QEMUFile *file;
     size_t len;
-    void *file;
-} QEMUFileRDMA;
+};
 
 /*
  * Main structure for IB Send/Recv control messages.
@@ -2518,15 +2523,19 @@ static void *qemu_rdma_data_init(const char *host_port, Error **errp)
  * SEND messages for control only.
  * VM's ram is handled with regular RDMA messages.
  */
-static ssize_t qemu_rdma_put_buffer(void *opaque, const uint8_t *buf,
-                                    int64_t pos, size_t size)
-{
-    QEMUFileRDMA *r = opaque;
-    QEMUFile *f = r->file;
-    RDMAContext *rdma = r->rdma;
-    size_t remaining = size;
-    uint8_t * data = (void *) buf;
+static ssize_t qio_channel_rdma_writev(QIOChannel *ioc,
+                                       const struct iovec *iov,
+                                       size_t niov,
+                                       int *fds,
+                                       size_t nfds,
+                                       Error **errp)
+{
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
+    QEMUFile *f = rioc->file;
+    RDMAContext *rdma = rioc->rdma;
     int ret;
+    ssize_t done = 0;
+    size_t i;
 
     CHECK_ERROR_STATE();
 
@@ -2540,27 +2549,31 @@ static ssize_t qemu_rdma_put_buffer(void *opaque, const uint8_t *buf,
         return ret;
     }
 
-    while (remaining) {
-        RDMAControlHeader head;
+    for (i = 0; i < niov; i++) {
+        size_t remaining = iov[i].iov_len;
+        uint8_t * data = (void *)iov[i].iov_base;
+        while (remaining) {
+            RDMAControlHeader head;
 
-        r->len = MIN(remaining, RDMA_SEND_INCREMENT);
-        remaining -= r->len;
+            rioc->len = MIN(remaining, RDMA_SEND_INCREMENT);
+            remaining -= rioc->len;
 
-        /* Guaranteed to fit due to RDMA_SEND_INCREMENT MIN above */
-        head.len = (uint32_t)r->len;
-        head.type = RDMA_CONTROL_QEMU_FILE;
+            head.len = rioc->len;
+            head.type = RDMA_CONTROL_QEMU_FILE;
 
-        ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL);
+            ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL);
 
-        if (ret < 0) {
-            rdma->error_state = ret;
-            return ret;
-        }
+            if (ret < 0) {
+                rdma->error_state = ret;
+                return ret;
+            }
 
-        data += r->len;
+            data += rioc->len;
+            done += rioc->len;
+        }
     }
 
-    return size;
+    return done;
 }
 
 static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf,
@@ -2585,41 +2598,65 @@ static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf,
  * RDMA links don't use bytestreams, so we have to
  * return bytes to QEMUFile opportunistically.
  */
-static ssize_t qemu_rdma_get_buffer(void *opaque, uint8_t *buf,
-                                    int64_t pos, size_t size)
-{
-    QEMUFileRDMA *r = opaque;
-    RDMAContext *rdma = r->rdma;
+static ssize_t qio_channel_rdma_readv(QIOChannel *ioc,
+                                      const struct iovec *iov,
+                                      size_t niov,
+                                      int **fds,
+                                      size_t *nfds,
+                                      Error **errp)
+{
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
+    RDMAContext *rdma = rioc->rdma;
     RDMAControlHeader head;
     int ret = 0;
+    ssize_t i;
+    size_t done = 0;
 
     CHECK_ERROR_STATE();
 
-    /*
-     * First, we hold on to the last SEND message we
-     * were given and dish out the bytes until we run
-     * out of bytes.
-     */
-    r->len = qemu_rdma_fill(r->rdma, buf, size, 0);
-    if (r->len) {
-        return r->len;
-    }
+    for (i = 0; i < niov; i++) {
+        size_t want = iov[i].iov_len;
+        uint8_t *data = (void *)iov[i].iov_base;
 
-    /*
-     * Once we run out, we block and wait for another
-     * SEND message to arrive.
-     */
-    ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
+        /*
+         * First, we hold on to the last SEND message we
+         * were given and dish out the bytes until we run
+         * out of bytes.
+         */
+        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
+        if (ret > 0) {
+            done += ret;
+            if (ret < want) {
+                break;
+            } else {
+                continue;
+            }
+        }
 
-    if (ret < 0) {
-        rdma->error_state = ret;
-        return ret;
-    }
+        /*
+         * Once we run out, we block and wait for another
+         * SEND message to arrive.
+         */
+        ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
 
-    /*
-     * SEND was received with new bytes, now try again.
-     */
-    return qemu_rdma_fill(r->rdma, buf, size, 0);
+        if (ret < 0) {
+            rdma->error_state = ret;
+            return ret;
+        }
+
+        /*
+         * SEND was received with new bytes, now try again.
+         */
+        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
+        if (ret > 0) {
+            done += ret;
+            if (ret < want) {
+                break;
+            }
+        }
+    }
+    rioc->len = done;
+    return rioc->len;
 }
 
 /*
@@ -2646,15 +2683,16 @@ static int qemu_rdma_drain_cq(QEMUFile *f, RDMAContext *rdma)
     return 0;
 }
 
-static int qemu_rdma_close(void *opaque)
+static int qio_channel_rdma_close(QIOChannel *ioc,
+                                  Error **errp)
 {
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
     trace_qemu_rdma_close();
-    QEMUFileRDMA *r = opaque;
-    if (r->rdma) {
-        qemu_rdma_cleanup(r->rdma);
-        g_free(r->rdma);
+    if (rioc->rdma) {
+        qemu_rdma_cleanup(rioc->rdma);
+        g_free(rioc->rdma);
+        rioc->rdma = NULL;
     }
-    g_free(r);
     return 0;
 }
 
@@ -2696,8 +2734,8 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque,
                                   ram_addr_t block_offset, ram_addr_t offset,
                                   size_t size, uint64_t *bytes_sent)
 {
-    QEMUFileRDMA *rfile = opaque;
-    RDMAContext *rdma = rfile->rdma;
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
+    RDMAContext *rdma = rioc->rdma;
     int ret;
 
     CHECK_ERROR_STATE();
@@ -2951,8 +2989,8 @@ static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque)
                              };
     RDMAControlHeader blocks = { .type = RDMA_CONTROL_RAM_BLOCKS_RESULT,
                                  .repeat = 1 };
-    QEMUFileRDMA *rfile = opaque;
-    RDMAContext *rdma = rfile->rdma;
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
+    RDMAContext *rdma = rioc->rdma;
     RDMALocalBlocks *local = &rdma->local_ram_blocks;
     RDMAControlHeader head;
     RDMARegister *reg, *registers;
@@ -3207,9 +3245,10 @@ out:
  * We've already built our local RAMBlock list, but not yet sent the list to
  * the source.
  */
-static int rdma_block_notification_handle(QEMUFileRDMA *rfile, const char *name)
+static int
+rdma_block_notification_handle(QIOChannelRDMA *rioc, const char *name)
 {
-    RDMAContext *rdma = rfile->rdma;
+    RDMAContext *rdma = rioc->rdma;
     int curr;
     int found = -1;
 
@@ -3251,8 +3290,8 @@ static int rdma_load_hook(QEMUFile *f, void *opaque, uint64_t flags, void *data)
 static int qemu_rdma_registration_start(QEMUFile *f, void *opaque,
                                         uint64_t flags, void *data)
 {
-    QEMUFileRDMA *rfile = opaque;
-    RDMAContext *rdma = rfile->rdma;
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
+    RDMAContext *rdma = rioc->rdma;
 
     CHECK_ERROR_STATE();
 
@@ -3271,8 +3310,8 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
                                        uint64_t flags, void *data)
 {
     Error *local_err = NULL, **errp = &local_err;
-    QEMUFileRDMA *rfile = opaque;
-    RDMAContext *rdma = rfile->rdma;
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
+    RDMAContext *rdma = rioc->rdma;
     RDMAControlHeader head = { .len = 0, .repeat = 1 };
     int ret = 0;
 
@@ -3368,55 +3407,78 @@ err:
     return ret;
 }
 
-static int qemu_rdma_get_fd(void *opaque)
-{
-    QEMUFileRDMA *rfile = opaque;
-    RDMAContext *rdma = rfile->rdma;
-
-    return rdma->comp_channel->fd;
-}
-
-static const QEMUFileOps rdma_read_ops = {
-    .get_buffer    = qemu_rdma_get_buffer,
-    .get_fd        = qemu_rdma_get_fd,
-    .close         = qemu_rdma_close,
-};
-
 static const QEMUFileHooks rdma_read_hooks = {
     .hook_ram_load = rdma_load_hook,
 };
 
-static const QEMUFileOps rdma_write_ops = {
-    .put_buffer         = qemu_rdma_put_buffer,
-    .close              = qemu_rdma_close,
-};
-
 static const QEMUFileHooks rdma_write_hooks = {
     .before_ram_iterate = qemu_rdma_registration_start,
     .after_ram_iterate  = qemu_rdma_registration_stop,
     .save_page          = qemu_rdma_save_page,
 };
 
-static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
+
+static void qio_channel_rdma_finalize(Object *obj)
+{
+    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(obj);
+    if (rioc->rdma) {
+        qemu_rdma_cleanup(rioc->rdma);
+        g_free(rioc->rdma);
+        rioc->rdma = NULL;
+    }
+}
+
+static void qio_channel_rdma_class_init(ObjectClass *klass,
+                                        void *class_data G_GNUC_UNUSED)
+{
+    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
+
+    ioc_klass->io_writev = qio_channel_rdma_writev;
+    ioc_klass->io_readv = qio_channel_rdma_readv;
+    /* XXX
+    ioc_klass->io_set_blocking = qio_channel_rdma_set_blocking;
+    */
+    ioc_klass->io_close = qio_channel_rdma_close;
+    /* XXX
+    ioc_klass->io_create_watch = qio_channel_rdma_create_watch;
+    */
+}
+
+static const TypeInfo qio_channel_rdma_info = {
+    .parent = TYPE_QIO_CHANNEL,
+    .name = TYPE_QIO_CHANNEL_RDMA,
+    .instance_size = sizeof(QIOChannelRDMA),
+    .instance_finalize = qio_channel_rdma_finalize,
+    .class_init = qio_channel_rdma_class_init,
+};
+
+static void qio_channel_rdma_register_types(void)
+{
+    type_register_static(&qio_channel_rdma_info);
+}
+
+type_init(qio_channel_rdma_register_types);
+
+static QEMUFile *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
 {
-    QEMUFileRDMA *r;
+    QIOChannelRDMA *rioc;
 
     if (qemu_file_mode_is_not_valid(mode)) {
         return NULL;
     }
 
-    r = g_new0(QEMUFileRDMA, 1);
-    r->rdma = rdma;
+    rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA));
+    rioc->rdma = rdma;
 
     if (mode[0] == 'w') {
-        r->file = qemu_fopen_ops(r, &rdma_write_ops);
-        qemu_file_set_hooks(r->file, &rdma_write_hooks);
+        rioc->file = qemu_fopen_channel_output(QIO_CHANNEL(rioc));
+        qemu_file_set_hooks(rioc->file, &rdma_write_hooks);
     } else {
-        r->file = qemu_fopen_ops(r, &rdma_read_ops);
-        qemu_file_set_hooks(r->file, &rdma_read_hooks);
+        rioc->file = qemu_fopen_channel_input(QIO_CHANNEL(rioc));
+        qemu_file_set_hooks(rioc->file, &rdma_read_hooks);
     }
 
-    return r->file;
+    return rioc->file;
 }
 
 static void rdma_accept_incoming_migration(void *opaque)
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (12 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-03  9:52   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation Daniel P. Berrange
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Convert the exec savevm code to use QIOChannel and QEMUFileChannel,
instead of the stdio APIs.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/savevm.c   |  8 +++++---
 tests/Makefile       |  4 ++--
 tests/test-vmstate.c | 11 ++++++++++-
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/migration/savevm.c b/migration/savevm.c
index f2e1880..e57d7ce 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -51,6 +51,7 @@
 #include "block/snapshot.h"
 #include "block/qapi.h"
 #include "io/channel-buffer.h"
+#include "io/channel-file.h"
 
 
 #ifndef ETH_P_RARP
@@ -1990,6 +1991,7 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
+    QIOChannelFile *ioc;
     int saved_vm_running;
     int ret;
 
@@ -1997,11 +1999,11 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
     vm_stop(RUN_STATE_SAVE_VM);
     global_state_store_running();
 
-    f = qemu_fopen(filename, "wb");
-    if (!f) {
-        error_setg_file_open(errp, errno, filename);
+    ioc = qio_channel_file_new_path(filename, O_WRONLY | O_CREAT, 0660, errp);
+    if (!ioc) {
         goto the_end;
     }
+    f = qemu_fopen_channel_output(QIO_CHANNEL(ioc));
     ret = qemu_save_device_state(f);
     qemu_fclose(f);
     if (ret < 0) {
diff --git a/tests/Makefile b/tests/Makefile
index 5a1b25f..e8f759a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -423,8 +423,8 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
 	$(test-qapi-obj-y)
 tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
 	migration/vmstate.o migration/qemu-file.o \
-        migration/qemu-file-unix.o qjson.o \
-	$(test-qom-obj-y)
+        migration/qemu-file-channel.o qjson.o \
+	$(test-io-obj-y)
 tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
 	$(test-util-obj-y)
 tests/test-base64$(EXESUF): tests/test-base64.o \
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 0f943d5..6bbda8a 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -28,6 +28,7 @@
 #include "migration/migration.h"
 #include "migration/vmstate.h"
 #include "qemu/coroutine.h"
+#include "io/channel-file.h"
 
 static char temp_file[] = "/tmp/vmst.test.XXXXXX";
 static int temp_fd;
@@ -48,11 +49,17 @@ void yield_until_fd_readable(int fd)
 static QEMUFile *open_test_file(bool write)
 {
     int fd = dup(temp_fd);
+    QIOChannel *ioc;
     lseek(fd, 0, SEEK_SET);
     if (write) {
         g_assert_cmpint(ftruncate(fd, 0), ==, 0);
     }
-    return qemu_fdopen(fd, write ? "wb" : "rb");
+    ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
+    if (write) {
+        return qemu_fopen_channel_output(ioc);
+    } else {
+        return qemu_fopen_channel_input(ioc);
+    }
 }
 
 #define SUCCESS(val) \
@@ -468,6 +475,8 @@ int main(int argc, char **argv)
 {
     temp_fd = mkstemp(temp_file);
 
+    module_call_init(MODULE_INIT_QOM);
+
     g_test_init(&argc, &argv, NULL);
     g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
     g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (13 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-03  9:54   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct Daniel P. Berrange
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

The qemu_bufopen() method is no longer used, so the memory
buffer based QEMUFile backend can be deleted entirely.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  6 ---
 migration/qemu-file-buf.c     | 96 -------------------------------------------
 2 files changed, 102 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index cb79311..6b12960 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -141,7 +141,6 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode);
 QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
 QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
-QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
 void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
 int qemu_get_fd(QEMUFile *f);
 int qemu_fclose(QEMUFile *f);
@@ -167,11 +166,6 @@ ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
                      off_t pos, size_t count);
 
 
-/*
- * For use on files opened with qemu_bufopen
- */
-const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f);
-
 static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
 {
     qemu_put_byte(f, (int)v);
diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c
index 49516b8..c0bc38c 100644
--- a/migration/qemu-file-buf.c
+++ b/migration/qemu-file-buf.c
@@ -365,99 +365,3 @@ ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
 
     return count;
 }
-
-typedef struct QEMUBuffer {
-    QEMUSizedBuffer *qsb;
-    QEMUFile *file;
-    bool qsb_allocated;
-} QEMUBuffer;
-
-static ssize_t buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
-                              size_t size)
-{
-    QEMUBuffer *s = opaque;
-    ssize_t len = qsb_get_length(s->qsb) - pos;
-
-    if (len <= 0) {
-        return 0;
-    }
-
-    if (len > size) {
-        len = size;
-    }
-    return qsb_get_buffer(s->qsb, pos, len, buf);
-}
-
-static ssize_t buf_put_buffer(void *opaque, const uint8_t *buf,
-                              int64_t pos, size_t size)
-{
-    QEMUBuffer *s = opaque;
-
-    return qsb_write_at(s->qsb, buf, pos, size);
-}
-
-static int buf_close(void *opaque)
-{
-    QEMUBuffer *s = opaque;
-
-    if (s->qsb_allocated) {
-        qsb_free(s->qsb);
-    }
-
-    g_free(s);
-
-    return 0;
-}
-
-const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
-{
-    QEMUBuffer *p;
-
-    qemu_fflush(f);
-
-    p = f->opaque;
-
-    return p->qsb;
-}
-
-static const QEMUFileOps buf_read_ops = {
-    .get_buffer = buf_get_buffer,
-    .close =      buf_close,
-};
-
-static const QEMUFileOps buf_write_ops = {
-    .put_buffer = buf_put_buffer,
-    .close =      buf_close,
-};
-
-QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
-{
-    QEMUBuffer *s;
-
-    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
-        mode[1] != '\0') {
-        error_report("qemu_bufopen: Argument validity check failed");
-        return NULL;
-    }
-
-    s = g_new0(QEMUBuffer, 1);
-    s->qsb = input;
-
-    if (s->qsb == NULL) {
-        s->qsb = qsb_create(NULL, 0);
-        s->qsb_allocated = true;
-    }
-    if (!s->qsb) {
-        g_free(s);
-        error_report("qemu_bufopen: qsb_create failed");
-        return NULL;
-    }
-
-
-    if (mode[0] == 'r') {
-        s->file = qemu_fopen_ops(s, &buf_read_ops);
-    } else {
-        s->file = qemu_fopen_ops(s, &buf_write_ops);
-    }
-    return s->file;
-}
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (14 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-03  9:55   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation Daniel P. Berrange
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Now that we don't have have a buffer based QemuFile
implementation, the QEMUSizedBuffer code is also
unused and can be deleted. A simpler buffer class
also exists in util/buffer.c which other code can
used as needed.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  16 --
 include/qemu/typedefs.h       |   1 -
 migration/Makefile.objs       |   2 +-
 migration/qemu-file-buf.c     | 367 ------------------------------------------
 4 files changed, 1 insertion(+), 385 deletions(-)
 delete mode 100644 migration/qemu-file-buf.c

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 6b12960..da67931 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -127,13 +127,6 @@ typedef struct QEMUFileHooks {
     QEMURamSaveFunc *save_page;
 } QEMUFileHooks;
 
-struct QEMUSizedBuffer {
-    struct iovec *iov;
-    size_t n_iov;
-    size_t size; /* total allocated size in all iov's */
-    size_t used; /* number of used bytes */
-};
-
 QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
 QEMUFile *qemu_fdopen(int fd, const char *mode);
@@ -156,15 +149,6 @@ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size);
 bool qemu_file_mode_is_not_valid(const char *mode);
 bool qemu_file_is_writable(QEMUFile *f);
 
-QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len);
-void qsb_free(QEMUSizedBuffer *);
-size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t length);
-size_t qsb_get_length(const QEMUSizedBuffer *qsb);
-ssize_t qsb_get_buffer(const QEMUSizedBuffer *, off_t start, size_t count,
-                       uint8_t *buf);
-ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
-                     off_t pos, size_t count);
-
 
 static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
 {
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 78fe6e8..3f8dfbf 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -77,7 +77,6 @@ typedef struct QemuOpt QemuOpt;
 typedef struct QemuOpts QemuOpts;
 typedef struct QemuOptsList QemuOptsList;
 typedef struct QEMUSGList QEMUSGList;
-typedef struct QEMUSizedBuffer QEMUSizedBuffer;
 typedef struct QEMUTimer QEMUTimer;
 typedef struct QEMUTimerListGroup QEMUTimerListGroup;
 typedef struct QObject QObject;
diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 3c90c44..8ecb941 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,6 +1,6 @@
 common-obj-y += migration.o tcp.o unix.o fd.o exec.o
 common-obj-y += vmstate.o
-common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
+common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c
deleted file mode 100644
index c0bc38c..0000000
--- a/migration/qemu-file-buf.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- * Copyright (c) 2014 IBM Corp.
- *
- * Authors:
- *  Stefan Berger <stefanb@linux.vnet.ibm.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "qemu/sockets.h"
-#include "qemu/coroutine.h"
-#include "migration/migration.h"
-#include "migration/qemu-file.h"
-#include "migration/qemu-file-internal.h"
-#include "trace.h"
-
-#define QSB_CHUNK_SIZE      (1 << 10)
-#define QSB_MAX_CHUNK_SIZE  (16 * QSB_CHUNK_SIZE)
-
-/**
- * Create a QEMUSizedBuffer
- * This type of buffer uses scatter-gather lists internally and
- * can grow to any size. Any data array in the scatter-gather list
- * can hold different amount of bytes.
- *
- * @buffer: Optional buffer to copy into the QSB
- * @len: size of initial buffer; if @buffer is given, buffer must
- *       hold at least len bytes
- *
- * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
- */
-QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
-{
-    QEMUSizedBuffer *qsb;
-    size_t alloc_len, num_chunks, i, to_copy;
-    size_t chunk_size = (len > QSB_MAX_CHUNK_SIZE)
-                        ? QSB_MAX_CHUNK_SIZE
-                        : QSB_CHUNK_SIZE;
-
-    num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
-    alloc_len = num_chunks * chunk_size;
-
-    qsb = g_try_new0(QEMUSizedBuffer, 1);
-    if (!qsb) {
-        return NULL;
-    }
-
-    qsb->iov = g_try_new0(struct iovec, num_chunks);
-    if (!qsb->iov) {
-        g_free(qsb);
-        return NULL;
-    }
-
-    qsb->n_iov = num_chunks;
-
-    for (i = 0; i < num_chunks; i++) {
-        qsb->iov[i].iov_base = g_try_malloc0(chunk_size);
-        if (!qsb->iov[i].iov_base) {
-            /* qsb_free is safe since g_free can cope with NULL */
-            qsb_free(qsb);
-            return NULL;
-        }
-
-        qsb->iov[i].iov_len = chunk_size;
-        if (buffer) {
-            to_copy = (len - qsb->used) > chunk_size
-                      ? chunk_size : (len - qsb->used);
-            memcpy(qsb->iov[i].iov_base, &buffer[qsb->used], to_copy);
-            qsb->used += to_copy;
-        }
-    }
-
-    qsb->size = alloc_len;
-
-    return qsb;
-}
-
-/**
- * Free the QEMUSizedBuffer
- *
- * @qsb: The QEMUSizedBuffer to free
- */
-void qsb_free(QEMUSizedBuffer *qsb)
-{
-    size_t i;
-
-    if (!qsb) {
-        return;
-    }
-
-    for (i = 0; i < qsb->n_iov; i++) {
-        g_free(qsb->iov[i].iov_base);
-    }
-    g_free(qsb->iov);
-    g_free(qsb);
-}
-
-/**
- * Get the number of used bytes in the QEMUSizedBuffer
- *
- * @qsb: A QEMUSizedBuffer
- *
- * Returns the number of bytes currently used in this buffer
- */
-size_t qsb_get_length(const QEMUSizedBuffer *qsb)
-{
-    return qsb->used;
-}
-
-/**
- * Set the length of the buffer; the primary usage of this
- * function is to truncate the number of used bytes in the buffer.
- * The size will not be extended beyond the current number of
- * allocated bytes in the QEMUSizedBuffer.
- *
- * @qsb: A QEMUSizedBuffer
- * @new_len: The new length of bytes in the buffer
- *
- * Returns the number of bytes the buffer was truncated or extended
- * to.
- */
-size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
-{
-    if (new_len <= qsb->size) {
-        qsb->used = new_len;
-    } else {
-        qsb->used = qsb->size;
-    }
-    return qsb->used;
-}
-
-/**
- * Get the iovec that holds the data for a given position @pos.
- *
- * @qsb: A QEMUSizedBuffer
- * @pos: The index of a byte in the buffer
- * @d_off: Pointer to an offset that this function will indicate
- *         at what position within the returned iovec the byte
- *         is to be found
- *
- * Returns the index of the iovec that holds the byte at the given
- * index @pos in the byte stream; a negative number if the iovec
- * for the given position @pos does not exist.
- */
-static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
-                             off_t pos, off_t *d_off)
-{
-    ssize_t i;
-    off_t curr = 0;
-
-    if (pos > qsb->used) {
-        return -1;
-    }
-
-    for (i = 0; i < qsb->n_iov; i++) {
-        if (curr + qsb->iov[i].iov_len > pos) {
-            *d_off = pos - curr;
-            return i;
-        }
-        curr += qsb->iov[i].iov_len;
-    }
-    return -1;
-}
-
-/*
- * Convert the QEMUSizedBuffer into a flat buffer.
- *
- * Note: If at all possible, try to avoid this function since it
- *       may unnecessarily copy memory around.
- *
- * @qsb: pointer to QEMUSizedBuffer
- * @start: offset to start at
- * @count: number of bytes to copy
- * @buf: a pointer to a buffer to write into (at least @count bytes)
- *
- * Returns the number of bytes copied into the output buffer
- */
-ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
-                       size_t count, uint8_t *buffer)
-{
-    const struct iovec *iov;
-    size_t to_copy, all_copy;
-    ssize_t index;
-    off_t s_off;
-    off_t d_off = 0;
-    char *s;
-
-    if (start > qsb->used) {
-        return 0;
-    }
-
-    all_copy = qsb->used - start;
-    if (all_copy > count) {
-        all_copy = count;
-    } else {
-        count = all_copy;
-    }
-
-    index = qsb_get_iovec(qsb, start, &s_off);
-    if (index < 0) {
-        return 0;
-    }
-
-    while (all_copy > 0) {
-        iov = &qsb->iov[index];
-
-        s = iov->iov_base;
-
-        to_copy = iov->iov_len - s_off;
-        if (to_copy > all_copy) {
-            to_copy = all_copy;
-        }
-        memcpy(&buffer[d_off], &s[s_off], to_copy);
-
-        d_off += to_copy;
-        all_copy -= to_copy;
-
-        s_off = 0;
-        index++;
-    }
-
-    return count;
-}
-
-/**
- * Grow the QEMUSizedBuffer to the given size and allocate
- * memory for it.
- *
- * @qsb: A QEMUSizedBuffer
- * @new_size: The new size of the buffer
- *
- * Return:
- *    a negative error code in case of memory allocation failure
- * or
- *    the new size of the buffer. The returned size may be greater or equal
- *    to @new_size.
- */
-static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
-{
-    size_t needed_chunks, i;
-
-    if (qsb->size < new_size) {
-        struct iovec *new_iov;
-        size_t size_diff = new_size - qsb->size;
-        size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
-                             ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
-
-        needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
-
-        new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
-        if (new_iov == NULL) {
-            return -ENOMEM;
-        }
-
-        /* Allocate new chunks as needed into new_iov */
-        for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
-            new_iov[i].iov_base = g_try_malloc0(chunk_size);
-            new_iov[i].iov_len = chunk_size;
-            if (!new_iov[i].iov_base) {
-                size_t j;
-
-                /* Free previously allocated new chunks */
-                for (j = qsb->n_iov; j < i; j++) {
-                    g_free(new_iov[j].iov_base);
-                }
-                g_free(new_iov);
-
-                return -ENOMEM;
-            }
-        }
-
-        /*
-         * Now we can't get any allocation errors, copy over to new iov
-         * and switch.
-         */
-        for (i = 0; i < qsb->n_iov; i++) {
-            new_iov[i] = qsb->iov[i];
-        }
-
-        qsb->n_iov += needed_chunks;
-        g_free(qsb->iov);
-        qsb->iov = new_iov;
-        qsb->size += (needed_chunks * chunk_size);
-    }
-
-    return qsb->size;
-}
-
-/**
- * Write into the QEMUSizedBuffer at a given position and a given
- * number of bytes. This function will automatically grow the
- * QEMUSizedBuffer.
- *
- * @qsb: A QEMUSizedBuffer
- * @source: A byte array to copy data from
- * @pos: The position within the @qsb to write data to
- * @size: The number of bytes to copy into the @qsb
- *
- * Returns @size or a negative error code in case of memory allocation failure,
- *           or with an invalid 'pos'
- */
-ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
-                     off_t pos, size_t count)
-{
-    ssize_t rc = qsb_grow(qsb, pos + count);
-    size_t to_copy;
-    size_t all_copy = count;
-    const struct iovec *iov;
-    ssize_t index;
-    char *dest;
-    off_t d_off, s_off = 0;
-
-    if (rc < 0) {
-        return rc;
-    }
-
-    if (pos + count > qsb->used) {
-        qsb->used = pos + count;
-    }
-
-    index = qsb_get_iovec(qsb, pos, &d_off);
-    if (index < 0) {
-        return -EINVAL;
-    }
-
-    while (all_copy > 0) {
-        iov = &qsb->iov[index];
-
-        dest = iov->iov_base;
-
-        to_copy = iov->iov_len - d_off;
-        if (to_copy > all_copy) {
-            to_copy = all_copy;
-        }
-
-        memcpy(&dest[d_off], &source[s_off], to_copy);
-
-        s_off += to_copy;
-        all_copy -= to_copy;
-
-        d_off = 0;
-        index++;
-    }
-
-    return count;
-}
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (15 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-03  9:56   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation Daniel P. Berrange
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Now that the tcp, unix and fd migration backends have converted
to use the QIOChannel based QEMUFile, there is no user remaining
for the sockets based QEMUFile impl and it can be deleted.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |   2 -
 migration/Makefile.objs       |   2 +-
 migration/qemu-file-unix.c    | 324 ------------------------------------------
 3 files changed, 1 insertion(+), 327 deletions(-)
 delete mode 100644 migration/qemu-file-unix.c

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index da67931..dc4b7ab 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -129,8 +129,6 @@ typedef struct QEMUFileHooks {
 
 QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
-QEMUFile *qemu_fdopen(int fd, const char *mode);
-QEMUFile *qemu_fopen_socket(int fd, const char *mode);
 QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
 QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 8ecb941..2c71056 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,6 +1,6 @@
 common-obj-y += migration.o tcp.o unix.o fd.o exec.o
 common-obj-y += vmstate.o
-common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
+common-obj-y += qemu-file.o qemu-file-stdio.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c
deleted file mode 100644
index 6ca53e7..0000000
--- a/migration/qemu-file-unix.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "qemu/sockets.h"
-#include "qemu/coroutine.h"
-#include "migration/qemu-file.h"
-#include "migration/qemu-file-internal.h"
-
-typedef struct QEMUFileSocket {
-    int fd;
-    QEMUFile *file;
-} QEMUFileSocket;
-
-static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
-                                    int64_t pos)
-{
-    QEMUFileSocket *s = opaque;
-    ssize_t len;
-    ssize_t size = iov_size(iov, iovcnt);
-    ssize_t offset = 0;
-    int     err;
-
-    while (size > 0) {
-        len = iov_send(s->fd, iov, iovcnt, offset, size);
-
-        if (len > 0) {
-            size -= len;
-            offset += len;
-        }
-
-        if (size > 0) {
-            err = socket_error();
-
-            if (err != EAGAIN && err != EWOULDBLOCK) {
-                error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
-                             err, (size_t)size, (size_t)len);
-                /*
-                 * If I've already sent some but only just got the error, I
-                 * could return the amount validly sent so far and wait for the
-                 * next call to report the error, but I'd rather flag the error
-                 * immediately.
-                 */
-                return -err;
-            }
-
-            /* Emulate blocking */
-            GPollFD pfd;
-
-            pfd.fd = s->fd;
-            pfd.events = G_IO_OUT | G_IO_ERR;
-            pfd.revents = 0;
-            TFR(err = g_poll(&pfd, 1, -1 /* no timeout */));
-            /* Errors other than EINTR intentionally ignored */
-        }
-     }
-
-    return offset;
-}
-
-static int socket_get_fd(void *opaque)
-{
-    QEMUFileSocket *s = opaque;
-
-    return s->fd;
-}
-
-static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
-                                 size_t size)
-{
-    QEMUFileSocket *s = opaque;
-    ssize_t len;
-
-    for (;;) {
-        len = qemu_recv(s->fd, buf, size, 0);
-        if (len != -1) {
-            break;
-        }
-        if (socket_error() == EAGAIN) {
-            yield_until_fd_readable(s->fd);
-        } else if (socket_error() != EINTR) {
-            break;
-        }
-    }
-
-    if (len == -1) {
-        len = -socket_error();
-    }
-    return len;
-}
-
-static int socket_close(void *opaque)
-{
-    QEMUFileSocket *s = opaque;
-    closesocket(s->fd);
-    g_free(s);
-    return 0;
-}
-
-static int socket_shutdown(void *opaque, bool rd, bool wr)
-{
-    QEMUFileSocket *s = opaque;
-
-    if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
-        return -errno;
-    } else {
-        return 0;
-    }
-}
-
-static int socket_return_close(void *opaque)
-{
-    QEMUFileSocket *s = opaque;
-    /*
-     * Note: We don't close the socket, that should be done by the forward
-     * path.
-     */
-    g_free(s);
-    return 0;
-}
-
-static const QEMUFileOps socket_return_read_ops = {
-    .get_fd          = socket_get_fd,
-    .get_buffer      = socket_get_buffer,
-    .close           = socket_return_close,
-    .shut_down       = socket_shutdown,
-};
-
-static const QEMUFileOps socket_return_write_ops = {
-    .get_fd          = socket_get_fd,
-    .writev_buffer   = socket_writev_buffer,
-    .close           = socket_return_close,
-    .shut_down       = socket_shutdown,
-};
-
-/*
- * Give a QEMUFile* off the same socket but data in the opposite
- * direction.
- */
-static QEMUFile *socket_get_return_path(void *opaque)
-{
-    QEMUFileSocket *forward = opaque;
-    QEMUFileSocket *reverse;
-
-    if (qemu_file_get_error(forward->file)) {
-        /* If the forward file is in error, don't try and open a return */
-        return NULL;
-    }
-
-    reverse = g_malloc0(sizeof(QEMUFileSocket));
-    reverse->fd = forward->fd;
-    /* I don't think there's a better way to tell which direction 'this' is */
-    if (forward->file->ops->get_buffer != NULL) {
-        /* being called from the read side, so we need to be able to write */
-        return qemu_fopen_ops(reverse, &socket_return_write_ops);
-    } else {
-        return qemu_fopen_ops(reverse, &socket_return_read_ops);
-    }
-}
-
-static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
-                                  int64_t pos)
-{
-    QEMUFileSocket *s = opaque;
-    ssize_t len, offset;
-    ssize_t size = iov_size(iov, iovcnt);
-    ssize_t total = 0;
-
-    assert(iovcnt > 0);
-    offset = 0;
-    while (size > 0) {
-        /* Find the next start position; skip all full-sized vector elements  */
-        while (offset >= iov[0].iov_len) {
-            offset -= iov[0].iov_len;
-            iov++, iovcnt--;
-        }
-
-        /* skip `offset' bytes from the (now) first element, undo it on exit */
-        assert(iovcnt > 0);
-        iov[0].iov_base += offset;
-        iov[0].iov_len -= offset;
-
-        do {
-            len = writev(s->fd, iov, iovcnt);
-        } while (len == -1 && errno == EINTR);
-        if (len == -1) {
-            return -errno;
-        }
-
-        /* Undo the changes above */
-        iov[0].iov_base -= offset;
-        iov[0].iov_len += offset;
-
-        /* Prepare for the next iteration */
-        offset += len;
-        total += len;
-        size -= len;
-    }
-
-    return total;
-}
-
-static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
-                              size_t size)
-{
-    QEMUFileSocket *s = opaque;
-    ssize_t len;
-
-    for (;;) {
-        len = read(s->fd, buf, size);
-        if (len != -1) {
-            break;
-        }
-        if (errno == EAGAIN) {
-            yield_until_fd_readable(s->fd);
-        } else if (errno != EINTR) {
-            break;
-        }
-    }
-
-    if (len == -1) {
-        len = -errno;
-    }
-    return len;
-}
-
-static int unix_close(void *opaque)
-{
-    QEMUFileSocket *s = opaque;
-    close(s->fd);
-    g_free(s);
-    return 0;
-}
-
-static const QEMUFileOps unix_read_ops = {
-    .get_fd =     socket_get_fd,
-    .get_buffer = unix_get_buffer,
-    .close =      unix_close
-};
-
-static const QEMUFileOps unix_write_ops = {
-    .get_fd =     socket_get_fd,
-    .writev_buffer = unix_writev_buffer,
-    .close =      unix_close
-};
-
-QEMUFile *qemu_fdopen(int fd, const char *mode)
-{
-    QEMUFileSocket *s;
-
-    if (mode == NULL ||
-        (mode[0] != 'r' && mode[0] != 'w') ||
-        mode[1] != 'b' || mode[2] != 0) {
-        fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
-        return NULL;
-    }
-
-    s = g_new0(QEMUFileSocket, 1);
-    s->fd = fd;
-
-    if (mode[0] == 'r') {
-        s->file = qemu_fopen_ops(s, &unix_read_ops);
-    } else {
-        s->file = qemu_fopen_ops(s, &unix_write_ops);
-    }
-    return s->file;
-}
-
-static const QEMUFileOps socket_read_ops = {
-    .get_fd          = socket_get_fd,
-    .get_buffer      = socket_get_buffer,
-    .close           = socket_close,
-    .shut_down       = socket_shutdown,
-    .get_return_path = socket_get_return_path
-};
-
-static const QEMUFileOps socket_write_ops = {
-    .get_fd          = socket_get_fd,
-    .writev_buffer   = socket_writev_buffer,
-    .close           = socket_close,
-    .shut_down       = socket_shutdown,
-    .get_return_path = socket_get_return_path
-};
-
-QEMUFile *qemu_fopen_socket(int fd, const char *mode)
-{
-    QEMUFileSocket *s;
-
-    if (qemu_file_mode_is_not_valid(mode)) {
-        return NULL;
-    }
-
-    s = g_new0(QEMUFileSocket, 1);
-    s->fd = fd;
-    if (mode[0] == 'w') {
-        qemu_set_block(s->fd);
-        s->file = qemu_fopen_ops(s, &socket_write_ops);
-    } else {
-        s->file = qemu_fopen_ops(s, &socket_read_ops);
-    }
-    return s->file;
-}
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (16 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-03  9:58   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c Daniel P. Berrange
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Now that the exec migration backend and savevm have converted
to use the QIOChannel based QEMUFile, there is no user remaining
for the stdio based QEMUFile impl and it can be deleted.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |   2 -
 migration/Makefile.objs       |   2 +-
 migration/qemu-file-stdio.c   | 195 ------------------------------------------
 3 files changed, 1 insertion(+), 198 deletions(-)
 delete mode 100644 migration/qemu-file-stdio.c

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index dc4b7ab..6a66735 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -128,10 +128,8 @@ typedef struct QEMUFileHooks {
 } QEMUFileHooks;
 
 QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
-QEMUFile *qemu_fopen(const char *filename, const char *mode);
 QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
 QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
-QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
 void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
 int qemu_get_fd(QEMUFile *f);
 int qemu_fclose(QEMUFile *f);
diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 2c71056..a127f31 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -1,6 +1,6 @@
 common-obj-y += migration.o tcp.o unix.o fd.o exec.o
 common-obj-y += vmstate.o
-common-obj-y += qemu-file.o qemu-file-stdio.o
+common-obj-y += qemu-file.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 
diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c
deleted file mode 100644
index 9bde9db..0000000
--- a/migration/qemu-file-stdio.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "qemu/coroutine.h"
-#include "migration/qemu-file.h"
-
-typedef struct QEMUFileStdio {
-    FILE *stdio_file;
-    QEMUFile *file;
-} QEMUFileStdio;
-
-static int stdio_get_fd(void *opaque)
-{
-    QEMUFileStdio *s = opaque;
-
-    return fileno(s->stdio_file);
-}
-
-static ssize_t stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
-                                size_t size)
-{
-    QEMUFileStdio *s = opaque;
-    size_t res;
-
-    res = fwrite(buf, 1, size, s->stdio_file);
-
-    if (res != size) {
-        return -errno;
-    }
-    return res;
-}
-
-static ssize_t stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
-                                size_t size)
-{
-    QEMUFileStdio *s = opaque;
-    FILE *fp = s->stdio_file;
-    ssize_t bytes;
-
-    for (;;) {
-        clearerr(fp);
-        bytes = fread(buf, 1, size, fp);
-        if (bytes != 0 || !ferror(fp)) {
-            break;
-        }
-        if (errno == EAGAIN) {
-            yield_until_fd_readable(fileno(fp));
-        } else if (errno != EINTR) {
-            break;
-        }
-    }
-    return bytes;
-}
-
-static int stdio_pclose(void *opaque)
-{
-    QEMUFileStdio *s = opaque;
-    int ret;
-    ret = pclose(s->stdio_file);
-    if (ret == -1) {
-        ret = -errno;
-    } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
-        /* close succeeded, but non-zero exit code: */
-        ret = -EIO; /* fake errno value */
-    }
-    g_free(s);
-    return ret;
-}
-
-static int stdio_fclose(void *opaque)
-{
-    QEMUFileStdio *s = opaque;
-    int ret = 0;
-
-    if (qemu_file_is_writable(s->file)) {
-        int fd = fileno(s->stdio_file);
-        struct stat st;
-
-        ret = fstat(fd, &st);
-        if (ret == 0 && S_ISREG(st.st_mode)) {
-            /*
-             * If the file handle is a regular file make sure the
-             * data is flushed to disk before signaling success.
-             */
-            ret = fsync(fd);
-            if (ret != 0) {
-                ret = -errno;
-                return ret;
-            }
-        }
-    }
-    if (fclose(s->stdio_file) == EOF) {
-        ret = -errno;
-    }
-    g_free(s);
-    return ret;
-}
-
-static const QEMUFileOps stdio_pipe_read_ops = {
-    .get_fd =     stdio_get_fd,
-    .get_buffer = stdio_get_buffer,
-    .close =      stdio_pclose
-};
-
-static const QEMUFileOps stdio_pipe_write_ops = {
-    .get_fd =     stdio_get_fd,
-    .put_buffer = stdio_put_buffer,
-    .close =      stdio_pclose
-};
-
-QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
-{
-    FILE *stdio_file;
-    QEMUFileStdio *s;
-
-    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
-        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
-        return NULL;
-    }
-
-    stdio_file = popen(command, mode);
-    if (stdio_file == NULL) {
-        return NULL;
-    }
-
-    s = g_new0(QEMUFileStdio, 1);
-
-    s->stdio_file = stdio_file;
-
-    if (mode[0] == 'r') {
-        s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
-    } else {
-        s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
-    }
-    return s->file;
-}
-
-static const QEMUFileOps stdio_file_read_ops = {
-    .get_fd =     stdio_get_fd,
-    .get_buffer = stdio_get_buffer,
-    .close =      stdio_fclose
-};
-
-static const QEMUFileOps stdio_file_write_ops = {
-    .get_fd =     stdio_get_fd,
-    .put_buffer = stdio_put_buffer,
-    .close =      stdio_fclose
-};
-
-QEMUFile *qemu_fopen(const char *filename, const char *mode)
-{
-    QEMUFileStdio *s;
-
-    if (qemu_file_mode_is_not_valid(mode)) {
-        return NULL;
-    }
-
-    s = g_new0(QEMUFileStdio, 1);
-
-    s->stdio_file = fopen(filename, mode);
-    if (!s->stdio_file) {
-        goto fail;
-    }
-
-    if (mode[0] == 'w') {
-        s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
-    } else {
-        s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
-    }
-    return s->file;
-fail:
-    g_free(s);
-    return NULL;
-}
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (17 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-05 18:32   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend Daniel P. Berrange
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Now that the memory buffer based QEMUFile impl is gone, there
is no need for any backend to be accessing internals of the
QEMUFile struct, so it can be moved back into qemu-file.c

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/qemu-file-internal.h | 54 ------------------------------------------
 migration/qemu-file.c          | 24 ++++++++++++++++++-
 2 files changed, 23 insertions(+), 55 deletions(-)
 delete mode 100644 migration/qemu-file-internal.h

diff --git a/migration/qemu-file-internal.h b/migration/qemu-file-internal.h
deleted file mode 100644
index 8fdfa95..0000000
--- a/migration/qemu-file-internal.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef QEMU_FILE_INTERNAL_H
-#define QEMU_FILE_INTERNAL_H 1
-
-#include "qemu-common.h"
-#include "qemu/iov.h"
-
-#define IO_BUF_SIZE 32768
-#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
-
-struct QEMUFile {
-    const QEMUFileOps *ops;
-    const QEMUFileHooks *hooks;
-    void *opaque;
-
-    int64_t bytes_xfer;
-    int64_t xfer_limit;
-
-    int64_t pos; /* start of buffer when writing, end of buffer
-                    when reading */
-    int buf_index;
-    int buf_size; /* 0 when writing */
-    uint8_t buf[IO_BUF_SIZE];
-
-    struct iovec iov[MAX_IOV_SIZE];
-    unsigned int iovcnt;
-
-    int last_error;
-};
-
-#endif
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index fc5977e..333f418 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -29,9 +29,31 @@
 #include "qemu/coroutine.h"
 #include "migration/migration.h"
 #include "migration/qemu-file.h"
-#include "migration/qemu-file-internal.h"
 #include "trace.h"
 
+#define IO_BUF_SIZE 32768
+#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
+
+struct QEMUFile {
+    const QEMUFileOps *ops;
+    const QEMUFileHooks *hooks;
+    void *opaque;
+
+    int64_t bytes_xfer;
+    int64_t xfer_limit;
+
+    int64_t pos; /* start of buffer when writing, end of buffer
+                    when reading */
+    int buf_index;
+    int buf_size; /* 0 when writing */
+    uint8_t buf[IO_BUF_SIZE];
+
+    struct iovec iov[MAX_IOV_SIZE];
+    unsigned int iovcnt;
+
+    int last_error;
+};
+
 /*
  * Stop a file from being read/written - not all backing files can do this
  * typically only sockets can.
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (18 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-12 17:09   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers Daniel P. Berrange
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

This extends the TCP migration backend so that it can make use
of QIOChannelTLS to provide transparent TLS encryption. To
trigger enablement the URI on the incoming and outgoing sides
should have 'tls-creds=ID' appended, eg

   tcp:$HOST:$PORT,tls-creds=ID

where ID is the object identifier of a set of TLS credentials
previously created using object_add / -object. There is not
currently any support for checking the migration client
certificate names against ACLs. This is pending a conversion
of the ACL code to QOM.

There is no support for dynamically negotiating use of TLS
between the incoming/outgoing side. Both sides must agree
on use of TLS out of band and set the URI accordingly. In
practice it is expected that the administrator will just
turn on use of TLS on their hosts in the libvirt config
and then libvirt will instruct QEMU to use TLS for migration.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 migration/tcp.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 qemu-options.hx |   7 +-
 2 files changed, 264 insertions(+), 16 deletions(-)

diff --git a/migration/tcp.c b/migration/tcp.c
index ac73977..bef861c 100644
--- a/migration/tcp.c
+++ b/migration/tcp.c
@@ -22,6 +22,8 @@
 #include "migration/migration.h"
 #include "migration/qemu-file.h"
 #include "io/channel-socket.h"
+#include "io/channel-tls.h"
+#include "crypto/tlscreds.h"
 
 //#define DEBUG_MIGRATION_TCP
 
@@ -33,6 +35,22 @@
     do { } while (0)
 #endif
 
+typedef struct {
+    MigrationState *s;
+    QCryptoTLSCreds *tlscreds;
+    char *hostname;
+} TCPConnectData;
+
+typedef struct {
+    MigrationState *s;
+    QCryptoTLSCreds *tlscreds;
+} TCPListenData;
+
+typedef struct {
+    MigrationState *s;
+    QIOChannel *ioc;
+} TCPConnectTLSData;
+
 
 static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
 {
@@ -51,21 +69,174 @@ static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
 }
 
 
+static void tcp_connect_data_free(gpointer opaque)
+{
+    TCPConnectData *data = opaque;
+    if (!data) {
+        return;
+    }
+    g_free(data->hostname);
+    object_unref(OBJECT(data->tlscreds));
+    g_free(data);
+}
+
+
+static void tcp_listen_data_free(gpointer opaque)
+{
+    TCPListenData *data = opaque;
+    if (!data) {
+        return;
+    }
+    object_unref(OBJECT(data->tlscreds));
+    g_free(data);
+}
+
+
+static void tcp_connect_tls_data_free(gpointer opaque)
+{
+    TCPConnectTLSData *data = opaque;
+    if (!data) {
+        return;
+    }
+    object_unref(OBJECT(data->ioc));
+    g_free(data);
+}
+
+
+static char *tcp_get_opt_str(const char *host_port,
+                             const char *key)
+{
+    const char *offset, *end;
+
+    offset = strstr(host_port, key);
+    if (!offset) {
+        return NULL;
+    }
+
+    offset += strlen(key);
+    if (offset[0] != '=') {
+        return NULL;
+    }
+    offset++;
+    end = strchr(offset, ',');
+    if (end) {
+        return g_strndup(offset, end - offset);
+    } else {
+        return g_strdup(offset);
+    }
+}
+
+
+static QCryptoTLSCreds *tcp_get_tls_creds(const char *host_port,
+                                          bool is_listen,
+                                          Error **errp)
+{
+    char *credname = NULL;
+    Object *creds;
+    QCryptoTLSCreds *ret;
+
+    credname = tcp_get_opt_str(host_port, "tls-creds");
+    if (!credname) {
+        return NULL;
+    }
+
+    creds = object_resolve_path_component(
+        object_get_objects_root(), credname);
+    if (!creds) {
+        error_setg(errp, "No TLS credentials with id '%s'",
+                   credname);
+        goto error;
+    }
+    ret = (QCryptoTLSCreds *)object_dynamic_cast(
+        creds, TYPE_QCRYPTO_TLS_CREDS);
+    if (!ret) {
+        error_setg(errp, "Object with id '%s' is not TLS credentials",
+                   credname);
+        goto error;
+    }
+    if (is_listen) {
+        if (ret->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+            error_setg(errp, "%s",
+                       "Expected TLS credentials for server endpoint");
+            goto error;
+        }
+    } else {
+        if (ret->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+            error_setg(errp, "%s",
+                       "Expected TLS credentials for client endpoint");
+            goto error;
+        }
+    }
+
+    g_free(credname);
+    object_ref(OBJECT(ret));
+    return ret;
+
+ error:
+    g_free(credname);
+    return NULL;
+}
+
+
+static void tcp_outgoing_migration_tls(Object *src,
+                                       Error *err,
+                                       gpointer opaque)
+{
+    TCPConnectTLSData *data = opaque;
+    QIOChannel *ioc = QIO_CHANNEL(src);
+
+    if (err) {
+        DPRINTF("migrate connect TLS error: %s\n", error_get_pretty(err));
+        data->s->file = NULL;
+        migrate_fd_error(data->s);
+    } else {
+        DPRINTF("migrate connect success\n");
+        data->s->file = qemu_fopen_channel_output(ioc);
+        migrate_fd_connect(data->s);
+    }
+}
+
+
 static void tcp_outgoing_migration(Object *src,
                                    Error *err,
                                    gpointer opaque)
 {
-    MigrationState *s = opaque;
+    TCPConnectData *data = opaque;
     QIOChannel *sioc = QIO_CHANNEL(src);
 
     if (err) {
         DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
-        s->file = NULL;
-        migrate_fd_error(s);
+        data->s->file = NULL;
+        migrate_fd_error(data->s);
     } else {
-        DPRINTF("migrate connect success\n");
-        s->file = qemu_fopen_channel_output(sioc);
-        migrate_fd_connect(s);
+        if (data->tlscreds) {
+            Error *local_err = NULL;
+            QIOChannelTLS *tioc = qio_channel_tls_new_client(
+                sioc, data->tlscreds, data->hostname,
+                &local_err);
+            if (!tioc) {
+                DPRINTF("migrate tls setup error: %s\n",
+                        error_get_pretty(local_err));
+                error_free(local_err);
+                data->s->file = NULL;
+                migrate_fd_error(data->s);
+            } else {
+                TCPConnectTLSData *tdata =
+                    g_new0(TCPConnectTLSData, 1);
+                DPRINTF("migrate connect tls handshake begin\n");
+                tdata->s = data->s;
+                tdata->ioc = sioc;
+                object_ref(OBJECT(sioc));
+                qio_channel_tls_handshake(tioc,
+                                          tcp_outgoing_migration_tls,
+                                          tdata,
+                                          tcp_connect_tls_data_free);
+            }
+        } else {
+            DPRINTF("migrate connect success\n");
+            data->s->file = qemu_fopen_channel_output(sioc);
+            migrate_fd_connect(data->s);
+        }
     }
     object_unref(src);
 }
@@ -77,21 +248,56 @@ void tcp_start_outgoing_migration(MigrationState *s,
 {
     SocketAddress *saddr = tcp_build_address(host_port, errp);
     QIOChannelSocket *sioc;
+    Error *local_err = NULL;
+    QCryptoTLSCreds *creds;
+    TCPConnectData *data;
 
     if (!saddr) {
         return;
     }
 
+    creds = tcp_get_tls_creds(host_port, false, errp);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        qapi_free_SocketAddress(saddr);
+        return;
+    }
+
+    data = g_new0(TCPConnectData, 1);
+    data->s = s;
+    if (creds) {
+        data->hostname = g_strdup(saddr->u.inet->host);
+        data->tlscreds = creds;
+    }
+
     sioc = qio_channel_socket_new();
     qio_channel_socket_connect_async(sioc,
                                      saddr,
                                      tcp_outgoing_migration,
-                                     s,
-                                     NULL);
+                                     data,
+                                     tcp_connect_data_free);
     qapi_free_SocketAddress(saddr);
 }
 
 
+static void tcp_incoming_migration_tls(Object *src,
+                                       Error *err,
+                                       gpointer opaque)
+{
+    QIOChannel *ioc = QIO_CHANNEL(src);
+
+    if (err) {
+        DPRINTF("migrate listen TLS error: %s\n", error_get_pretty(err));
+        object_unref(OBJECT(ioc));
+    } else {
+        DPRINTF("migrate listen success\n");
+        QEMUFile *f = qemu_fopen_channel_input(ioc);
+
+        process_incoming_migration(f);
+    }
+}
+
+
 static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
                                               GIOCondition condition,
                                               gpointer opaque)
@@ -99,6 +305,7 @@ static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
     QEMUFile *f;
     QIOChannelSocket *cioc;
     Error *err = NULL;
+    TCPListenData *data = opaque;
 
     cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
                                      &err);
@@ -108,16 +315,38 @@ static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
         goto out;
     }
 
-    DPRINTF("accepted migration\n");
+    if (data->tlscreds) {
+        DPRINTF("Starting client TLS\n");
+        QIOChannelTLS *tioc = qio_channel_tls_new_server(
+            QIO_CHANNEL(cioc), data->tlscreds,
+            NULL, /* XXX pass ACL name */
+            &err);
+        object_unref(OBJECT(cioc));
+        if (!tioc) {
+            DPRINTF("migrate tls setup error: %s\n",
+                    error_get_pretty(err));
+            error_free(err);
+            goto out;
+        } else {
+            DPRINTF("migrate connect tls handshake begin\n");
+            qio_channel_tls_handshake(tioc,
+                                      tcp_incoming_migration_tls,
+                                      NULL,
+                                      NULL);
+        }
+    } else {
+        DPRINTF("accepted migration\n");
 
-    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
-    object_unref(OBJECT(cioc));
+        f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
+        object_unref(OBJECT(cioc));
 
-    process_incoming_migration(f);
+        process_incoming_migration(f);
+    }
 
 out:
     /* Close listening socket as its no longer needed */
     qio_channel_close(ioc, NULL);
+    object_unref(OBJECT(ioc));
     return FALSE;
 }
 
@@ -126,23 +355,39 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
 {
     SocketAddress *saddr = tcp_build_address(host_port, errp);
     QIOChannelSocket *listen_ioc;
+    TCPListenData *data;
+    Error *local_err = NULL;
+    QCryptoTLSCreds *creds;
 
     if (!saddr) {
         return;
     }
 
+    creds = tcp_get_tls_creds(host_port, true, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        qapi_free_SocketAddress(saddr);
+        return;
+    }
+
     listen_ioc = qio_channel_socket_new();
     if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
         object_unref(OBJECT(listen_ioc));
         qapi_free_SocketAddress(saddr);
+        object_unref(OBJECT(creds));
         return;
     }
 
+    data = g_new0(TCPListenData, 1);
+    if (creds) {
+        data->tlscreds = creds;
+    }
+
     qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
                           G_IO_IN,
                           tcp_accept_incoming_migration,
-                          listen_ioc,
-                          (GDestroyNotify)object_unref);
+                          data,
+                          tcp_listen_data_free);
 
     qapi_free_SocketAddress(saddr);
 }
diff --git a/qemu-options.hx b/qemu-options.hx
index 215d00d..3f16cfc 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3364,7 +3364,7 @@ Set TB size.
 ETEXI
 
 DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
-    "-incoming tcp:[host]:port[,to=maxport][,ipv4][,ipv6]\n" \
+    "-incoming tcp:[host]:port[,to=maxport][,ipv4][,ipv6][,tls-creds=ID]\n" \
     "-incoming rdma:host:port[,ipv4][,ipv6]\n" \
     "-incoming unix:socketpath\n" \
     "                prepare for incoming migration, listen on\n" \
@@ -3377,11 +3377,14 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
     "                wait for the URI to be specified via migrate_incoming\n",
     QEMU_ARCH_ALL)
 STEXI
-@item -incoming tcp:[@var{host}]:@var{port}[,to=@var{maxport}][,ipv4][,ipv6]
+@item -incoming tcp:[@var{host}]:@var{port}[,to=@var{maxport}][,ipv4][,ipv6][,tls-creds=ID]
 @itemx -incoming rdma:@var{host}:@var{port}[,ipv4][,ipv6]
 @findex -incoming
 Prepare for incoming migration, listen on a given tcp port.
 
+If the @var{tls-creds} parameter is specified, it should refer to the ID
+of a TLS credentials object previously created with @var{-object}.
+
 @item -incoming unix:@var{socketpath}
 Prepare for incoming migration, listen on a given unix socket.
 
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (19 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-12 15:48   ` Dr. David Alan Gilbert
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile Daniel P. Berrange
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

All the remaining QEMUFile implementations provide an iovec
based write handler, so the put_buffer callback can be removed
to simplify the code.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  9 ---------
 migration/qemu-file.c         | 36 ++++++++----------------------------
 migration/savevm.c            |  8 --------
 3 files changed, 8 insertions(+), 45 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 6a66735..4ee40e4 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -29,14 +29,6 @@
 
 #include <stdint.h>
 
-/* This function writes a chunk of data to a file at the given position.
- * The pos argument can be ignored if the file is only being used for
- * streaming.  The handler must write all of the data or return a negative
- * errno value.
- */
-typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
-                                        int64_t pos, size_t size);
-
 /* Read a chunk of data from a file at the given position.  The pos argument
  * can be ignored if the file is only be used for streaming.  The number of
  * bytes actually read should be returned.
@@ -110,7 +102,6 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
 typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
 
 typedef struct QEMUFileOps {
-    QEMUFilePutBufferFunc *put_buffer;
     QEMUFileGetBufferFunc *get_buffer;
     QEMUFileCloseFunc *close;
     QEMUFileGetFD *get_fd;
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 333f418..372a6b9 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -128,7 +128,7 @@ void qemu_file_set_error(QEMUFile *f, int ret)
 
 bool qemu_file_is_writable(QEMUFile *f)
 {
-    return f->ops->writev_buffer || f->ops->put_buffer;
+    return f->ops->writev_buffer;
 }
 
 /**
@@ -147,16 +147,9 @@ void qemu_fflush(QEMUFile *f)
         return;
     }
 
-    if (f->ops->writev_buffer) {
-        if (f->iovcnt > 0) {
-            expect = iov_size(f->iov, f->iovcnt);
-            ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
-        }
-    } else {
-        if (f->buf_index > 0) {
-            expect = f->buf_index;
-            ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
-        }
+    if (f->iovcnt > 0) {
+        expect = iov_size(f->iov, f->iovcnt);
+        ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
     }
 
     if (ret >= 0) {
@@ -336,11 +329,6 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size)
 
 void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size)
 {
-    if (!f->ops->writev_buffer) {
-        qemu_put_buffer(f, buf, size);
-        return;
-    }
-
     if (f->last_error) {
         return;
     }
@@ -364,9 +352,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size)
         }
         memcpy(f->buf + f->buf_index, buf, l);
         f->bytes_xfer += l;
-        if (f->ops->writev_buffer) {
-            add_to_iovec(f, f->buf + f->buf_index, l);
-        }
+        add_to_iovec(f, f->buf + f->buf_index, l);
         f->buf_index += l;
         if (f->buf_index == IO_BUF_SIZE) {
             qemu_fflush(f);
@@ -387,9 +373,7 @@ void qemu_put_byte(QEMUFile *f, int v)
 
     f->buf[f->buf_index] = v;
     f->bytes_xfer++;
-    if (f->ops->writev_buffer) {
-        add_to_iovec(f, f->buf + f->buf_index, 1);
-    }
+    add_to_iovec(f, f->buf + f->buf_index, 1);
     f->buf_index++;
     if (f->buf_index == IO_BUF_SIZE) {
         qemu_fflush(f);
@@ -553,12 +537,8 @@ int64_t qemu_ftell_fast(QEMUFile *f)
     int64_t ret = f->pos;
     int i;
 
-    if (f->ops->writev_buffer) {
-        for (i = 0; i < f->iovcnt; i++) {
-            ret += f->iov[i].iov_len;
-        }
-    } else {
-        ret += f->buf_index;
+    for (i = 0; i < f->iovcnt; i++) {
+        ret += f->iov[i].iov_len;
     }
 
     return ret;
diff --git a/migration/savevm.c b/migration/savevm.c
index e57d7ce..a991c0c 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -160,13 +160,6 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
     return qiov.size;
 }
 
-static ssize_t block_put_buffer(void *opaque, const uint8_t *buf,
-                                int64_t pos, size_t size)
-{
-    bdrv_save_vmstate(opaque, buf, pos, size);
-    return size;
-}
-
 static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
                                 size_t size)
 {
@@ -184,7 +177,6 @@ static const QEMUFileOps bdrv_read_ops = {
 };
 
 static const QEMUFileOps bdrv_write_ops = {
-    .put_buffer     = block_put_buffer,
     .writev_buffer  = block_writev_buffer,
     .close          = bdrv_fclose
 };
-- 
2.5.0

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

* [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (20 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers Daniel P. Berrange
@ 2016-01-12 11:44 ` Daniel P. Berrange
  2016-02-12 15:51   ` Dr. David Alan Gilbert
  2016-01-12 11:59 ` [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
  2016-01-20 18:01 ` Daniel P. Berrange
  23 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

Now that there is a set_blocking callback in QEMUFileOps,
and all users needing non-blocking support have been
converted to QIOChannel, there is no longer any codepath
requiring the qemu_get_fd() method for QEMUFile. Remove it
to avoid further code being introduced with an expectation
of direct file handle access.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/migration/qemu-file.h |  1 -
 migration/qemu-file.c         | 14 --------------
 2 files changed, 15 deletions(-)

diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
index 4ee40e4..68bc165 100644
--- a/include/migration/qemu-file.h
+++ b/include/migration/qemu-file.h
@@ -104,7 +104,6 @@ typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
 typedef struct QEMUFileOps {
     QEMUFileGetBufferFunc *get_buffer;
     QEMUFileCloseFunc *close;
-    QEMUFileGetFD *get_fd;
     QEMUFileSetBlocking *set_blocking;
     QEMUFileWritevBufferFunc *writev_buffer;
     QEMURetPathFunc *get_return_path;
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 372a6b9..baef865 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -267,14 +267,6 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
     return len;
 }
 
-int qemu_get_fd(QEMUFile *f)
-{
-    if (f->ops->get_fd) {
-        return f->ops->get_fd(f->opaque);
-    }
-    return -1;
-}
-
 void qemu_update_position(QEMUFile *f, size_t size)
 {
     f->pos += size;
@@ -687,11 +679,5 @@ void qemu_file_set_blocking(QEMUFile *f, bool block)
 {
     if (f->ops->set_blocking) {
         f->ops->set_blocking(f->opaque, block);
-    } else {
-        if (block) {
-            qemu_set_block(qemu_get_fd(f));
-        } else {
-            qemu_set_nonblock(qemu_get_fd(f));
-        }
     }
 }
-- 
2.5.0

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

* Re: [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
@ 2016-01-12 11:58   ` Cornelia Huck
  2016-01-12 12:01     ` Daniel P. Berrange
  2016-02-12 17:19   ` Dr. David Alan Gilbert
  1 sibling, 1 reply; 66+ messages in thread
From: Cornelia Huck @ 2016-01-12 11:58 UTC (permalink / raw)
  To: Daniel P. Berrange
  Cc: Amit Shah, Juan Quintela, qemu-devel, Jason J. Herne,
	Dr. David Alan Gilbert

On Tue, 12 Jan 2016 11:43:55 +0000
"Daniel P. Berrange" <berrange@redhat.com> wrote:

> The s390 skeys monitor command needs to write out a plain text
> file. Currently it is using the QEMUFile class for this. There
> is no real benefit to this, and the downside is that it needs to
> snprintf via an intermediate buffer. Switching to regular FILE
> objects simplifies the code.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  hw/s390x/s390-skeys.c | 19 +++++++------------
>  1 file changed, 7 insertions(+), 12 deletions(-)

> @@ -124,7 +119,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
>          return;
>      }
> 
> -    f = qemu_fopen(filename, "wb");
> +    f = fopen(filename, "wb");
>      if (!f) {
>          error_setg_file_open(errp, errno, filename);
>          return;

Hmm...

https://marc.info/?l=qemu-devel&m=143740278908660&w=2

We'd lose the benefits from qemu_fopen() here again, or am I missing
something?

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

* Re: [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (21 preceding siblings ...)
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile Daniel P. Berrange
@ 2016-01-12 11:59 ` Daniel P. Berrange
  2016-01-20 18:01 ` Daniel P. Berrange
  23 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 11:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

BTW, also available at

  https://github.com/berrange/qemu/tree/io-channel-migration-1

On Tue, Jan 12, 2016 at 11:43:54AM +0000, Daniel P. Berrange wrote:
> This is a formal posting of patches that were previously
> previewed at:
> 
>   FYI: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg00829.html
> 
> The primary goal of this series of patches is to support TLS on the
> migration data channel. The bulk of the work in this series though,
> is converting the various QEMUFile implementations to be baed on the
> new QIOChannel framework.
> 
> At the end of this current series there is just one remaining impl
> of QEMUFileOps that is not based on QIOChannel - the one in savevm.c
> that is using BlockDriverState. It would be possible to create a
> QIOChannel wrapper around BlockDriverState too, at which point all
> QEMUFile impls would be QIOChannel based. This would then let us
> cut out the QEMUFileOps driver callbacks entirely and thus simply
> code even more. This patch series is already too large, so I left
> that for now.
> 
> The first 6 patchs are some basic clean ups to QEMUFile code
> 
> The 7th patch introduces the QIOChannel based QEMUFile impl
> 
> Patches 8-14 convert the various migration protocols to use
> the QIOChannel based QEMUFile impl.
> 
> Patches 15-18 remove the now unused QEMUFile impls that do
> not use QIOChanel
> 
> Patches 19, 21 and 22 does some more cleanup
> 
> Patch 20 achieves the original stated primary goal of adding
> TLS encryption to the TCP migration backend.
> 
> Overall we have a net win of deleting 500 lines of code,
> despite adding more features, which is always nice.
> 
> I testing unix, tcp, exec migrations. I don't have the ability
> to test RDMA migration, and that's the patch I'm also least
> confident about code quality of, so would appreciated some
> independant testing of that one in particular.
> 
> 
> Daniel P. Berrange (22):
>   s390: use FILE instead of QEMUFile for creating text file
>   migration: remove use of qemu_bufopen from vmstate tests
>   migration: ensure qemu_fflush() always writes full data amount
>   migration: split migration hooks out of QEMUFileOps
>   migration: introduce set_blocking function in QEMUFileOps
>   migration: force QEMUFile to blocking mode for outgoing migration
>   migration: introduce a new QEMUFile impl based on QIOChannel
>   migration: convert post-copy to use QIOChannelBuffer
>   migration: convert unix socket protocol to use QIOChannel
>   migration: convert tcp socket protocol to use QIOChannel
>   migration: convert fd socket protocol to use QIOChannel
>   migration: convert exec socket protocol to use QIOChannel
>   migration: convert RDMA to use QIOChannel interface
>   migration: convert savevm to use QIOChannel for writing to files
>   migration: delete QEMUFile buffer implementation
>   migration: delete QEMUSizedBuffer struct
>   migration: delete QEMUFile sockets implementation
>   migration: delete QEMUFile stdio implementation
>   migration: move definition of struct QEMUFile back into qemu-file.c
>   migration: support TLS encryption with TCP migration backend
>   migration: remove support for non-iovec based write handlers
>   migration: remove qemu_get_fd method from QEMUFile
> 
>  docs/migration.txt             |   4 +-
>  hw/s390x/s390-skeys.c          |  19 +-
>  include/migration/qemu-file.h  |  57 ++---
>  include/qemu/typedefs.h        |   1 -
>  include/sysemu/sysemu.h        |   2 +-
>  migration/Makefile.objs        |   6 +-
>  migration/exec.c               |  48 +++--
>  migration/fd.c                 |  57 +++--
>  migration/migration.c          |  24 +--
>  migration/qemu-file-buf.c      | 463 -----------------------------------------
>  migration/qemu-file-channel.c  | 201 ++++++++++++++++++
>  migration/qemu-file-internal.h |  53 -----
>  migration/qemu-file-stdio.c    | 195 -----------------
>  migration/qemu-file-unix.c     | 324 ----------------------------
>  migration/qemu-file.c          | 110 +++++-----
>  migration/rdma.c               | 256 ++++++++++++++---------
>  migration/savevm.c             |  57 ++---
>  migration/tcp.c                | 372 +++++++++++++++++++++++++++++----
>  migration/unix.c               | 103 +++++----
>  qemu-options.hx                |   7 +-
>  tests/Makefile                 |   6 +-
>  tests/test-vmstate.c           |  55 ++---
>  22 files changed, 975 insertions(+), 1445 deletions(-)
>  delete mode 100644 migration/qemu-file-buf.c
>  create mode 100644 migration/qemu-file-channel.c
>  delete mode 100644 migration/qemu-file-internal.h
>  delete mode 100644 migration/qemu-file-stdio.c
>  delete mode 100644 migration/qemu-file-unix.c
> 
> -- 
> 2.5.0
> 

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file
  2016-01-12 11:58   ` Cornelia Huck
@ 2016-01-12 12:01     ` Daniel P. Berrange
  2016-01-12 12:05       ` Cornelia Huck
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-12 12:01 UTC (permalink / raw)
  To: Cornelia Huck
  Cc: Amit Shah, Juan Quintela, qemu-devel, Jason J. Herne,
	Dr. David Alan Gilbert

On Tue, Jan 12, 2016 at 12:58:10PM +0100, Cornelia Huck wrote:
> On Tue, 12 Jan 2016 11:43:55 +0000
> "Daniel P. Berrange" <berrange@redhat.com> wrote:
> 
> > The s390 skeys monitor command needs to write out a plain text
> > file. Currently it is using the QEMUFile class for this. There
> > is no real benefit to this, and the downside is that it needs to
> > snprintf via an intermediate buffer. Switching to regular FILE
> > objects simplifies the code.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  hw/s390x/s390-skeys.c | 19 +++++++------------
> >  1 file changed, 7 insertions(+), 12 deletions(-)
> 
> > @@ -124,7 +119,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
> >          return;
> >      }
> > 
> > -    f = qemu_fopen(filename, "wb");
> > +    f = fopen(filename, "wb");
> >      if (!f) {
> >          error_setg_file_open(errp, errno, filename);
> >          return;
> 
> Hmm...
> 
> https://marc.info/?l=qemu-devel&m=143740278908660&w=2
> 
> We'd lose the benefits from qemu_fopen() here again, or am I missing
> something?

Oh, that message shouldn't really have recommended qemu_fopen() - it only
needs qemu_open() to get the fd passing support. I'll change this to use
qemu_open() + fdopen() instead, so we still support FD passing while
using normal stdio.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file
  2016-01-12 12:01     ` Daniel P. Berrange
@ 2016-01-12 12:05       ` Cornelia Huck
  0 siblings, 0 replies; 66+ messages in thread
From: Cornelia Huck @ 2016-01-12 12:05 UTC (permalink / raw)
  To: Daniel P. Berrange
  Cc: Amit Shah, Juan Quintela, qemu-devel, Jason J. Herne,
	Dr. David Alan Gilbert

On Tue, 12 Jan 2016 12:01:21 +0000
"Daniel P. Berrange" <berrange@redhat.com> wrote:

> On Tue, Jan 12, 2016 at 12:58:10PM +0100, Cornelia Huck wrote:
> > On Tue, 12 Jan 2016 11:43:55 +0000
> > "Daniel P. Berrange" <berrange@redhat.com> wrote:
> > 
> > > The s390 skeys monitor command needs to write out a plain text
> > > file. Currently it is using the QEMUFile class for this. There
> > > is no real benefit to this, and the downside is that it needs to
> > > snprintf via an intermediate buffer. Switching to regular FILE
> > > objects simplifies the code.
> > > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  hw/s390x/s390-skeys.c | 19 +++++++------------
> > >  1 file changed, 7 insertions(+), 12 deletions(-)
> > 
> > > @@ -124,7 +119,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
> > >          return;
> > >      }
> > > 
> > > -    f = qemu_fopen(filename, "wb");
> > > +    f = fopen(filename, "wb");
> > >      if (!f) {
> > >          error_setg_file_open(errp, errno, filename);
> > >          return;
> > 
> > Hmm...
> > 
> > https://marc.info/?l=qemu-devel&m=143740278908660&w=2
> > 
> > We'd lose the benefits from qemu_fopen() here again, or am I missing
> > something?
> 
> Oh, that message shouldn't really have recommended qemu_fopen() - it only
> needs qemu_open() to get the fd passing support. I'll change this to use
> qemu_open() + fdopen() instead, so we still support FD passing while
> using normal stdio.

Sounds good.

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

* Re: [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS
  2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
                   ` (22 preceding siblings ...)
  2016-01-12 11:59 ` [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
@ 2016-01-20 18:01 ` Daniel P. Berrange
  23 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-20 18:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Amit Shah, Dr. David Alan Gilbert, Juan Quintela

ping, any thoughts on this series.

This native encryption is pretty important to the openstack community,
along with NBD encryption, so I'd like to try and get it ready in
time for 2.6.

Regards,
Daniel

On Tue, Jan 12, 2016 at 11:43:54AM +0000, Daniel P. Berrange wrote:
> This is a formal posting of patches that were previously
> previewed at:
> 
>   FYI: https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg00829.html
> 
> The primary goal of this series of patches is to support TLS on the
> migration data channel. The bulk of the work in this series though,
> is converting the various QEMUFile implementations to be baed on the
> new QIOChannel framework.
> 
> At the end of this current series there is just one remaining impl
> of QEMUFileOps that is not based on QIOChannel - the one in savevm.c
> that is using BlockDriverState. It would be possible to create a
> QIOChannel wrapper around BlockDriverState too, at which point all
> QEMUFile impls would be QIOChannel based. This would then let us
> cut out the QEMUFileOps driver callbacks entirely and thus simply
> code even more. This patch series is already too large, so I left
> that for now.
> 
> The first 6 patchs are some basic clean ups to QEMUFile code
> 
> The 7th patch introduces the QIOChannel based QEMUFile impl
> 
> Patches 8-14 convert the various migration protocols to use
> the QIOChannel based QEMUFile impl.
> 
> Patches 15-18 remove the now unused QEMUFile impls that do
> not use QIOChanel
> 
> Patches 19, 21 and 22 does some more cleanup
> 
> Patch 20 achieves the original stated primary goal of adding
> TLS encryption to the TCP migration backend.
> 
> Overall we have a net win of deleting 500 lines of code,
> despite adding more features, which is always nice.
> 
> I testing unix, tcp, exec migrations. I don't have the ability
> to test RDMA migration, and that's the patch I'm also least
> confident about code quality of, so would appreciated some
> independant testing of that one in particular.
> 
> 
> Daniel P. Berrange (22):
>   s390: use FILE instead of QEMUFile for creating text file
>   migration: remove use of qemu_bufopen from vmstate tests
>   migration: ensure qemu_fflush() always writes full data amount
>   migration: split migration hooks out of QEMUFileOps
>   migration: introduce set_blocking function in QEMUFileOps
>   migration: force QEMUFile to blocking mode for outgoing migration
>   migration: introduce a new QEMUFile impl based on QIOChannel
>   migration: convert post-copy to use QIOChannelBuffer
>   migration: convert unix socket protocol to use QIOChannel
>   migration: convert tcp socket protocol to use QIOChannel
>   migration: convert fd socket protocol to use QIOChannel
>   migration: convert exec socket protocol to use QIOChannel
>   migration: convert RDMA to use QIOChannel interface
>   migration: convert savevm to use QIOChannel for writing to files
>   migration: delete QEMUFile buffer implementation
>   migration: delete QEMUSizedBuffer struct
>   migration: delete QEMUFile sockets implementation
>   migration: delete QEMUFile stdio implementation
>   migration: move definition of struct QEMUFile back into qemu-file.c
>   migration: support TLS encryption with TCP migration backend
>   migration: remove support for non-iovec based write handlers
>   migration: remove qemu_get_fd method from QEMUFile
> 
>  docs/migration.txt             |   4 +-
>  hw/s390x/s390-skeys.c          |  19 +-
>  include/migration/qemu-file.h  |  57 ++---
>  include/qemu/typedefs.h        |   1 -
>  include/sysemu/sysemu.h        |   2 +-
>  migration/Makefile.objs        |   6 +-
>  migration/exec.c               |  48 +++--
>  migration/fd.c                 |  57 +++--
>  migration/migration.c          |  24 +--
>  migration/qemu-file-buf.c      | 463 -----------------------------------------
>  migration/qemu-file-channel.c  | 201 ++++++++++++++++++
>  migration/qemu-file-internal.h |  53 -----
>  migration/qemu-file-stdio.c    | 195 -----------------
>  migration/qemu-file-unix.c     | 324 ----------------------------
>  migration/qemu-file.c          | 110 +++++-----
>  migration/rdma.c               | 256 ++++++++++++++---------
>  migration/savevm.c             |  57 ++---
>  migration/tcp.c                | 372 +++++++++++++++++++++++++++++----
>  migration/unix.c               | 103 +++++----
>  qemu-options.hx                |   7 +-
>  tests/Makefile                 |   6 +-
>  tests/test-vmstate.c           |  55 ++---
>  22 files changed, 975 insertions(+), 1445 deletions(-)
>  delete mode 100644 migration/qemu-file-buf.c
>  create mode 100644 migration/qemu-file-channel.c
>  delete mode 100644 migration/qemu-file-internal.h
>  delete mode 100644 migration/qemu-file-stdio.c
>  delete mode 100644 migration/qemu-file-unix.c
> 
> -- 
> 2.5.0
> 

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer Daniel P. Berrange
@ 2016-01-25 19:38   ` Dr. David Alan Gilbert
  2016-01-25 22:15     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-25 19:38 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> The post-copy code does some I/O to/from an intermediate
> in-memory buffer rather than direct to the underlying
> I/O channel. Switch this code to use QIOChannelBuffer
> instead of QEMUSizedBuffer.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  docs/migration.txt      |  4 ++--
>  include/sysemu/sysemu.h |  2 +-
>  migration/migration.c   | 15 +++++++--------
>  migration/savevm.c      | 41 +++++++++++++----------------------------
>  4 files changed, 23 insertions(+), 39 deletions(-)
> 
> diff --git a/docs/migration.txt b/docs/migration.txt
> index fda8d61..11703de 100644
> --- a/docs/migration.txt
> +++ b/docs/migration.txt
> @@ -403,8 +403,8 @@ listen thread:                     --- page -- page -- page -- page -- page --
>  
>  On receipt of CMD_PACKAGED (1)
>     All the data associated with the package - the ( ... ) section in the
> -diagram - is read into memory (into a QEMUSizedBuffer), and the main thread
> -recurses into qemu_loadvm_state_main to process the contents of the package (2)
> +diagram - is read into memory, and the main thread recurses into
> +qemu_loadvm_state_main to process the contents of the package (2)
>  which contains commands (3,6) and devices (4...)
>  
>  On receipt of 'postcopy listen' - 3 -(i.e. the 1st command in the package)
> diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> index 3bb8897..0f59912 100644
> --- a/include/sysemu/sysemu.h
> +++ b/include/sysemu/sysemu.h
> @@ -120,7 +120,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
>                                uint16_t len, uint8_t *data);
>  void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
>  void qemu_savevm_send_open_return_path(QEMUFile *f);
> -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
> +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len);
>  void qemu_savevm_send_postcopy_advise(QEMUFile *f);
>  void qemu_savevm_send_postcopy_listen(QEMUFile *f);
>  void qemu_savevm_send_postcopy_run(QEMUFile *f);
> diff --git a/migration/migration.c b/migration/migration.c
> index 715f069..e921b20 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -33,6 +33,7 @@
>  #include "qom/cpu.h"
>  #include "exec/memory.h"
>  #include "exec/address-spaces.h"
> +#include "io/channel-buffer.h"
>  
>  #define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
>  
> @@ -1401,7 +1402,8 @@ static int await_return_path_close_on_source(MigrationState *ms)
>  static int postcopy_start(MigrationState *ms, bool *old_vm_running)
>  {
>      int ret;
> -    const QEMUSizedBuffer *qsb;
> +    QIOChannelBuffer *bioc;
> +    QEMUFile *fb;
>      int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
>      migrate_set_state(ms, MIGRATION_STATUS_ACTIVE,
>                        MIGRATION_STATUS_POSTCOPY_ACTIVE);
> @@ -1456,11 +1458,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
>       * So we wrap the device state up in a package with a length at the start;
>       * to do this we use a qemu_buf to hold the whole of the device state.
>       */
> -    QEMUFile *fb = qemu_bufopen("w", NULL);
> -    if (!fb) {
> -        error_report("Failed to create buffered file");
> -        goto fail;
> -    }
> +    bioc = qio_channel_buffer_new(4096);
> +    fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc));

Why is that _input ?
Also, what's your naming converntion; my 'qsb' was just an
abbreviation of (Q)EMU(S)ized(B)uffer;  what's a bioc?

> +    object_unref(OBJECT(bioc));
>  
>      /*
>       * Make sure the receiver can get incoming pages before we send the rest
> @@ -1474,10 +1474,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
>      qemu_savevm_send_postcopy_run(fb);
>  
>      /* <><> end of stuff going into the package */
> -    qsb = qemu_buf_get(fb);
>  
>      /* Now send that blob */
> -    if (qemu_savevm_send_packaged(ms->file, qsb)) {
> +    if (qemu_savevm_send_packaged(ms->file, bioc->data, bioc->usage)) {
>          goto fail_closefb;
>      }
>      qemu_fclose(fb);
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 0ad1b93..f2e1880 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -50,6 +50,7 @@
>  #include "qemu/iov.h"
>  #include "block/snapshot.h"
>  #include "block/qapi.h"
> +#include "io/channel-buffer.h"
>  
>  
>  #ifndef ETH_P_RARP
> @@ -760,10 +761,8 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
>   *    0 on success
>   *    -ve on error
>   */
> -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
> +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len)
>  {
> -    size_t cur_iov;
> -    size_t len = qsb_get_length(qsb);
>      uint32_t tmp;
>  
>      if (len > MAX_VM_CMD_PACKAGED_SIZE) {
> @@ -777,18 +776,7 @@ int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
>      trace_qemu_savevm_send_packaged();
>      qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
>  
> -    /* all the data follows (concatinating the iov's) */
> -    for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
> -        /* The iov entries are partially filled */
> -        size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
> -        len -= towrite;
> -
> -        if (!towrite) {
> -            break;
> -        }
> -
> -        qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
> -    }
> +    qemu_put_buffer(f, (const uint8_t *)buf, len);
>  
>      return 0;
>  }
> @@ -1548,9 +1536,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
>  static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
>  {
>      int ret;
> -    uint8_t *buffer;
>      uint32_t length;
> -    QEMUSizedBuffer *qsb;
> +    QIOChannelBuffer *bioc;
>  
>      length = qemu_get_be32(mis->from_src_file);
>      trace_loadvm_handle_cmd_packaged(length);
> @@ -1559,28 +1546,26 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
>          error_report("Unreasonably large packaged state: %u", length);
>          return -1;
>      }
> -    buffer = g_malloc0(length);
> -    ret = qemu_get_buffer(mis->from_src_file, buffer, (int)length);
> +
> +    bioc = qio_channel_buffer_new(length);
> +    ret = qemu_get_buffer(mis->from_src_file,
> +                          (uint8_t *)bioc->data,
> +                          (int)length);

Actually, qemu_get_buffer takes a size_t now; so you can fix that at the same time.

>      if (ret != length) {
> -        g_free(buffer);
> +        object_unref(OBJECT(bioc));
>          error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%d\n",
>                  ret, length);
>          return (ret < 0) ? ret : -EAGAIN;
>      }
> +    bioc->usage += length;

I'm a bit surprised you've not wrapped feeding the data
into the qio_channel_buffer up a bit rather than having the callers
prod at it's buffer/usage elements directly.

Dave

>      trace_loadvm_handle_cmd_packaged_received(ret);
>  
> -    /* Setup a dummy QEMUFile that actually reads from the buffer */
> -    qsb = qsb_create(buffer, length);
> -    g_free(buffer); /* Because qsb_create copies */
> -    if (!qsb) {
> -        error_report("Unable to create qsb");
> -    }
> -    QEMUFile *packf = qemu_bufopen("r", qsb);
> +    QEMUFile *packf = qemu_fopen_channel_input(QIO_CHANNEL(bioc));
>  
>      ret = qemu_loadvm_state_main(packf, mis);
>      trace_loadvm_handle_cmd_packaged_main(ret);
>      qemu_fclose(packf);
> -    qsb_free(qsb);
> +    object_unref(OBJECT(bioc));
>  
>      return ret;
>  }
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer
  2016-01-25 19:38   ` Dr. David Alan Gilbert
@ 2016-01-25 22:15     ` Daniel P. Berrange
  2016-01-26 18:59       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-01-25 22:15 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Mon, Jan 25, 2016 at 07:38:59PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > The post-copy code does some I/O to/from an intermediate
> > in-memory buffer rather than direct to the underlying
> > I/O channel. Switch this code to use QIOChannelBuffer
> > instead of QEMUSizedBuffer.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  docs/migration.txt      |  4 ++--
> >  include/sysemu/sysemu.h |  2 +-
> >  migration/migration.c   | 15 +++++++--------
> >  migration/savevm.c      | 41 +++++++++++++----------------------------
> >  4 files changed, 23 insertions(+), 39 deletions(-)
> > 
> > diff --git a/docs/migration.txt b/docs/migration.txt
> > index fda8d61..11703de 100644
> > --- a/docs/migration.txt
> > +++ b/docs/migration.txt
> > @@ -403,8 +403,8 @@ listen thread:                     --- page -- page -- page -- page -- page --
> >  
> >  On receipt of CMD_PACKAGED (1)
> >     All the data associated with the package - the ( ... ) section in the
> > -diagram - is read into memory (into a QEMUSizedBuffer), and the main thread
> > -recurses into qemu_loadvm_state_main to process the contents of the package (2)
> > +diagram - is read into memory, and the main thread recurses into
> > +qemu_loadvm_state_main to process the contents of the package (2)
> >  which contains commands (3,6) and devices (4...)
> >  
> >  On receipt of 'postcopy listen' - 3 -(i.e. the 1st command in the package)
> > diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> > index 3bb8897..0f59912 100644
> > --- a/include/sysemu/sysemu.h
> > +++ b/include/sysemu/sysemu.h
> > @@ -120,7 +120,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
> >                                uint16_t len, uint8_t *data);
> >  void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
> >  void qemu_savevm_send_open_return_path(QEMUFile *f);
> > -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
> > +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len);
> >  void qemu_savevm_send_postcopy_advise(QEMUFile *f);
> >  void qemu_savevm_send_postcopy_listen(QEMUFile *f);
> >  void qemu_savevm_send_postcopy_run(QEMUFile *f);
> > diff --git a/migration/migration.c b/migration/migration.c
> > index 715f069..e921b20 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -33,6 +33,7 @@
> >  #include "qom/cpu.h"
> >  #include "exec/memory.h"
> >  #include "exec/address-spaces.h"
> > +#include "io/channel-buffer.h"
> >  
> >  #define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
> >  
> > @@ -1401,7 +1402,8 @@ static int await_return_path_close_on_source(MigrationState *ms)
> >  static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> >  {
> >      int ret;
> > -    const QEMUSizedBuffer *qsb;
> > +    QIOChannelBuffer *bioc;
> > +    QEMUFile *fb;
> >      int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
> >      migrate_set_state(ms, MIGRATION_STATUS_ACTIVE,
> >                        MIGRATION_STATUS_POSTCOPY_ACTIVE);
> > @@ -1456,11 +1458,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> >       * So we wrap the device state up in a package with a length at the start;
> >       * to do this we use a qemu_buf to hold the whole of the device state.
> >       */
> > -    QEMUFile *fb = qemu_bufopen("w", NULL);
> > -    if (!fb) {
> > -        error_report("Failed to create buffered file");
> > -        goto fail;
> > -    }
> > +    bioc = qio_channel_buffer_new(4096);
> > +    fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc));
> 
> Why is that _input ?

A mistake - should be output given that the old code used "w".

> Also, what's your naming converntion; my 'qsb' was just an
> abbreviation of (Q)EMU(S)ized(B)uffer;  what's a bioc?

In the vast majority of cases where you just have a pointer
to the generic base class QIOChannel, then I'll use 'ioc' as
the standard variable name - ie 'io' and 'c' for channel.

If I have a specialized subtype, I prefix a single letter
reflecting the name of the subtype. eg 's' for QIOChannelSocket
giving "sioc" and 'b' for QIOChannelBuffer giving "bioc" etc.

> > +    object_unref(OBJECT(bioc));
> >  
> >      /*
> >       * Make sure the receiver can get incoming pages before we send the rest
> > @@ -1474,10 +1474,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> >      qemu_savevm_send_postcopy_run(fb);
> >  
> >      /* <><> end of stuff going into the package */
> > -    qsb = qemu_buf_get(fb);
> >  
> >      /* Now send that blob */
> > -    if (qemu_savevm_send_packaged(ms->file, qsb)) {
> > +    if (qemu_savevm_send_packaged(ms->file, bioc->data, bioc->usage)) {
> >          goto fail_closefb;
> >      }
> >      qemu_fclose(fb);
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index 0ad1b93..f2e1880 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -50,6 +50,7 @@
> >  #include "qemu/iov.h"
> >  #include "block/snapshot.h"
> >  #include "block/qapi.h"
> > +#include "io/channel-buffer.h"
> >  
> >  
> >  #ifndef ETH_P_RARP
> > @@ -760,10 +761,8 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
> >   *    0 on success
> >   *    -ve on error
> >   */
> > -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
> > +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len)
> >  {
> > -    size_t cur_iov;
> > -    size_t len = qsb_get_length(qsb);
> >      uint32_t tmp;
> >  
> >      if (len > MAX_VM_CMD_PACKAGED_SIZE) {
> > @@ -777,18 +776,7 @@ int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
> >      trace_qemu_savevm_send_packaged();
> >      qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
> >  
> > -    /* all the data follows (concatinating the iov's) */
> > -    for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
> > -        /* The iov entries are partially filled */
> > -        size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
> > -        len -= towrite;
> > -
> > -        if (!towrite) {
> > -            break;
> > -        }
> > -
> > -        qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
> > -    }
> > +    qemu_put_buffer(f, (const uint8_t *)buf, len);
> >  
> >      return 0;
> >  }
> > @@ -1548,9 +1536,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
> >  static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
> >  {
> >      int ret;
> > -    uint8_t *buffer;
> >      uint32_t length;
> > -    QEMUSizedBuffer *qsb;
> > +    QIOChannelBuffer *bioc;
> >  
> >      length = qemu_get_be32(mis->from_src_file);
> >      trace_loadvm_handle_cmd_packaged(length);
> > @@ -1559,28 +1546,26 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
> >          error_report("Unreasonably large packaged state: %u", length);
> >          return -1;
> >      }
> > -    buffer = g_malloc0(length);
> > -    ret = qemu_get_buffer(mis->from_src_file, buffer, (int)length);
> > +
> > +    bioc = qio_channel_buffer_new(length);
> > +    ret = qemu_get_buffer(mis->from_src_file,
> > +                          (uint8_t *)bioc->data,
> > +                          (int)length);
> 
> Actually, qemu_get_buffer takes a size_t now; so you can fix that at the same time.

Great.

> 
> >      if (ret != length) {
> > -        g_free(buffer);
> > +        object_unref(OBJECT(bioc));
> >          error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%d\n",
> >                  ret, length);
> >          return (ret < 0) ? ret : -EAGAIN;
> >      }
> > +    bioc->usage += length;
> 
> I'm a bit surprised you've not wrapped feeding the data
> into the qio_channel_buffer up a bit rather than having the callers
> prod at it's buffer/usage elements directly.

I figured it was better to avoid extra memcpy's in the migration code,
so decided to directly pass the internal buffer to get_qemu_buffer().


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer
  2016-01-25 22:15     ` Daniel P. Berrange
@ 2016-01-26 18:59       ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-26 18:59 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Mon, Jan 25, 2016 at 07:38:59PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > The post-copy code does some I/O to/from an intermediate
> > > in-memory buffer rather than direct to the underlying
> > > I/O channel. Switch this code to use QIOChannelBuffer
> > > instead of QEMUSizedBuffer.
> > > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  docs/migration.txt      |  4 ++--
> > >  include/sysemu/sysemu.h |  2 +-
> > >  migration/migration.c   | 15 +++++++--------
> > >  migration/savevm.c      | 41 +++++++++++++----------------------------
> > >  4 files changed, 23 insertions(+), 39 deletions(-)
> > > 
> > > diff --git a/docs/migration.txt b/docs/migration.txt
> > > index fda8d61..11703de 100644
> > > --- a/docs/migration.txt
> > > +++ b/docs/migration.txt
> > > @@ -403,8 +403,8 @@ listen thread:                     --- page -- page -- page -- page -- page --
> > >  
> > >  On receipt of CMD_PACKAGED (1)
> > >     All the data associated with the package - the ( ... ) section in the
> > > -diagram - is read into memory (into a QEMUSizedBuffer), and the main thread
> > > -recurses into qemu_loadvm_state_main to process the contents of the package (2)
> > > +diagram - is read into memory, and the main thread recurses into
> > > +qemu_loadvm_state_main to process the contents of the package (2)
> > >  which contains commands (3,6) and devices (4...)
> > >  
> > >  On receipt of 'postcopy listen' - 3 -(i.e. the 1st command in the package)
> > > diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> > > index 3bb8897..0f59912 100644
> > > --- a/include/sysemu/sysemu.h
> > > +++ b/include/sysemu/sysemu.h
> > > @@ -120,7 +120,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
> > >                                uint16_t len, uint8_t *data);
> > >  void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
> > >  void qemu_savevm_send_open_return_path(QEMUFile *f);
> > > -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
> > > +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len);
> > >  void qemu_savevm_send_postcopy_advise(QEMUFile *f);
> > >  void qemu_savevm_send_postcopy_listen(QEMUFile *f);
> > >  void qemu_savevm_send_postcopy_run(QEMUFile *f);
> > > diff --git a/migration/migration.c b/migration/migration.c
> > > index 715f069..e921b20 100644
> > > --- a/migration/migration.c
> > > +++ b/migration/migration.c
> > > @@ -33,6 +33,7 @@
> > >  #include "qom/cpu.h"
> > >  #include "exec/memory.h"
> > >  #include "exec/address-spaces.h"
> > > +#include "io/channel-buffer.h"
> > >  
> > >  #define MAX_THROTTLE  (32 << 20)      /* Migration transfer speed throttling */
> > >  
> > > @@ -1401,7 +1402,8 @@ static int await_return_path_close_on_source(MigrationState *ms)
> > >  static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> > >  {
> > >      int ret;
> > > -    const QEMUSizedBuffer *qsb;
> > > +    QIOChannelBuffer *bioc;
> > > +    QEMUFile *fb;
> > >      int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
> > >      migrate_set_state(ms, MIGRATION_STATUS_ACTIVE,
> > >                        MIGRATION_STATUS_POSTCOPY_ACTIVE);
> > > @@ -1456,11 +1458,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> > >       * So we wrap the device state up in a package with a length at the start;
> > >       * to do this we use a qemu_buf to hold the whole of the device state.
> > >       */
> > > -    QEMUFile *fb = qemu_bufopen("w", NULL);
> > > -    if (!fb) {
> > > -        error_report("Failed to create buffered file");
> > > -        goto fail;
> > > -    }
> > > +    bioc = qio_channel_buffer_new(4096);
> > > +    fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc));
> > 
> > Why is that _input ?
> 
> A mistake - should be output given that the old code used "w".

OK, that makes sense then.

> > Also, what's your naming converntion; my 'qsb' was just an
> > abbreviation of (Q)EMU(S)ized(B)uffer;  what's a bioc?
> 
> In the vast majority of cases where you just have a pointer
> to the generic base class QIOChannel, then I'll use 'ioc' as
> the standard variable name - ie 'io' and 'c' for channel.
> 
> If I have a specialized subtype, I prefix a single letter
> reflecting the name of the subtype. eg 's' for QIOChannelSocket
> giving "sioc" and 'b' for QIOChannelBuffer giving "bioc" etc.

OK, my preference there would have been iocb just because it's the
same order as the thing it's abbreviating; but that's just a personal
preference.

> > > +    object_unref(OBJECT(bioc));
> > >  
> > >      /*
> > >       * Make sure the receiver can get incoming pages before we send the rest
> > > @@ -1474,10 +1474,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
> > >      qemu_savevm_send_postcopy_run(fb);
> > >  
> > >      /* <><> end of stuff going into the package */
> > > -    qsb = qemu_buf_get(fb);
> > >  
> > >      /* Now send that blob */
> > > -    if (qemu_savevm_send_packaged(ms->file, qsb)) {
> > > +    if (qemu_savevm_send_packaged(ms->file, bioc->data, bioc->usage)) {
> > >          goto fail_closefb;
> > >      }
> > >      qemu_fclose(fb);
> > > diff --git a/migration/savevm.c b/migration/savevm.c
> > > index 0ad1b93..f2e1880 100644
> > > --- a/migration/savevm.c
> > > +++ b/migration/savevm.c
> > > @@ -50,6 +50,7 @@
> > >  #include "qemu/iov.h"
> > >  #include "block/snapshot.h"
> > >  #include "block/qapi.h"
> > > +#include "io/channel-buffer.h"
> > >  
> > >  
> > >  #ifndef ETH_P_RARP
> > > @@ -760,10 +761,8 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
> > >   *    0 on success
> > >   *    -ve on error
> > >   */
> > > -int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
> > > +int qemu_savevm_send_packaged(QEMUFile *f, const char *buf, size_t len)
> > >  {
> > > -    size_t cur_iov;
> > > -    size_t len = qsb_get_length(qsb);
> > >      uint32_t tmp;
> > >  
> > >      if (len > MAX_VM_CMD_PACKAGED_SIZE) {
> > > @@ -777,18 +776,7 @@ int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
> > >      trace_qemu_savevm_send_packaged();
> > >      qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
> > >  
> > > -    /* all the data follows (concatinating the iov's) */
> > > -    for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
> > > -        /* The iov entries are partially filled */
> > > -        size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
> > > -        len -= towrite;
> > > -
> > > -        if (!towrite) {
> > > -            break;
> > > -        }
> > > -
> > > -        qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
> > > -    }
> > > +    qemu_put_buffer(f, (const uint8_t *)buf, len);
> > >  
> > >      return 0;
> > >  }
> > > @@ -1548,9 +1536,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
> > >  static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
> > >  {
> > >      int ret;
> > > -    uint8_t *buffer;
> > >      uint32_t length;
> > > -    QEMUSizedBuffer *qsb;
> > > +    QIOChannelBuffer *bioc;
> > >  
> > >      length = qemu_get_be32(mis->from_src_file);
> > >      trace_loadvm_handle_cmd_packaged(length);
> > > @@ -1559,28 +1546,26 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
> > >          error_report("Unreasonably large packaged state: %u", length);
> > >          return -1;
> > >      }
> > > -    buffer = g_malloc0(length);
> > > -    ret = qemu_get_buffer(mis->from_src_file, buffer, (int)length);
> > > +
> > > +    bioc = qio_channel_buffer_new(length);
> > > +    ret = qemu_get_buffer(mis->from_src_file,
> > > +                          (uint8_t *)bioc->data,
> > > +                          (int)length);
> > 
> > Actually, qemu_get_buffer takes a size_t now; so you can fix that at the same time.
> 
> Great.
> 
> > 
> > >      if (ret != length) {
> > > -        g_free(buffer);
> > > +        object_unref(OBJECT(bioc));
> > >          error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%d\n",
> > >                  ret, length);
> > >          return (ret < 0) ? ret : -EAGAIN;
> > >      }
> > > +    bioc->usage += length;
> > 
> > I'm a bit surprised you've not wrapped feeding the data
> > into the qio_channel_buffer up a bit rather than having the callers
> > prod at it's buffer/usage elements directly.
> 
> I figured it was better to avoid extra memcpy's in the migration code,
> so decided to directly pass the internal buffer to get_qemu_buffer().

Yes, avoiding copies is good; I was just thinking more of a function that
incremented the usage or something like that.

Dave

> 
> 
> Regards,
> Daniel
> -- 
> |: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org              -o-             http://virt-manager.org :|
> |: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
> |: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests Daniel P. Berrange
@ 2016-01-28 17:45   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-28 17:45 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Some of the test-vmstate.c test cases use a temporary file
> while others use a memory buffer. To facilitate the future
> removal of the qemu_bufopen() function, convert all the tests
> to use a temporary file.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  tests/Makefile       |  2 +-
>  tests/test-vmstate.c | 44 +++++++++++++-------------------------------
>  2 files changed, 14 insertions(+), 32 deletions(-)
> 
> diff --git a/tests/Makefile b/tests/Makefile
> index b7352f1..5a1b25f 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -422,7 +422,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
>  	hw/core/fw-path-provider.o \
>  	$(test-qapi-obj-y)
>  tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
> -	migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \
> +	migration/vmstate.o migration/qemu-file.o \
>          migration/qemu-file-unix.o qjson.o \
>  	$(test-qom-obj-y)
>  tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
> diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
> index 4d13bd0..0f943d5 100644
> --- a/tests/test-vmstate.c
> +++ b/tests/test-vmstate.c
> @@ -43,11 +43,6 @@ void yield_until_fd_readable(int fd)
>      select(fd + 1, &fds, NULL, NULL, NULL);
>  }
>  
> -/*
> - * Some tests use 'open_test_file' to work on a real fd, some use
> - * an in memory file (QEMUSizedBuffer+qemu_bufopen); we could pick one
> - * but this way we test both.
> - */
>  
>  /* Duplicate temp_fd and seek to the beginning of the file */
>  static QEMUFile *open_test_file(bool write)
> @@ -60,20 +55,6 @@ static QEMUFile *open_test_file(bool write)
>      return qemu_fdopen(fd, write ? "wb" : "rb");
>  }
>  
> -/*
> - * Check that the contents of the memory-buffered file f match
> - * the given size/data.
> - */
> -static void check_mem_file(QEMUFile *f, void *data, size_t size)
> -{
> -    uint8_t *result = g_malloc(size);
> -    const QEMUSizedBuffer *qsb = qemu_buf_get(f);
> -    g_assert_cmpint(qsb_get_length(qsb), ==, size);
> -    g_assert_cmpint(qsb_get_buffer(qsb, 0, size, result), ==, size);
> -    g_assert_cmpint(memcmp(result, data, size), ==, 0);
> -    g_free(result);
> -}
> -
>  #define SUCCESS(val) \
>      g_assert_cmpint((val), ==, 0)
>  
> @@ -391,7 +372,7 @@ static const VMStateDescription vmstate_skipping = {
>  
>  static void test_save_noskip(void)
>  {
> -    QEMUFile *fsave = qemu_bufopen("w", NULL);
> +    QEMUFile *fsave = open_test_file(true);
>      TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
>                         .skip_c_e = false };
>      vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
> @@ -405,13 +386,14 @@ static void test_save_noskip(void)
>          0, 0, 0, 5,             /* e */
>          0, 0, 0, 0, 0, 0, 0, 6, /* f */
>      };
> -    check_mem_file(fsave, expected, sizeof(expected));
> +
>      qemu_fclose(fsave);
> +    compare_vmstate(expected, sizeof(expected));
>  }
>  
>  static void test_save_skip(void)
>  {
> -    QEMUFile *fsave = qemu_bufopen("w", NULL);
> +    QEMUFile *fsave = open_test_file(true);
>      TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
>                         .skip_c_e = true };
>      vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
> @@ -423,13 +405,14 @@ static void test_save_skip(void)
>          0, 0, 0, 0, 0, 0, 0, 4, /* d */
>          0, 0, 0, 0, 0, 0, 0, 6, /* f */
>      };
> -    check_mem_file(fsave, expected, sizeof(expected));
>  
>      qemu_fclose(fsave);
> +    compare_vmstate(expected, sizeof(expected));
>  }
>  
>  static void test_load_noskip(void)
>  {
> +    QEMUFile *fsave = open_test_file(true);
>      uint8_t buf[] = {
>          0, 0, 0, 10,             /* a */
>          0, 0, 0, 20,             /* b */
> @@ -439,10 +422,10 @@ static void test_load_noskip(void)
>          0, 0, 0, 0, 0, 0, 0, 60, /* f */
>          QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
>      };
> +    qemu_put_buffer(fsave, buf, sizeof(buf));
> +    qemu_fclose(fsave);
>  
> -    QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
> -    g_assert(qsb);
> -    QEMUFile *loading = qemu_bufopen("r", qsb);
> +    QEMUFile *loading = open_test_file(false);
>      TestStruct obj = { .skip_c_e = false };
>      vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
>      g_assert(!qemu_file_get_error(loading));
> @@ -453,11 +436,11 @@ static void test_load_noskip(void)
>      g_assert_cmpint(obj.e, ==, 50);
>      g_assert_cmpint(obj.f, ==, 60);
>      qemu_fclose(loading);
> -    qsb_free(qsb);
>  }
>  
>  static void test_load_skip(void)
>  {
> +    QEMUFile *fsave = open_test_file(true);
>      uint8_t buf[] = {
>          0, 0, 0, 10,             /* a */
>          0, 0, 0, 20,             /* b */
> @@ -465,10 +448,10 @@ static void test_load_skip(void)
>          0, 0, 0, 0, 0, 0, 0, 60, /* f */
>          QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
>      };
> +    qemu_put_buffer(fsave, buf, sizeof(buf));
> +    qemu_fclose(fsave);
>  
> -    QEMUSizedBuffer *qsb = qsb_create(buf, sizeof(buf));
> -    g_assert(qsb);
> -    QEMUFile *loading = qemu_bufopen("r", qsb);
> +    QEMUFile *loading = open_test_file(false);
>      TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
>      vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
>      g_assert(!qemu_file_get_error(loading));
> @@ -479,7 +462,6 @@ static void test_load_skip(void)
>      g_assert_cmpint(obj.e, ==, 500);
>      g_assert_cmpint(obj.f, ==, 60);
>      qemu_fclose(loading);
> -    qsb_free(qsb);
>  }
>  
>  int main(int argc, char **argv)
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount Daniel P. Berrange
@ 2016-01-28 17:53   ` Dr. David Alan Gilbert
  2016-02-03 13:31     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-28 17:53 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> The QEMUFile writev_buffer / put_buffer functions are expected
> to write out the full set of requested data, blocking until
> complete. The qemu_fflush() caller does not expect to deal with
> partial writes. Clarify the function comments and add a sanity
> check to the code to catch mistaken implementations.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  include/migration/qemu-file.h |  6 ++++--
>  migration/qemu-file.c         | 16 ++++++++++++----
>  2 files changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index b5d08d2..5debe8c 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -29,7 +29,8 @@
>  
>  /* This function writes a chunk of data to a file at the given position.
>   * The pos argument can be ignored if the file is only being used for
> - * streaming.  The handler should try to write all of the data it can.
> + * streaming.  The handler must write all of the data or return a negative
> + * errno value.
>   */
>  typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
>                                          int64_t pos, size_t size);
> @@ -55,7 +56,8 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
>  typedef int (QEMUFileGetFD)(void *opaque);
>  
>  /*
> - * This function writes an iovec to file.
> + * This function writes an iovec to file. The handler must write all
> + * of the data or return a negative errno value.
>   */
>  typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
>                                             int iovcnt, int64_t pos);
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 0bbd257..f89e64e 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -107,11 +107,13 @@ bool qemu_file_is_writable(QEMUFile *f)
>   * Flushes QEMUFile buffer
>   *
>   * If there is writev_buffer QEMUFileOps it uses it otherwise uses
> - * put_buffer ops.
> + * put_buffer ops. This will flush all pending data. If data was
> + * only partially flushed, it will set an error state.
>   */
>  void qemu_fflush(QEMUFile *f)
>  {
>      ssize_t ret = 0;
> +    ssize_t expect = 0;
>  
>      if (!qemu_file_is_writable(f)) {
>          return;
> @@ -119,21 +121,27 @@ void qemu_fflush(QEMUFile *f)
>  
>      if (f->ops->writev_buffer) {
>          if (f->iovcnt > 0) {
> +            expect = iov_size(f->iov, f->iovcnt);
>              ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
>          }
>      } else {
>          if (f->buf_index > 0) {
> +            expect = f->buf_index;
>              ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
>          }
>      }
> +
>      if (ret >= 0) {
>          f->pos += ret;
>      }
> -    f->buf_index = 0;
> -    f->iovcnt = 0;
> -    if (ret < 0) {
> +    /* We expect the QEMUFile write impl to send the full
> +     * data set we requested, so sanity check that.
> +     */
> +    if (ret < 0 || ret != expect) {
>          qemu_file_set_error(f, ret);

You could simplify that to     if (ret != expect)     couldn't you?

In the case you're trying to guard against, the value past
to qemu_file_set_error is potentially truncated; which in the worst
case could make it appear as success; although I doubt that
can happen in our uses.

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Dave

>      }
> +    f->buf_index = 0;
> +    f->iovcnt = 0;
>  }
>  
>  void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps Daniel P. Berrange
@ 2016-01-28 17:57   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-28 17:57 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> The QEMUFileOps struct contains the I/O subsystem callbacks
> and the migration stage hooks. Split the hooks out into a
> separate QEMUFileHooks struct to make it easier to refactor
> the I/O side of QEMUFile without affecting the hooks.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h  | 10 +++++++---
>  migration/qemu-file-internal.h |  1 +
>  migration/qemu-file.c          | 24 +++++++++++++++---------
>  migration/rdma.c               |  8 ++++++++
>  4 files changed, 31 insertions(+), 12 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index 5debe8c..ddffc6a 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -109,13 +109,16 @@ typedef struct QEMUFileOps {
>      QEMUFileCloseFunc *close;
>      QEMUFileGetFD *get_fd;
>      QEMUFileWritevBufferFunc *writev_buffer;
> +    QEMURetPathFunc *get_return_path;
> +    QEMUFileShutdownFunc *shut_down;
> +} QEMUFileOps;
> +
> +typedef struct QEMUFileHooks {
>      QEMURamHookFunc *before_ram_iterate;
>      QEMURamHookFunc *after_ram_iterate;
>      QEMURamHookFunc *hook_ram_load;
>      QEMURamSaveFunc *save_page;
> -    QEMURetPathFunc *get_return_path;
> -    QEMUFileShutdownFunc *shut_down;
> -} QEMUFileOps;
> +} QEMUFileHooks;
>  
>  struct QEMUSizedBuffer {
>      struct iovec *iov;
> @@ -130,6 +133,7 @@ QEMUFile *qemu_fdopen(int fd, const char *mode);
>  QEMUFile *qemu_fopen_socket(int fd, const char *mode);
>  QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
>  QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
> +void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
>  int qemu_get_fd(QEMUFile *f);
>  int qemu_fclose(QEMUFile *f);
>  int64_t qemu_ftell(QEMUFile *f);
> diff --git a/migration/qemu-file-internal.h b/migration/qemu-file-internal.h
> index d95e853..8fdfa95 100644
> --- a/migration/qemu-file-internal.h
> +++ b/migration/qemu-file-internal.h
> @@ -33,6 +33,7 @@
>  
>  struct QEMUFile {
>      const QEMUFileOps *ops;
> +    const QEMUFileHooks *hooks;
>      void *opaque;
>  
>      int64_t bytes_xfer;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index f89e64e..337cb4c 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -79,6 +79,12 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
>      return f;
>  }
>  
> +
> +void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
> +{
> +    f->hooks = hooks;
> +}
> +
>  /*
>   * Get last error for stream f
>   *
> @@ -148,8 +154,8 @@ void ram_control_before_iterate(QEMUFile *f, uint64_t flags)
>  {
>      int ret = 0;
>  
> -    if (f->ops->before_ram_iterate) {
> -        ret = f->ops->before_ram_iterate(f, f->opaque, flags, NULL);
> +    if (f->hooks && f->hooks->before_ram_iterate) {
> +        ret = f->hooks->before_ram_iterate(f, f->opaque, flags, NULL);
>          if (ret < 0) {
>              qemu_file_set_error(f, ret);
>          }
> @@ -160,8 +166,8 @@ void ram_control_after_iterate(QEMUFile *f, uint64_t flags)
>  {
>      int ret = 0;
>  
> -    if (f->ops->after_ram_iterate) {
> -        ret = f->ops->after_ram_iterate(f, f->opaque, flags, NULL);
> +    if (f->hooks && f->hooks->after_ram_iterate) {
> +        ret = f->hooks->after_ram_iterate(f, f->opaque, flags, NULL);
>          if (ret < 0) {
>              qemu_file_set_error(f, ret);
>          }
> @@ -172,8 +178,8 @@ void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data)
>  {
>      int ret = -EINVAL;
>  
> -    if (f->ops->hook_ram_load) {
> -        ret = f->ops->hook_ram_load(f, f->opaque, flags, data);
> +    if (f->hooks && f->hooks->hook_ram_load) {
> +        ret = f->hooks->hook_ram_load(f, f->opaque, flags, data);
>          if (ret < 0) {
>              qemu_file_set_error(f, ret);
>          }
> @@ -192,9 +198,9 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
>                               ram_addr_t offset, size_t size,
>                               uint64_t *bytes_sent)
>  {
> -    if (f->ops->save_page) {
> -        int ret = f->ops->save_page(f, f->opaque, block_offset,
> -                                    offset, size, bytes_sent);
> +    if (f->hooks && f->hooks->save_page) {
> +        int ret = f->hooks->save_page(f, f->opaque, block_offset,
> +                                      offset, size, bytes_sent);
>  
>          if (ret != RAM_SAVE_CONTROL_DELAYED) {
>              if (bytes_sent && *bytes_sent > 0) {
> diff --git a/migration/rdma.c b/migration/rdma.c
> index dcabb91..bffbfaf 100644
> --- a/migration/rdma.c
> +++ b/migration/rdma.c
> @@ -3380,12 +3380,18 @@ static const QEMUFileOps rdma_read_ops = {
>      .get_buffer    = qemu_rdma_get_buffer,
>      .get_fd        = qemu_rdma_get_fd,
>      .close         = qemu_rdma_close,
> +};
> +
> +static const QEMUFileHooks rdma_read_hooks = {
>      .hook_ram_load = rdma_load_hook,
>  };
>  
>  static const QEMUFileOps rdma_write_ops = {
>      .put_buffer         = qemu_rdma_put_buffer,
>      .close              = qemu_rdma_close,
> +};
> +
> +static const QEMUFileHooks rdma_write_hooks = {
>      .before_ram_iterate = qemu_rdma_registration_start,
>      .after_ram_iterate  = qemu_rdma_registration_stop,
>      .save_page          = qemu_rdma_save_page,
> @@ -3404,8 +3410,10 @@ static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
>  
>      if (mode[0] == 'w') {
>          r->file = qemu_fopen_ops(r, &rdma_write_ops);
> +        qemu_file_set_hooks(r->file, &rdma_write_hooks);
>      } else {
>          r->file = qemu_fopen_ops(r, &rdma_read_ops);
> +        qemu_file_set_hooks(r->file, &rdma_read_hooks);
>      }
>  
>      return r->file;
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps Daniel P. Berrange
@ 2016-01-28 18:00   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-28 18:00 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Remove the assumption that every QEMUFile implementation has
> a file descriptor available by introducing a new function
> in QEMUFileOps to change the blocking state of a QEMUFile.
> 
> If not set, it will fallback to the original code using
> the get_fd method.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |  5 +++++
>  migration/migration.c         |  4 +---
>  migration/qemu-file.c         | 10 +++++++---
>  3 files changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index ddffc6a..072bb38 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -55,6 +55,10 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
>   */
>  typedef int (QEMUFileGetFD)(void *opaque);
>  
> +/* Called to change the blocking mode of the file
> + */
> +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
> +
>  /*
>   * This function writes an iovec to file. The handler must write all
>   * of the data or return a negative errno value.
> @@ -108,6 +112,7 @@ typedef struct QEMUFileOps {
>      QEMUFileGetBufferFunc *get_buffer;
>      QEMUFileCloseFunc *close;
>      QEMUFileGetFD *get_fd;
> +    QEMUFileSetBlocking *set_blocking;
>      QEMUFileWritevBufferFunc *writev_buffer;
>      QEMURetPathFunc *get_return_path;
>      QEMUFileShutdownFunc *shut_down;
> diff --git a/migration/migration.c b/migration/migration.c
> index c842499..c964a8d 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -408,11 +408,9 @@ static void process_incoming_migration_co(void *opaque)
>  void process_incoming_migration(QEMUFile *f)
>  {
>      Coroutine *co = qemu_coroutine_create(process_incoming_migration_co);
> -    int fd = qemu_get_fd(f);
>  
> -    assert(fd != -1);
>      migrate_decompress_threads_create();
> -    qemu_set_nonblock(fd);
> +    qemu_file_set_blocking(f, false);
>      qemu_coroutine_enter(co, f);
>  }
>  
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 337cb4c..fc5977e 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -683,9 +683,13 @@ size_t qemu_get_counted_string(QEMUFile *f, char buf[256])
>   */
>  void qemu_file_set_blocking(QEMUFile *f, bool block)
>  {
> -    if (block) {
> -        qemu_set_block(qemu_get_fd(f));
> +    if (f->ops->set_blocking) {
> +        f->ops->set_blocking(f->opaque, block);
>      } else {
> -        qemu_set_nonblock(qemu_get_fd(f));
> +        if (block) {
> +            qemu_set_block(qemu_get_fd(f));
> +        } else {
> +            qemu_set_nonblock(qemu_get_fd(f));
> +        }
>      }
>  }
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration Daniel P. Berrange
@ 2016-01-28 18:17   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-01-28 18:17 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Instead of relying on the default QEMUFile I/O blocking flag
> state, explicitly turn on blocking I/O for outgoing migration
> since it takes place in a background thread.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/migration.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/migration/migration.c b/migration/migration.c
> index c964a8d..715f069 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -1732,6 +1732,7 @@ void migrate_fd_connect(MigrationState *s)
>      s->expected_downtime = max_downtime/1000000;
>      s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
>  
> +    qemu_file_set_blocking(s->file, true);

Yes OK; fd_connect is the outgoing side and qemu_fopen_socket
already sets blocking on "w".

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

>      qemu_file_set_rate_limit(s->file,
>                               s->bandwidth_limit / XFER_LIMIT_RATIO);
>  
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel Daniel P. Berrange
@ 2016-02-02 17:06   ` Dr. David Alan Gilbert
  2016-02-03 13:37     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 17:06 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Introduce a new QEMUFile implementation that is based on
> the QIOChannel objects. This impl is different from existing
> impls in that there is no file descriptor that can be made
> available, as some channels may be based on higher level
> protocols such as TLS.
> 
> Although the QIOChannel based implementation can trivially
> provide a bi-directional stream, initially we have separate
> functions for opening input & output directions to fit with
> the expectation of the current QEMUFile interface.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  include/migration/qemu-file.h |   4 +
>  migration/Makefile.objs       |   1 +
>  migration/qemu-file-channel.c | 201 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 206 insertions(+)
>  create mode 100644 migration/qemu-file-channel.c
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index 072bb38..cb79311 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -23,7 +23,9 @@
>   */
>  #ifndef QEMU_FILE_H
>  #define QEMU_FILE_H 1
> +#include "qemu-common.h"
>  #include "exec/cpu-common.h"
> +#include "io/channel.h"
>  
>  #include <stdint.h>
>  
> @@ -136,6 +138,8 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
>  QEMUFile *qemu_fopen(const char *filename, const char *mode);
>  QEMUFile *qemu_fdopen(int fd, const char *mode);
>  QEMUFile *qemu_fopen_socket(int fd, const char *mode);
> +QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
> +QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
>  QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
>  QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
>  void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 0cac6d7..b357e2f 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,6 +1,7 @@
>  common-obj-y += migration.o tcp.o
>  common-obj-y += vmstate.o
>  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
> +common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
>  common-obj-$(CONFIG_RDMA) += rdma.o
> diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c
> new file mode 100644
> index 0000000..09a7170
> --- /dev/null
> +++ b/migration/qemu-file-channel.c
> @@ -0,0 +1,201 @@
> +/*
> + * QEMUFile backend for QIOChannel objects
> + *
> + * Copyright (c) 2015 Red Hat, Inc
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "migration/qemu-file.h"
> +#include "io/channel-socket.h"
> +#include "qemu/iov.h"
> +
> +
> +/**
> + * @skip: number of bytes to advance head of @iov
> + * @iov: pointer to iov array, updated on success
> + * @iovcnt: number of elements in @iov, updated on success
> + * @oldiov: pointer single element to hold old info from @iov
> + *
> + * This will update @iov so that its head is advanced
> + * by @skip bytes. To do this, zero or more complete
> + * elements of @iov will be skipped over. The new head
> + * of @iov will then have its base & len updated to
> + * skip the remaining number of bytes. @oldiov will
> + * hold the original data from the new head of @iov.
> + */
> +static void channel_skip_iov(size_t skip,
> +                             struct iovec **iov,
> +                             int *iovcnt,
> +                             struct iovec *oldiov)
> +{
> +    ssize_t done = 0;
> +    size_t i;
> +    for (i = 0; i < *iovcnt; i++) {
> +        if ((*iov)[i].iov_len <= skip) {
> +            done += (*iov)[i].iov_len;
> +            skip -= (*iov)[i].iov_len;
> +        } else {
> +            done += skip;
> +            oldiov->iov_base = (*iov)[i].iov_base;
> +            oldiov->iov_len = (*iov)[i].iov_len;
> +            (*iov)[i].iov_len -= skip;
> +            (*iov)[i].iov_base += skip;
> +            *iov = *iov + i;
> +            *iovcnt = *iovcnt - i;
> +            break;
> +        }
> +    }
> +}
> +
> +static ssize_t channel_writev_buffer(void *opaque,
> +                                     struct iovec *iov,
> +                                     int iovcnt,
> +                                     int64_t pos)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> +    ssize_t done = 0;
> +    ssize_t want = iov_size(iov, iovcnt);
> +    struct iovec oldiov = { NULL, 0 };
> +
> +    while (done < want) {
> +        ssize_t len;
> +        struct iovec *cur = iov;
> +        int curcnt = iovcnt;
> +
> +        channel_skip_iov(done, &cur, &curcnt, &oldiov);
> +
> +        len = qio_channel_writev(ioc, cur, curcnt, NULL);
> +        if (oldiov.iov_base) {
> +            /* Restore original caller's info in @iov */
> +            cur[0].iov_base = oldiov.iov_base;
> +            cur[0].iov_len = oldiov.iov_len;
> +            oldiov.iov_base = NULL;
> +            oldiov.iov_len = 0;
> +        }
> +        if (len == QIO_CHANNEL_ERR_BLOCK) {
> +            qio_channel_wait(ioc, G_IO_OUT);
> +            continue;
> +        }
> +        if (len < 0) {
> +            /* XXX handle Error objects */
> +            return -EIO;

It's best to return 'len' rather than lose what little
error information you had (similarly below).

> +        }
> +
> +        done += len;
> +    }
> +    return done;
> +}
> +
> +
> +static ssize_t channel_get_buffer(void *opaque,
> +                                  uint8_t *buf,
> +                                  int64_t pos,
> +                                  size_t size)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> +    ssize_t ret;
> +
> + reread:
> +    ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> +    if (ret < 0) {
> +        if (ret == QIO_CHANNEL_ERR_BLOCK) {
> +            qio_channel_yield(ioc, G_IO_IN);
> +            goto reread;
> +        } else {
> +            /* XXX handle Error * object */
> +            return -EIO;
> +        }
> +    }
> +    return ret;


I'd prefer a loop to a goto; generally the only places we
use goto is an error exit.

  do {
       ret = qio_channel_read(ioc, (char *)buf, size, NULL);
       if (ret == QIO_CHANNEL_ERR_BLOCK) {
           qio_channel_yield(ioc, G_IO_IN);
       }
  } while (ret == QIO_CHANNEL_ERR_BLOCK);

  return ret;

and IMHO the loop is clearer.

> +}
> +
> +
> +static int channel_close(void *opaque)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> +    qio_channel_close(ioc, NULL);
> +    object_unref(OBJECT(ioc));
> +    return 0;
> +}
> +
> +
> +static int channel_shutdown(void *opaque,
> +                            bool rd,
> +                            bool wr)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> +
> +    if (qio_channel_has_feature(ioc,
> +                                QIO_CHANNEL_FEATURE_SHUTDOWN)) {
> +        QIOChannelShutdown mode;
> +        if (rd && wr) {
> +            mode = QIO_CHANNEL_SHUTDOWN_BOTH;
> +        } else if (rd) {
> +            mode = QIO_CHANNEL_SHUTDOWN_READ;
> +        } else {
> +            mode = QIO_CHANNEL_SHUTDOWN_WRITE;
> +        }
> +        if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
> +            /* XXX handler Error * object */
> +            return -EIO;
> +        }
> +    }
> +    return 0;
> +}
> +
> +
> +static int channel_set_blocking(void *opaque,
> +                                bool enabled)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> +
> +    if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +
> +static const QEMUFileOps channel_input_ops = {
> +    .get_buffer = channel_get_buffer,
> +    .close = channel_close,
> +    .shut_down = channel_shutdown,
> +    .set_blocking = channel_set_blocking,
> +};
> +
> +
> +static const QEMUFileOps channel_output_ops = {
> +    .writev_buffer = channel_writev_buffer,
> +    .close = channel_close,
> +    .shut_down = channel_shutdown,
> +    .set_blocking = channel_set_blocking,
> +};
> +
> +
> +QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
> +{
> +    object_ref(OBJECT(ioc));
> +    return qemu_fopen_ops(ioc, &channel_input_ops);
> +}
> +
> +QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
> +{
> +    object_ref(OBJECT(ioc));
> +    return qemu_fopen_ops(ioc, &channel_output_ops);
> +}

Dave

> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel Daniel P. Berrange
@ 2016-02-02 18:02   ` Dr. David Alan Gilbert
  2016-02-03 11:25     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 18:02 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Convert the unix socket migration protocol driver to use
> QIOChannel and QEMUFileChannel, instead of plain sockets
> APIs. It can be unconditionally built, since the socket
> impl of QIOChannel will report a suitable error on platforms
> where UNIX sockets are unavailable.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/Makefile.objs |   4 +-
>  migration/migration.c   |   4 ++
>  migration/unix.c        | 103 +++++++++++++++++++++++++++++++-----------------
>  3 files changed, 72 insertions(+), 39 deletions(-)
> 
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index b357e2f..a5f8a03 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,11 +1,11 @@
> -common-obj-y += migration.o tcp.o
> +common-obj-y += migration.o tcp.o unix.o
>  common-obj-y += vmstate.o
>  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
>  common-obj-$(CONFIG_RDMA) += rdma.o
> -common-obj-$(CONFIG_POSIX) += exec.o unix.o fd.o
> +common-obj-$(CONFIG_POSIX) += exec.o fd.o
>  
>  common-obj-y += block.o
>  
> diff --git a/migration/migration.c b/migration/migration.c
> index e921b20..1c5f12e 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -312,8 +312,10 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
>  #if !defined(WIN32)
>      } else if (strstart(uri, "exec:", &p)) {
>          exec_start_incoming_migration(p, errp);
> +#endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_incoming_migration(p, errp);
> +#if !defined(WIN32)
>      } else if (strstart(uri, "fd:", &p)) {
>          fd_start_incoming_migration(p, errp);
>  #endif
> @@ -1017,8 +1019,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
>  #if !defined(WIN32)
>      } else if (strstart(uri, "exec:", &p)) {
>          exec_start_outgoing_migration(s, p, &local_err);
> +#endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_outgoing_migration(s, p, &local_err);
> +#if !defined(WIN32)
>      } else if (strstart(uri, "fd:", &p)) {
>          fd_start_outgoing_migration(s, p, &local_err);
>  #endif
> diff --git a/migration/unix.c b/migration/unix.c
> index b591813..4674640 100644
> --- a/migration/unix.c
> +++ b/migration/unix.c
> @@ -1,10 +1,11 @@
>  /*
>   * QEMU live migration via Unix Domain Sockets
>   *
> - * Copyright Red Hat, Inc. 2009
> + * Copyright Red Hat, Inc. 2009-2015

year++ ?

>   *
>   * Authors:
>   *  Chris Lalancette <clalance@redhat.com>
> + *  Daniel P. Berrange <berrange@redhat.com>
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2.  See
>   * the COPYING file in the top-level directory.
> @@ -17,11 +18,9 @@
>  
>  #include "qemu-common.h"
>  #include "qemu/error-report.h"
> -#include "qemu/sockets.h"
> -#include "qemu/main-loop.h"
>  #include "migration/migration.h"
>  #include "migration/qemu-file.h"
> -#include "block/block.h"
> +#include "io/channel-socket.h"
>  
>  //#define DEBUG_MIGRATION_UNIX
>  
> @@ -33,71 +32,101 @@
>      do { } while (0)
>  #endif
>  
> -static void unix_wait_for_connect(int fd, Error *err, void *opaque)
> +
> +static SocketAddress *unix_build_address(const char *path)
> +{
> +    SocketAddress *saddr;
> +
> +    saddr = g_new0(SocketAddress, 1);
> +    saddr->type = SOCKET_ADDRESS_KIND_UNIX;
> +    saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
> +    saddr->u.q_unix->path = g_strdup(path);
> +
> +    return saddr;
> +}
> +
> +
> +static void unix_outgoing_migration(Object *src,
> +                                    Error *err,
> +                                    gpointer opaque)
>  {
>      MigrationState *s = opaque;
> +    QIOChannel *sioc = QIO_CHANNEL(src);
>  
> -    if (fd < 0) {
> +    if (err) {
>          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
>          s->file = NULL;
>          migrate_fd_error(s);
>      } else {
>          DPRINTF("migrate connect success\n");
> -        s->file = qemu_fopen_socket(fd, "wb");
> +        s->file = qemu_fopen_channel_output(sioc);
>          migrate_fd_connect(s);
>      }
> +    object_unref(src);
>  }
>  
> +
>  void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp)
>  {
> -    unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
> +    SocketAddress *saddr = unix_build_address(path);
> +    QIOChannelSocket *sioc;
> +    sioc = qio_channel_socket_new();
> +    qio_channel_socket_connect_async(sioc,
> +                                     saddr,
> +                                     unix_outgoing_migration,
> +                                     s,
> +                                     NULL);
> +    qapi_free_SocketAddress(saddr);

It took me a bit of digging to see that qio_channel_socket_connect_async
takes a copy of the address; it's not mentioned in channel-socket.h

>  }
>  
> -static void unix_accept_incoming_migration(void *opaque)
> +
> +static gboolean unix_accept_incoming_migration(QIOChannel *ioc,
> +                                               GIOCondition condition,
> +                                               gpointer opaque)
>  {
> -    struct sockaddr_un addr;
> -    socklen_t addrlen = sizeof(addr);
> -    int s = (intptr_t)opaque;
>      QEMUFile *f;
> -    int c, err;
> -
> -    do {
> -        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
> -        err = errno;
> -    } while (c < 0 && err == EINTR);
> -    qemu_set_fd_handler(s, NULL, NULL, NULL);
> -    close(s);
> +    QIOChannelSocket *cioc;

(not important but...) why is that a cioc not a sioc?

> +    Error *err = NULL;
>  
> -    DPRINTF("accepted migration\n");
> -
> -    if (c < 0) {
> +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> +                                     &err);
> +    if (!cioc) {
>          error_report("could not accept migration connection (%s)",
> -                     strerror(err));
> -        return;
> -    }
> -
> -    f = qemu_fopen_socket(c, "rb");
> -    if (f == NULL) {
> -        error_report("could not qemu_fopen socket");
> +                     error_get_pretty(err));
>          goto out;
>      }
>  
> +    DPRINTF("accepted migration\n");

Feel free to replace any DPRINTF's by trace_ entries.

> +
> +    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> +    object_unref(OBJECT(cioc));
> +
>      process_incoming_migration(f);
> -    return;
>  
>  out:
> -    close(c);
> +    /* Close listening socket as its no longer needed */
> +    qio_channel_close(ioc, NULL);
> +    return FALSE;
>  }
>  
> +
>  void unix_start_incoming_migration(const char *path, Error **errp)
>  {
> -    int s;
> +    SocketAddress *saddr = unix_build_address(path);
> +    QIOChannelSocket *listen_ioc;
>  
> -    s = unix_listen(path, NULL, 0, errp);
> -    if (s < 0) {
> +    listen_ioc = qio_channel_socket_new();
> +    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {

OK, so for a unix socket I don't think _sync ever blocks, so we're OK.

> +        object_unref(OBJECT(listen_ioc));
> +        qapi_free_SocketAddress(saddr);
>          return;
>      }
>  
> -    qemu_set_fd_handler(s, unix_accept_incoming_migration, NULL,
> -                        (void *)(intptr_t)s);
> +    qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
> +                          G_IO_IN,
> +                          unix_accept_incoming_migration,
> +                          listen_ioc,
> +                          (GDestroyNotify)object_unref);
> +
> +    qapi_free_SocketAddress(saddr);
>  }

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 10/22] migration: convert tcp socket protocol to use QIOChannel
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 10/22] migration: convert tcp " Daniel P. Berrange
@ 2016-02-02 18:19   ` Dr. David Alan Gilbert
  2016-02-03 10:02     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 18:19 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Convert the tcp socket migration protocol driver to use
> QIOChannel and QEMUFileChannel, instead of plain sockets
> APIs.
> 
> While this now looks pretty similar to the migration/unix.c
> file from the previous patch, it was decided not to merge
> the two, because when TLS is added to the TCP impl later,
> this file diverge from unix.c once again.

Hmm OK, although I'd kind of like to see merging, but lets
see the TLS code later in the series....

> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/tcp.c | 119 ++++++++++++++++++++++++++++++++++++++------------------
>  1 file changed, 82 insertions(+), 37 deletions(-)
> 
> diff --git a/migration/tcp.c b/migration/tcp.c
> index ae89172..ac73977 100644
> --- a/migration/tcp.c
> +++ b/migration/tcp.c
> @@ -2,9 +2,11 @@
>   * QEMU live migration
>   *
>   * Copyright IBM, Corp. 2008
> + * Copyright Red Hat, Inc. 2015
>   *
>   * Authors:
>   *  Anthony Liguori   <aliguori@us.ibm.com>
> + *  Daniel P. Berrange <berrange@redhat.com>
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2.  See
>   * the COPYING file in the top-level directory.
> @@ -17,11 +19,9 @@
>  
>  #include "qemu-common.h"
>  #include "qemu/error-report.h"
> -#include "qemu/sockets.h"
>  #include "migration/migration.h"
>  #include "migration/qemu-file.h"
> -#include "block/block.h"
> -#include "qemu/main-loop.h"
> +#include "io/channel-socket.h"
>  
>  //#define DEBUG_MIGRATION_TCP
>  
> @@ -33,71 +33,116 @@
>      do { } while (0)
>  #endif
>  
> -static void tcp_wait_for_connect(int fd, Error *err, void *opaque)
> +
> +static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
> +{
> +    InetSocketAddress *iaddr = inet_parse(host_port, errp);
> +    SocketAddress *saddr;
> +
> +    if (!iaddr) {
> +        return NULL;
> +    }
> +
> +    saddr = g_new0(SocketAddress, 1);
> +    saddr->type = SOCKET_ADDRESS_KIND_INET;
> +    saddr->u.inet = iaddr;
> +
> +    return saddr;
> +}
> +
> +
> +static void tcp_outgoing_migration(Object *src,
> +                                   Error *err,
> +                                   gpointer opaque)
>  {
>      MigrationState *s = opaque;
> +    QIOChannel *sioc = QIO_CHANNEL(src);
>  
> -    if (fd < 0) {
> +    if (err) {
>          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
>          s->file = NULL;
>          migrate_fd_error(s);
>      } else {
>          DPRINTF("migrate connect success\n");
> -        s->file = qemu_fopen_socket(fd, "wb");
> +        s->file = qemu_fopen_channel_output(sioc);
>          migrate_fd_connect(s);
>      }
> +    object_unref(src);
>  }
>  
> -void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
> +
> +void tcp_start_outgoing_migration(MigrationState *s,
> +                                  const char *host_port,
> +                                  Error **errp)
>  {
> -    inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
> +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> +    QIOChannelSocket *sioc;
> +
> +    if (!saddr) {
> +        return;
> +    }
> +
> +    sioc = qio_channel_socket_new();
> +    qio_channel_socket_connect_async(sioc,
> +                                     saddr,
> +                                     tcp_outgoing_migration,
> +                                     s,
> +                                     NULL);
> +    qapi_free_SocketAddress(saddr);
>  }
>  
> -static void tcp_accept_incoming_migration(void *opaque)
> +
> +static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
> +                                              GIOCondition condition,
> +                                              gpointer opaque)
>  {
> -    struct sockaddr_in addr;
> -    socklen_t addrlen = sizeof(addr);
> -    int s = (intptr_t)opaque;
>      QEMUFile *f;
> -    int c, err;
> +    QIOChannelSocket *cioc;
> +    Error *err = NULL;
>  
> -    do {
> -        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
> -        err = socket_error();
> -    } while (c < 0 && err == EINTR);
> -    qemu_set_fd_handler(s, NULL, NULL, NULL);
> -    closesocket(s);
> -
> -    DPRINTF("accepted migration\n");
> -
> -    if (c < 0) {
> +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> +                                     &err);
> +    if (!cioc) {
>          error_report("could not accept migration connection (%s)",
> -                     strerror(err));
> -        return;
> -    }
> -
> -    f = qemu_fopen_socket(c, "rb");
> -    if (f == NULL) {
> -        error_report("could not qemu_fopen socket");
> +                     error_get_pretty(err));
>          goto out;
>      }
>  
> +    DPRINTF("accepted migration\n");
> +
> +    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> +    object_unref(OBJECT(cioc));
> +
>      process_incoming_migration(f);
> -    return;
>  
>  out:
> -    closesocket(c);
> +    /* Close listening socket as its no longer needed */
> +    qio_channel_close(ioc, NULL);
> +    return FALSE;
>  }
>  
> +
>  void tcp_start_incoming_migration(const char *host_port, Error **errp)
>  {
> -    int s;
> +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> +    QIOChannelSocket *listen_ioc;
>  
> -    s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
> -    if (s < 0) {
> +    if (!saddr) {
>          return;
>      }
>  
> -    qemu_set_fd_handler(s, tcp_accept_incoming_migration, NULL,
> -                        (void *)(intptr_t)s);
> +    listen_ioc = qio_channel_socket_new();
> +    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {

In this case, although weird, that could block couldn't it?
The case I'm thinking of is using the migrate_incoming command with a hostname
(I've used it with hostnames before as aliases for networks to listen on,
admittedly it be rare for it to be DNS that would block).

(Other comments on the unix-socket match here as well).

Dave

> +        object_unref(OBJECT(listen_ioc));
> +        qapi_free_SocketAddress(saddr);
> +        return;
> +    }
> +
> +    qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
> +                          G_IO_IN,
> +                          tcp_accept_incoming_migration,
> +                          listen_ioc,
> +                          (GDestroyNotify)object_unref);
> +
> +    qapi_free_SocketAddress(saddr);
>  }
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 11/22] migration: convert fd socket protocol to use QIOChannel
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 11/22] migration: convert fd " Daniel P. Berrange
@ 2016-02-02 18:46   ` Dr. David Alan Gilbert
  2016-02-03 10:05     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 18:46 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Convert the fd socket migration protocol driver to use
> QIOChannel and QEMUFileChannel, instead of plain sockets
> APIs. It can be unconditionally built because the
> QIOChannel APIs it uses will take care to report suitable
> error messages if needed.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/Makefile.objs |  4 ++--
>  migration/fd.c          | 57 ++++++++++++++++++++++++++++++++-----------------
>  migration/migration.c   |  4 ----
>  3 files changed, 39 insertions(+), 26 deletions(-)
> 
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index a5f8a03..64f95cd 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,11 +1,11 @@
> -common-obj-y += migration.o tcp.o unix.o
> +common-obj-y += migration.o tcp.o unix.o fd.o
>  common-obj-y += vmstate.o
>  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
>  common-obj-$(CONFIG_RDMA) += rdma.o
> -common-obj-$(CONFIG_POSIX) += exec.o fd.o
> +common-obj-$(CONFIG_POSIX) += exec.o
>  
>  common-obj-y += block.o
>  
> diff --git a/migration/fd.c b/migration/fd.c
> index 3e4bed0..8d48e0d 100644
> --- a/migration/fd.c
> +++ b/migration/fd.c
> @@ -20,6 +20,8 @@
>  #include "monitor/monitor.h"
>  #include "migration/qemu-file.h"
>  #include "block/block.h"
> +#include "io/channel-file.h"
> +#include "io/channel-socket.h"
>  
>  //#define DEBUG_MIGRATION_FD
>  
> @@ -33,56 +35,71 @@
>  
>  static bool fd_is_socket(int fd)
>  {
> -    struct stat stat;
> -    int ret = fstat(fd, &stat);
> -    if (ret == -1) {
> -        /* When in doubt say no */
> -        return false;
> -    }
> -    return S_ISSOCK(stat.st_mode);
> +    int optval;
> +    socklen_t optlen;
> +    optlen = sizeof(optval);
> +    return getsockopt(fd,
> +                      SOL_SOCKET,
> +                      SO_TYPE,
> +                      (char *)&optval,
> +                      &optlen) == 0;

Should that be qemu_getsockopt ?

>  }
>  
>  void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
>  {
> +    QIOChannel *ioc;
>      int fd = monitor_get_fd(cur_mon, fdname, errp);
>      if (fd == -1) {
>          return;
>      }
>  
>      if (fd_is_socket(fd)) {
> -        s->file = qemu_fopen_socket(fd, "wb");
> +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> +        if (!ioc) {
> +            close(fd);
> +            return;
> +        }

Have you considered moving this fd_is_socket detection
glue down into channel-file.c?  It's here so that a socket
passed via an fd will be able to use a shutdown() method.
It would be nice to do the same thing to sockets in the same
situation in other places, so it would make sense if it worked
on any fd that went through channels.
The tricky bit is at that level you return a QIOChannelFile rather
than a generic QIOChannel pointer.
(One place I'd like to be able to a shutdown is on an nbd channel
for example).

>      } else {
> -        s->file = qemu_fdopen(fd, "wb");
> +        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
>      }
> +    s->file = qemu_fopen_channel_output(ioc);
>  
>      migrate_fd_connect(s);
>  }
>  
> -static void fd_accept_incoming_migration(void *opaque)
> +static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
> +                                             GIOCondition condition,
> +                                             gpointer opaque)
>  {
>      QEMUFile *f = opaque;
> -
> -    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
>      process_incoming_migration(f);
> +    return FALSE;

Please comment the magical FALSE.

>  }
>  
>  void fd_start_incoming_migration(const char *infd, Error **errp)
>  {
> -    int fd;
>      QEMUFile *f;
> +    QIOChannel *ioc;
> +    int fd;
>  
>      DPRINTF("Attempting to start an incoming migration via fd\n");
>  
>      fd = strtol(infd, NULL, 0);
>      if (fd_is_socket(fd)) {
> -        f = qemu_fopen_socket(fd, "rb");
> +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> +        if (!ioc) {
> +            close(fd);
> +            return;
> +        }

Wouldn't it be better to move this check outside of this if, so that
you test the output of both the socket_new_fd and the file_new_fd ?

Dave

>      } else {
> -        f = qemu_fdopen(fd, "rb");
> -    }
> -    if(f == NULL) {
> -        error_setg_errno(errp, errno, "failed to open the source descriptor");
> -        return;
> +        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
>      }
> +    f = qemu_fopen_channel_input(ioc);
> +    object_unref(OBJECT(ioc));
>  
> -    qemu_set_fd_handler(fd, fd_accept_incoming_migration, NULL, f);
> +    qio_channel_add_watch(ioc,
> +                          G_IO_IN,
> +                          fd_accept_incoming_migration,
> +                          f,
> +                          NULL);
>  }
> diff --git a/migration/migration.c b/migration/migration.c
> index 1c5f12e..211879e 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -315,10 +315,8 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
>  #endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_incoming_migration(p, errp);
> -#if !defined(WIN32)
>      } else if (strstart(uri, "fd:", &p)) {
>          fd_start_incoming_migration(p, errp);
> -#endif
>      } else {
>          error_setg(errp, "unknown migration protocol: %s", uri);
>      }
> @@ -1022,10 +1020,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
>  #endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_outgoing_migration(s, p, &local_err);
> -#if !defined(WIN32)
>      } else if (strstart(uri, "fd:", &p)) {
>          fd_start_outgoing_migration(s, p, &local_err);
> -#endif
>      } else {
>          error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri",
>                     "a valid migration protocol");
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 12/22] migration: convert exec socket protocol to use QIOChannel
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 12/22] migration: convert exec " Daniel P. Berrange
@ 2016-02-02 18:53   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 18:53 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Convert the exec socket migration protocol driver to use
> QIOChannel and QEMUFileChannel, instead of the stdio
> popen APIs. It can be unconditionally built because the
> QIOChannelCommand class can report suitable error messages
> on platforms which can't fork processes.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/Makefile.objs |  3 +--
>  migration/exec.c        | 48 ++++++++++++++++++++++++++++++------------------
>  migration/migration.c   |  4 ----
>  3 files changed, 31 insertions(+), 24 deletions(-)
> 
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 64f95cd..3c90c44 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,11 +1,10 @@
> -common-obj-y += migration.o tcp.o unix.o fd.o
> +common-obj-y += migration.o tcp.o unix.o fd.o exec.o
>  common-obj-y += vmstate.o
>  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
>  common-obj-$(CONFIG_RDMA) += rdma.o
> -common-obj-$(CONFIG_POSIX) += exec.o
>  
>  common-obj-y += block.o
>  
> diff --git a/migration/exec.c b/migration/exec.c
> index 8406d2b..6159aba 100644
> --- a/migration/exec.c
> +++ b/migration/exec.c
> @@ -15,14 +15,8 @@
>   * GNU GPL, version 2 or (at your option) any later version.
>   */
>  
> -#include "qemu-common.h"
> -#include "qemu/sockets.h"
> -#include "qemu/main-loop.h"
>  #include "migration/migration.h"
> -#include "migration/qemu-file.h"
> -#include "block/block.h"
> -#include <sys/types.h>
> -#include <sys/wait.h>
> +#include "io/channel-command.h"
>  
>  //#define DEBUG_MIGRATION_EXEC
>  
> @@ -36,34 +30,52 @@
>  
>  void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
>  {
> -    s->file = qemu_popen_cmd(command, "w");
> -    if (s->file == NULL) {
> -        error_setg_errno(errp, errno, "failed to popen the migration target");
> +    QIOChannel *ioc;
> +    const char *argv[] = { "/bin/sh", "-c", command, NULL };
> +
> +    DPRINTF("Attempting to start an outgoing migration\n");

No new DPRINTF's - trace_ please.

> +    ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
> +                                                    O_WRONLY,
> +                                                    errp));
> +    if (!ioc) {
>          return;
>      }
>  
> +    s->file = qemu_fopen_channel_output(ioc);
> +    object_unref(OBJECT(ioc));
> +
>      migrate_fd_connect(s);
>  }
>  
> -static void exec_accept_incoming_migration(void *opaque)
> +static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
> +                                               GIOCondition condition,
> +                                               gpointer opaque)
>  {
>      QEMUFile *f = opaque;
> -
> -    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
>      process_incoming_migration(f);
> +    return FALSE;

As previous patch, comment the magical FALSE.

Other than those two minor ones;

(If we're lucky this might fix the rcu race that I can trigger with exec: migration).

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Dave

>  }
>  
>  void exec_start_incoming_migration(const char *command, Error **errp)
>  {
>      QEMUFile *f;
> +    QIOChannel *ioc;
> +    const char *argv[] = { "/bin/sh", "-c", command, NULL };
>  
>      DPRINTF("Attempting to start an incoming migration\n");
> -    f = qemu_popen_cmd(command, "r");
> -    if(f == NULL) {
> -        error_setg_errno(errp, errno, "failed to popen the migration source");
> +    ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
> +                                                    O_RDONLY,
> +                                                    errp));
> +    if (!ioc) {
>          return;
>      }
>  
> -    qemu_set_fd_handler(qemu_get_fd(f), exec_accept_incoming_migration, NULL,
> -                        f);
> +    f = qemu_fopen_channel_input(ioc);
> +    object_unref(OBJECT(ioc));
> +
> +    qio_channel_add_watch(ioc,
> +                          G_IO_IN,
> +                          exec_accept_incoming_migration,
> +                          f,
> +                          NULL);
>  }
> diff --git a/migration/migration.c b/migration/migration.c
> index 211879e..2d2079d 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -309,10 +309,8 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
>      } else if (strstart(uri, "rdma:", &p)) {
>          rdma_start_incoming_migration(p, errp);
>  #endif
> -#if !defined(WIN32)
>      } else if (strstart(uri, "exec:", &p)) {
>          exec_start_incoming_migration(p, errp);
> -#endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_incoming_migration(p, errp);
>      } else if (strstart(uri, "fd:", &p)) {
> @@ -1014,10 +1012,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
>      } else if (strstart(uri, "rdma:", &p)) {
>          rdma_start_outgoing_migration(s, p, &local_err);
>  #endif
> -#if !defined(WIN32)
>      } else if (strstart(uri, "exec:", &p)) {
>          exec_start_outgoing_migration(s, p, &local_err);
> -#endif
>      } else if (strstart(uri, "unix:", &p)) {
>          unix_start_outgoing_migration(s, p, &local_err);
>      } else if (strstart(uri, "fd:", &p)) {
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface Daniel P. Berrange
@ 2016-02-02 20:01   ` Dr. David Alan Gilbert
  2016-02-03 11:37     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-02 20:01 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> This converts the RDMA code to provide a subclass of
> QIOChannel that uses RDMA for the data transport.
> 
> The RDMA code would be much better off it it could
> be split up in a generic RDMA layer, a QIOChannel
> impl based on RMDA, and then the RMDA migration
> glue. This is left as a future exercise for the brave.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  migration/rdma.c | 260 ++++++++++++++++++++++++++++++++++---------------------
>  1 file changed, 161 insertions(+), 99 deletions(-)
> 
> diff --git a/migration/rdma.c b/migration/rdma.c
> index bffbfaf..3e961cb 100644
> --- a/migration/rdma.c
> +++ b/migration/rdma.c
> @@ -374,14 +374,19 @@ typedef struct RDMAContext {
>      GHashTable *blockmap;
>  } RDMAContext;
>  
> -/*
> - * Interface to the rest of the migration call stack.
> - */
> -typedef struct QEMUFileRDMA {
> +#define TYPE_QIO_CHANNEL_RDMA "qio-channel-rdma"
> +#define QIO_CHANNEL_RDMA(obj)                                     \
> +    OBJECT_CHECK(QIOChannelRDMA, (obj), TYPE_QIO_CHANNEL_RDMA)
> +
> +typedef struct QIOChannelRDMA QIOChannelRDMA;
> +
> +
> +struct QIOChannelRDMA {
> +    QIOChannel parent;
>      RDMAContext *rdma;
> +    QEMUFile *file;
>      size_t len;
> -    void *file;
> -} QEMUFileRDMA;
> +};
>  
>  /*
>   * Main structure for IB Send/Recv control messages.
> @@ -2518,15 +2523,19 @@ static void *qemu_rdma_data_init(const char *host_port, Error **errp)
>   * SEND messages for control only.
>   * VM's ram is handled with regular RDMA messages.
>   */
> -static ssize_t qemu_rdma_put_buffer(void *opaque, const uint8_t *buf,
> -                                    int64_t pos, size_t size)
> -{
> -    QEMUFileRDMA *r = opaque;
> -    QEMUFile *f = r->file;
> -    RDMAContext *rdma = r->rdma;
> -    size_t remaining = size;
> -    uint8_t * data = (void *) buf;
> +static ssize_t qio_channel_rdma_writev(QIOChannel *ioc,
> +                                       const struct iovec *iov,
> +                                       size_t niov,
> +                                       int *fds,
> +                                       size_t nfds,
> +                                       Error **errp)
> +{
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
> +    QEMUFile *f = rioc->file;
> +    RDMAContext *rdma = rioc->rdma;
>      int ret;
> +    ssize_t done = 0;
> +    size_t i;
>  
>      CHECK_ERROR_STATE();
>  
> @@ -2540,27 +2549,31 @@ static ssize_t qemu_rdma_put_buffer(void *opaque, const uint8_t *buf,
>          return ret;
>      }
>  
> -    while (remaining) {
> -        RDMAControlHeader head;
> +    for (i = 0; i < niov; i++) {
> +        size_t remaining = iov[i].iov_len;
> +        uint8_t * data = (void *)iov[i].iov_base;
> +        while (remaining) {
> +            RDMAControlHeader head;
>  
> -        r->len = MIN(remaining, RDMA_SEND_INCREMENT);
> -        remaining -= r->len;
> +            rioc->len = MIN(remaining, RDMA_SEND_INCREMENT);
> +            remaining -= rioc->len;
>  
> -        /* Guaranteed to fit due to RDMA_SEND_INCREMENT MIN above */
> -        head.len = (uint32_t)r->len;
> -        head.type = RDMA_CONTROL_QEMU_FILE;
> +            head.len = rioc->len;
> +            head.type = RDMA_CONTROL_QEMU_FILE;
>  
> -        ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL);
> +            ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL);
>  
> -        if (ret < 0) {
> -            rdma->error_state = ret;
> -            return ret;
> -        }
> +            if (ret < 0) {
> +                rdma->error_state = ret;
> +                return ret;
> +            }
>  
> -        data += r->len;
> +            data += rioc->len;
> +            done += rioc->len;
> +        }
>      }
>  
> -    return size;
> +    return done;
>  }
>  
>  static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf,
> @@ -2585,41 +2598,65 @@ static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf,
>   * RDMA links don't use bytestreams, so we have to
>   * return bytes to QEMUFile opportunistically.
>   */
> -static ssize_t qemu_rdma_get_buffer(void *opaque, uint8_t *buf,
> -                                    int64_t pos, size_t size)
> -{
> -    QEMUFileRDMA *r = opaque;
> -    RDMAContext *rdma = r->rdma;
> +static ssize_t qio_channel_rdma_readv(QIOChannel *ioc,
> +                                      const struct iovec *iov,
> +                                      size_t niov,
> +                                      int **fds,
> +                                      size_t *nfds,
> +                                      Error **errp)
> +{
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
> +    RDMAContext *rdma = rioc->rdma;
>      RDMAControlHeader head;
>      int ret = 0;
> +    ssize_t i;
> +    size_t done = 0;
>  
>      CHECK_ERROR_STATE();
>  
> -    /*
> -     * First, we hold on to the last SEND message we
> -     * were given and dish out the bytes until we run
> -     * out of bytes.
> -     */
> -    r->len = qemu_rdma_fill(r->rdma, buf, size, 0);
> -    if (r->len) {
> -        return r->len;
> -    }
> +    for (i = 0; i < niov; i++) {
> +        size_t want = iov[i].iov_len;
> +        uint8_t *data = (void *)iov[i].iov_base;
>  
> -    /*
> -     * Once we run out, we block and wait for another
> -     * SEND message to arrive.
> -     */
> -    ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
> +        /*
> +         * First, we hold on to the last SEND message we
> +         * were given and dish out the bytes until we run
> +         * out of bytes.
> +         */
> +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> +        if (ret > 0) {
> +            done += ret;
> +            if (ret < want) {
> +                break;
> +            } else {
> +                continue;
> +            }

> +        }
>  
> -    if (ret < 0) {
> -        rdma->error_state = ret;
> -        return ret;
> -    }
> +        /*
> +         * Once we run out, we block and wait for another
> +         * SEND message to arrive.
> +         */
> +        ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
>  
> -    /*
> -     * SEND was received with new bytes, now try again.
> -     */
> -    return qemu_rdma_fill(r->rdma, buf, size, 0);
> +        if (ret < 0) {
> +            rdma->error_state = ret;
> +            return ret;
> +        }
> +
> +        /*
> +         * SEND was received with new bytes, now try again.
> +         */
> +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> +        if (ret > 0) {
> +            done += ret;
> +            if (ret < want) {
> +                break;
> +            }
> +        }

I don't quite understand the behaviour of this loop.
If rdma_fill returns less than you wanted for the first iov we break.
If it returns 0 then we try and get some more.
The weird thing to me is if we have two iov entries; if the
amount returned by the qemu_rdma_fill happens to match the size of
the 1st iov then I think we end up doing the exchange_recv and
waiting for more.  Is that what we want? Why?

Dave

> +    }
> +    rioc->len = done;
> +    return rioc->len;
>  }
>  
>  /*
> @@ -2646,15 +2683,16 @@ static int qemu_rdma_drain_cq(QEMUFile *f, RDMAContext *rdma)
>      return 0;
>  }
>  
> -static int qemu_rdma_close(void *opaque)
> +static int qio_channel_rdma_close(QIOChannel *ioc,
> +                                  Error **errp)
>  {
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
>      trace_qemu_rdma_close();
> -    QEMUFileRDMA *r = opaque;
> -    if (r->rdma) {
> -        qemu_rdma_cleanup(r->rdma);
> -        g_free(r->rdma);
> +    if (rioc->rdma) {
> +        qemu_rdma_cleanup(rioc->rdma);
> +        g_free(rioc->rdma);
> +        rioc->rdma = NULL;
>      }
> -    g_free(r);
>      return 0;
>  }
>  
> @@ -2696,8 +2734,8 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque,
>                                    ram_addr_t block_offset, ram_addr_t offset,
>                                    size_t size, uint64_t *bytes_sent)
>  {
> -    QEMUFileRDMA *rfile = opaque;
> -    RDMAContext *rdma = rfile->rdma;
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
> +    RDMAContext *rdma = rioc->rdma;
>      int ret;
>  
>      CHECK_ERROR_STATE();
> @@ -2951,8 +2989,8 @@ static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque)
>                               };
>      RDMAControlHeader blocks = { .type = RDMA_CONTROL_RAM_BLOCKS_RESULT,
>                                   .repeat = 1 };
> -    QEMUFileRDMA *rfile = opaque;
> -    RDMAContext *rdma = rfile->rdma;
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
> +    RDMAContext *rdma = rioc->rdma;
>      RDMALocalBlocks *local = &rdma->local_ram_blocks;
>      RDMAControlHeader head;
>      RDMARegister *reg, *registers;
> @@ -3207,9 +3245,10 @@ out:
>   * We've already built our local RAMBlock list, but not yet sent the list to
>   * the source.
>   */
> -static int rdma_block_notification_handle(QEMUFileRDMA *rfile, const char *name)
> +static int
> +rdma_block_notification_handle(QIOChannelRDMA *rioc, const char *name)
>  {
> -    RDMAContext *rdma = rfile->rdma;
> +    RDMAContext *rdma = rioc->rdma;
>      int curr;
>      int found = -1;
>  
> @@ -3251,8 +3290,8 @@ static int rdma_load_hook(QEMUFile *f, void *opaque, uint64_t flags, void *data)
>  static int qemu_rdma_registration_start(QEMUFile *f, void *opaque,
>                                          uint64_t flags, void *data)
>  {
> -    QEMUFileRDMA *rfile = opaque;
> -    RDMAContext *rdma = rfile->rdma;
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
> +    RDMAContext *rdma = rioc->rdma;
>  
>      CHECK_ERROR_STATE();
>  
> @@ -3271,8 +3310,8 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
>                                         uint64_t flags, void *data)
>  {
>      Error *local_err = NULL, **errp = &local_err;
> -    QEMUFileRDMA *rfile = opaque;
> -    RDMAContext *rdma = rfile->rdma;
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
> +    RDMAContext *rdma = rioc->rdma;
>      RDMAControlHeader head = { .len = 0, .repeat = 1 };
>      int ret = 0;
>  
> @@ -3368,55 +3407,78 @@ err:
>      return ret;
>  }
>  
> -static int qemu_rdma_get_fd(void *opaque)
> -{
> -    QEMUFileRDMA *rfile = opaque;
> -    RDMAContext *rdma = rfile->rdma;
> -
> -    return rdma->comp_channel->fd;
> -}
> -
> -static const QEMUFileOps rdma_read_ops = {
> -    .get_buffer    = qemu_rdma_get_buffer,
> -    .get_fd        = qemu_rdma_get_fd,
> -    .close         = qemu_rdma_close,
> -};
> -
>  static const QEMUFileHooks rdma_read_hooks = {
>      .hook_ram_load = rdma_load_hook,
>  };
>  
> -static const QEMUFileOps rdma_write_ops = {
> -    .put_buffer         = qemu_rdma_put_buffer,
> -    .close              = qemu_rdma_close,
> -};
> -
>  static const QEMUFileHooks rdma_write_hooks = {
>      .before_ram_iterate = qemu_rdma_registration_start,
>      .after_ram_iterate  = qemu_rdma_registration_stop,
>      .save_page          = qemu_rdma_save_page,
>  };
>  
> -static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
> +
> +static void qio_channel_rdma_finalize(Object *obj)
> +{
> +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(obj);
> +    if (rioc->rdma) {
> +        qemu_rdma_cleanup(rioc->rdma);
> +        g_free(rioc->rdma);
> +        rioc->rdma = NULL;
> +    }
> +}
> +
> +static void qio_channel_rdma_class_init(ObjectClass *klass,
> +                                        void *class_data G_GNUC_UNUSED)
> +{
> +    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
> +
> +    ioc_klass->io_writev = qio_channel_rdma_writev;
> +    ioc_klass->io_readv = qio_channel_rdma_readv;
> +    /* XXX
> +    ioc_klass->io_set_blocking = qio_channel_rdma_set_blocking;
> +    */
> +    ioc_klass->io_close = qio_channel_rdma_close;
> +    /* XXX
> +    ioc_klass->io_create_watch = qio_channel_rdma_create_watch;
> +    */
> +}
> +
> +static const TypeInfo qio_channel_rdma_info = {
> +    .parent = TYPE_QIO_CHANNEL,
> +    .name = TYPE_QIO_CHANNEL_RDMA,
> +    .instance_size = sizeof(QIOChannelRDMA),
> +    .instance_finalize = qio_channel_rdma_finalize,
> +    .class_init = qio_channel_rdma_class_init,
> +};
> +
> +static void qio_channel_rdma_register_types(void)
> +{
> +    type_register_static(&qio_channel_rdma_info);
> +}
> +
> +type_init(qio_channel_rdma_register_types);
> +
> +static QEMUFile *qemu_fopen_rdma(RDMAContext *rdma, const char *mode)
>  {
> -    QEMUFileRDMA *r;
> +    QIOChannelRDMA *rioc;
>  
>      if (qemu_file_mode_is_not_valid(mode)) {
>          return NULL;
>      }
>  
> -    r = g_new0(QEMUFileRDMA, 1);
> -    r->rdma = rdma;
> +    rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA));
> +    rioc->rdma = rdma;
>  
>      if (mode[0] == 'w') {
> -        r->file = qemu_fopen_ops(r, &rdma_write_ops);
> -        qemu_file_set_hooks(r->file, &rdma_write_hooks);
> +        rioc->file = qemu_fopen_channel_output(QIO_CHANNEL(rioc));
> +        qemu_file_set_hooks(rioc->file, &rdma_write_hooks);
>      } else {
> -        r->file = qemu_fopen_ops(r, &rdma_read_ops);
> -        qemu_file_set_hooks(r->file, &rdma_read_hooks);
> +        rioc->file = qemu_fopen_channel_input(QIO_CHANNEL(rioc));
> +        qemu_file_set_hooks(rioc->file, &rdma_read_hooks);
>      }
>  
> -    return r->file;
> +    return rioc->file;
>  }
>  
>  static void rdma_accept_incoming_migration(void *opaque)
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files Daniel P. Berrange
@ 2016-02-03  9:52   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03  9:52 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Convert the exec savevm code to use QIOChannel and QEMUFileChannel,
> instead of the stdio APIs.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  migration/savevm.c   |  8 +++++---
>  tests/Makefile       |  4 ++--
>  tests/test-vmstate.c | 11 ++++++++++-
>  3 files changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/migration/savevm.c b/migration/savevm.c
> index f2e1880..e57d7ce 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -51,6 +51,7 @@
>  #include "block/snapshot.h"
>  #include "block/qapi.h"
>  #include "io/channel-buffer.h"
> +#include "io/channel-file.h"
>  
>  
>  #ifndef ETH_P_RARP
> @@ -1990,6 +1991,7 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
>  void qmp_xen_save_devices_state(const char *filename, Error **errp)
>  {
>      QEMUFile *f;
> +    QIOChannelFile *ioc;
>      int saved_vm_running;
>      int ret;
>  
> @@ -1997,11 +1999,11 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
>      vm_stop(RUN_STATE_SAVE_VM);
>      global_state_store_running();
>  
> -    f = qemu_fopen(filename, "wb");
> -    if (!f) {
> -        error_setg_file_open(errp, errno, filename);
> +    ioc = qio_channel_file_new_path(filename, O_WRONLY | O_CREAT, 0660, errp);
> +    if (!ioc) {
>          goto the_end;
>      }
> +    f = qemu_fopen_channel_output(QIO_CHANNEL(ioc));
>      ret = qemu_save_device_state(f);
>      qemu_fclose(f);
>      if (ret < 0) {
> diff --git a/tests/Makefile b/tests/Makefile
> index 5a1b25f..e8f759a 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -423,8 +423,8 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
>  	$(test-qapi-obj-y)
>  tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
>  	migration/vmstate.o migration/qemu-file.o \
> -        migration/qemu-file-unix.o qjson.o \
> -	$(test-qom-obj-y)
> +        migration/qemu-file-channel.o qjson.o \
> +	$(test-io-obj-y)
>  tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
>  	$(test-util-obj-y)
>  tests/test-base64$(EXESUF): tests/test-base64.o \
> diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
> index 0f943d5..6bbda8a 100644
> --- a/tests/test-vmstate.c
> +++ b/tests/test-vmstate.c
> @@ -28,6 +28,7 @@
>  #include "migration/migration.h"
>  #include "migration/vmstate.h"
>  #include "qemu/coroutine.h"
> +#include "io/channel-file.h"
>  
>  static char temp_file[] = "/tmp/vmst.test.XXXXXX";
>  static int temp_fd;
> @@ -48,11 +49,17 @@ void yield_until_fd_readable(int fd)
>  static QEMUFile *open_test_file(bool write)
>  {
>      int fd = dup(temp_fd);
> +    QIOChannel *ioc;
>      lseek(fd, 0, SEEK_SET);
>      if (write) {
>          g_assert_cmpint(ftruncate(fd, 0), ==, 0);
>      }
> -    return qemu_fdopen(fd, write ? "wb" : "rb");
> +    ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
> +    if (write) {
> +        return qemu_fopen_channel_output(ioc);
> +    } else {
> +        return qemu_fopen_channel_input(ioc);
> +    }
>  }
>  
>  #define SUCCESS(val) \
> @@ -468,6 +475,8 @@ int main(int argc, char **argv)
>  {
>      temp_fd = mkstemp(temp_file);
>  
> +    module_call_init(MODULE_INIT_QOM);
> +
>      g_test_init(&argc, &argv, NULL);
>      g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
>      g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation Daniel P. Berrange
@ 2016-02-03  9:54   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03  9:54 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> The qemu_bufopen() method is no longer used, so the memory
> buffer based QEMUFile backend can be deleted entirely.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |  6 ---
>  migration/qemu-file-buf.c     | 96 -------------------------------------------
>  2 files changed, 102 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index cb79311..6b12960 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -141,7 +141,6 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode);
>  QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
>  QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
>  QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
> -QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
>  void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
>  int qemu_get_fd(QEMUFile *f);
>  int qemu_fclose(QEMUFile *f);
> @@ -167,11 +166,6 @@ ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
>                       off_t pos, size_t count);
>  
>  
> -/*
> - * For use on files opened with qemu_bufopen
> - */
> -const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f);
> -
>  static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
>  {
>      qemu_put_byte(f, (int)v);
> diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c
> index 49516b8..c0bc38c 100644
> --- a/migration/qemu-file-buf.c
> +++ b/migration/qemu-file-buf.c
> @@ -365,99 +365,3 @@ ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
>  
>      return count;
>  }
> -
> -typedef struct QEMUBuffer {
> -    QEMUSizedBuffer *qsb;
> -    QEMUFile *file;
> -    bool qsb_allocated;
> -} QEMUBuffer;
> -
> -static ssize_t buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> -                              size_t size)
> -{
> -    QEMUBuffer *s = opaque;
> -    ssize_t len = qsb_get_length(s->qsb) - pos;
> -
> -    if (len <= 0) {
> -        return 0;
> -    }
> -
> -    if (len > size) {
> -        len = size;
> -    }
> -    return qsb_get_buffer(s->qsb, pos, len, buf);
> -}
> -
> -static ssize_t buf_put_buffer(void *opaque, const uint8_t *buf,
> -                              int64_t pos, size_t size)
> -{
> -    QEMUBuffer *s = opaque;
> -
> -    return qsb_write_at(s->qsb, buf, pos, size);
> -}
> -
> -static int buf_close(void *opaque)
> -{
> -    QEMUBuffer *s = opaque;
> -
> -    if (s->qsb_allocated) {
> -        qsb_free(s->qsb);
> -    }
> -
> -    g_free(s);
> -
> -    return 0;
> -}
> -
> -const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
> -{
> -    QEMUBuffer *p;
> -
> -    qemu_fflush(f);
> -
> -    p = f->opaque;
> -
> -    return p->qsb;
> -}
> -
> -static const QEMUFileOps buf_read_ops = {
> -    .get_buffer = buf_get_buffer,
> -    .close =      buf_close,
> -};
> -
> -static const QEMUFileOps buf_write_ops = {
> -    .put_buffer = buf_put_buffer,
> -    .close =      buf_close,
> -};
> -
> -QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
> -{
> -    QEMUBuffer *s;
> -
> -    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
> -        mode[1] != '\0') {
> -        error_report("qemu_bufopen: Argument validity check failed");
> -        return NULL;
> -    }
> -
> -    s = g_new0(QEMUBuffer, 1);
> -    s->qsb = input;
> -
> -    if (s->qsb == NULL) {
> -        s->qsb = qsb_create(NULL, 0);
> -        s->qsb_allocated = true;
> -    }
> -    if (!s->qsb) {
> -        g_free(s);
> -        error_report("qemu_bufopen: qsb_create failed");
> -        return NULL;
> -    }
> -
> -
> -    if (mode[0] == 'r') {
> -        s->file = qemu_fopen_ops(s, &buf_read_ops);
> -    } else {
> -        s->file = qemu_fopen_ops(s, &buf_write_ops);
> -    }
> -    return s->file;
> -}
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct Daniel P. Berrange
@ 2016-02-03  9:55   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03  9:55 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Now that we don't have have a buffer based QemuFile
> implementation, the QEMUSizedBuffer code is also
> unused and can be deleted. A simpler buffer class
> also exists in util/buffer.c which other code can
> used as needed.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |  16 --
>  include/qemu/typedefs.h       |   1 -
>  migration/Makefile.objs       |   2 +-
>  migration/qemu-file-buf.c     | 367 ------------------------------------------
>  4 files changed, 1 insertion(+), 385 deletions(-)
>  delete mode 100644 migration/qemu-file-buf.c
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index 6b12960..da67931 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -127,13 +127,6 @@ typedef struct QEMUFileHooks {
>      QEMURamSaveFunc *save_page;
>  } QEMUFileHooks;
>  
> -struct QEMUSizedBuffer {
> -    struct iovec *iov;
> -    size_t n_iov;
> -    size_t size; /* total allocated size in all iov's */
> -    size_t used; /* number of used bytes */
> -};
> -
>  QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
>  QEMUFile *qemu_fopen(const char *filename, const char *mode);
>  QEMUFile *qemu_fdopen(int fd, const char *mode);
> @@ -156,15 +149,6 @@ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size);
>  bool qemu_file_mode_is_not_valid(const char *mode);
>  bool qemu_file_is_writable(QEMUFile *f);
>  
> -QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len);
> -void qsb_free(QEMUSizedBuffer *);
> -size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t length);
> -size_t qsb_get_length(const QEMUSizedBuffer *qsb);
> -ssize_t qsb_get_buffer(const QEMUSizedBuffer *, off_t start, size_t count,
> -                       uint8_t *buf);
> -ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
> -                     off_t pos, size_t count);
> -
>  
>  static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
>  {
> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> index 78fe6e8..3f8dfbf 100644
> --- a/include/qemu/typedefs.h
> +++ b/include/qemu/typedefs.h
> @@ -77,7 +77,6 @@ typedef struct QemuOpt QemuOpt;
>  typedef struct QemuOpts QemuOpts;
>  typedef struct QemuOptsList QemuOptsList;
>  typedef struct QEMUSGList QEMUSGList;
> -typedef struct QEMUSizedBuffer QEMUSizedBuffer;
>  typedef struct QEMUTimer QEMUTimer;
>  typedef struct QEMUTimerListGroup QEMUTimerListGroup;
>  typedef struct QObject QObject;
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 3c90c44..8ecb941 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,6 +1,6 @@
>  common-obj-y += migration.o tcp.o unix.o fd.o exec.o
>  common-obj-y += vmstate.o
> -common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
> +common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
> diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c
> deleted file mode 100644
> index c0bc38c..0000000
> --- a/migration/qemu-file-buf.c
> +++ /dev/null
> @@ -1,367 +0,0 @@
> -/*
> - * QEMU System Emulator
> - *
> - * Copyright (c) 2003-2008 Fabrice Bellard
> - * Copyright (c) 2014 IBM Corp.
> - *
> - * Authors:
> - *  Stefan Berger <stefanb@linux.vnet.ibm.com>
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a copy
> - * of this software and associated documentation files (the "Software"), to deal
> - * in the Software without restriction, including without limitation the rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -#include "qemu-common.h"
> -#include "qemu/error-report.h"
> -#include "qemu/iov.h"
> -#include "qemu/sockets.h"
> -#include "qemu/coroutine.h"
> -#include "migration/migration.h"
> -#include "migration/qemu-file.h"
> -#include "migration/qemu-file-internal.h"
> -#include "trace.h"
> -
> -#define QSB_CHUNK_SIZE      (1 << 10)
> -#define QSB_MAX_CHUNK_SIZE  (16 * QSB_CHUNK_SIZE)
> -
> -/**
> - * Create a QEMUSizedBuffer
> - * This type of buffer uses scatter-gather lists internally and
> - * can grow to any size. Any data array in the scatter-gather list
> - * can hold different amount of bytes.
> - *
> - * @buffer: Optional buffer to copy into the QSB
> - * @len: size of initial buffer; if @buffer is given, buffer must
> - *       hold at least len bytes
> - *
> - * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
> - */
> -QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
> -{
> -    QEMUSizedBuffer *qsb;
> -    size_t alloc_len, num_chunks, i, to_copy;
> -    size_t chunk_size = (len > QSB_MAX_CHUNK_SIZE)
> -                        ? QSB_MAX_CHUNK_SIZE
> -                        : QSB_CHUNK_SIZE;
> -
> -    num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
> -    alloc_len = num_chunks * chunk_size;
> -
> -    qsb = g_try_new0(QEMUSizedBuffer, 1);
> -    if (!qsb) {
> -        return NULL;
> -    }
> -
> -    qsb->iov = g_try_new0(struct iovec, num_chunks);
> -    if (!qsb->iov) {
> -        g_free(qsb);
> -        return NULL;
> -    }
> -
> -    qsb->n_iov = num_chunks;
> -
> -    for (i = 0; i < num_chunks; i++) {
> -        qsb->iov[i].iov_base = g_try_malloc0(chunk_size);
> -        if (!qsb->iov[i].iov_base) {
> -            /* qsb_free is safe since g_free can cope with NULL */
> -            qsb_free(qsb);
> -            return NULL;
> -        }
> -
> -        qsb->iov[i].iov_len = chunk_size;
> -        if (buffer) {
> -            to_copy = (len - qsb->used) > chunk_size
> -                      ? chunk_size : (len - qsb->used);
> -            memcpy(qsb->iov[i].iov_base, &buffer[qsb->used], to_copy);
> -            qsb->used += to_copy;
> -        }
> -    }
> -
> -    qsb->size = alloc_len;
> -
> -    return qsb;
> -}
> -
> -/**
> - * Free the QEMUSizedBuffer
> - *
> - * @qsb: The QEMUSizedBuffer to free
> - */
> -void qsb_free(QEMUSizedBuffer *qsb)
> -{
> -    size_t i;
> -
> -    if (!qsb) {
> -        return;
> -    }
> -
> -    for (i = 0; i < qsb->n_iov; i++) {
> -        g_free(qsb->iov[i].iov_base);
> -    }
> -    g_free(qsb->iov);
> -    g_free(qsb);
> -}
> -
> -/**
> - * Get the number of used bytes in the QEMUSizedBuffer
> - *
> - * @qsb: A QEMUSizedBuffer
> - *
> - * Returns the number of bytes currently used in this buffer
> - */
> -size_t qsb_get_length(const QEMUSizedBuffer *qsb)
> -{
> -    return qsb->used;
> -}
> -
> -/**
> - * Set the length of the buffer; the primary usage of this
> - * function is to truncate the number of used bytes in the buffer.
> - * The size will not be extended beyond the current number of
> - * allocated bytes in the QEMUSizedBuffer.
> - *
> - * @qsb: A QEMUSizedBuffer
> - * @new_len: The new length of bytes in the buffer
> - *
> - * Returns the number of bytes the buffer was truncated or extended
> - * to.
> - */
> -size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
> -{
> -    if (new_len <= qsb->size) {
> -        qsb->used = new_len;
> -    } else {
> -        qsb->used = qsb->size;
> -    }
> -    return qsb->used;
> -}
> -
> -/**
> - * Get the iovec that holds the data for a given position @pos.
> - *
> - * @qsb: A QEMUSizedBuffer
> - * @pos: The index of a byte in the buffer
> - * @d_off: Pointer to an offset that this function will indicate
> - *         at what position within the returned iovec the byte
> - *         is to be found
> - *
> - * Returns the index of the iovec that holds the byte at the given
> - * index @pos in the byte stream; a negative number if the iovec
> - * for the given position @pos does not exist.
> - */
> -static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
> -                             off_t pos, off_t *d_off)
> -{
> -    ssize_t i;
> -    off_t curr = 0;
> -
> -    if (pos > qsb->used) {
> -        return -1;
> -    }
> -
> -    for (i = 0; i < qsb->n_iov; i++) {
> -        if (curr + qsb->iov[i].iov_len > pos) {
> -            *d_off = pos - curr;
> -            return i;
> -        }
> -        curr += qsb->iov[i].iov_len;
> -    }
> -    return -1;
> -}
> -
> -/*
> - * Convert the QEMUSizedBuffer into a flat buffer.
> - *
> - * Note: If at all possible, try to avoid this function since it
> - *       may unnecessarily copy memory around.
> - *
> - * @qsb: pointer to QEMUSizedBuffer
> - * @start: offset to start at
> - * @count: number of bytes to copy
> - * @buf: a pointer to a buffer to write into (at least @count bytes)
> - *
> - * Returns the number of bytes copied into the output buffer
> - */
> -ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
> -                       size_t count, uint8_t *buffer)
> -{
> -    const struct iovec *iov;
> -    size_t to_copy, all_copy;
> -    ssize_t index;
> -    off_t s_off;
> -    off_t d_off = 0;
> -    char *s;
> -
> -    if (start > qsb->used) {
> -        return 0;
> -    }
> -
> -    all_copy = qsb->used - start;
> -    if (all_copy > count) {
> -        all_copy = count;
> -    } else {
> -        count = all_copy;
> -    }
> -
> -    index = qsb_get_iovec(qsb, start, &s_off);
> -    if (index < 0) {
> -        return 0;
> -    }
> -
> -    while (all_copy > 0) {
> -        iov = &qsb->iov[index];
> -
> -        s = iov->iov_base;
> -
> -        to_copy = iov->iov_len - s_off;
> -        if (to_copy > all_copy) {
> -            to_copy = all_copy;
> -        }
> -        memcpy(&buffer[d_off], &s[s_off], to_copy);
> -
> -        d_off += to_copy;
> -        all_copy -= to_copy;
> -
> -        s_off = 0;
> -        index++;
> -    }
> -
> -    return count;
> -}
> -
> -/**
> - * Grow the QEMUSizedBuffer to the given size and allocate
> - * memory for it.
> - *
> - * @qsb: A QEMUSizedBuffer
> - * @new_size: The new size of the buffer
> - *
> - * Return:
> - *    a negative error code in case of memory allocation failure
> - * or
> - *    the new size of the buffer. The returned size may be greater or equal
> - *    to @new_size.
> - */
> -static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
> -{
> -    size_t needed_chunks, i;
> -
> -    if (qsb->size < new_size) {
> -        struct iovec *new_iov;
> -        size_t size_diff = new_size - qsb->size;
> -        size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
> -                             ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
> -
> -        needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
> -
> -        new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
> -        if (new_iov == NULL) {
> -            return -ENOMEM;
> -        }
> -
> -        /* Allocate new chunks as needed into new_iov */
> -        for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
> -            new_iov[i].iov_base = g_try_malloc0(chunk_size);
> -            new_iov[i].iov_len = chunk_size;
> -            if (!new_iov[i].iov_base) {
> -                size_t j;
> -
> -                /* Free previously allocated new chunks */
> -                for (j = qsb->n_iov; j < i; j++) {
> -                    g_free(new_iov[j].iov_base);
> -                }
> -                g_free(new_iov);
> -
> -                return -ENOMEM;
> -            }
> -        }
> -
> -        /*
> -         * Now we can't get any allocation errors, copy over to new iov
> -         * and switch.
> -         */
> -        for (i = 0; i < qsb->n_iov; i++) {
> -            new_iov[i] = qsb->iov[i];
> -        }
> -
> -        qsb->n_iov += needed_chunks;
> -        g_free(qsb->iov);
> -        qsb->iov = new_iov;
> -        qsb->size += (needed_chunks * chunk_size);
> -    }
> -
> -    return qsb->size;
> -}
> -
> -/**
> - * Write into the QEMUSizedBuffer at a given position and a given
> - * number of bytes. This function will automatically grow the
> - * QEMUSizedBuffer.
> - *
> - * @qsb: A QEMUSizedBuffer
> - * @source: A byte array to copy data from
> - * @pos: The position within the @qsb to write data to
> - * @size: The number of bytes to copy into the @qsb
> - *
> - * Returns @size or a negative error code in case of memory allocation failure,
> - *           or with an invalid 'pos'
> - */
> -ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
> -                     off_t pos, size_t count)
> -{
> -    ssize_t rc = qsb_grow(qsb, pos + count);
> -    size_t to_copy;
> -    size_t all_copy = count;
> -    const struct iovec *iov;
> -    ssize_t index;
> -    char *dest;
> -    off_t d_off, s_off = 0;
> -
> -    if (rc < 0) {
> -        return rc;
> -    }
> -
> -    if (pos + count > qsb->used) {
> -        qsb->used = pos + count;
> -    }
> -
> -    index = qsb_get_iovec(qsb, pos, &d_off);
> -    if (index < 0) {
> -        return -EINVAL;
> -    }
> -
> -    while (all_copy > 0) {
> -        iov = &qsb->iov[index];
> -
> -        dest = iov->iov_base;
> -
> -        to_copy = iov->iov_len - d_off;
> -        if (to_copy > all_copy) {
> -            to_copy = all_copy;
> -        }
> -
> -        memcpy(&dest[d_off], &source[s_off], to_copy);
> -
> -        s_off += to_copy;
> -        all_copy -= to_copy;
> -
> -        d_off = 0;
> -        index++;
> -    }
> -
> -    return count;
> -}
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation Daniel P. Berrange
@ 2016-02-03  9:56   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03  9:56 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Now that the tcp, unix and fd migration backends have converted
> to use the QIOChannel based QEMUFile, there is no user remaining
> for the sockets based QEMUFile impl and it can be deleted.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |   2 -
>  migration/Makefile.objs       |   2 +-
>  migration/qemu-file-unix.c    | 324 ------------------------------------------
>  3 files changed, 1 insertion(+), 327 deletions(-)
>  delete mode 100644 migration/qemu-file-unix.c
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index da67931..dc4b7ab 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -129,8 +129,6 @@ typedef struct QEMUFileHooks {
>  
>  QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
>  QEMUFile *qemu_fopen(const char *filename, const char *mode);
> -QEMUFile *qemu_fdopen(int fd, const char *mode);
> -QEMUFile *qemu_fopen_socket(int fd, const char *mode);
>  QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
>  QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
>  QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 8ecb941..2c71056 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,6 +1,6 @@
>  common-obj-y += migration.o tcp.o unix.o fd.o exec.o
>  common-obj-y += vmstate.o
> -common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
> +common-obj-y += qemu-file.o qemu-file-stdio.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
> diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c
> deleted file mode 100644
> index 6ca53e7..0000000
> --- a/migration/qemu-file-unix.c
> +++ /dev/null
> @@ -1,324 +0,0 @@
> -/*
> - * QEMU System Emulator
> - *
> - * Copyright (c) 2003-2008 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a copy
> - * of this software and associated documentation files (the "Software"), to deal
> - * in the Software without restriction, including without limitation the rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -#include "qemu-common.h"
> -#include "qemu/error-report.h"
> -#include "qemu/iov.h"
> -#include "qemu/sockets.h"
> -#include "qemu/coroutine.h"
> -#include "migration/qemu-file.h"
> -#include "migration/qemu-file-internal.h"
> -
> -typedef struct QEMUFileSocket {
> -    int fd;
> -    QEMUFile *file;
> -} QEMUFileSocket;
> -
> -static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> -                                    int64_t pos)
> -{
> -    QEMUFileSocket *s = opaque;
> -    ssize_t len;
> -    ssize_t size = iov_size(iov, iovcnt);
> -    ssize_t offset = 0;
> -    int     err;
> -
> -    while (size > 0) {
> -        len = iov_send(s->fd, iov, iovcnt, offset, size);
> -
> -        if (len > 0) {
> -            size -= len;
> -            offset += len;
> -        }
> -
> -        if (size > 0) {
> -            err = socket_error();
> -
> -            if (err != EAGAIN && err != EWOULDBLOCK) {
> -                error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
> -                             err, (size_t)size, (size_t)len);
> -                /*
> -                 * If I've already sent some but only just got the error, I
> -                 * could return the amount validly sent so far and wait for the
> -                 * next call to report the error, but I'd rather flag the error
> -                 * immediately.
> -                 */
> -                return -err;
> -            }
> -
> -            /* Emulate blocking */
> -            GPollFD pfd;
> -
> -            pfd.fd = s->fd;
> -            pfd.events = G_IO_OUT | G_IO_ERR;
> -            pfd.revents = 0;
> -            TFR(err = g_poll(&pfd, 1, -1 /* no timeout */));
> -            /* Errors other than EINTR intentionally ignored */
> -        }
> -     }
> -
> -    return offset;
> -}
> -
> -static int socket_get_fd(void *opaque)
> -{
> -    QEMUFileSocket *s = opaque;
> -
> -    return s->fd;
> -}
> -
> -static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> -                                 size_t size)
> -{
> -    QEMUFileSocket *s = opaque;
> -    ssize_t len;
> -
> -    for (;;) {
> -        len = qemu_recv(s->fd, buf, size, 0);
> -        if (len != -1) {
> -            break;
> -        }
> -        if (socket_error() == EAGAIN) {
> -            yield_until_fd_readable(s->fd);
> -        } else if (socket_error() != EINTR) {
> -            break;
> -        }
> -    }
> -
> -    if (len == -1) {
> -        len = -socket_error();
> -    }
> -    return len;
> -}
> -
> -static int socket_close(void *opaque)
> -{
> -    QEMUFileSocket *s = opaque;
> -    closesocket(s->fd);
> -    g_free(s);
> -    return 0;
> -}
> -
> -static int socket_shutdown(void *opaque, bool rd, bool wr)
> -{
> -    QEMUFileSocket *s = opaque;
> -
> -    if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
> -        return -errno;
> -    } else {
> -        return 0;
> -    }
> -}
> -
> -static int socket_return_close(void *opaque)
> -{
> -    QEMUFileSocket *s = opaque;
> -    /*
> -     * Note: We don't close the socket, that should be done by the forward
> -     * path.
> -     */
> -    g_free(s);
> -    return 0;
> -}
> -
> -static const QEMUFileOps socket_return_read_ops = {
> -    .get_fd          = socket_get_fd,
> -    .get_buffer      = socket_get_buffer,
> -    .close           = socket_return_close,
> -    .shut_down       = socket_shutdown,
> -};
> -
> -static const QEMUFileOps socket_return_write_ops = {
> -    .get_fd          = socket_get_fd,
> -    .writev_buffer   = socket_writev_buffer,
> -    .close           = socket_return_close,
> -    .shut_down       = socket_shutdown,
> -};
> -
> -/*
> - * Give a QEMUFile* off the same socket but data in the opposite
> - * direction.
> - */
> -static QEMUFile *socket_get_return_path(void *opaque)
> -{
> -    QEMUFileSocket *forward = opaque;
> -    QEMUFileSocket *reverse;
> -
> -    if (qemu_file_get_error(forward->file)) {
> -        /* If the forward file is in error, don't try and open a return */
> -        return NULL;
> -    }
> -
> -    reverse = g_malloc0(sizeof(QEMUFileSocket));
> -    reverse->fd = forward->fd;
> -    /* I don't think there's a better way to tell which direction 'this' is */
> -    if (forward->file->ops->get_buffer != NULL) {
> -        /* being called from the read side, so we need to be able to write */
> -        return qemu_fopen_ops(reverse, &socket_return_write_ops);
> -    } else {
> -        return qemu_fopen_ops(reverse, &socket_return_read_ops);
> -    }
> -}
> -
> -static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
> -                                  int64_t pos)
> -{
> -    QEMUFileSocket *s = opaque;
> -    ssize_t len, offset;
> -    ssize_t size = iov_size(iov, iovcnt);
> -    ssize_t total = 0;
> -
> -    assert(iovcnt > 0);
> -    offset = 0;
> -    while (size > 0) {
> -        /* Find the next start position; skip all full-sized vector elements  */
> -        while (offset >= iov[0].iov_len) {
> -            offset -= iov[0].iov_len;
> -            iov++, iovcnt--;
> -        }
> -
> -        /* skip `offset' bytes from the (now) first element, undo it on exit */
> -        assert(iovcnt > 0);
> -        iov[0].iov_base += offset;
> -        iov[0].iov_len -= offset;
> -
> -        do {
> -            len = writev(s->fd, iov, iovcnt);
> -        } while (len == -1 && errno == EINTR);
> -        if (len == -1) {
> -            return -errno;
> -        }
> -
> -        /* Undo the changes above */
> -        iov[0].iov_base -= offset;
> -        iov[0].iov_len += offset;
> -
> -        /* Prepare for the next iteration */
> -        offset += len;
> -        total += len;
> -        size -= len;
> -    }
> -
> -    return total;
> -}
> -
> -static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> -                              size_t size)
> -{
> -    QEMUFileSocket *s = opaque;
> -    ssize_t len;
> -
> -    for (;;) {
> -        len = read(s->fd, buf, size);
> -        if (len != -1) {
> -            break;
> -        }
> -        if (errno == EAGAIN) {
> -            yield_until_fd_readable(s->fd);
> -        } else if (errno != EINTR) {
> -            break;
> -        }
> -    }
> -
> -    if (len == -1) {
> -        len = -errno;
> -    }
> -    return len;
> -}
> -
> -static int unix_close(void *opaque)
> -{
> -    QEMUFileSocket *s = opaque;
> -    close(s->fd);
> -    g_free(s);
> -    return 0;
> -}
> -
> -static const QEMUFileOps unix_read_ops = {
> -    .get_fd =     socket_get_fd,
> -    .get_buffer = unix_get_buffer,
> -    .close =      unix_close
> -};
> -
> -static const QEMUFileOps unix_write_ops = {
> -    .get_fd =     socket_get_fd,
> -    .writev_buffer = unix_writev_buffer,
> -    .close =      unix_close
> -};
> -
> -QEMUFile *qemu_fdopen(int fd, const char *mode)
> -{
> -    QEMUFileSocket *s;
> -
> -    if (mode == NULL ||
> -        (mode[0] != 'r' && mode[0] != 'w') ||
> -        mode[1] != 'b' || mode[2] != 0) {
> -        fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
> -        return NULL;
> -    }
> -
> -    s = g_new0(QEMUFileSocket, 1);
> -    s->fd = fd;
> -
> -    if (mode[0] == 'r') {
> -        s->file = qemu_fopen_ops(s, &unix_read_ops);
> -    } else {
> -        s->file = qemu_fopen_ops(s, &unix_write_ops);
> -    }
> -    return s->file;
> -}
> -
> -static const QEMUFileOps socket_read_ops = {
> -    .get_fd          = socket_get_fd,
> -    .get_buffer      = socket_get_buffer,
> -    .close           = socket_close,
> -    .shut_down       = socket_shutdown,
> -    .get_return_path = socket_get_return_path
> -};
> -
> -static const QEMUFileOps socket_write_ops = {
> -    .get_fd          = socket_get_fd,
> -    .writev_buffer   = socket_writev_buffer,
> -    .close           = socket_close,
> -    .shut_down       = socket_shutdown,
> -    .get_return_path = socket_get_return_path
> -};
> -
> -QEMUFile *qemu_fopen_socket(int fd, const char *mode)
> -{
> -    QEMUFileSocket *s;
> -
> -    if (qemu_file_mode_is_not_valid(mode)) {
> -        return NULL;
> -    }
> -
> -    s = g_new0(QEMUFileSocket, 1);
> -    s->fd = fd;
> -    if (mode[0] == 'w') {
> -        qemu_set_block(s->fd);
> -        s->file = qemu_fopen_ops(s, &socket_write_ops);
> -    } else {
> -        s->file = qemu_fopen_ops(s, &socket_read_ops);
> -    }
> -    return s->file;
> -}
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation Daniel P. Berrange
@ 2016-02-03  9:58   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03  9:58 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Now that the exec migration backend and savevm have converted
> to use the QIOChannel based QEMUFile, there is no user remaining
> for the stdio based QEMUFile impl and it can be deleted.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |   2 -
>  migration/Makefile.objs       |   2 +-
>  migration/qemu-file-stdio.c   | 195 ------------------------------------------
>  3 files changed, 1 insertion(+), 198 deletions(-)
>  delete mode 100644 migration/qemu-file-stdio.c
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index dc4b7ab..6a66735 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -128,10 +128,8 @@ typedef struct QEMUFileHooks {
>  } QEMUFileHooks;
>  
>  QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
> -QEMUFile *qemu_fopen(const char *filename, const char *mode);
>  QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
>  QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
> -QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
>  void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
>  int qemu_get_fd(QEMUFile *f);
>  int qemu_fclose(QEMUFile *f);
> diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> index 2c71056..a127f31 100644
> --- a/migration/Makefile.objs
> +++ b/migration/Makefile.objs
> @@ -1,6 +1,6 @@
>  common-obj-y += migration.o tcp.o unix.o fd.o exec.o
>  common-obj-y += vmstate.o
> -common-obj-y += qemu-file.o qemu-file-stdio.o
> +common-obj-y += qemu-file.o
>  common-obj-y += qemu-file-channel.o
>  common-obj-y += xbzrle.o postcopy-ram.o
>  
> diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c
> deleted file mode 100644
> index 9bde9db..0000000
> --- a/migration/qemu-file-stdio.c
> +++ /dev/null
> @@ -1,195 +0,0 @@
> -/*
> - * QEMU System Emulator
> - *
> - * Copyright (c) 2003-2008 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a copy
> - * of this software and associated documentation files (the "Software"), to deal
> - * in the Software without restriction, including without limitation the rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -#include "qemu-common.h"
> -#include "qemu/coroutine.h"
> -#include "migration/qemu-file.h"
> -
> -typedef struct QEMUFileStdio {
> -    FILE *stdio_file;
> -    QEMUFile *file;
> -} QEMUFileStdio;
> -
> -static int stdio_get_fd(void *opaque)
> -{
> -    QEMUFileStdio *s = opaque;
> -
> -    return fileno(s->stdio_file);
> -}
> -
> -static ssize_t stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
> -                                size_t size)
> -{
> -    QEMUFileStdio *s = opaque;
> -    size_t res;
> -
> -    res = fwrite(buf, 1, size, s->stdio_file);
> -
> -    if (res != size) {
> -        return -errno;
> -    }
> -    return res;
> -}
> -
> -static ssize_t stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
> -                                size_t size)
> -{
> -    QEMUFileStdio *s = opaque;
> -    FILE *fp = s->stdio_file;
> -    ssize_t bytes;
> -
> -    for (;;) {
> -        clearerr(fp);
> -        bytes = fread(buf, 1, size, fp);
> -        if (bytes != 0 || !ferror(fp)) {
> -            break;
> -        }
> -        if (errno == EAGAIN) {
> -            yield_until_fd_readable(fileno(fp));
> -        } else if (errno != EINTR) {
> -            break;
> -        }
> -    }
> -    return bytes;
> -}
> -
> -static int stdio_pclose(void *opaque)
> -{
> -    QEMUFileStdio *s = opaque;
> -    int ret;
> -    ret = pclose(s->stdio_file);
> -    if (ret == -1) {
> -        ret = -errno;
> -    } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
> -        /* close succeeded, but non-zero exit code: */
> -        ret = -EIO; /* fake errno value */
> -    }
> -    g_free(s);
> -    return ret;
> -}
> -
> -static int stdio_fclose(void *opaque)
> -{
> -    QEMUFileStdio *s = opaque;
> -    int ret = 0;
> -
> -    if (qemu_file_is_writable(s->file)) {
> -        int fd = fileno(s->stdio_file);
> -        struct stat st;
> -
> -        ret = fstat(fd, &st);
> -        if (ret == 0 && S_ISREG(st.st_mode)) {
> -            /*
> -             * If the file handle is a regular file make sure the
> -             * data is flushed to disk before signaling success.
> -             */
> -            ret = fsync(fd);
> -            if (ret != 0) {
> -                ret = -errno;
> -                return ret;
> -            }
> -        }
> -    }
> -    if (fclose(s->stdio_file) == EOF) {
> -        ret = -errno;
> -    }
> -    g_free(s);
> -    return ret;
> -}
> -
> -static const QEMUFileOps stdio_pipe_read_ops = {
> -    .get_fd =     stdio_get_fd,
> -    .get_buffer = stdio_get_buffer,
> -    .close =      stdio_pclose
> -};
> -
> -static const QEMUFileOps stdio_pipe_write_ops = {
> -    .get_fd =     stdio_get_fd,
> -    .put_buffer = stdio_put_buffer,
> -    .close =      stdio_pclose
> -};
> -
> -QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
> -{
> -    FILE *stdio_file;
> -    QEMUFileStdio *s;
> -
> -    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
> -        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
> -        return NULL;
> -    }
> -
> -    stdio_file = popen(command, mode);
> -    if (stdio_file == NULL) {
> -        return NULL;
> -    }
> -
> -    s = g_new0(QEMUFileStdio, 1);
> -
> -    s->stdio_file = stdio_file;
> -
> -    if (mode[0] == 'r') {
> -        s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
> -    } else {
> -        s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
> -    }
> -    return s->file;
> -}
> -
> -static const QEMUFileOps stdio_file_read_ops = {
> -    .get_fd =     stdio_get_fd,
> -    .get_buffer = stdio_get_buffer,
> -    .close =      stdio_fclose
> -};
> -
> -static const QEMUFileOps stdio_file_write_ops = {
> -    .get_fd =     stdio_get_fd,
> -    .put_buffer = stdio_put_buffer,
> -    .close =      stdio_fclose
> -};
> -
> -QEMUFile *qemu_fopen(const char *filename, const char *mode)
> -{
> -    QEMUFileStdio *s;
> -
> -    if (qemu_file_mode_is_not_valid(mode)) {
> -        return NULL;
> -    }
> -
> -    s = g_new0(QEMUFileStdio, 1);
> -
> -    s->stdio_file = fopen(filename, mode);
> -    if (!s->stdio_file) {
> -        goto fail;
> -    }
> -
> -    if (mode[0] == 'w') {
> -        s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
> -    } else {
> -        s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
> -    }
> -    return s->file;
> -fail:
> -    g_free(s);
> -    return NULL;
> -}
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 10/22] migration: convert tcp socket protocol to use QIOChannel
  2016-02-02 18:19   ` Dr. David Alan Gilbert
@ 2016-02-03 10:02     ` Daniel P. Berrange
  2016-02-03 10:33       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 10:02 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Tue, Feb 02, 2016 at 06:19:03PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > Convert the tcp socket migration protocol driver to use
> > QIOChannel and QEMUFileChannel, instead of plain sockets
> > APIs.
> > 
> > While this now looks pretty similar to the migration/unix.c
> > file from the previous patch, it was decided not to merge
> > the two, because when TLS is added to the TCP impl later,
> > this file diverge from unix.c once again.
> 
> Hmm OK, although I'd kind of like to see merging, but lets
> see the TLS code later in the series....
> 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  migration/tcp.c | 119 ++++++++++++++++++++++++++++++++++++++------------------
> >  1 file changed, 82 insertions(+), 37 deletions(-)
> > 
> > diff --git a/migration/tcp.c b/migration/tcp.c
> > index ae89172..ac73977 100644
> > --- a/migration/tcp.c
> > +++ b/migration/tcp.c
> > @@ -2,9 +2,11 @@
> >   * QEMU live migration
> >   *
> >   * Copyright IBM, Corp. 2008
> > + * Copyright Red Hat, Inc. 2015
> >   *
> >   * Authors:
> >   *  Anthony Liguori   <aliguori@us.ibm.com>
> > + *  Daniel P. Berrange <berrange@redhat.com>
> >   *
> >   * This work is licensed under the terms of the GNU GPL, version 2.  See
> >   * the COPYING file in the top-level directory.
> > @@ -17,11 +19,9 @@
> >  
> >  #include "qemu-common.h"
> >  #include "qemu/error-report.h"
> > -#include "qemu/sockets.h"
> >  #include "migration/migration.h"
> >  #include "migration/qemu-file.h"
> > -#include "block/block.h"
> > -#include "qemu/main-loop.h"
> > +#include "io/channel-socket.h"
> >  
> >  //#define DEBUG_MIGRATION_TCP
> >  
> > @@ -33,71 +33,116 @@
> >      do { } while (0)
> >  #endif
> >  
> > -static void tcp_wait_for_connect(int fd, Error *err, void *opaque)
> > +
> > +static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
> > +{
> > +    InetSocketAddress *iaddr = inet_parse(host_port, errp);
> > +    SocketAddress *saddr;
> > +
> > +    if (!iaddr) {
> > +        return NULL;
> > +    }
> > +
> > +    saddr = g_new0(SocketAddress, 1);
> > +    saddr->type = SOCKET_ADDRESS_KIND_INET;
> > +    saddr->u.inet = iaddr;
> > +
> > +    return saddr;
> > +}
> > +
> > +
> > +static void tcp_outgoing_migration(Object *src,
> > +                                   Error *err,
> > +                                   gpointer opaque)
> >  {
> >      MigrationState *s = opaque;
> > +    QIOChannel *sioc = QIO_CHANNEL(src);
> >  
> > -    if (fd < 0) {
> > +    if (err) {
> >          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
> >          s->file = NULL;
> >          migrate_fd_error(s);
> >      } else {
> >          DPRINTF("migrate connect success\n");
> > -        s->file = qemu_fopen_socket(fd, "wb");
> > +        s->file = qemu_fopen_channel_output(sioc);
> >          migrate_fd_connect(s);
> >      }
> > +    object_unref(src);
> >  }
> >  
> > -void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
> > +
> > +void tcp_start_outgoing_migration(MigrationState *s,
> > +                                  const char *host_port,
> > +                                  Error **errp)
> >  {
> > -    inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
> > +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> > +    QIOChannelSocket *sioc;
> > +
> > +    if (!saddr) {
> > +        return;
> > +    }
> > +
> > +    sioc = qio_channel_socket_new();
> > +    qio_channel_socket_connect_async(sioc,
> > +                                     saddr,
> > +                                     tcp_outgoing_migration,
> > +                                     s,
> > +                                     NULL);
> > +    qapi_free_SocketAddress(saddr);
> >  }
> >  
> > -static void tcp_accept_incoming_migration(void *opaque)
> > +
> > +static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
> > +                                              GIOCondition condition,
> > +                                              gpointer opaque)
> >  {
> > -    struct sockaddr_in addr;
> > -    socklen_t addrlen = sizeof(addr);
> > -    int s = (intptr_t)opaque;
> >      QEMUFile *f;
> > -    int c, err;
> > +    QIOChannelSocket *cioc;
> > +    Error *err = NULL;
> >  
> > -    do {
> > -        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
> > -        err = socket_error();
> > -    } while (c < 0 && err == EINTR);
> > -    qemu_set_fd_handler(s, NULL, NULL, NULL);
> > -    closesocket(s);
> > -
> > -    DPRINTF("accepted migration\n");
> > -
> > -    if (c < 0) {
> > +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> > +                                     &err);
> > +    if (!cioc) {
> >          error_report("could not accept migration connection (%s)",
> > -                     strerror(err));
> > -        return;
> > -    }
> > -
> > -    f = qemu_fopen_socket(c, "rb");
> > -    if (f == NULL) {
> > -        error_report("could not qemu_fopen socket");
> > +                     error_get_pretty(err));
> >          goto out;
> >      }
> >  
> > +    DPRINTF("accepted migration\n");
> > +
> > +    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> > +    object_unref(OBJECT(cioc));
> > +
> >      process_incoming_migration(f);
> > -    return;
> >  
> >  out:
> > -    closesocket(c);
> > +    /* Close listening socket as its no longer needed */
> > +    qio_channel_close(ioc, NULL);
> > +    return FALSE;
> >  }
> >  
> > +
> >  void tcp_start_incoming_migration(const char *host_port, Error **errp)
> >  {
> > -    int s;
> > +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> > +    QIOChannelSocket *listen_ioc;
> >  
> > -    s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
> > -    if (s < 0) {
> > +    if (!saddr) {
> >          return;
> >      }
> >  
> > -    qemu_set_fd_handler(s, tcp_accept_incoming_migration, NULL,
> > -                        (void *)(intptr_t)s);
> > +    listen_ioc = qio_channel_socket_new();
> > +    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
> 
> In this case, although weird, that could block couldn't it?
> The case I'm thinking of is using the migrate_incoming command with a hostname
> (I've used it with hostnames before as aliases for networks to listen on,
> admittedly it be rare for it to be DNS that would block).

Yes it certainly could block and this is undesirable in general. The problem
is that the only way we can provide errors back for the monitor reponse is
if we do this synchronously from this method.  If I ran async then we'd have
no ability to report errors about non-existant host names, already in use tcp
port, etc.

I'm not really sure what todo about this long term, but the only way would
be if the monitor response was able to be sent back asychronously from
this method call. Then we can start an async listen call, and respond to
the monitor when done.

Since the current code being replaced is also blocking, I felt solving
that problem is best left to a future patch series. At least with this
explicit method naming with _sync() suffix we can easily identify the
problems in future

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 11/22] migration: convert fd socket protocol to use QIOChannel
  2016-02-02 18:46   ` Dr. David Alan Gilbert
@ 2016-02-03 10:05     ` Daniel P. Berrange
  2016-02-03 10:29       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 10:05 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Tue, Feb 02, 2016 at 06:46:01PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > Convert the fd socket migration protocol driver to use
> > QIOChannel and QEMUFileChannel, instead of plain sockets
> > APIs. It can be unconditionally built because the
> > QIOChannel APIs it uses will take care to report suitable
> > error messages if needed.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  migration/Makefile.objs |  4 ++--
> >  migration/fd.c          | 57 ++++++++++++++++++++++++++++++++-----------------
> >  migration/migration.c   |  4 ----
> >  3 files changed, 39 insertions(+), 26 deletions(-)
> > 
> > diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> > index a5f8a03..64f95cd 100644
> > --- a/migration/Makefile.objs
> > +++ b/migration/Makefile.objs
> > @@ -1,11 +1,11 @@
> > -common-obj-y += migration.o tcp.o unix.o
> > +common-obj-y += migration.o tcp.o unix.o fd.o
> >  common-obj-y += vmstate.o
> >  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
> >  common-obj-y += qemu-file-channel.o
> >  common-obj-y += xbzrle.o postcopy-ram.o
> >  
> >  common-obj-$(CONFIG_RDMA) += rdma.o
> > -common-obj-$(CONFIG_POSIX) += exec.o fd.o
> > +common-obj-$(CONFIG_POSIX) += exec.o
> >  
> >  common-obj-y += block.o
> >  
> > diff --git a/migration/fd.c b/migration/fd.c
> > index 3e4bed0..8d48e0d 100644
> > --- a/migration/fd.c
> > +++ b/migration/fd.c
> > @@ -20,6 +20,8 @@
> >  #include "monitor/monitor.h"
> >  #include "migration/qemu-file.h"
> >  #include "block/block.h"
> > +#include "io/channel-file.h"
> > +#include "io/channel-socket.h"
> >  
> >  //#define DEBUG_MIGRATION_FD
> >  
> > @@ -33,56 +35,71 @@
> >  
> >  static bool fd_is_socket(int fd)
> >  {
> > -    struct stat stat;
> > -    int ret = fstat(fd, &stat);
> > -    if (ret == -1) {
> > -        /* When in doubt say no */
> > -        return false;
> > -    }
> > -    return S_ISSOCK(stat.st_mode);
> > +    int optval;
> > +    socklen_t optlen;
> > +    optlen = sizeof(optval);
> > +    return getsockopt(fd,
> > +                      SOL_SOCKET,
> > +                      SO_TYPE,
> > +                      (char *)&optval,
> > +                      &optlen) == 0;
> 
> Should that be qemu_getsockopt ?

Yes.

> >  void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
> >  {
> > +    QIOChannel *ioc;
> >      int fd = monitor_get_fd(cur_mon, fdname, errp);
> >      if (fd == -1) {
> >          return;
> >      }
> >  
> >      if (fd_is_socket(fd)) {
> > -        s->file = qemu_fopen_socket(fd, "wb");
> > +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> > +        if (!ioc) {
> > +            close(fd);
> > +            return;
> > +        }
> 
> Have you considered moving this fd_is_socket detection
> glue down into channel-file.c?  It's here so that a socket
> passed via an fd will be able to use a shutdown() method.
> It would be nice to do the same thing to sockets in the same
> situation in other places, so it would make sense if it worked
> on any fd that went through channels.
> The tricky bit is at that level you return a QIOChannelFile rather
> than a generic QIOChannel pointer.
> (One place I'd like to be able to a shutdown is on an nbd channel
> for example).

Yeah, the complexity is that we have to return two different
class instances depending on the type of FD in use. We could
introduce some helper method todo this though.


> > -static void fd_accept_incoming_migration(void *opaque)
> > +static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
> > +                                             GIOCondition condition,
> > +                                             gpointer opaque)
> >  {
> >      QEMUFile *f = opaque;
> > -
> > -    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
> >      process_incoming_migration(f);
> > +    return FALSE;
> 
> Please comment the magical FALSE.

FALSE is the standard value any glib event loop handled need to
return to cause glib to unregister it. I'm not sure we really
want to comment every event handle in this way.

> >  void fd_start_incoming_migration(const char *infd, Error **errp)
> >  {
> > -    int fd;
> >      QEMUFile *f;
> > +    QIOChannel *ioc;
> > +    int fd;
> >  
> >      DPRINTF("Attempting to start an incoming migration via fd\n");
> >  
> >      fd = strtol(infd, NULL, 0);
> >      if (fd_is_socket(fd)) {
> > -        f = qemu_fopen_socket(fd, "rb");
> > +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> > +        if (!ioc) {
> > +            close(fd);
> > +            return;
> > +        }
> 
> Wouldn't it be better to move this check outside of this if, so that
> you test the output of both the socket_new_fd and the file_new_fd ?

qio_channel_file_new_fd() can never fail - only the socket_new_fd can
fail (when trying to query the sockaddr_t data).

> >      } else {
> > -        f = qemu_fdopen(fd, "rb");
> > -    }
> > -    if(f == NULL) {
> > -        error_setg_errno(errp, errno, "failed to open the source descriptor");
> > -        return;
> > +        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
> >      }
> > +    f = qemu_fopen_channel_input(ioc);
> > +    object_unref(OBJECT(ioc));
> >  
> > -    qemu_set_fd_handler(fd, fd_accept_incoming_migration, NULL, f);
> > +    qio_channel_add_watch(ioc,
> > +                          G_IO_IN,
> > +                          fd_accept_incoming_migration,
> > +                          f,
> > +                          NULL);
> >  }


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 11/22] migration: convert fd socket protocol to use QIOChannel
  2016-02-03 10:05     ` Daniel P. Berrange
@ 2016-02-03 10:29       ` Dr. David Alan Gilbert
  2016-02-03 10:39         ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03 10:29 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Tue, Feb 02, 2016 at 06:46:01PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > Convert the fd socket migration protocol driver to use
> > > QIOChannel and QEMUFileChannel, instead of plain sockets
> > > APIs. It can be unconditionally built because the
> > > QIOChannel APIs it uses will take care to report suitable
> > > error messages if needed.
> > > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  migration/Makefile.objs |  4 ++--
> > >  migration/fd.c          | 57 ++++++++++++++++++++++++++++++++-----------------
> > >  migration/migration.c   |  4 ----
> > >  3 files changed, 39 insertions(+), 26 deletions(-)
> > > 
> > > diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> > > index a5f8a03..64f95cd 100644
> > > --- a/migration/Makefile.objs
> > > +++ b/migration/Makefile.objs
> > > @@ -1,11 +1,11 @@
> > > -common-obj-y += migration.o tcp.o unix.o
> > > +common-obj-y += migration.o tcp.o unix.o fd.o
> > >  common-obj-y += vmstate.o
> > >  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
> > >  common-obj-y += qemu-file-channel.o
> > >  common-obj-y += xbzrle.o postcopy-ram.o
> > >  
> > >  common-obj-$(CONFIG_RDMA) += rdma.o
> > > -common-obj-$(CONFIG_POSIX) += exec.o fd.o
> > > +common-obj-$(CONFIG_POSIX) += exec.o
> > >  
> > >  common-obj-y += block.o
> > >  
> > > diff --git a/migration/fd.c b/migration/fd.c
> > > index 3e4bed0..8d48e0d 100644
> > > --- a/migration/fd.c
> > > +++ b/migration/fd.c
> > > @@ -20,6 +20,8 @@
> > >  #include "monitor/monitor.h"
> > >  #include "migration/qemu-file.h"
> > >  #include "block/block.h"
> > > +#include "io/channel-file.h"
> > > +#include "io/channel-socket.h"
> > >  
> > >  //#define DEBUG_MIGRATION_FD
> > >  
> > > @@ -33,56 +35,71 @@
> > >  
> > >  static bool fd_is_socket(int fd)
> > >  {
> > > -    struct stat stat;
> > > -    int ret = fstat(fd, &stat);
> > > -    if (ret == -1) {
> > > -        /* When in doubt say no */
> > > -        return false;
> > > -    }
> > > -    return S_ISSOCK(stat.st_mode);
> > > +    int optval;
> > > +    socklen_t optlen;
> > > +    optlen = sizeof(optval);
> > > +    return getsockopt(fd,
> > > +                      SOL_SOCKET,
> > > +                      SO_TYPE,
> > > +                      (char *)&optval,
> > > +                      &optlen) == 0;
> > 
> > Should that be qemu_getsockopt ?
> 
> Yes.
> 
> > >  void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
> > >  {
> > > +    QIOChannel *ioc;
> > >      int fd = monitor_get_fd(cur_mon, fdname, errp);
> > >      if (fd == -1) {
> > >          return;
> > >      }
> > >  
> > >      if (fd_is_socket(fd)) {
> > > -        s->file = qemu_fopen_socket(fd, "wb");
> > > +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> > > +        if (!ioc) {
> > > +            close(fd);
> > > +            return;
> > > +        }
> > 
> > Have you considered moving this fd_is_socket detection
> > glue down into channel-file.c?  It's here so that a socket
> > passed via an fd will be able to use a shutdown() method.
> > It would be nice to do the same thing to sockets in the same
> > situation in other places, so it would make sense if it worked
> > on any fd that went through channels.
> > The tricky bit is at that level you return a QIOChannelFile rather
> > than a generic QIOChannel pointer.
> > (One place I'd like to be able to a shutdown is on an nbd channel
> > for example).
> 
> Yeah, the complexity is that we have to return two different
> class instances depending on the type of FD in use. We could
> introduce some helper method todo this though.

Is there any reason they return the subclasses rather than the
common parent?

> > > -static void fd_accept_incoming_migration(void *opaque)
> > > +static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
> > > +                                             GIOCondition condition,
> > > +                                             gpointer opaque)
> > >  {
> > >      QEMUFile *f = opaque;
> > > -
> > > -    qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL);
> > >      process_incoming_migration(f);
> > > +    return FALSE;
> > 
> > Please comment the magical FALSE.
> 
> FALSE is the standard value any glib event loop handled need to
> return to cause glib to unregister it. I'm not sure we really
> want to comment every event handle in this way.

I'd prefer we did.  It doesn't need to be big and detailed,
but either a function comment, or something as simple as:
    return FALSE; /* unregister */

it's not something I immediately recognised, and it took a bit of digging
around for me to find the answer.

> > >  void fd_start_incoming_migration(const char *infd, Error **errp)
> > >  {
> > > -    int fd;
> > >      QEMUFile *f;
> > > +    QIOChannel *ioc;
> > > +    int fd;
> > >  
> > >      DPRINTF("Attempting to start an incoming migration via fd\n");
> > >  
> > >      fd = strtol(infd, NULL, 0);
> > >      if (fd_is_socket(fd)) {
> > > -        f = qemu_fopen_socket(fd, "rb");
> > > +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> > > +        if (!ioc) {
> > > +            close(fd);
> > > +            return;
> > > +        }
> > 
> > Wouldn't it be better to move this check outside of this if, so that
> > you test the output of both the socket_new_fd and the file_new_fd ?
> 
> qio_channel_file_new_fd() can never fail - only the socket_new_fd can
> fail (when trying to query the sockaddr_t data).

OK, I'm not too fussed about this bit, but:
  1) It's easier to read - one level less of nesting
  2) It avoids making an assumption about qio_channel_file_new_fd() never
     failing, which is something you happen to know but you treat as
     API;  it costs nothing to avoid making that assumption.

Dave

> 
> > >      } else {
> > > -        f = qemu_fdopen(fd, "rb");
> > > -    }
> > > -    if(f == NULL) {
> > > -        error_setg_errno(errp, errno, "failed to open the source descriptor");
> > > -        return;
> > > +        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
> > >      }
> > > +    f = qemu_fopen_channel_input(ioc);
> > > +    object_unref(OBJECT(ioc));
> > >  
> > > -    qemu_set_fd_handler(fd, fd_accept_incoming_migration, NULL, f);
> > > +    qio_channel_add_watch(ioc,
> > > +                          G_IO_IN,
> > > +                          fd_accept_incoming_migration,
> > > +                          f,
> > > +                          NULL);
> > >  }
> 
> 
> Regards,
> Daniel
> -- 
> |: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org              -o-             http://virt-manager.org :|
> |: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
> |: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 10/22] migration: convert tcp socket protocol to use QIOChannel
  2016-02-03 10:02     ` Daniel P. Berrange
@ 2016-02-03 10:33       ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03 10:33 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Tue, Feb 02, 2016 at 06:19:03PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > Convert the tcp socket migration protocol driver to use
> > > QIOChannel and QEMUFileChannel, instead of plain sockets
> > > APIs.
> > > 
> > > While this now looks pretty similar to the migration/unix.c
> > > file from the previous patch, it was decided not to merge
> > > the two, because when TLS is added to the TCP impl later,
> > > this file diverge from unix.c once again.
> > 
> > Hmm OK, although I'd kind of like to see merging, but lets
> > see the TLS code later in the series....
> > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  migration/tcp.c | 119 ++++++++++++++++++++++++++++++++++++++------------------
> > >  1 file changed, 82 insertions(+), 37 deletions(-)
> > > 
> > > diff --git a/migration/tcp.c b/migration/tcp.c
> > > index ae89172..ac73977 100644
> > > --- a/migration/tcp.c
> > > +++ b/migration/tcp.c
> > > @@ -2,9 +2,11 @@
> > >   * QEMU live migration
> > >   *
> > >   * Copyright IBM, Corp. 2008
> > > + * Copyright Red Hat, Inc. 2015
> > >   *
> > >   * Authors:
> > >   *  Anthony Liguori   <aliguori@us.ibm.com>
> > > + *  Daniel P. Berrange <berrange@redhat.com>
> > >   *
> > >   * This work is licensed under the terms of the GNU GPL, version 2.  See
> > >   * the COPYING file in the top-level directory.
> > > @@ -17,11 +19,9 @@
> > >  
> > >  #include "qemu-common.h"
> > >  #include "qemu/error-report.h"
> > > -#include "qemu/sockets.h"
> > >  #include "migration/migration.h"
> > >  #include "migration/qemu-file.h"
> > > -#include "block/block.h"
> > > -#include "qemu/main-loop.h"
> > > +#include "io/channel-socket.h"
> > >  
> > >  //#define DEBUG_MIGRATION_TCP
> > >  
> > > @@ -33,71 +33,116 @@
> > >      do { } while (0)
> > >  #endif
> > >  
> > > -static void tcp_wait_for_connect(int fd, Error *err, void *opaque)
> > > +
> > > +static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
> > > +{
> > > +    InetSocketAddress *iaddr = inet_parse(host_port, errp);
> > > +    SocketAddress *saddr;
> > > +
> > > +    if (!iaddr) {
> > > +        return NULL;
> > > +    }
> > > +
> > > +    saddr = g_new0(SocketAddress, 1);
> > > +    saddr->type = SOCKET_ADDRESS_KIND_INET;
> > > +    saddr->u.inet = iaddr;
> > > +
> > > +    return saddr;
> > > +}
> > > +
> > > +
> > > +static void tcp_outgoing_migration(Object *src,
> > > +                                   Error *err,
> > > +                                   gpointer opaque)
> > >  {
> > >      MigrationState *s = opaque;
> > > +    QIOChannel *sioc = QIO_CHANNEL(src);
> > >  
> > > -    if (fd < 0) {
> > > +    if (err) {
> > >          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
> > >          s->file = NULL;
> > >          migrate_fd_error(s);
> > >      } else {
> > >          DPRINTF("migrate connect success\n");
> > > -        s->file = qemu_fopen_socket(fd, "wb");
> > > +        s->file = qemu_fopen_channel_output(sioc);
> > >          migrate_fd_connect(s);
> > >      }
> > > +    object_unref(src);
> > >  }
> > >  
> > > -void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
> > > +
> > > +void tcp_start_outgoing_migration(MigrationState *s,
> > > +                                  const char *host_port,
> > > +                                  Error **errp)
> > >  {
> > > -    inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
> > > +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> > > +    QIOChannelSocket *sioc;
> > > +
> > > +    if (!saddr) {
> > > +        return;
> > > +    }
> > > +
> > > +    sioc = qio_channel_socket_new();
> > > +    qio_channel_socket_connect_async(sioc,
> > > +                                     saddr,
> > > +                                     tcp_outgoing_migration,
> > > +                                     s,
> > > +                                     NULL);
> > > +    qapi_free_SocketAddress(saddr);
> > >  }
> > >  
> > > -static void tcp_accept_incoming_migration(void *opaque)
> > > +
> > > +static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
> > > +                                              GIOCondition condition,
> > > +                                              gpointer opaque)
> > >  {
> > > -    struct sockaddr_in addr;
> > > -    socklen_t addrlen = sizeof(addr);
> > > -    int s = (intptr_t)opaque;
> > >      QEMUFile *f;
> > > -    int c, err;
> > > +    QIOChannelSocket *cioc;
> > > +    Error *err = NULL;
> > >  
> > > -    do {
> > > -        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
> > > -        err = socket_error();
> > > -    } while (c < 0 && err == EINTR);
> > > -    qemu_set_fd_handler(s, NULL, NULL, NULL);
> > > -    closesocket(s);
> > > -
> > > -    DPRINTF("accepted migration\n");
> > > -
> > > -    if (c < 0) {
> > > +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> > > +                                     &err);
> > > +    if (!cioc) {
> > >          error_report("could not accept migration connection (%s)",
> > > -                     strerror(err));
> > > -        return;
> > > -    }
> > > -
> > > -    f = qemu_fopen_socket(c, "rb");
> > > -    if (f == NULL) {
> > > -        error_report("could not qemu_fopen socket");
> > > +                     error_get_pretty(err));
> > >          goto out;
> > >      }
> > >  
> > > +    DPRINTF("accepted migration\n");
> > > +
> > > +    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> > > +    object_unref(OBJECT(cioc));
> > > +
> > >      process_incoming_migration(f);
> > > -    return;
> > >  
> > >  out:
> > > -    closesocket(c);
> > > +    /* Close listening socket as its no longer needed */
> > > +    qio_channel_close(ioc, NULL);
> > > +    return FALSE;
> > >  }
> > >  
> > > +
> > >  void tcp_start_incoming_migration(const char *host_port, Error **errp)
> > >  {
> > > -    int s;
> > > +    SocketAddress *saddr = tcp_build_address(host_port, errp);
> > > +    QIOChannelSocket *listen_ioc;
> > >  
> > > -    s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
> > > -    if (s < 0) {
> > > +    if (!saddr) {
> > >          return;
> > >      }
> > >  
> > > -    qemu_set_fd_handler(s, tcp_accept_incoming_migration, NULL,
> > > -                        (void *)(intptr_t)s);
> > > +    listen_ioc = qio_channel_socket_new();
> > > +    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
> > 
> > In this case, although weird, that could block couldn't it?
> > The case I'm thinking of is using the migrate_incoming command with a hostname
> > (I've used it with hostnames before as aliases for networks to listen on,
> > admittedly it be rare for it to be DNS that would block).
> 
> Yes it certainly could block and this is undesirable in general. The problem
> is that the only way we can provide errors back for the monitor reponse is
> if we do this synchronously from this method.  If I ran async then we'd have
> no ability to report errors about non-existant host names, already in use tcp
> port, etc.
> 
> I'm not really sure what todo about this long term, but the only way would
> be if the monitor response was able to be sent back asychronously from
> this method call. Then we can start an async listen call, and respond to
> the monitor when done.
> 
> Since the current code being replaced is also blocking, I felt solving
> that problem is best left to a future patch series. At least with this
> explicit method naming with _sync() suffix we can easily identify the
> problems in future

Yeh that's fair enough.  Failed incoming migrations generally just quit anyway.

Dave

> 
> Regards,
> Daniel
> -- 
> |: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org              -o-             http://virt-manager.org :|
> |: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
> |: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 11/22] migration: convert fd socket protocol to use QIOChannel
  2016-02-03 10:29       ` Dr. David Alan Gilbert
@ 2016-02-03 10:39         ` Daniel P. Berrange
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 10:39 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Wed, Feb 03, 2016 at 10:29:50AM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > On Tue, Feb 02, 2016 at 06:46:01PM +0000, Dr. David Alan Gilbert wrote:
> > > >  void fd_start_incoming_migration(const char *infd, Error **errp)
> > > >  {
> > > > -    int fd;
> > > >      QEMUFile *f;
> > > > +    QIOChannel *ioc;
> > > > +    int fd;
> > > >  
> > > >      DPRINTF("Attempting to start an incoming migration via fd\n");
> > > >  
> > > >      fd = strtol(infd, NULL, 0);
> > > >      if (fd_is_socket(fd)) {
> > > > -        f = qemu_fopen_socket(fd, "rb");
> > > > +        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
> > > > +        if (!ioc) {
> > > > +            close(fd);
> > > > +            return;
> > > > +        }
> > > 
> > > Wouldn't it be better to move this check outside of this if, so that
> > > you test the output of both the socket_new_fd and the file_new_fd ?
> > 
> > qio_channel_file_new_fd() can never fail - only the socket_new_fd can
> > fail (when trying to query the sockaddr_t data).
> 
> OK, I'm not too fussed about this bit, but:
>   1) It's easier to read - one level less of nesting
>   2) It avoids making an assumption about qio_channel_file_new_fd() never
>      failing, which is something you happen to know but you treat as
>      API;  it costs nothing to avoid making that assumption.

Note that qio_channel_file_new_fd() does not accept a 'Error **errp' since
there is no failure condition. So if we pushed the failure check up it'd
be feel like a logic error as we'd be introducing a error return path
from the method where 'errp' may not be set.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel
  2016-02-02 18:02   ` Dr. David Alan Gilbert
@ 2016-02-03 11:25     ` Daniel P. Berrange
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 11:25 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Tue, Feb 02, 2016 at 06:02:13PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > Convert the unix socket migration protocol driver to use
> > QIOChannel and QEMUFileChannel, instead of plain sockets
> > APIs. It can be unconditionally built, since the socket
> > impl of QIOChannel will report a suitable error on platforms
> > where UNIX sockets are unavailable.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  migration/Makefile.objs |   4 +-
> >  migration/migration.c   |   4 ++
> >  migration/unix.c        | 103 +++++++++++++++++++++++++++++++-----------------
> >  3 files changed, 72 insertions(+), 39 deletions(-)
> > 
> > diff --git a/migration/Makefile.objs b/migration/Makefile.objs
> > index b357e2f..a5f8a03 100644
> > --- a/migration/Makefile.objs
> > +++ b/migration/Makefile.objs
> > @@ -1,11 +1,11 @@
> > -common-obj-y += migration.o tcp.o
> > +common-obj-y += migration.o tcp.o unix.o
> >  common-obj-y += vmstate.o
> >  common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o
> >  common-obj-y += qemu-file-channel.o
> >  common-obj-y += xbzrle.o postcopy-ram.o
> >  
> >  common-obj-$(CONFIG_RDMA) += rdma.o
> > -common-obj-$(CONFIG_POSIX) += exec.o unix.o fd.o
> > +common-obj-$(CONFIG_POSIX) += exec.o fd.o
> >  
> >  common-obj-y += block.o
> >  
> > diff --git a/migration/migration.c b/migration/migration.c
> > index e921b20..1c5f12e 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -312,8 +312,10 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
> >  #if !defined(WIN32)
> >      } else if (strstart(uri, "exec:", &p)) {
> >          exec_start_incoming_migration(p, errp);
> > +#endif
> >      } else if (strstart(uri, "unix:", &p)) {
> >          unix_start_incoming_migration(p, errp);
> > +#if !defined(WIN32)
> >      } else if (strstart(uri, "fd:", &p)) {
> >          fd_start_incoming_migration(p, errp);
> >  #endif
> > @@ -1017,8 +1019,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
> >  #if !defined(WIN32)
> >      } else if (strstart(uri, "exec:", &p)) {
> >          exec_start_outgoing_migration(s, p, &local_err);
> > +#endif
> >      } else if (strstart(uri, "unix:", &p)) {
> >          unix_start_outgoing_migration(s, p, &local_err);
> > +#if !defined(WIN32)
> >      } else if (strstart(uri, "fd:", &p)) {
> >          fd_start_outgoing_migration(s, p, &local_err);
> >  #endif
> > diff --git a/migration/unix.c b/migration/unix.c
> > index b591813..4674640 100644
> > --- a/migration/unix.c
> > +++ b/migration/unix.c
> > @@ -1,10 +1,11 @@
> >  /*
> >   * QEMU live migration via Unix Domain Sockets
> >   *
> > - * Copyright Red Hat, Inc. 2009
> > + * Copyright Red Hat, Inc. 2009-2015
> 
> year++ ?
> 
> >   *
> >   * Authors:
> >   *  Chris Lalancette <clalance@redhat.com>
> > + *  Daniel P. Berrange <berrange@redhat.com>
> >   *
> >   * This work is licensed under the terms of the GNU GPL, version 2.  See
> >   * the COPYING file in the top-level directory.
> > @@ -17,11 +18,9 @@
> >  
> >  #include "qemu-common.h"
> >  #include "qemu/error-report.h"
> > -#include "qemu/sockets.h"
> > -#include "qemu/main-loop.h"
> >  #include "migration/migration.h"
> >  #include "migration/qemu-file.h"
> > -#include "block/block.h"
> > +#include "io/channel-socket.h"
> >  
> >  //#define DEBUG_MIGRATION_UNIX
> >  
> > @@ -33,71 +32,101 @@
> >      do { } while (0)
> >  #endif
> >  
> > -static void unix_wait_for_connect(int fd, Error *err, void *opaque)
> > +
> > +static SocketAddress *unix_build_address(const char *path)
> > +{
> > +    SocketAddress *saddr;
> > +
> > +    saddr = g_new0(SocketAddress, 1);
> > +    saddr->type = SOCKET_ADDRESS_KIND_UNIX;
> > +    saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
> > +    saddr->u.q_unix->path = g_strdup(path);
> > +
> > +    return saddr;
> > +}
> > +
> > +
> > +static void unix_outgoing_migration(Object *src,
> > +                                    Error *err,
> > +                                    gpointer opaque)
> >  {
> >      MigrationState *s = opaque;
> > +    QIOChannel *sioc = QIO_CHANNEL(src);
> >  
> > -    if (fd < 0) {
> > +    if (err) {
> >          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
> >          s->file = NULL;
> >          migrate_fd_error(s);
> >      } else {
> >          DPRINTF("migrate connect success\n");
> > -        s->file = qemu_fopen_socket(fd, "wb");
> > +        s->file = qemu_fopen_channel_output(sioc);
> >          migrate_fd_connect(s);
> >      }
> > +    object_unref(src);
> >  }
> >  
> > +
> >  void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp)
> >  {
> > -    unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
> > +    SocketAddress *saddr = unix_build_address(path);
> > +    QIOChannelSocket *sioc;
> > +    sioc = qio_channel_socket_new();
> > +    qio_channel_socket_connect_async(sioc,
> > +                                     saddr,
> > +                                     unix_outgoing_migration,
> > +                                     s,
> > +                                     NULL);
> > +    qapi_free_SocketAddress(saddr);
> 
> It took me a bit of digging to see that qio_channel_socket_connect_async
> takes a copy of the address; it's not mentioned in channel-socket.h
> 
> >  }
> >  
> > -static void unix_accept_incoming_migration(void *opaque)
> > +
> > +static gboolean unix_accept_incoming_migration(QIOChannel *ioc,
> > +                                               GIOCondition condition,
> > +                                               gpointer opaque)
> >  {
> > -    struct sockaddr_un addr;
> > -    socklen_t addrlen = sizeof(addr);
> > -    int s = (intptr_t)opaque;
> >      QEMUFile *f;
> > -    int c, err;
> > -
> > -    do {
> > -        c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
> > -        err = errno;
> > -    } while (c < 0 && err == EINTR);
> > -    qemu_set_fd_handler(s, NULL, NULL, NULL);
> > -    close(s);
> > +    QIOChannelSocket *cioc;
> 
> (not important but...) why is that a cioc not a sioc?

IIRC an earlier version of this patch had already used sioc for another
variable. I'll change this now though.

> 
> > +    Error *err = NULL;
> >  
> > -    DPRINTF("accepted migration\n");
> > -
> > -    if (c < 0) {
> > +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> > +                                     &err);
> > +    if (!cioc) {
> >          error_report("could not accept migration connection (%s)",
> > -                     strerror(err));
> > -        return;
> > -    }
> > -
> > -    f = qemu_fopen_socket(c, "rb");
> > -    if (f == NULL) {
> > -        error_report("could not qemu_fopen socket");
> > +                     error_get_pretty(err));
> >          goto out;
> >      }
> >  
> > +    DPRINTF("accepted migration\n");
> 
> Feel free to replace any DPRINTF's by trace_ entries.

Rather than change all my patches in this regard, I'll create an
add-on patch to introduce some useful trace_ entries across all
the migration backends in one go.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface
  2016-02-02 20:01   ` Dr. David Alan Gilbert
@ 2016-02-03 11:37     ` Daniel P. Berrange
  2016-02-03 13:23       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 11:37 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Tue, Feb 02, 2016 at 08:01:36PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > This converts the RDMA code to provide a subclass of
> > QIOChannel that uses RDMA for the data transport.
> > 
> > The RDMA code would be much better off it it could
> > be split up in a generic RDMA layer, a QIOChannel
> > impl based on RMDA, and then the RMDA migration
> > glue. This is left as a future exercise for the brave.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  migration/rdma.c | 260 ++++++++++++++++++++++++++++++++++---------------------
> >  1 file changed, 161 insertions(+), 99 deletions(-)
> > 

> > +static ssize_t qio_channel_rdma_readv(QIOChannel *ioc,
> > +                                      const struct iovec *iov,
> > +                                      size_t niov,
> > +                                      int **fds,
> > +                                      size_t *nfds,
> > +                                      Error **errp)
> > +{
> > +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
> > +    RDMAContext *rdma = rioc->rdma;
> >      RDMAControlHeader head;
> >      int ret = 0;
> > +    ssize_t i;
> > +    size_t done = 0;
> >  
> >      CHECK_ERROR_STATE();
> >  
> > -    /*
> > -     * First, we hold on to the last SEND message we
> > -     * were given and dish out the bytes until we run
> > -     * out of bytes.
> > -     */
> > -    r->len = qemu_rdma_fill(r->rdma, buf, size, 0);
> > -    if (r->len) {
> > -        return r->len;
> > -    }
> > +    for (i = 0; i < niov; i++) {
> > +        size_t want = iov[i].iov_len;
> > +        uint8_t *data = (void *)iov[i].iov_base;
> >  
> > -    /*
> > -     * Once we run out, we block and wait for another
> > -     * SEND message to arrive.
> > -     */
> > -    ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
> > +        /*
> > +         * First, we hold on to the last SEND message we
> > +         * were given and dish out the bytes until we run
> > +         * out of bytes.
> > +         */
> > +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> > +        if (ret > 0) {
> > +            done += ret;
> > +            if (ret < want) {
> > +                break;
> > +            } else {
> > +                continue;
> > +            }
> 
> > +        }
> >  
> > -    if (ret < 0) {
> > -        rdma->error_state = ret;
> > -        return ret;
> > -    }
> > +        /*
> > +         * Once we run out, we block and wait for another
> > +         * SEND message to arrive.
> > +         */
> > +        ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
> >  
> > -    /*
> > -     * SEND was received with new bytes, now try again.
> > -     */
> > -    return qemu_rdma_fill(r->rdma, buf, size, 0);
> > +        if (ret < 0) {
> > +            rdma->error_state = ret;
> > +            return ret;
> > +        }
> > +
> > +        /*
> > +         * SEND was received with new bytes, now try again.
> > +         */
> > +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> > +        if (ret > 0) {
> > +            done += ret;
> > +            if (ret < want) {
> > +                break;
> > +            }
> > +        }
> 
> I don't quite understand the behaviour of this loop.
> If rdma_fill returns less than you wanted for the first iov we break.
> If it returns 0 then we try and get some more.
> The weird thing to me is if we have two iov entries; if the
> amount returned by the qemu_rdma_fill happens to match the size of
> the 1st iov then I think we end up doing the exchange_recv and
> waiting for more.  Is that what we want? Why?

No, it isn't quite what we want. If we have successfully received
some data in a preceeding iov, then we shouldn't wait for more data
for any following iov. I'll rework this bit of code to work better

In fact technically, we should not block for data at all when the
channel is in non-blocking mode. Fixing that would require some
refactoring of qemu_rdma_block_for_wrid() so that we could tell
it to only look for an already completed work request and not
block

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface
  2016-02-03 11:37     ` Daniel P. Berrange
@ 2016-02-03 13:23       ` Dr. David Alan Gilbert
  2016-02-03 13:25         ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-03 13:23 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Tue, Feb 02, 2016 at 08:01:36PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > This converts the RDMA code to provide a subclass of
> > > QIOChannel that uses RDMA for the data transport.
> > > 
> > > The RDMA code would be much better off it it could
> > > be split up in a generic RDMA layer, a QIOChannel
> > > impl based on RMDA, and then the RMDA migration
> > > glue. This is left as a future exercise for the brave.
> > > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  migration/rdma.c | 260 ++++++++++++++++++++++++++++++++++---------------------
> > >  1 file changed, 161 insertions(+), 99 deletions(-)
> > > 
> 
> > > +static ssize_t qio_channel_rdma_readv(QIOChannel *ioc,
> > > +                                      const struct iovec *iov,
> > > +                                      size_t niov,
> > > +                                      int **fds,
> > > +                                      size_t *nfds,
> > > +                                      Error **errp)
> > > +{
> > > +    QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
> > > +    RDMAContext *rdma = rioc->rdma;
> > >      RDMAControlHeader head;
> > >      int ret = 0;
> > > +    ssize_t i;
> > > +    size_t done = 0;
> > >  
> > >      CHECK_ERROR_STATE();
> > >  
> > > -    /*
> > > -     * First, we hold on to the last SEND message we
> > > -     * were given and dish out the bytes until we run
> > > -     * out of bytes.
> > > -     */
> > > -    r->len = qemu_rdma_fill(r->rdma, buf, size, 0);
> > > -    if (r->len) {
> > > -        return r->len;
> > > -    }
> > > +    for (i = 0; i < niov; i++) {
> > > +        size_t want = iov[i].iov_len;
> > > +        uint8_t *data = (void *)iov[i].iov_base;
> > >  
> > > -    /*
> > > -     * Once we run out, we block and wait for another
> > > -     * SEND message to arrive.
> > > -     */
> > > -    ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
> > > +        /*
> > > +         * First, we hold on to the last SEND message we
> > > +         * were given and dish out the bytes until we run
> > > +         * out of bytes.
> > > +         */
> > > +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> > > +        if (ret > 0) {
> > > +            done += ret;
> > > +            if (ret < want) {
> > > +                break;
> > > +            } else {
> > > +                continue;
> > > +            }
> > 
> > > +        }
> > >  
> > > -    if (ret < 0) {
> > > -        rdma->error_state = ret;
> > > -        return ret;
> > > -    }
> > > +        /*
> > > +         * Once we run out, we block and wait for another
> > > +         * SEND message to arrive.
> > > +         */
> > > +        ret = qemu_rdma_exchange_recv(rdma, &head, RDMA_CONTROL_QEMU_FILE);
> > >  
> > > -    /*
> > > -     * SEND was received with new bytes, now try again.
> > > -     */
> > > -    return qemu_rdma_fill(r->rdma, buf, size, 0);
> > > +        if (ret < 0) {
> > > +            rdma->error_state = ret;
> > > +            return ret;
> > > +        }
> > > +
> > > +        /*
> > > +         * SEND was received with new bytes, now try again.
> > > +         */
> > > +        ret = qemu_rdma_fill(rioc->rdma, data, want, 0);
> > > +        if (ret > 0) {
> > > +            done += ret;
> > > +            if (ret < want) {
> > > +                break;
> > > +            }
> > > +        }
> > 
> > I don't quite understand the behaviour of this loop.
> > If rdma_fill returns less than you wanted for the first iov we break.
> > If it returns 0 then we try and get some more.
> > The weird thing to me is if we have two iov entries; if the
> > amount returned by the qemu_rdma_fill happens to match the size of
> > the 1st iov then I think we end up doing the exchange_recv and
> > waiting for more.  Is that what we want? Why?
> 
> No, it isn't quite what we want. If we have successfully received
> some data in a preceeding iov, then we shouldn't wait for more data
> for any following iov. I'll rework this bit of code to work better
> 
> In fact technically, we should not block for data at all when the
> channel is in non-blocking mode. Fixing that would require some
> refactoring of qemu_rdma_block_for_wrid() so that we could tell
> it to only look for an already completed work request and not
> block

I wouldn't go changing qemu_rdma_block_for_wrid unless you need
to.

Dave

> 
> Regards,
> Daniel
> -- 
> |: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org              -o-             http://virt-manager.org :|
> |: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
> |: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface
  2016-02-03 13:23       ` Dr. David Alan Gilbert
@ 2016-02-03 13:25         ` Daniel P. Berrange
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 13:25 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Wed, Feb 03, 2016 at 01:23:04PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > On Tue, Feb 02, 2016 at 08:01:36PM +0000, Dr. David Alan Gilbert wrote:
> > > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > > This converts the RDMA code to provide a subclass of
> > > > QIOChannel that uses RDMA for the data transport.
> > > > 
> > > > The RDMA code would be much better off it it could
> > > > be split up in a generic RDMA layer, a QIOChannel
> > > > impl based on RMDA, and then the RMDA migration
> > > > glue. This is left as a future exercise for the brave.
> > > > 
> > > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > > ---
> > > >  migration/rdma.c | 260 ++++++++++++++++++++++++++++++++++---------------------
> > > >  1 file changed, 161 insertions(+), 99 deletions(-)
> > > > 

> > > 
> > > I don't quite understand the behaviour of this loop.
> > > If rdma_fill returns less than you wanted for the first iov we break.
> > > If it returns 0 then we try and get some more.
> > > The weird thing to me is if we have two iov entries; if the
> > > amount returned by the qemu_rdma_fill happens to match the size of
> > > the 1st iov then I think we end up doing the exchange_recv and
> > > waiting for more.  Is that what we want? Why?
> > 
> > No, it isn't quite what we want. If we have successfully received
> > some data in a preceeding iov, then we shouldn't wait for more data
> > for any following iov. I'll rework this bit of code to work better
> > 
> > In fact technically, we should not block for data at all when the
> > channel is in non-blocking mode. Fixing that would require some
> > refactoring of qemu_rdma_block_for_wrid() so that we could tell
> > it to only look for an already completed work request and not
> > block
> 
> I wouldn't go changing qemu_rdma_block_for_wrid unless you need
> to.

Yeah, I won't do it now - just something to think about for the future
to properly do non-blocking I/o channels.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount
  2016-01-28 17:53   ` Dr. David Alan Gilbert
@ 2016-02-03 13:31     ` Daniel P. Berrange
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 13:31 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Thu, Jan 28, 2016 at 05:53:46PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > The QEMUFile writev_buffer / put_buffer functions are expected
> > to write out the full set of requested data, blocking until
> > complete. The qemu_fflush() caller does not expect to deal with
> > partial writes. Clarify the function comments and add a sanity
> > check to the code to catch mistaken implementations.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  include/migration/qemu-file.h |  6 ++++--
> >  migration/qemu-file.c         | 16 ++++++++++++----
> >  2 files changed, 16 insertions(+), 6 deletions(-)
> > 
> > diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> > index b5d08d2..5debe8c 100644
> > --- a/include/migration/qemu-file.h
> > +++ b/include/migration/qemu-file.h
> > @@ -29,7 +29,8 @@
> >  
> >  /* This function writes a chunk of data to a file at the given position.
> >   * The pos argument can be ignored if the file is only being used for
> > - * streaming.  The handler should try to write all of the data it can.
> > + * streaming.  The handler must write all of the data or return a negative
> > + * errno value.
> >   */
> >  typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
> >                                          int64_t pos, size_t size);
> > @@ -55,7 +56,8 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
> >  typedef int (QEMUFileGetFD)(void *opaque);
> >  
> >  /*
> > - * This function writes an iovec to file.
> > + * This function writes an iovec to file. The handler must write all
> > + * of the data or return a negative errno value.
> >   */
> >  typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
> >                                             int iovcnt, int64_t pos);
> > diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> > index 0bbd257..f89e64e 100644
> > --- a/migration/qemu-file.c
> > +++ b/migration/qemu-file.c
> > @@ -107,11 +107,13 @@ bool qemu_file_is_writable(QEMUFile *f)
> >   * Flushes QEMUFile buffer
> >   *
> >   * If there is writev_buffer QEMUFileOps it uses it otherwise uses
> > - * put_buffer ops.
> > + * put_buffer ops. This will flush all pending data. If data was
> > + * only partially flushed, it will set an error state.
> >   */
> >  void qemu_fflush(QEMUFile *f)
> >  {
> >      ssize_t ret = 0;
> > +    ssize_t expect = 0;
> >  
> >      if (!qemu_file_is_writable(f)) {
> >          return;
> > @@ -119,21 +121,27 @@ void qemu_fflush(QEMUFile *f)
> >  
> >      if (f->ops->writev_buffer) {
> >          if (f->iovcnt > 0) {
> > +            expect = iov_size(f->iov, f->iovcnt);
> >              ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> >          }
> >      } else {
> >          if (f->buf_index > 0) {
> > +            expect = f->buf_index;
> >              ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
> >          }
> >      }
> > +
> >      if (ret >= 0) {
> >          f->pos += ret;
> >      }
> > -    f->buf_index = 0;
> > -    f->iovcnt = 0;
> > -    if (ret < 0) {
> > +    /* We expect the QEMUFile write impl to send the full
> > +     * data set we requested, so sanity check that.
> > +     */
> > +    if (ret < 0 || ret != expect) {
> >          qemu_file_set_error(f, ret);
> 
> You could simplify that to     if (ret != expect)     couldn't you?
> 
> In the case you're trying to guard against, the value past
> to qemu_file_set_error is potentially truncated; which in the worst
> case could make it appear as success; although I doubt that
> can happen in our uses.

qemu_file_set_error expects an errni, so in fact my code was
buggy if the ret != expect part got evaluated, so I'll change
this to

     if (ret != expect) {
        qemu_file_set_error(f, ret < 0 ? ret : -EIO);
     }


> 
> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel
  2016-02-02 17:06   ` Dr. David Alan Gilbert
@ 2016-02-03 13:37     ` Daniel P. Berrange
  2016-02-12 17:16       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-03 13:37 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Tue, Feb 02, 2016 at 05:06:24PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > Introduce a new QEMUFile implementation that is based on
> > the QIOChannel objects. This impl is different from existing
> > impls in that there is no file descriptor that can be made
> > available, as some channels may be based on higher level
> > protocols such as TLS.
> > 
> > Although the QIOChannel based implementation can trivially
> > provide a bi-directional stream, initially we have separate
> > functions for opening input & output directions to fit with
> > the expectation of the current QEMUFile interface.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  include/migration/qemu-file.h |   4 +
> >  migration/Makefile.objs       |   1 +
> >  migration/qemu-file-channel.c | 201 ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 206 insertions(+)
> >  create mode 100644 migration/qemu-file-channel.c

> > +static ssize_t channel_writev_buffer(void *opaque,
> > +                                     struct iovec *iov,
> > +                                     int iovcnt,
> > +                                     int64_t pos)
> > +{
> > +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> > +    ssize_t done = 0;
> > +    ssize_t want = iov_size(iov, iovcnt);
> > +    struct iovec oldiov = { NULL, 0 };
> > +
> > +    while (done < want) {
> > +        ssize_t len;
> > +        struct iovec *cur = iov;
> > +        int curcnt = iovcnt;
> > +
> > +        channel_skip_iov(done, &cur, &curcnt, &oldiov);
> > +
> > +        len = qio_channel_writev(ioc, cur, curcnt, NULL);
> > +        if (oldiov.iov_base) {
> > +            /* Restore original caller's info in @iov */
> > +            cur[0].iov_base = oldiov.iov_base;
> > +            cur[0].iov_len = oldiov.iov_len;
> > +            oldiov.iov_base = NULL;
> > +            oldiov.iov_len = 0;
> > +        }
> > +        if (len == QIO_CHANNEL_ERR_BLOCK) {
> > +            qio_channel_wait(ioc, G_IO_OUT);
> > +            continue;
> > +        }
> > +        if (len < 0) {
> > +            /* XXX handle Error objects */
> > +            return -EIO;
> 
> It's best to return 'len' rather than lose what little
> error information you had (similarly below).

In this case 'len' is in fact just '-1', as all error
info is in the Error ** parameter, but the QEMUFile API
contract requires an errno value. So we don't have much
choice but to return a fixed EIO - returning 'len' would
also be a fixed errno - whichever errno corresponds to
the value -1.

I'd like to switch QEMUFile over to use Error **errp
parameters for error reporting, so that we can make
detailed error info available throughout the migration
I/O code. That ought to wait until after this series
is done though, to avoid complicating it yet more.

> 
> > +        }
> > +
> > +        done += len;
> > +    }
> > +    return done;
> > +}
> > +
> > +
> > +static ssize_t channel_get_buffer(void *opaque,
> > +                                  uint8_t *buf,
> > +                                  int64_t pos,
> > +                                  size_t size)
> > +{
> > +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> > +    ssize_t ret;
> > +
> > + reread:
> > +    ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> > +    if (ret < 0) {
> > +        if (ret == QIO_CHANNEL_ERR_BLOCK) {
> > +            qio_channel_yield(ioc, G_IO_IN);
> > +            goto reread;
> > +        } else {
> > +            /* XXX handle Error * object */
> > +            return -EIO;
> > +        }
> > +    }
> > +    return ret;
> 
> 
> I'd prefer a loop to a goto; generally the only places we
> use goto is an error exit.
> 
>   do {
>        ret = qio_channel_read(ioc, (char *)buf, size, NULL);
>        if (ret == QIO_CHANNEL_ERR_BLOCK) {
>            qio_channel_yield(ioc, G_IO_IN);
>        }
>   } while (ret == QIO_CHANNEL_ERR_BLOCK);
> 
>   return ret;
> 
> and IMHO the loop is clearer.

Ok, will change that.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c Daniel P. Berrange
@ 2016-02-05 18:32   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-05 18:32 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Now that the memory buffer based QEMUFile impl is gone, there
> is no need for any backend to be accessing internals of the
> QEMUFile struct, so it can be moved back into qemu-file.c
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  migration/qemu-file-internal.h | 54 ------------------------------------------
>  migration/qemu-file.c          | 24 ++++++++++++++++++-
>  2 files changed, 23 insertions(+), 55 deletions(-)
>  delete mode 100644 migration/qemu-file-internal.h
> 
> diff --git a/migration/qemu-file-internal.h b/migration/qemu-file-internal.h
> deleted file mode 100644
> index 8fdfa95..0000000
> --- a/migration/qemu-file-internal.h
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -/*
> - * QEMU System Emulator
> - *
> - * Copyright (c) 2003-2008 Fabrice Bellard
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a copy
> - * of this software and associated documentation files (the "Software"), to deal
> - * in the Software without restriction, including without limitation the rights
> - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> - * copies of the Software, and to permit persons to whom the Software is
> - * furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice shall be included in
> - * all copies or substantial portions of the Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> - * THE SOFTWARE.
> - */
> -
> -#ifndef QEMU_FILE_INTERNAL_H
> -#define QEMU_FILE_INTERNAL_H 1
> -
> -#include "qemu-common.h"
> -#include "qemu/iov.h"
> -
> -#define IO_BUF_SIZE 32768
> -#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> -
> -struct QEMUFile {
> -    const QEMUFileOps *ops;
> -    const QEMUFileHooks *hooks;
> -    void *opaque;
> -
> -    int64_t bytes_xfer;
> -    int64_t xfer_limit;
> -
> -    int64_t pos; /* start of buffer when writing, end of buffer
> -                    when reading */
> -    int buf_index;
> -    int buf_size; /* 0 when writing */
> -    uint8_t buf[IO_BUF_SIZE];
> -
> -    struct iovec iov[MAX_IOV_SIZE];
> -    unsigned int iovcnt;
> -
> -    int last_error;
> -};
> -
> -#endif
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index fc5977e..333f418 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -29,9 +29,31 @@
>  #include "qemu/coroutine.h"
>  #include "migration/migration.h"
>  #include "migration/qemu-file.h"
> -#include "migration/qemu-file-internal.h"
>  #include "trace.h"
>  
> +#define IO_BUF_SIZE 32768
> +#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
> +
> +struct QEMUFile {
> +    const QEMUFileOps *ops;
> +    const QEMUFileHooks *hooks;
> +    void *opaque;
> +
> +    int64_t bytes_xfer;
> +    int64_t xfer_limit;
> +
> +    int64_t pos; /* start of buffer when writing, end of buffer
> +                    when reading */
> +    int buf_index;
> +    int buf_size; /* 0 when writing */
> +    uint8_t buf[IO_BUF_SIZE];
> +
> +    struct iovec iov[MAX_IOV_SIZE];
> +    unsigned int iovcnt;
> +
> +    int last_error;
> +};
> +
>  /*
>   * Stop a file from being read/written - not all backing files can do this
>   * typically only sockets can.
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers Daniel P. Berrange
@ 2016-02-12 15:48   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-12 15:48 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> All the remaining QEMUFile implementations provide an iovec
> based write handler, so the put_buffer callback can be removed
> to simplify the code.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> ---
>  include/migration/qemu-file.h |  9 ---------
>  migration/qemu-file.c         | 36 ++++++++----------------------------
>  migration/savevm.c            |  8 --------
>  3 files changed, 8 insertions(+), 45 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index 6a66735..4ee40e4 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -29,14 +29,6 @@
>  
>  #include <stdint.h>
>  
> -/* This function writes a chunk of data to a file at the given position.
> - * The pos argument can be ignored if the file is only being used for
> - * streaming.  The handler must write all of the data or return a negative
> - * errno value.
> - */
> -typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
> -                                        int64_t pos, size_t size);
> -
>  /* Read a chunk of data from a file at the given position.  The pos argument
>   * can be ignored if the file is only be used for streaming.  The number of
>   * bytes actually read should be returned.
> @@ -110,7 +102,6 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
>  typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
>  
>  typedef struct QEMUFileOps {
> -    QEMUFilePutBufferFunc *put_buffer;
>      QEMUFileGetBufferFunc *get_buffer;
>      QEMUFileCloseFunc *close;
>      QEMUFileGetFD *get_fd;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 333f418..372a6b9 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -128,7 +128,7 @@ void qemu_file_set_error(QEMUFile *f, int ret)
>  
>  bool qemu_file_is_writable(QEMUFile *f)
>  {
> -    return f->ops->writev_buffer || f->ops->put_buffer;
> +    return f->ops->writev_buffer;
>  }
>  
>  /**
> @@ -147,16 +147,9 @@ void qemu_fflush(QEMUFile *f)
>          return;
>      }
>  
> -    if (f->ops->writev_buffer) {
> -        if (f->iovcnt > 0) {
> -            expect = iov_size(f->iov, f->iovcnt);
> -            ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
> -        }
> -    } else {
> -        if (f->buf_index > 0) {
> -            expect = f->buf_index;
> -            ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
> -        }
> +    if (f->iovcnt > 0) {
> +        expect = iov_size(f->iov, f->iovcnt);
> +        ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
>      }
>  
>      if (ret >= 0) {
> @@ -336,11 +329,6 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size)
>  
>  void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size)
>  {
> -    if (!f->ops->writev_buffer) {
> -        qemu_put_buffer(f, buf, size);
> -        return;
> -    }
> -
>      if (f->last_error) {
>          return;
>      }
> @@ -364,9 +352,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size)
>          }
>          memcpy(f->buf + f->buf_index, buf, l);
>          f->bytes_xfer += l;
> -        if (f->ops->writev_buffer) {
> -            add_to_iovec(f, f->buf + f->buf_index, l);
> -        }
> +        add_to_iovec(f, f->buf + f->buf_index, l);
>          f->buf_index += l;
>          if (f->buf_index == IO_BUF_SIZE) {
>              qemu_fflush(f);
> @@ -387,9 +373,7 @@ void qemu_put_byte(QEMUFile *f, int v)
>  
>      f->buf[f->buf_index] = v;
>      f->bytes_xfer++;
> -    if (f->ops->writev_buffer) {
> -        add_to_iovec(f, f->buf + f->buf_index, 1);
> -    }
> +    add_to_iovec(f, f->buf + f->buf_index, 1);
>      f->buf_index++;
>      if (f->buf_index == IO_BUF_SIZE) {
>          qemu_fflush(f);
> @@ -553,12 +537,8 @@ int64_t qemu_ftell_fast(QEMUFile *f)
>      int64_t ret = f->pos;
>      int i;
>  
> -    if (f->ops->writev_buffer) {
> -        for (i = 0; i < f->iovcnt; i++) {
> -            ret += f->iov[i].iov_len;
> -        }
> -    } else {
> -        ret += f->buf_index;
> +    for (i = 0; i < f->iovcnt; i++) {
> +        ret += f->iov[i].iov_len;
>      }
>  
>      return ret;
> diff --git a/migration/savevm.c b/migration/savevm.c
> index e57d7ce..a991c0c 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -160,13 +160,6 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
>      return qiov.size;
>  }
>  
> -static ssize_t block_put_buffer(void *opaque, const uint8_t *buf,
> -                                int64_t pos, size_t size)
> -{
> -    bdrv_save_vmstate(opaque, buf, pos, size);
> -    return size;
> -}
> -
>  static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
>                                  size_t size)
>  {
> @@ -184,7 +177,6 @@ static const QEMUFileOps bdrv_read_ops = {
>  };
>  
>  static const QEMUFileOps bdrv_write_ops = {
> -    .put_buffer     = block_put_buffer,
>      .writev_buffer  = block_writev_buffer,
>      .close          = bdrv_fclose
>  };
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile Daniel P. Berrange
@ 2016-02-12 15:51   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-12 15:51 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Now that there is a set_blocking callback in QEMUFileOps,
> and all users needing non-blocking support have been
> converted to QIOChannel, there is no longer any codepath
> requiring the qemu_get_fd() method for QEMUFile. Remove it
> to avoid further code being introduced with an expectation
> of direct file handle access.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Dave

> ---
>  include/migration/qemu-file.h |  1 -
>  migration/qemu-file.c         | 14 --------------
>  2 files changed, 15 deletions(-)
> 
> diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
> index 4ee40e4..68bc165 100644
> --- a/include/migration/qemu-file.h
> +++ b/include/migration/qemu-file.h
> @@ -104,7 +104,6 @@ typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
>  typedef struct QEMUFileOps {
>      QEMUFileGetBufferFunc *get_buffer;
>      QEMUFileCloseFunc *close;
> -    QEMUFileGetFD *get_fd;
>      QEMUFileSetBlocking *set_blocking;
>      QEMUFileWritevBufferFunc *writev_buffer;
>      QEMURetPathFunc *get_return_path;
> diff --git a/migration/qemu-file.c b/migration/qemu-file.c
> index 372a6b9..baef865 100644
> --- a/migration/qemu-file.c
> +++ b/migration/qemu-file.c
> @@ -267,14 +267,6 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
>      return len;
>  }
>  
> -int qemu_get_fd(QEMUFile *f)
> -{
> -    if (f->ops->get_fd) {
> -        return f->ops->get_fd(f->opaque);
> -    }
> -    return -1;
> -}
> -
>  void qemu_update_position(QEMUFile *f, size_t size)
>  {
>      f->pos += size;
> @@ -687,11 +679,5 @@ void qemu_file_set_blocking(QEMUFile *f, bool block)
>  {
>      if (f->ops->set_blocking) {
>          f->ops->set_blocking(f->opaque, block);
> -    } else {
> -        if (block) {
> -            qemu_set_block(qemu_get_fd(f));
> -        } else {
> -            qemu_set_nonblock(qemu_get_fd(f));
> -        }
>      }
>  }
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend
  2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend Daniel P. Berrange
@ 2016-02-12 17:09   ` Dr. David Alan Gilbert
  2016-02-12 17:25     ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-12 17:09 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> This extends the TCP migration backend so that it can make use
> of QIOChannelTLS to provide transparent TLS encryption. To
> trigger enablement the URI on the incoming and outgoing sides
> should have 'tls-creds=ID' appended, eg
> 
>    tcp:$HOST:$PORT,tls-creds=ID
> 
> where ID is the object identifier of a set of TLS credentials
> previously created using object_add / -object. There is not
> currently any support for checking the migration client
> certificate names against ACLs. This is pending a conversion
> of the ACL code to QOM.

Does that change the option passed or is that just different
in the way the tls-creds are set up?

> There is no support for dynamically negotiating use of TLS
> between the incoming/outgoing side. Both sides must agree
> on use of TLS out of band and set the URI accordingly. In
> practice it is expected that the administrator will just
> turn on use of TLS on their hosts in the libvirt config
> and then libvirt will instruct QEMU to use TLS for migration.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

> ---
>  migration/tcp.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  qemu-options.hx |   7 +-
>  2 files changed, 264 insertions(+), 16 deletions(-)
> 
> diff --git a/migration/tcp.c b/migration/tcp.c
> index ac73977..bef861c 100644
> --- a/migration/tcp.c
> +++ b/migration/tcp.c
> @@ -22,6 +22,8 @@
>  #include "migration/migration.h"
>  #include "migration/qemu-file.h"
>  #include "io/channel-socket.h"
> +#include "io/channel-tls.h"
> +#include "crypto/tlscreds.h"
>  
>  //#define DEBUG_MIGRATION_TCP
>  
> @@ -33,6 +35,22 @@
>      do { } while (0)
>  #endif
>  
> +typedef struct {
> +    MigrationState *s;
> +    QCryptoTLSCreds *tlscreds;
> +    char *hostname;
> +} TCPConnectData;
> +
> +typedef struct {
> +    MigrationState *s;
> +    QCryptoTLSCreds *tlscreds;
> +} TCPListenData;
> +
> +typedef struct {
> +    MigrationState *s;
> +    QIOChannel *ioc;
> +} TCPConnectTLSData;
> +

what makes it TCP specific rather than sharing most of this between transports? i.e. should
this work for fd migration ? (rdma is probably not reasonable
giving it's scribbling directly in the other hosts RAM).
Certainly those types dont really look TCP specific.

>  static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
>  {
> @@ -51,21 +69,174 @@ static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
>  }
>  
>  
> +static void tcp_connect_data_free(gpointer opaque)
> +{
> +    TCPConnectData *data = opaque;
> +    if (!data) {
> +        return;
> +    }
> +    g_free(data->hostname);
> +    object_unref(OBJECT(data->tlscreds));
> +    g_free(data);
> +}
> +
> +
> +static void tcp_listen_data_free(gpointer opaque)
> +{
> +    TCPListenData *data = opaque;
> +    if (!data) {
> +        return;
> +    }
> +    object_unref(OBJECT(data->tlscreds));
> +    g_free(data);
> +}
> +
> +
> +static void tcp_connect_tls_data_free(gpointer opaque)
> +{
> +    TCPConnectTLSData *data = opaque;
> +    if (!data) {
> +        return;
> +    }
> +    object_unref(OBJECT(data->ioc));
> +    g_free(data);
> +}
> +
> +
> +static char *tcp_get_opt_str(const char *host_port,
> +                             const char *key)
> +{
> +    const char *offset, *end;
> +
> +    offset = strstr(host_port, key);
> +    if (!offset) {
> +        return NULL;
> +    }
> +
> +    offset += strlen(key);
> +    if (offset[0] != '=') {
> +        return NULL;
> +    }
> +    offset++;
> +    end = strchr(offset, ',');
> +    if (end) {
> +        return g_strndup(offset, end - offset);
> +    } else {
> +        return g_strdup(offset);
> +    }
> +}
> +
> +
> +static QCryptoTLSCreds *tcp_get_tls_creds(const char *host_port,
> +                                          bool is_listen,
> +                                          Error **errp)
> +{
> +    char *credname = NULL;
> +    Object *creds;
> +    QCryptoTLSCreds *ret;
> +
> +    credname = tcp_get_opt_str(host_port, "tls-creds");
> +    if (!credname) {
> +        return NULL;
> +    }

At what point does it get saner just to throw host_port into a qemu_opts 
and let it parse it?

> +    creds = object_resolve_path_component(
> +        object_get_objects_root(), credname);
> +    if (!creds) {
> +        error_setg(errp, "No TLS credentials with id '%s'",
> +                   credname);
> +        goto error;
> +    }
> +    ret = (QCryptoTLSCreds *)object_dynamic_cast(
> +        creds, TYPE_QCRYPTO_TLS_CREDS);
> +    if (!ret) {
> +        error_setg(errp, "Object with id '%s' is not TLS credentials",
> +                   credname);
> +        goto error;
> +    }
> +    if (is_listen) {
> +        if (ret->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
> +            error_setg(errp, "%s",
> +                       "Expected TLS credentials for server endpoint");
> +            goto error;
> +        }
> +    } else {
> +        if (ret->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
> +            error_setg(errp, "%s",
> +                       "Expected TLS credentials for client endpoint");
> +            goto error;
> +        }
> +    }
> +
> +    g_free(credname);
> +    object_ref(OBJECT(ret));
> +    return ret;
> +
> + error:
> +    g_free(credname);
> +    return NULL;
> +}
> +
> +
> +static void tcp_outgoing_migration_tls(Object *src,
> +                                       Error *err,
> +                                       gpointer opaque)
> +{
> +    TCPConnectTLSData *data = opaque;
> +    QIOChannel *ioc = QIO_CHANNEL(src);
> +
> +    if (err) {
> +        DPRINTF("migrate connect TLS error: %s\n", error_get_pretty(err));

error_report ?

> +        data->s->file = NULL;
> +        migrate_fd_error(data->s);
> +    } else {
> +        DPRINTF("migrate connect success\n");

trace_

> +        data->s->file = qemu_fopen_channel_output(ioc);
> +        migrate_fd_connect(data->s);
> +    }
> +}
> +
> +
>  static void tcp_outgoing_migration(Object *src,
>                                     Error *err,
>                                     gpointer opaque)
>  {
> -    MigrationState *s = opaque;
> +    TCPConnectData *data = opaque;
>      QIOChannel *sioc = QIO_CHANNEL(src);
>  
>      if (err) {
>          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
> -        s->file = NULL;
> -        migrate_fd_error(s);
> +        data->s->file = NULL;
> +        migrate_fd_error(data->s);
>      } else {
> -        DPRINTF("migrate connect success\n");
> -        s->file = qemu_fopen_channel_output(sioc);
> -        migrate_fd_connect(s);
> +        if (data->tlscreds) {
> +            Error *local_err = NULL;
> +            QIOChannelTLS *tioc = qio_channel_tls_new_client(
> +                sioc, data->tlscreds, data->hostname,
> +                &local_err);
> +            if (!tioc) {
> +                DPRINTF("migrate tls setup error: %s\n",
> +                        error_get_pretty(local_err));

error_report ?  More below I think - just make sure that
any errors normally get logged.

> +                error_free(local_err);
> +                data->s->file = NULL;
> +                migrate_fd_error(data->s);
> +            } else {
> +                TCPConnectTLSData *tdata =
> +                    g_new0(TCPConnectTLSData, 1);
> +                DPRINTF("migrate connect tls handshake begin\n");
> +                tdata->s = data->s;
> +                tdata->ioc = sioc;
> +                object_ref(OBJECT(sioc));
> +                qio_channel_tls_handshake(tioc,
> +                                          tcp_outgoing_migration_tls,
> +                                          tdata,
> +                                          tcp_connect_tls_data_free);
> +            }
> +        } else {
> +            DPRINTF("migrate connect success\n");
> +            data->s->file = qemu_fopen_channel_output(sioc);
> +            migrate_fd_connect(data->s);
> +        }
>      }
>      object_unref(src);
>  }
> @@ -77,21 +248,56 @@ void tcp_start_outgoing_migration(MigrationState *s,
>  {
>      SocketAddress *saddr = tcp_build_address(host_port, errp);
>      QIOChannelSocket *sioc;
> +    Error *local_err = NULL;
> +    QCryptoTLSCreds *creds;
> +    TCPConnectData *data;
>  
>      if (!saddr) {
>          return;
>      }
>  
> +    creds = tcp_get_tls_creds(host_port, false, errp);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        qapi_free_SocketAddress(saddr);
> +        return;
> +    }
> +
> +    data = g_new0(TCPConnectData, 1);
> +    data->s = s;
> +    if (creds) {
> +        data->hostname = g_strdup(saddr->u.inet->host);
> +        data->tlscreds = creds;
> +    }
> +
>      sioc = qio_channel_socket_new();
>      qio_channel_socket_connect_async(sioc,
>                                       saddr,
>                                       tcp_outgoing_migration,
> -                                     s,
> -                                     NULL);
> +                                     data,
> +                                     tcp_connect_data_free);
>      qapi_free_SocketAddress(saddr);
>  }
>  
>  
> +static void tcp_incoming_migration_tls(Object *src,
> +                                       Error *err,
> +                                       gpointer opaque)
> +{
> +    QIOChannel *ioc = QIO_CHANNEL(src);
> +
> +    if (err) {
> +        DPRINTF("migrate listen TLS error: %s\n", error_get_pretty(err));
> +        object_unref(OBJECT(ioc));
> +    } else {
> +        DPRINTF("migrate listen success\n");
> +        QEMUFile *f = qemu_fopen_channel_input(ioc);
> +
> +        process_incoming_migration(f);
> +    }
> +}
> +
> +
>  static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
>                                                GIOCondition condition,
>                                                gpointer opaque)
> @@ -99,6 +305,7 @@ static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
>      QEMUFile *f;
>      QIOChannelSocket *cioc;
>      Error *err = NULL;
> +    TCPListenData *data = opaque;
>  
>      cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
>                                       &err);
> @@ -108,16 +315,38 @@ static gboolean tcp_accept_incoming_migration(QIOChannel *ioc,
>          goto out;
>      }
>  
> -    DPRINTF("accepted migration\n");
> +    if (data->tlscreds) {
> +        DPRINTF("Starting client TLS\n");
> +        QIOChannelTLS *tioc = qio_channel_tls_new_server(
> +            QIO_CHANNEL(cioc), data->tlscreds,
> +            NULL, /* XXX pass ACL name */
> +            &err);
> +        object_unref(OBJECT(cioc));
> +        if (!tioc) {
> +            DPRINTF("migrate tls setup error: %s\n",
> +                    error_get_pretty(err));
> +            error_free(err);
> +            goto out;
> +        } else {
> +            DPRINTF("migrate connect tls handshake begin\n");
> +            qio_channel_tls_handshake(tioc,
> +                                      tcp_incoming_migration_tls,
> +                                      NULL,
> +                                      NULL);
> +        }
> +    } else {
> +        DPRINTF("accepted migration\n");
>  
> -    f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> -    object_unref(OBJECT(cioc));
> +        f = qemu_fopen_channel_input(QIO_CHANNEL(cioc));
> +        object_unref(OBJECT(cioc));
>  
> -    process_incoming_migration(f);
> +        process_incoming_migration(f);
> +    }
>  
>  out:
>      /* Close listening socket as its no longer needed */
>      qio_channel_close(ioc, NULL);
> +    object_unref(OBJECT(ioc));
>      return FALSE;
>  }
>  
> @@ -126,23 +355,39 @@ void tcp_start_incoming_migration(const char *host_port, Error **errp)
>  {
>      SocketAddress *saddr = tcp_build_address(host_port, errp);
>      QIOChannelSocket *listen_ioc;
> +    TCPListenData *data;
> +    Error *local_err = NULL;
> +    QCryptoTLSCreds *creds;
>  
>      if (!saddr) {
>          return;
>      }
>  
> +    creds = tcp_get_tls_creds(host_port, true, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        qapi_free_SocketAddress(saddr);
> +        return;
> +    }
> +
>      listen_ioc = qio_channel_socket_new();
>      if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
>          object_unref(OBJECT(listen_ioc));
>          qapi_free_SocketAddress(saddr);
> +        object_unref(OBJECT(creds));
>          return;
>      }
>  
> +    data = g_new0(TCPListenData, 1);
> +    if (creds) {
> +        data->tlscreds = creds;
> +    }
> +
>      qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
>                            G_IO_IN,
>                            tcp_accept_incoming_migration,
> -                          listen_ioc,
> -                          (GDestroyNotify)object_unref);
> +                          data,
> +                          tcp_listen_data_free);
>  
>      qapi_free_SocketAddress(saddr);
>  }
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 215d00d..3f16cfc 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -3364,7 +3364,7 @@ Set TB size.
>  ETEXI
>  
>  DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
> -    "-incoming tcp:[host]:port[,to=maxport][,ipv4][,ipv6]\n" \
> +    "-incoming tcp:[host]:port[,to=maxport][,ipv4][,ipv6][,tls-creds=ID]\n" \
>      "-incoming rdma:host:port[,ipv4][,ipv6]\n" \
>      "-incoming unix:socketpath\n" \
>      "                prepare for incoming migration, listen on\n" \
> @@ -3377,11 +3377,14 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
>      "                wait for the URI to be specified via migrate_incoming\n",
>      QEMU_ARCH_ALL)
>  STEXI
> -@item -incoming tcp:[@var{host}]:@var{port}[,to=@var{maxport}][,ipv4][,ipv6]
> +@item -incoming tcp:[@var{host}]:@var{port}[,to=@var{maxport}][,ipv4][,ipv6][,tls-creds=ID]
>  @itemx -incoming rdma:@var{host}:@var{port}[,ipv4][,ipv6]
>  @findex -incoming
>  Prepare for incoming migration, listen on a given tcp port.
>  
> +If the @var{tls-creds} parameter is specified, it should refer to the ID
> +of a TLS credentials object previously created with @var{-object}.
> +
>  @item -incoming unix:@var{socketpath}
>  Prepare for incoming migration, listen on a given unix socket.
>  
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel
  2016-02-03 13:37     ` Daniel P. Berrange
@ 2016-02-12 17:16       ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-12 17:16 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Tue, Feb 02, 2016 at 05:06:24PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > Introduce a new QEMUFile implementation that is based on
> > > the QIOChannel objects. This impl is different from existing
> > > impls in that there is no file descriptor that can be made
> > > available, as some channels may be based on higher level
> > > protocols such as TLS.
> > > 
> > > Although the QIOChannel based implementation can trivially
> > > provide a bi-directional stream, initially we have separate
> > > functions for opening input & output directions to fit with
> > > the expectation of the current QEMUFile interface.
> > > 
> > > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > > ---
> > >  include/migration/qemu-file.h |   4 +
> > >  migration/Makefile.objs       |   1 +
> > >  migration/qemu-file-channel.c | 201 ++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 206 insertions(+)
> > >  create mode 100644 migration/qemu-file-channel.c
> 
> > > +static ssize_t channel_writev_buffer(void *opaque,
> > > +                                     struct iovec *iov,
> > > +                                     int iovcnt,
> > > +                                     int64_t pos)
> > > +{
> > > +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> > > +    ssize_t done = 0;
> > > +    ssize_t want = iov_size(iov, iovcnt);
> > > +    struct iovec oldiov = { NULL, 0 };
> > > +
> > > +    while (done < want) {
> > > +        ssize_t len;
> > > +        struct iovec *cur = iov;
> > > +        int curcnt = iovcnt;
> > > +
> > > +        channel_skip_iov(done, &cur, &curcnt, &oldiov);
> > > +
> > > +        len = qio_channel_writev(ioc, cur, curcnt, NULL);
> > > +        if (oldiov.iov_base) {
> > > +            /* Restore original caller's info in @iov */
> > > +            cur[0].iov_base = oldiov.iov_base;
> > > +            cur[0].iov_len = oldiov.iov_len;
> > > +            oldiov.iov_base = NULL;
> > > +            oldiov.iov_len = 0;
> > > +        }
> > > +        if (len == QIO_CHANNEL_ERR_BLOCK) {
> > > +            qio_channel_wait(ioc, G_IO_OUT);
> > > +            continue;
> > > +        }
> > > +        if (len < 0) {
> > > +            /* XXX handle Error objects */
> > > +            return -EIO;
> > 
> > It's best to return 'len' rather than lose what little
> > error information you had (similarly below).
> 
> In this case 'len' is in fact just '-1', as all error
> info is in the Error ** parameter, but the QEMUFile API
> contract requires an errno value. So we don't have much
> choice but to return a fixed EIO - returning 'len' would
> also be a fixed errno - whichever errno corresponds to
> the value -1.

Oh, I see - that's a shame that they didn't pass the
error along, but yeh if they're just returning -1 that makes
sense.

> I'd like to switch QEMUFile over to use Error **errp
> parameters for error reporting, so that we can make
> detailed error info available throughout the migration
> I/O code. That ought to wait until after this series
> is done though, to avoid complicating it yet more.

OK, you could use a local_error I guess;  I just worry
about not having any error information at all.

Dave

> 
> > 
> > > +        }
> > > +
> > > +        done += len;
> > > +    }
> > > +    return done;
> > > +}
> > > +
> > > +
> > > +static ssize_t channel_get_buffer(void *opaque,
> > > +                                  uint8_t *buf,
> > > +                                  int64_t pos,
> > > +                                  size_t size)
> > > +{
> > > +    QIOChannel *ioc = QIO_CHANNEL(opaque);
> > > +    ssize_t ret;
> > > +
> > > + reread:
> > > +    ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> > > +    if (ret < 0) {
> > > +        if (ret == QIO_CHANNEL_ERR_BLOCK) {
> > > +            qio_channel_yield(ioc, G_IO_IN);
> > > +            goto reread;
> > > +        } else {
> > > +            /* XXX handle Error * object */
> > > +            return -EIO;
> > > +        }
> > > +    }
> > > +    return ret;
> > 
> > 
> > I'd prefer a loop to a goto; generally the only places we
> > use goto is an error exit.
> > 
> >   do {
> >        ret = qio_channel_read(ioc, (char *)buf, size, NULL);
> >        if (ret == QIO_CHANNEL_ERR_BLOCK) {
> >            qio_channel_yield(ioc, G_IO_IN);
> >        }
> >   } while (ret == QIO_CHANNEL_ERR_BLOCK);
> > 
> >   return ret;
> > 
> > and IMHO the loop is clearer.
> 
> Ok, will change that.
> 
> Regards,
> Daniel
> -- 
> |: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org              -o-             http://virt-manager.org :|
> |: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
> |: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file
  2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
  2016-01-12 11:58   ` Cornelia Huck
@ 2016-02-12 17:19   ` Dr. David Alan Gilbert
  1 sibling, 0 replies; 66+ messages in thread
From: Dr. David Alan Gilbert @ 2016-02-12 17:19 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Amit Shah, qemu-devel, Juan Quintela

* Daniel P. Berrange (berrange@redhat.com) wrote:
> The s390 skeys monitor command needs to write out a plain text
> file. Currently it is using the QEMUFile class for this. There
> is no real benefit to this, and the downside is that it needs to
> snprintf via an intermediate buffer. Switching to regular FILE
> objects simplifies the code.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Dave

> ---
>  hw/s390x/s390-skeys.c | 19 +++++++------------
>  1 file changed, 7 insertions(+), 12 deletions(-)
> 
> diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
> index 539ef6d..637ccf5 100644
> --- a/hw/s390x/s390-skeys.c
> +++ b/hw/s390x/s390-skeys.c
> @@ -45,15 +45,11 @@ void s390_skeys_init(void)
>      qdev_init_nofail(DEVICE(obj));
>  }
>  
> -static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
> +static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn,
>                         uint64_t count, Error **errp)
>  {
>      uint64_t curpage = startgfn;
>      uint64_t maxpage = curpage + count - 1;
> -    const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
> -                      " ch=%d, reserved=%d\n";
> -    char buf[128];
> -    int len;
>  
>      for (; curpage <= maxpage; curpage++) {
>          uint8_t acc = (*keys & 0xF0) >> 4;
> @@ -62,10 +58,9 @@ static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
>          int ch = (*keys & 0x02);
>          int res = (*keys & 0x01);
>  
> -        len = snprintf(buf, sizeof(buf), fmt, curpage,
> -                       *keys, acc, fp, ref, ch, res);
> -        assert(len < sizeof(buf));
> -        qemu_put_buffer(f, (uint8_t *)buf, len);
> +        fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
> +                " ch=%d, reserved=%d\n",
> +                curpage, *keys, acc, fp, ref, ch, res);
>          keys++;
>      }
>  }
> @@ -115,7 +110,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
>      vaddr cur_gfn = 0;
>      uint8_t *buf;
>      int ret;
> -    QEMUFile *f;
> +    FILE *f;
>  
>      /* Quick check to see if guest is using storage keys*/
>      if (!skeyclass->skeys_enabled(ss)) {
> @@ -124,7 +119,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
>          return;
>      }
>  
> -    f = qemu_fopen(filename, "wb");
> +    f = fopen(filename, "wb");
>      if (!f) {
>          error_setg_file_open(errp, errno, filename);
>          return;
> @@ -161,7 +156,7 @@ out_free:
>      error_propagate(errp, lerr);
>      g_free(buf);
>  out:
> -    qemu_fclose(f);
> +    fclose(f);
>  }
>  
>  static void qemu_s390_skeys_init(Object *obj)
> -- 
> 2.5.0
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

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

* Re: [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend
  2016-02-12 17:09   ` Dr. David Alan Gilbert
@ 2016-02-12 17:25     ` Daniel P. Berrange
  2016-02-15 11:00       ` Daniel P. Berrange
  0 siblings, 1 reply; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-12 17:25 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Fri, Feb 12, 2016 at 05:09:52PM +0000, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrange (berrange@redhat.com) wrote:
> > This extends the TCP migration backend so that it can make use
> > of QIOChannelTLS to provide transparent TLS encryption. To
> > trigger enablement the URI on the incoming and outgoing sides
> > should have 'tls-creds=ID' appended, eg
> > 
> >    tcp:$HOST:$PORT,tls-creds=ID
> > 
> > where ID is the object identifier of a set of TLS credentials
> > previously created using object_add / -object. There is not
> > currently any support for checking the migration client
> > certificate names against ACLs. This is pending a conversion
> > of the ACL code to QOM.
> 
> Does that change the option passed or is that just different
> in the way the tls-creds are set up?

It will mean another new paramter will be added. For example
the above command will become something like this:

   tcp:$HOST:$PORT,tls-creds=ID,auth=ID

where 'auth=ID' provides the ID of an object implementing
the authentication/authorization check

> > +typedef struct {
> > +    MigrationState *s;
> > +    QCryptoTLSCreds *tlscreds;
> > +    char *hostname;
> > +} TCPConnectData;
> > +
> > +typedef struct {
> > +    MigrationState *s;
> > +    QCryptoTLSCreds *tlscreds;
> > +} TCPListenData;
> > +
> > +typedef struct {
> > +    MigrationState *s;
> > +    QIOChannel *ioc;
> > +} TCPConnectTLSData;
> > +
> 
> what makes it TCP specific rather than sharing most of this between transports? i.e. should
> this work for fd migration ? (rdma is probably not reasonable
> giving it's scribbling directly in the other hosts RAM).
> Certainly those types dont really look TCP specific.

TLS as a protocol doesn't have any limitations, but as part of having
the client validate the x509 certificates, it needs to have a hostname
or IP address to validate against the certificate. This is available
for TCP and RDMA, but there's no user provided hostname for unix,
exec, and fd migration protocols.

We could extend the syntax for each of those, so that the user could
provide a hostname, and that would then allow us to wire up TLS for
that backend. If we did that, then it would make sense to have the
TLS setup in a separate migration/tls.c file, that we could activate
over all channels.

> > +static QCryptoTLSCreds *tcp_get_tls_creds(const char *host_port,
> > +                                          bool is_listen,
> > +                                          Error **errp)
> > +{
> > +    char *credname = NULL;
> > +    Object *creds;
> > +    QCryptoTLSCreds *ret;
> > +
> > +    credname = tcp_get_opt_str(host_port, "tls-creds");
> > +    if (!credname) {
> > +        return NULL;
> > +    }
> 
> At what point does it get saner just to throw host_port into a qemu_opts 
> and let it parse it?

Possibly quite soon :-)

> > +static void tcp_outgoing_migration_tls(Object *src,
> > +                                       Error *err,
> > +                                       gpointer opaque)
> > +{
> > +    TCPConnectTLSData *data = opaque;
> > +    QIOChannel *ioc = QIO_CHANNEL(src);
> > +
> > +    if (err) {
> > +        DPRINTF("migrate connect TLS error: %s\n", error_get_pretty(err));
> 
> error_report ?

Is it desirable for code triggered from the QMP/HMP monitor to be
doing that. I thought we were not supposed todo that in general.
Normally we could propagate an error back to the monitor, but
since migrate happens in the background, we've no way todo that.
We really need to be able to feed the errors back to the client
app over QMP somehow, but there's no mechanism for that right
now :-(

Perhaps 'info migrate' should have a field to report the actual
error message when status == failed ?  Or we could define an
async event that we emit to the client with the actual error.
Either would make life nicer for libvirt, which can't report
any good errors - this is the main reason libvirt currently
does all TCP connection setup itself and uses fd:, and not
tcp:.  Libvirt will need to use tcp: again though, to get
TLS working, unless we add a 'hostname' field to the 'fd:'
protocol....

> > +        data->s->file = NULL;
> > +        migrate_fd_error(data->s);
> > +    } else {
> > +        DPRINTF("migrate connect success\n");
> 
> trace_

Yep, I mentioned in a repl to a previous review, that I
intend to do a single cleanup patch at the end which
adds some consistent trace points across all the backend
drivers for migrate.

> > +        data->s->file = qemu_fopen_channel_output(ioc);
> > +        migrate_fd_connect(data->s);
> > +    }
> > +}
> > +
> > +
> >  static void tcp_outgoing_migration(Object *src,
> >                                     Error *err,
> >                                     gpointer opaque)
> >  {
> > -    MigrationState *s = opaque;
> > +    TCPConnectData *data = opaque;
> >      QIOChannel *sioc = QIO_CHANNEL(src);
> >  
> >      if (err) {
> >          DPRINTF("migrate connect error: %s\n", error_get_pretty(err));
> > -        s->file = NULL;
> > -        migrate_fd_error(s);
> > +        data->s->file = NULL;
> > +        migrate_fd_error(data->s);
> >      } else {
> > -        DPRINTF("migrate connect success\n");
> > -        s->file = qemu_fopen_channel_output(sioc);
> > -        migrate_fd_connect(s);
> > +        if (data->tlscreds) {
> > +            Error *local_err = NULL;
> > +            QIOChannelTLS *tioc = qio_channel_tls_new_client(
> > +                sioc, data->tlscreds, data->hostname,
> > +                &local_err);
> > +            if (!tioc) {
> > +                DPRINTF("migrate tls setup error: %s\n",
> > +                        error_get_pretty(local_err));
> 
> error_report ?  More below I think - just make sure that
> any errors normally get logged.

Same issue as above.


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend
  2016-02-12 17:25     ` Daniel P. Berrange
@ 2016-02-15 11:00       ` Daniel P. Berrange
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel P. Berrange @ 2016-02-15 11:00 UTC (permalink / raw)
  To: Dr. David Alan Gilbert; +Cc: Amit Shah, qemu-devel, Juan Quintela

On Fri, Feb 12, 2016 at 05:25:31PM +0000, Daniel P. Berrange wrote:
> On Fri, Feb 12, 2016 at 05:09:52PM +0000, Dr. David Alan Gilbert wrote:
> > * Daniel P. Berrange (berrange@redhat.com) wrote:
> > > This extends the TCP migration backend so that it can make use
> > > of QIOChannelTLS to provide transparent TLS encryption. To
> > > trigger enablement the URI on the incoming and outgoing sides
> > > should have 'tls-creds=ID' appended, eg
> > > 
> > >    tcp:$HOST:$PORT,tls-creds=ID
> > > 
> > > where ID is the object identifier of a set of TLS credentials
> > > previously created using object_add / -object. There is not
> > > currently any support for checking the migration client
> > > certificate names against ACLs. This is pending a conversion
> > > of the ACL code to QOM.
> > 
> > Does that change the option passed or is that just different
> > in the way the tls-creds are set up?
> 
> It will mean another new paramter will be added. For example
> the above command will become something like this:
> 
>    tcp:$HOST:$PORT,tls-creds=ID,auth=ID
> 
> where 'auth=ID' provides the ID of an object implementing
> the authentication/authorization check
> 
> > > +typedef struct {
> > > +    MigrationState *s;
> > > +    QCryptoTLSCreds *tlscreds;
> > > +    char *hostname;
> > > +} TCPConnectData;
> > > +
> > > +typedef struct {
> > > +    MigrationState *s;
> > > +    QCryptoTLSCreds *tlscreds;
> > > +} TCPListenData;
> > > +
> > > +typedef struct {
> > > +    MigrationState *s;
> > > +    QIOChannel *ioc;
> > > +} TCPConnectTLSData;
> > > +
> > 
> > what makes it TCP specific rather than sharing most of this between transports? i.e. should
> > this work for fd migration ? (rdma is probably not reasonable
> > giving it's scribbling directly in the other hosts RAM).
> > Certainly those types dont really look TCP specific.
> 
> TLS as a protocol doesn't have any limitations, but as part of having
> the client validate the x509 certificates, it needs to have a hostname
> or IP address to validate against the certificate. This is available
> for TCP and RDMA, but there's no user provided hostname for unix,
> exec, and fd migration protocols.
> 
> We could extend the syntax for each of those, so that the user could
> provide a hostname, and that would then allow us to wire up TLS for
> that backend. If we did that, then it would make sense to have the
> TLS setup in a separate migration/tls.c file, that we could activate
> over all channels.
> 
> > > +static QCryptoTLSCreds *tcp_get_tls_creds(const char *host_port,
> > > +                                          bool is_listen,
> > > +                                          Error **errp)
> > > +{
> > > +    char *credname = NULL;
> > > +    Object *creds;
> > > +    QCryptoTLSCreds *ret;
> > > +
> > > +    credname = tcp_get_opt_str(host_port, "tls-creds");
> > > +    if (!credname) {
> > > +        return NULL;
> > > +    }
> > 
> > At what point does it get saner just to throw host_port into a qemu_opts 
> > and let it parse it?
> 
> Possibly quite soon :-)

So, having thought about this some more, I think rather than munging
parameters onto the end of the URI, it'll make more sense to use the
'migrate-set-parameters' QMP call ie. to enable use of tls

  migrate-set-parameters tls-creds=tls0

and then to deal with the problem I mention above about not having a
hostname available for fd/exec migration, we can also allow

  migrate-set-parameters tls-hostname=peerhostname

which would set the hostname to be used to validate the x509 certificate.
This would be quite nice for libvirt, since we can carry on using the
fd: migration and establish the connection ourselves, while letting QEMU
do the x509 validation.

This would in turn motivate moving of the TLS IO Channel creation into
a separate file, instead of having it inline in tcp.c. This would in
turn let me address the feedback you had previous about possibility of
unix: and tcp: code being dealt with in the same file to avoid the
code duplication.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

end of thread, other threads:[~2016-02-15 11:00 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-12 11:43 [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 01/22] s390: use FILE instead of QEMUFile for creating text file Daniel P. Berrange
2016-01-12 11:58   ` Cornelia Huck
2016-01-12 12:01     ` Daniel P. Berrange
2016-01-12 12:05       ` Cornelia Huck
2016-02-12 17:19   ` Dr. David Alan Gilbert
2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 02/22] migration: remove use of qemu_bufopen from vmstate tests Daniel P. Berrange
2016-01-28 17:45   ` Dr. David Alan Gilbert
2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 03/22] migration: ensure qemu_fflush() always writes full data amount Daniel P. Berrange
2016-01-28 17:53   ` Dr. David Alan Gilbert
2016-02-03 13:31     ` Daniel P. Berrange
2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 04/22] migration: split migration hooks out of QEMUFileOps Daniel P. Berrange
2016-01-28 17:57   ` Dr. David Alan Gilbert
2016-01-12 11:43 ` [Qemu-devel] [PATCH v1 05/22] migration: introduce set_blocking function in QEMUFileOps Daniel P. Berrange
2016-01-28 18:00   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 06/22] migration: force QEMUFile to blocking mode for outgoing migration Daniel P. Berrange
2016-01-28 18:17   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 07/22] migration: introduce a new QEMUFile impl based on QIOChannel Daniel P. Berrange
2016-02-02 17:06   ` Dr. David Alan Gilbert
2016-02-03 13:37     ` Daniel P. Berrange
2016-02-12 17:16       ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 08/22] migration: convert post-copy to use QIOChannelBuffer Daniel P. Berrange
2016-01-25 19:38   ` Dr. David Alan Gilbert
2016-01-25 22:15     ` Daniel P. Berrange
2016-01-26 18:59       ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 09/22] migration: convert unix socket protocol to use QIOChannel Daniel P. Berrange
2016-02-02 18:02   ` Dr. David Alan Gilbert
2016-02-03 11:25     ` Daniel P. Berrange
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 10/22] migration: convert tcp " Daniel P. Berrange
2016-02-02 18:19   ` Dr. David Alan Gilbert
2016-02-03 10:02     ` Daniel P. Berrange
2016-02-03 10:33       ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 11/22] migration: convert fd " Daniel P. Berrange
2016-02-02 18:46   ` Dr. David Alan Gilbert
2016-02-03 10:05     ` Daniel P. Berrange
2016-02-03 10:29       ` Dr. David Alan Gilbert
2016-02-03 10:39         ` Daniel P. Berrange
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 12/22] migration: convert exec " Daniel P. Berrange
2016-02-02 18:53   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 13/22] migration: convert RDMA to use QIOChannel interface Daniel P. Berrange
2016-02-02 20:01   ` Dr. David Alan Gilbert
2016-02-03 11:37     ` Daniel P. Berrange
2016-02-03 13:23       ` Dr. David Alan Gilbert
2016-02-03 13:25         ` Daniel P. Berrange
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 14/22] migration: convert savevm to use QIOChannel for writing to files Daniel P. Berrange
2016-02-03  9:52   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 15/22] migration: delete QEMUFile buffer implementation Daniel P. Berrange
2016-02-03  9:54   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 16/22] migration: delete QEMUSizedBuffer struct Daniel P. Berrange
2016-02-03  9:55   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 17/22] migration: delete QEMUFile sockets implementation Daniel P. Berrange
2016-02-03  9:56   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 18/22] migration: delete QEMUFile stdio implementation Daniel P. Berrange
2016-02-03  9:58   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 19/22] migration: move definition of struct QEMUFile back into qemu-file.c Daniel P. Berrange
2016-02-05 18:32   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 20/22] migration: support TLS encryption with TCP migration backend Daniel P. Berrange
2016-02-12 17:09   ` Dr. David Alan Gilbert
2016-02-12 17:25     ` Daniel P. Berrange
2016-02-15 11:00       ` Daniel P. Berrange
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 21/22] migration: remove support for non-iovec based write handlers Daniel P. Berrange
2016-02-12 15:48   ` Dr. David Alan Gilbert
2016-01-12 11:44 ` [Qemu-devel] [PATCH v1 22/22] migration: remove qemu_get_fd method from QEMUFile Daniel P. Berrange
2016-02-12 15:51   ` Dr. David Alan Gilbert
2016-01-12 11:59 ` [Qemu-devel] [PATCH v1 00/22] Convert migration to QIOChannel & support TLS Daniel P. Berrange
2016-01-20 18:01 ` Daniel P. Berrange

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.