All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Migration via unix sockets.
@ 2009-08-05 15:24 Chris Lalancette
  2009-08-10 10:23 ` Chris Lalancette
  0 siblings, 1 reply; 11+ messages in thread
From: Chris Lalancette @ 2009-08-05 15:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Chris Lalancette

Implement migration via unix sockets.  While you can fake this using
exec and netcat, this involves forking another process and is
generally not very nice.  By doing this directly in qemu, we can avoid
the copy through the external nc command.  This is useful for
implementations (such as libvirt) that want to do "secure" migration;
we pipe the data on the sending side into the unix socket, libvirt
picks it up, encrypts it, and transports it, and then on the remote
side libvirt decrypts it, dumps it to another unix socket, and
feeds it into qemu.

The implementation is straightforward and looks very similar to
migration-exec.c and migration-tcp.c

Signed-off-by: Chris Lalancette <clalance@redhat.com>
---
 Makefile         |    2 +-
 migration-unix.c |  216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 migration.c      |    4 +
 migration.h      |    6 ++
 4 files changed, 227 insertions(+), 1 deletions(-)
 create mode 100644 migration-unix.c

diff --git a/Makefile b/Makefile
index d3f999e..c5763b7 100644
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ obj-$(CONFIG_BRLAPI) += baum.o
 LIBS+=$(BRLAPI_LIBS)
 
 obj-$(CONFIG_WIN32) += tap-win32.o
-obj-$(CONFIG_POSIX) += migration-exec.o
+obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o
 
 ifdef CONFIG_COREAUDIO
 AUDIO_PT = y
diff --git a/migration-unix.c b/migration-unix.c
new file mode 100644
index 0000000..a26587a
--- /dev/null
+++ b/migration-unix.c
@@ -0,0 +1,216 @@
+/*
+ * QEMU live migration via Unix Domain Sockets
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_UNIX
+
+#ifdef DEBUG_MIGRATION_UNIX
+#define dprintf(fmt, ...) \
+    do { printf("migration-unix: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int unix_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int unix_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int unix_close(FdMigrationState *s)
+{
+    dprintf("unix_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+static void unix_wait_for_connect(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int val, ret;
+    socklen_t valsize = sizeof(val);
+
+    dprintf("connect completed\n");
+    do {
+        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret < 0) {
+        migrate_fd_error(s);
+        return;
+    }
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (val == 0)
+        migrate_fd_connect(s);
+    else {
+        dprintf("error connecting %d\n", val);
+        migrate_fd_error(s);
+    }
+}
+
+MigrationState *unix_start_outgoing_migration(const char *path,
+					      int64_t bandwidth_limit,
+					      int detach)
+{
+    FdMigrationState *s;
+    struct sockaddr_un addr;
+    int ret;
+
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->get_error = unix_errno;
+    s->write = unix_write;
+    s->close = unix_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (s->fd < 0) {
+        dprintf("Unable to open socket");
+        goto err_after_alloc;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    do {
+        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
+        if (ret == -1)
+	    ret = -(s->get_error(s));
+
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+	    qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+    } while (ret == -EINTR);
+
+    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+        dprintf("connect failed\n");
+        goto err_after_open;
+    } else if (ret >= 0)
+        migrate_fd_connect(s);
+
+    return &s->mig_state;
+
+err_after_open:
+    close(s->fd);
+
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void unix_accept_incoming_migration(void *opaque)
+{
+    struct sockaddr_un addr;
+    socklen_t addrlen = sizeof(addr);
+    int s = (unsigned long)opaque;
+    QEMUFile *f;
+    int c, ret;
+
+    do {
+        c = accept(s, (struct sockaddr *)&addr, &addrlen);
+    } while (c == -1 && socket_error() == EINTR);
+
+    dprintf("accepted migration\n");
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        return;
+    }
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto out_fopen;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+
+    /* we've successfully migrated, close the server socket */
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    close(s);
+
+out_fopen:
+    qemu_fclose(f);
+out:
+    close(c);
+}
+
+int unix_start_incoming_migration(const char *path)
+{
+    struct sockaddr_un un;
+    int sock;
+
+    dprintf("Attempting to start an incoming migration\n");
+
+    sock = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
+        return -EINVAL;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+
+    unlink(un.sun_path);
+    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+    if (listen(sock, 1) < 0) {
+        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+
+    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
+			 (void *)(unsigned long)sock);
+
+    return 0;
+
+err:
+    close(sock);
+
+    return -EINVAL;
+}
diff --git a/migration.c b/migration.c
index ee64d41..34e2bc1 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,8 @@ void qemu_start_incoming_migration(const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         exec_start_incoming_migration(p);
+    else if (strstart(uri, "unix:", &p))
+        unix_start_incoming_migration(p);
 #endif
     else
         fprintf(stderr, "unknown migration protocol: %s\n", uri);
@@ -58,6 +60,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         s = exec_start_outgoing_migration(p, max_throttle, detach);
+    else if (strstart(uri, "unix:", &p))
+        s = unix_start_outgoing_migration(p, max_throttle, detach);
 #endif
     else
         monitor_printf(mon, "unknown migration protocol: %s\n", uri);
diff --git a/migration.h b/migration.h
index 37c7f8e..0ed1fcb 100644
--- a/migration.h
+++ b/migration.h
@@ -73,6 +73,12 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
 					     int64_t bandwidth_limit,
 					     int detach);
 
+int unix_start_incoming_migration(const char *path);
+
+MigrationState *unix_start_outgoing_migration(const char *path,
+					      int64_t bandwidth_limit,
+					      int detach);
+
 void migrate_fd_monitor_suspend(FdMigrationState *s);
 
 void migrate_fd_error(FdMigrationState *s);
-- 
1.6.0.6

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

* Re: [Qemu-devel] [PATCH] Migration via unix sockets.
  2009-08-05 15:24 [Qemu-devel] [PATCH] Migration via unix sockets Chris Lalancette
@ 2009-08-10 10:23 ` Chris Lalancette
  2009-08-10 11:34   ` Avi Kivity
  0 siblings, 1 reply; 11+ messages in thread
From: Chris Lalancette @ 2009-08-10 10:23 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

Chris Lalancette wrote:
> Implement migration via unix sockets.  While you can fake this using
> exec and netcat, this involves forking another process and is
> generally not very nice.  By doing this directly in qemu, we can avoid
> the copy through the external nc command.  This is useful for
> implementations (such as libvirt) that want to do "secure" migration;
> we pipe the data on the sending side into the unix socket, libvirt
> picks it up, encrypts it, and transports it, and then on the remote
> side libvirt decrypts it, dumps it to another unix socket, and
> feeds it into qemu.
> 
> The implementation is straightforward and looks very similar to
> migration-exec.c and migration-tcp.c

ping?

> 
> Signed-off-by: Chris Lalancette <clalance@redhat.com>
> ---
>  Makefile         |    2 +-
>  migration-unix.c |  216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  migration.c      |    4 +
>  migration.h      |    6 ++
>  4 files changed, 227 insertions(+), 1 deletions(-)
>  create mode 100644 migration-unix.c
> 
> diff --git a/Makefile b/Makefile
> index d3f999e..c5763b7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -110,7 +110,7 @@ obj-$(CONFIG_BRLAPI) += baum.o
>  LIBS+=$(BRLAPI_LIBS)
>  
>  obj-$(CONFIG_WIN32) += tap-win32.o
> -obj-$(CONFIG_POSIX) += migration-exec.o
> +obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o
>  
>  ifdef CONFIG_COREAUDIO
>  AUDIO_PT = y
> diff --git a/migration-unix.c b/migration-unix.c
> new file mode 100644
> index 0000000..a26587a
> --- /dev/null
> +++ b/migration-unix.c
> @@ -0,0 +1,216 @@
> +/*
> + * QEMU live migration via Unix Domain Sockets
> + *
> + * Copyright Red Hat, Inc. 2009
> + *
> + * Authors:
> + *  Chris Lalancette <clalance@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu-common.h"
> +#include "qemu_socket.h"
> +#include "migration.h"
> +#include "qemu-char.h"
> +#include "sysemu.h"
> +#include "buffered_file.h"
> +#include "block.h"
> +
> +//#define DEBUG_MIGRATION_UNIX
> +
> +#ifdef DEBUG_MIGRATION_UNIX
> +#define dprintf(fmt, ...) \
> +    do { printf("migration-unix: " fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define dprintf(fmt, ...) \
> +    do { } while (0)
> +#endif
> +
> +static int unix_errno(FdMigrationState *s)
> +{
> +    return errno;
> +}
> +
> +static int unix_write(FdMigrationState *s, const void * buf, size_t size)
> +{
> +    return write(s->fd, buf, size);
> +}
> +
> +static int unix_close(FdMigrationState *s)
> +{
> +    dprintf("unix_close\n");
> +    if (s->fd != -1) {
> +        close(s->fd);
> +        s->fd = -1;
> +    }
> +    return 0;
> +}
> +
> +static void unix_wait_for_connect(void *opaque)
> +{
> +    FdMigrationState *s = opaque;
> +    int val, ret;
> +    socklen_t valsize = sizeof(val);
> +
> +    dprintf("connect completed\n");
> +    do {
> +        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
> +    } while (ret == -1 && (s->get_error(s)) == EINTR);
> +
> +    if (ret < 0) {
> +        migrate_fd_error(s);
> +        return;
> +    }
> +
> +    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
> +
> +    if (val == 0)
> +        migrate_fd_connect(s);
> +    else {
> +        dprintf("error connecting %d\n", val);
> +        migrate_fd_error(s);
> +    }
> +}
> +
> +MigrationState *unix_start_outgoing_migration(const char *path,
> +					      int64_t bandwidth_limit,
> +					      int detach)
> +{
> +    FdMigrationState *s;
> +    struct sockaddr_un addr;
> +    int ret;
> +
> +    addr.sun_family = AF_UNIX;
> +    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
> +
> +    s = qemu_mallocz(sizeof(*s));
> +
> +    s->get_error = unix_errno;
> +    s->write = unix_write;
> +    s->close = unix_close;
> +    s->mig_state.cancel = migrate_fd_cancel;
> +    s->mig_state.get_status = migrate_fd_get_status;
> +    s->mig_state.release = migrate_fd_release;
> +
> +    s->state = MIG_STATE_ACTIVE;
> +    s->mon_resume = NULL;
> +    s->bandwidth_limit = bandwidth_limit;
> +    s->fd = socket(PF_UNIX, SOCK_STREAM, 0);
> +    if (s->fd < 0) {
> +        dprintf("Unable to open socket");
> +        goto err_after_alloc;
> +    }
> +
> +    socket_set_nonblock(s->fd);
> +
> +    if (!detach)
> +        migrate_fd_monitor_suspend(s);
> +
> +    do {
> +        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
> +        if (ret == -1)
> +	    ret = -(s->get_error(s));
> +
> +        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
> +	    qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
> +    } while (ret == -EINTR);
> +
> +    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
> +        dprintf("connect failed\n");
> +        goto err_after_open;
> +    } else if (ret >= 0)
> +        migrate_fd_connect(s);
> +
> +    return &s->mig_state;
> +
> +err_after_open:
> +    close(s->fd);
> +
> +err_after_alloc:
> +    qemu_free(s);
> +    return NULL;
> +}
> +
> +static void unix_accept_incoming_migration(void *opaque)
> +{
> +    struct sockaddr_un addr;
> +    socklen_t addrlen = sizeof(addr);
> +    int s = (unsigned long)opaque;
> +    QEMUFile *f;
> +    int c, ret;
> +
> +    do {
> +        c = accept(s, (struct sockaddr *)&addr, &addrlen);
> +    } while (c == -1 && socket_error() == EINTR);
> +
> +    dprintf("accepted migration\n");
> +
> +    if (c == -1) {
> +        fprintf(stderr, "could not accept migration connection\n");
> +        return;
> +    }
> +
> +    f = qemu_fopen_socket(c);
> +    if (f == NULL) {
> +        fprintf(stderr, "could not qemu_fopen socket\n");
> +        goto out;
> +    }
> +
> +    ret = qemu_loadvm_state(f);
> +    if (ret < 0) {
> +        fprintf(stderr, "load of migration failed\n");
> +        goto out_fopen;
> +    }
> +    qemu_announce_self();
> +    dprintf("successfully loaded vm state\n");
> +
> +    /* we've successfully migrated, close the server socket */
> +    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
> +    close(s);
> +
> +out_fopen:
> +    qemu_fclose(f);
> +out:
> +    close(c);
> +}
> +
> +int unix_start_incoming_migration(const char *path)
> +{
> +    struct sockaddr_un un;
> +    int sock;
> +
> +    dprintf("Attempting to start an incoming migration\n");
> +
> +    sock = socket(PF_UNIX, SOCK_STREAM, 0);
> +    if (sock < 0) {
> +        fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
> +        return -EINVAL;
> +    }
> +
> +    memset(&un, 0, sizeof(un));
> +    un.sun_family = AF_UNIX;
> +    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
> +
> +    unlink(un.sun_path);
> +    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
> +        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
> +        goto err;
> +    }
> +    if (listen(sock, 1) < 0) {
> +        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
> +        goto err;
> +    }
> +
> +    qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
> +			 (void *)(unsigned long)sock);
> +
> +    return 0;
> +
> +err:
> +    close(sock);
> +
> +    return -EINVAL;
> +}
> diff --git a/migration.c b/migration.c
> index ee64d41..34e2bc1 100644
> --- a/migration.c
> +++ b/migration.c
> @@ -43,6 +43,8 @@ void qemu_start_incoming_migration(const char *uri)
>  #if !defined(WIN32)
>      else if (strstart(uri, "exec:", &p))
>          exec_start_incoming_migration(p);
> +    else if (strstart(uri, "unix:", &p))
> +        unix_start_incoming_migration(p);
>  #endif
>      else
>          fprintf(stderr, "unknown migration protocol: %s\n", uri);
> @@ -58,6 +60,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
>  #if !defined(WIN32)
>      else if (strstart(uri, "exec:", &p))
>          s = exec_start_outgoing_migration(p, max_throttle, detach);
> +    else if (strstart(uri, "unix:", &p))
> +        s = unix_start_outgoing_migration(p, max_throttle, detach);
>  #endif
>      else
>          monitor_printf(mon, "unknown migration protocol: %s\n", uri);
> diff --git a/migration.h b/migration.h
> index 37c7f8e..0ed1fcb 100644
> --- a/migration.h
> +++ b/migration.h
> @@ -73,6 +73,12 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
>  					     int64_t bandwidth_limit,
>  					     int detach);
>  
> +int unix_start_incoming_migration(const char *path);
> +
> +MigrationState *unix_start_outgoing_migration(const char *path,
> +					      int64_t bandwidth_limit,
> +					      int detach);
> +
>  void migrate_fd_monitor_suspend(FdMigrationState *s);
>  
>  void migrate_fd_error(FdMigrationState *s);


-- 
Chris Lalancette

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

* Re: [Qemu-devel] [PATCH] Migration via unix sockets.
  2009-08-10 10:23 ` Chris Lalancette
@ 2009-08-10 11:34   ` Avi Kivity
  2009-08-11  9:15     ` Chris Lalancette
  0 siblings, 1 reply; 11+ messages in thread
From: Avi Kivity @ 2009-08-10 11:34 UTC (permalink / raw)
  To: Chris Lalancette; +Cc: qemu-devel

On 08/10/2009 01:23 PM, Chris Lalancette wrote:
> Chris Lalancette wrote:
>    
>> Implement migration via unix sockets.  While you can fake this using
>> exec and netcat, this involves forking another process and is
>> generally not very nice.  By doing this directly in qemu, we can avoid
>> the copy through the external nc command.  This is useful for
>> implementations (such as libvirt) that want to do "secure" migration;
>> we pipe the data on the sending side into the unix socket, libvirt
>> picks it up, encrypts it, and transports it, and then on the remote
>> side libvirt decrypts it, dumps it to another unix socket, and
>> feeds it into qemu.
>>
>> The implementation is straightforward and looks very similar to
>> migration-exec.c and migration-tcp.c
>>      
>
> ping?
>    

It would be nice to support migration via arbitrary fd using the recent 
SCM_RIGHTS support.

-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH] Migration via unix sockets.
  2009-08-10 11:34   ` Avi Kivity
@ 2009-08-11  9:15     ` Chris Lalancette
  2009-08-11  9:35       ` Avi Kivity
                         ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Chris Lalancette @ 2009-08-11  9:15 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1927 bytes --]

Avi Kivity wrote:
> On 08/10/2009 01:23 PM, Chris Lalancette wrote:
>> Chris Lalancette wrote:
>>    
>>> Implement migration via unix sockets.  While you can fake this using
>>> exec and netcat, this involves forking another process and is
>>> generally not very nice.  By doing this directly in qemu, we can avoid
>>> the copy through the external nc command.  This is useful for
>>> implementations (such as libvirt) that want to do "secure" migration;
>>> we pipe the data on the sending side into the unix socket, libvirt
>>> picks it up, encrypts it, and transports it, and then on the remote
>>> side libvirt decrypts it, dumps it to another unix socket, and
>>> feeds it into qemu.
>>>
>>> The implementation is straightforward and looks very similar to
>>> migration-exec.c and migration-tcp.c
>>>      
>> ping?
>>    
> 
> It would be nice to support migration via arbitrary fd using the recent 
> SCM_RIGHTS support.

A possible implementation of that is attached.  I have to say, though, that it
is way more clumsy to use than the unix implementation I posted earlier.  On the
outgoing side, you have to use the "getfd" monitor command to pass the fd using
SCM_RIGHTS, then you have to issue another monitor command to start the migration:

(qemu) getfd migration # passes opened fd via SCM_RIGHTS
(qemu) migrate -d fd:migration

On the incoming side, you have to pass the fd via the command-line.  That means
that you have to first arrange for it not to be closed on exec, and it also
means that qemu is now depending on the external program to correctly set up the
incoming socket so that qemu can just do the accept() on it.

None of these problems are insurmountable, but they do make it cumbersome to use
in general, and very difficult to use from the command-line.

The other option is that I've misunderstood your intent, and if that is the
case, please correct me where I'm wrong :).

-- 
Chris Lalancette

[-- Attachment #2: qemu-migration-fd.patch --]
[-- Type: text/x-patch, Size: 5054 bytes --]

diff --git a/Makefile b/Makefile
index c5763b7..a8cd0c9 100644
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ obj-$(CONFIG_BRLAPI) += baum.o
 LIBS+=$(BRLAPI_LIBS)
 
 obj-$(CONFIG_WIN32) += tap-win32.o
-obj-$(CONFIG_POSIX) += migration-exec.o
+obj-$(CONFIG_POSIX) += migration-exec.o migration-fd.o
 
 ifdef CONFIG_COREAUDIO
 AUDIO_PT = y
diff --git a/migration-fd.c b/migration-fd.c
new file mode 100644
index 0000000..fea5a43
--- /dev/null
+++ b/migration-fd.c
@@ -0,0 +1,146 @@
+/*
+ * QEMU live migration via generic fd
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "monitor.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION_FD
+
+#ifdef DEBUG_MIGRATION_FD
+#define dprintf(fmt, ...) \
+    do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int fd_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int fd_close(FdMigrationState *s)
+{
+    dprintf("fd_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach)
+{
+    FdMigrationState *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->fd = monitor_get_fd(mon, fdname);
+    if (s->fd == -1) {
+        dprintf("fd_migration: no file descriptor supplied via SCM_RIGHTS\n");
+	qemu_free(s);
+        return NULL;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    s->get_error = fd_errno;
+    s->write = fd_write;
+    s->close = fd_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    migrate_fd_connect(s);
+
+    return &s->mig_state;
+}
+
+static void fd_accept_incoming_migration(void *opaque)
+{
+    struct sockaddr addr;
+    socklen_t addrlen = sizeof(addr);
+    int s = (unsigned long)opaque;
+    QEMUFile *f;
+    int c, ret;
+
+    do {
+        c = accept(s, &addr, &addrlen);
+    } while (c == -1 && socket_error() == EINTR);
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        return;
+    }
+
+    dprintf("accepted migration\n");
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto out_fopen;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+
+    /* we've successfully migrated, close the server socket */
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    close(s);
+
+out_fopen:
+    qemu_fclose(f);
+out:
+    close(c);
+}
+
+int fd_start_incoming_migration(const char *infd)
+{
+    int fd;
+
+    dprintf("Attempting to start an fd incoming migration\n");
+
+    fd = strtol(infd, NULL, 0);
+
+    qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL,
+			 (void *)(unsigned long)fd);
+
+    return 0;
+}
diff --git a/migration.c b/migration.c
index 34e2bc1..c18d595 100644
--- a/migration.c
+++ b/migration.c
@@ -45,4 +45,6 @@ void qemu_start_incoming_migration(const char *uri)
         exec_start_incoming_migration(p);
+    else if (strstart(uri, "fd:", &p))
+        fd_start_incoming_migration(p);
 #endif
     else
         fprintf(stderr, "unknown migration protocol: %s\n", uri);
@@ -62,4 +64,6 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
         s = exec_start_outgoing_migration(p, max_throttle, detach);
+    else if (strstart(uri, "fd:", &p))
+        s = fd_start_outgoing_migration(mon, p, max_throttle, detach);
 #endif
     else
         monitor_printf(mon, "unknown migration protocol: %s\n", uri);
diff --git a/migration.h b/migration.h
index 0ed1fcb..96dad38 100644
--- a/migration.h
+++ b/migration.h
@@ -79,6 +79,13 @@ MigrationState *unix_start_outgoing_migration(const char *path,
 					      int64_t bandwidth_limit,
 					      int detach);
 
+int fd_start_incoming_migration(const char *path);
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach);
+
 void migrate_fd_monitor_suspend(FdMigrationState *s);
 
 void migrate_fd_error(FdMigrationState *s);

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

* Re: [Qemu-devel] [PATCH] Migration via unix sockets.
  2009-08-11  9:15     ` Chris Lalancette
@ 2009-08-11  9:35       ` Avi Kivity
  2009-08-11  9:44       ` [Qemu-devel] " Paolo Bonzini
  2009-08-11 10:20       ` [Qemu-devel] [PATCH] Migration via unix sockets Daniel P. Berrange
  2 siblings, 0 replies; 11+ messages in thread
From: Avi Kivity @ 2009-08-11  9:35 UTC (permalink / raw)
  To: Chris Lalancette; +Cc: qemu-devel

On 08/11/2009 12:15 PM, Chris Lalancette wrote:
> A possible implementation of that is attached.  I have to say, though, that it
> is way more clumsy to use than the unix implementation I posted earlier.  On the
> outgoing side, you have to use the "getfd" monitor command to pass the fd using
> SCM_RIGHTS, then you have to issue another monitor command to start the migration:
>
> (qemu) getfd migration # passes opened fd via SCM_RIGHTS
> (qemu) migrate -d fd:migration
>    

That doesn't seem so bad, especially if you're a program.

> On the incoming side, you have to pass the fd via the command-line.  That means
> that you have to first arrange for it not to be closed on exec, and it also
> means that qemu is now depending on the external program to correctly set up the
> incoming socket so that qemu can just do the accept() on it.
>
>    

I'd like to see a qemu monitor incoming migration command.

> None of these problems are insurmountable, but they do make it cumbersome to use
> in general, and very difficult to use from the command-line.
>    

These are intended for qemu control programs, not humans.

> The other option is that I've misunderstood your intent, and if that is the
> case, please correct me where I'm wrong :).
>    

No, I think you got it.

-- 
error compiling committee.c: too many arguments to function

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

* [Qemu-devel] Re: [PATCH] Migration via unix sockets.
  2009-08-11  9:15     ` Chris Lalancette
  2009-08-11  9:35       ` Avi Kivity
@ 2009-08-11  9:44       ` Paolo Bonzini
  2009-08-11 10:06         ` Avi Kivity
  2009-08-11 10:20       ` [Qemu-devel] [PATCH] Migration via unix sockets Daniel P. Berrange
  2 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2009-08-11  9:44 UTC (permalink / raw)
  To: Chris Lalancette; +Cc: Avi Kivity, qemu-devel

 > That means that you have to first arrange for it not to be closed on
 > exec, and it also means that qemu is now depending on the external
 > program to correctly set up the incoming socket so that qemu can just
 > do the accept() on it.

At this point, I wonder if it isn't better to move the accept to the 
external program, so that it could even use a pipe.  The accept can be 
replaced by

struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
poll (&pfd, 1, INFTIM);
if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL))
   handle_error ();

or the equivalent using select.

Paolo

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

* [Qemu-devel] Re: [PATCH] Migration via unix sockets.
  2009-08-11  9:44       ` [Qemu-devel] " Paolo Bonzini
@ 2009-08-11 10:06         ` Avi Kivity
  2009-08-12 12:20           ` [Qemu-devel] [PATCH] add file descriptor migration Paolo Bonzini
  0 siblings, 1 reply; 11+ messages in thread
From: Avi Kivity @ 2009-08-11 10:06 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Chris Lalancette, qemu-devel

On 08/11/2009 12:44 PM, Paolo Bonzini wrote:
> > That means that you have to first arrange for it not to be closed on
> > exec, and it also means that qemu is now depending on the external
> > program to correctly set up the incoming socket so that qemu can just
> > do the accept() on it.
>
> At this point, I wonder if it isn't better to move the accept to the 
> external program, so that it could even use a pipe.  The accept can be 
> replaced by
>
> struct pollfd pfd;
> pfd.fd = fd;
> pfd.events = POLLIN;
> poll (&pfd, 1, INFTIM);
> if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL))
>   handle_error ();
>
> or the equivalent using select.

Yes, arbitrary fd definitely needs to skip accept().

-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH] Migration via unix sockets.
  2009-08-11  9:15     ` Chris Lalancette
  2009-08-11  9:35       ` Avi Kivity
  2009-08-11  9:44       ` [Qemu-devel] " Paolo Bonzini
@ 2009-08-11 10:20       ` Daniel P. Berrange
  2 siblings, 0 replies; 11+ messages in thread
From: Daniel P. Berrange @ 2009-08-11 10:20 UTC (permalink / raw)
  To: Chris Lalancette; +Cc: Avi Kivity, qemu-devel

On Tue, Aug 11, 2009 at 11:15:59AM +0200, Chris Lalancette wrote:
> +static void fd_accept_incoming_migration(void *opaque)
> +{
> +    struct sockaddr addr;
> +    socklen_t addrlen = sizeof(addr);
> +    int s = (unsigned long)opaque;
> +    QEMUFile *f;
> +    int c, ret;
> +
> +    do {
> +        c = accept(s, &addr, &addrlen);
> +    } while (c == -1 && socket_error() == EINTR);

This bit doesn't make sense if we're just passing an open FD, since
it may not be a socket. Just declare that if passing a socket FD,
the FD must be a pre-accepted client, and remove this line.

Regards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

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

* [Qemu-devel] [PATCH] add file descriptor migration
  2009-08-11 10:06         ` Avi Kivity
@ 2009-08-12 12:20           ` Paolo Bonzini
  2009-08-18 13:56             ` [Qemu-devel] [PATCH v2] " Paolo Bonzini
  0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2009-08-12 12:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Chris Lalancette, Avi Kivity

This is the patch from Chris, with the accept removed and rebased above 
my previous cleanup.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Chris Lalancette <clalance@redhat.com>
Cc: Avi Kivity <avi@redhat.com>
---
 Makefile       |    2 +-
 hw/hw.h        |    1 +
 migration-fd.c |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 migration.c    |    4 ++
 migration.h    |    7 +++
 savevm.c       |   28 +++++++++++
 6 files changed, 178 insertions(+), 1 deletions(-)
 create mode 100644 migration-fd.c

diff --git a/Makefile b/Makefile
index 5279504..c7ff0be 100644
--- a/Makefile
+++ b/Makefile
@@ -93,7 +93,7 @@ obj-y += qdev.o qdev-properties.o ssi.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
 obj-$(CONFIG_WIN32) += tap-win32.o
-obj-$(CONFIG_POSIX) += migration-exec.o
+obj-$(CONFIG_POSIX) += migration-exec.o migration-fd.o
 
 audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
diff --git a/hw/hw.h b/hw/hw.h
index 322f077..91bf800 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -49,6 +49,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
                          QEMUFileRateLimit *rate_limit,
                          QEMUFileSetRateLimit *set_rate_limit);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd);
 QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
diff --git a/migration-fd.c b/migration-fd.c
new file mode 100644
index 0000000..794c2ac
--- /dev/null
+++ b/migration-fd.c
@@ -0,0 +1,137 @@
+/*
+ * QEMU live migration via generic fd
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "monitor.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION_FD
+
+#ifdef DEBUG_MIGRATION_FD
+#define dprintf(fmt, ...) \
+    do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int fd_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int fd_close(FdMigrationState *s)
+{
+    dprintf("fd_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach)
+{
+    FdMigrationState *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->fd = monitor_get_fd(mon, fdname);
+    if (s->fd == -1) {
+        dprintf("fd_migration: invalid file descriptor identifier\n");
+        goto err_after_alloc;
+    }
+
+    if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) {
+        dprintf("Unable to set nonblocking mode on file descriptor\n");
+        goto err_after_open;
+    }
+
+    s->get_error = fd_errno;
+    s->write = fd_write;
+    s->close = fd_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    migrate_fd_connect(s);
+    return &s->mig_state;
+
+err_after_open:
+    close(s->fd);
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void fd_accept_incoming_migration(void *opaque)
+{
+    QEMUFile *f = opaque;
+    int ret;
+
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto err;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+    /* we've successfully migrated, close the fd */
+    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    if (autostart)
+        vm_start();
+
+err:
+    qemu_fclose(f);
+}
+
+int fd_start_incoming_migration(const char *infd)
+{
+    int fd;
+    QEMUFile *f;
+
+    dprintf("Attempting to start an incoming migration via fd\n");
+
+    fd = strtol(infd, NULL, 0);
+    f = qemu_fdopen(fd, "rb");
+    if(f == NULL) {
+        dprintf("Unable to apply qemu wrapper to file descriptor\n");
+        return -errno;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL,
+			 (void *)(unsigned long)f);
+
+    return 0;
+}
diff --git a/migration.c b/migration.c
index ee64d41..0ca4399 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,8 @@ void qemu_start_incoming_migration(const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         exec_start_incoming_migration(p);
+    else if (strstart(uri, "fd:", &p))
+        fd_start_incoming_migration(p);
 #endif
     else
         fprintf(stderr, "unknown migration protocol: %s\n", uri);
@@ -58,6 +60,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         s = exec_start_outgoing_migration(p, max_throttle, detach);
+    else if (strstart(uri, "fd:", &p))
+        s = fd_start_outgoing_migration(mon, p, max_throttle, detach);
 #endif
     else
         monitor_printf(mon, "unknown migration protocol: %s\n", uri);
diff --git a/migration.h b/migration.h
index 37c7f8e..5033d02 100644
--- a/migration.h
+++ b/migration.h
@@ -73,6 +73,13 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
 					     int64_t bandwidth_limit,
 					     int detach);
 
+int fd_start_incoming_migration(const char *path);
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach);
+
 void migrate_fd_monitor_suspend(FdMigrationState *s);
 
 void migrate_fd_error(FdMigrationState *s);
diff --git a/savevm.c b/savevm.c
index 975e7ab..4575653 100644
--- a/savevm.c
+++ b/savevm.c
@@ -285,6 +285,34 @@ int qemu_stdio_fd(QEMUFile *f)
     return fd;
 }
 
+QEMUFile *qemu_fdopen(int fd, const char *mode)
+{
+    QEMUFileStdio *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 = qemu_mallocz(sizeof(QEMUFileStdio));
+    s->stdio_file = fdopen(fd, mode);
+    if (!s->stdio_file)
+        goto fail;
+
+    if(mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, NULL, NULL);
+    }
+    return s->file;
+
+fail:
+    qemu_free(s);
+    return NULL;
+}
+
 QEMUFile *qemu_fopen_socket(int fd)
 {
     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
-- 
1.6.2.5

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

* [Qemu-devel] [PATCH v2] add file descriptor migration
  2009-08-12 12:20           ` [Qemu-devel] [PATCH] add file descriptor migration Paolo Bonzini
@ 2009-08-18 13:56             ` Paolo Bonzini
  2009-08-18 13:59               ` [Qemu-devel] " Chris Lalancette
  0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2009-08-18 13:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: aliguori, Chris Lalancette

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Chris Lalancette <clalance@redhat.com>
---
	Change from v1: Chris spotted that I used F_SETFD instead of
	F_SETFL to set non-blocking mode in the outgoing migration
	code.

	Also, now that the migration code is fixed, we tested it with
	various kinds of file descriptors (pipes, UNIX sockets, FIFOs,
	files).

 Makefile       |    2 +-
 hw/hw.h        |    1 +
 migration-fd.c |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 migration.c    |    4 ++
 migration.h    |    7 +++
 savevm.c       |   28 +++++++++++
 6 files changed, 178 insertions(+), 1 deletions(-)
 create mode 100644 migration-fd.c

diff --git a/Makefile b/Makefile
index 5279504..c7ff0be 100644
--- a/Makefile
+++ b/Makefile
@@ -93,7 +93,7 @@ obj-y += qdev.o qdev-properties.o ssi.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
 obj-$(CONFIG_WIN32) += tap-win32.o
-obj-$(CONFIG_POSIX) += migration-exec.o
+obj-$(CONFIG_POSIX) += migration-exec.o migration-fd.o
 
 audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
diff --git a/hw/hw.h b/hw/hw.h
index 322f077..91bf800 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -49,6 +49,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
                          QEMUFileRateLimit *rate_limit,
                          QEMUFileSetRateLimit *set_rate_limit);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
 QEMUFile *qemu_fopen_socket(int fd);
 QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
 QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
diff --git a/migration-fd.c b/migration-fd.c
new file mode 100644
index 0000000..794c2ac
--- /dev/null
+++ b/migration-fd.c
@@ -0,0 +1,137 @@
+/*
+ * QEMU live migration via generic fd
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ *  Chris Lalancette <clalance@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "monitor.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION_FD
+
+#ifdef DEBUG_MIGRATION_FD
+#define dprintf(fmt, ...) \
+    do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int fd_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int fd_close(FdMigrationState *s)
+{
+    dprintf("fd_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach)
+{
+    FdMigrationState *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->fd = monitor_get_fd(mon, fdname);
+    if (s->fd == -1) {
+        dprintf("fd_migration: invalid file descriptor identifier\n");
+        goto err_after_alloc;
+    }
+
+    if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
+        dprintf("Unable to set nonblocking mode on file descriptor\n");
+        goto err_after_open;
+    }
+
+    s->get_error = fd_errno;
+    s->write = fd_write;
+    s->close = fd_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    migrate_fd_connect(s);
+    return &s->mig_state;
+
+err_after_open:
+    close(s->fd);
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void fd_accept_incoming_migration(void *opaque)
+{
+    QEMUFile *f = opaque;
+    int ret;
+
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto err;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+    /* we've successfully migrated, close the fd */
+    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+    if (autostart)
+        vm_start();
+
+err:
+    qemu_fclose(f);
+}
+
+int fd_start_incoming_migration(const char *infd)
+{
+    int fd;
+    QEMUFile *f;
+
+    dprintf("Attempting to start an incoming migration via fd\n");
+
+    fd = strtol(infd, NULL, 0);
+    f = qemu_fdopen(fd, "rb");
+    if(f == NULL) {
+        dprintf("Unable to apply qemu wrapper to file descriptor\n");
+        return -errno;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL,
+			 (void *)(unsigned long)f);
+
+    return 0;
+}
diff --git a/migration.c b/migration.c
index ee64d41..0ca4399 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,8 @@ void qemu_start_incoming_migration(const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         exec_start_incoming_migration(p);
+    else if (strstart(uri, "fd:", &p))
+        fd_start_incoming_migration(p);
 #endif
     else
         fprintf(stderr, "unknown migration protocol: %s\n", uri);
@@ -58,6 +60,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
 #if !defined(WIN32)
     else if (strstart(uri, "exec:", &p))
         s = exec_start_outgoing_migration(p, max_throttle, detach);
+    else if (strstart(uri, "fd:", &p))
+        s = fd_start_outgoing_migration(mon, p, max_throttle, detach);
 #endif
     else
         monitor_printf(mon, "unknown migration protocol: %s\n", uri);
diff --git a/migration.h b/migration.h
index 37c7f8e..5033d02 100644
--- a/migration.h
+++ b/migration.h
@@ -73,6 +73,13 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
 					     int64_t bandwidth_limit,
 					     int detach);
 
+int fd_start_incoming_migration(const char *path);
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+					    const char *fdname,
+					    int64_t bandwidth_limit,
+					    int detach);
+
 void migrate_fd_monitor_suspend(FdMigrationState *s);
 
 void migrate_fd_error(FdMigrationState *s);
diff --git a/savevm.c b/savevm.c
index 975e7ab..4575653 100644
--- a/savevm.c
+++ b/savevm.c
@@ -285,6 +285,34 @@ int qemu_stdio_fd(QEMUFile *f)
     return fd;
 }
 
+QEMUFile *qemu_fdopen(int fd, const char *mode)
+{
+    QEMUFileStdio *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 = qemu_mallocz(sizeof(QEMUFileStdio));
+    s->stdio_file = fdopen(fd, mode);
+    if (!s->stdio_file)
+        goto fail;
+
+    if(mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, NULL, NULL);
+    }
+    return s->file;
+
+fail:
+    qemu_free(s);
+    return NULL;
+}
+
 QEMUFile *qemu_fopen_socket(int fd)
 {
     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
-- 
1.6.2.5

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

* [Qemu-devel] Re: [PATCH v2] add file descriptor migration
  2009-08-18 13:56             ` [Qemu-devel] [PATCH v2] " Paolo Bonzini
@ 2009-08-18 13:59               ` Chris Lalancette
  0 siblings, 0 replies; 11+ messages in thread
From: Chris Lalancette @ 2009-08-18 13:59 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: aliguori, qemu-devel

Paolo Bonzini wrote:
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Chris Lalancette <clalance@redhat.com>
> ---
> 	Change from v1: Chris spotted that I used F_SETFD instead of
> 	F_SETFL to set non-blocking mode in the outgoing migration
> 	code.
> 
> 	Also, now that the migration code is fixed, we tested it with
> 	various kinds of file descriptors (pipes, UNIX sockets, FIFOs,
> 	files).

Along with the unify popen/fopen qemu wrappers patch, this patch works for my
purposes.

Acked-by: Chris Lalancette <clalance@redhat.com>

-- 
Chris Lalancette

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

end of thread, other threads:[~2009-08-18 13:59 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-05 15:24 [Qemu-devel] [PATCH] Migration via unix sockets Chris Lalancette
2009-08-10 10:23 ` Chris Lalancette
2009-08-10 11:34   ` Avi Kivity
2009-08-11  9:15     ` Chris Lalancette
2009-08-11  9:35       ` Avi Kivity
2009-08-11  9:44       ` [Qemu-devel] " Paolo Bonzini
2009-08-11 10:06         ` Avi Kivity
2009-08-12 12:20           ` [Qemu-devel] [PATCH] add file descriptor migration Paolo Bonzini
2009-08-18 13:56             ` [Qemu-devel] [PATCH v2] " Paolo Bonzini
2009-08-18 13:59               ` [Qemu-devel] " Chris Lalancette
2009-08-11 10:20       ` [Qemu-devel] [PATCH] Migration via unix sockets 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.