All of lore.kernel.org
 help / color / mirror / Atom feed
From: Charles Duffy <charles@dyfis.net>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Re: [BUG] Regression of exec migration
Date: Mon, 31 Aug 2009 17:55:46 -0500	[thread overview]
Message-ID: <h7hke3$3o8$1@ger.gmane.org> (raw)
In-Reply-To: <4A97FA9B.1030401@codemonkey.ws>

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

Anthony Liguori wrote:
> I think the fundamental problem is that exec migration shouldn't use 
> popen.  It should create a pipe() and do a proper fork/exec.
> 
> I don't think the f* function support asynchronous IO properly.

Per this thread and a suggestion from Anthony on IRC, I've taken a shot 
at modifying the exec: migration code to be closer to the original kvm 
implementation. The severe performance degradation no longer appears to 
be present.

This has been successfully smoke tested against the stable-0.11 branch; 
the rebase to master, attached, has only minor changes.

Signed-off-by: Charles Duffy <Charles_Duffy@dell.com>

[-- Attachment #2: 0001-stop-using-popen-for-outgoing-migrations.patch --]
[-- Type: text/x-patch, Size: 4058 bytes --]

>From c48ba672cd92d1d173fe9cb93f8e268d0d7952bc Mon Sep 17 00:00:00 2001
From: Charles Duffy <Charles_Duffy@dell.com>
Date: Fri, 28 Aug 2009 22:17:47 -0500
Subject: [PATCH 1/2] stop using popen for outgoing migrations

---
 migration-exec.c |   95 ++++++++++++++++++++++++++++++++++++-----------------
 qemu-common.h    |    2 +
 2 files changed, 66 insertions(+), 31 deletions(-)

diff --git a/migration-exec.c b/migration-exec.c
index b45c833..c36e756 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -31,25 +31,72 @@
     do { } while (0)
 #endif
 
-static int file_errno(FdMigrationState *s)
+// opaque is pid
+typedef struct ExecMigrationState
+{
+    pid_t pid;
+} ExecMigrationState;
+
+static int exec_errno(FdMigrationState *s)
 {
     return errno;
 }
 
-static int file_write(FdMigrationState *s, const void * buf, size_t size)
+static int exec_write(FdMigrationState *s, const void * buf, size_t size)
 {
     return write(s->fd, buf, size);
 }
 
 static int exec_close(FdMigrationState *s)
 {
+    int ret, status;
+
     dprintf("exec_close\n");
-    if (s->opaque) {
-        qemu_fclose(s->opaque);
-        s->opaque = NULL;
-        s->fd = -1;
+
+    close(s->fd);
+
+    if (!(s->opaque))
+        return -1;
+
+    do {
+        ret = waitpid(((ExecMigrationState*)(s->opaque))->pid, &status, 0);
+    } while (ret == -1 && errno == EINTR);
+
+    qemu_free(s->opaque);
+    s->opaque = 0;
+
+    return status;
+}
+
+static pid_t exec_start_migration(const char *command, int *fd) {
+    const char *argv[] = { "sh", "-c", command, NULL };
+    int fds[2];
+    pid_t pid;
+
+    if (pipe(fds) == -1) {
+        dprintf("pipe() (%s)\n", strerr(errno));
+        return 0;
     }
-    return 0;
+
+    pid = fork();
+    if(pid == -1) {
+        close(fds[0]);
+        close(fds[1]);
+        dprintf("fork error (%s)\n", strerror(errno));
+        return 0;
+    } else if (pid == 0) {
+        /* child process */
+        close(fds[1]);
+        dup2(fds[0], STDIN_FILENO);
+        execv("/bin/sh", (char **)argv);
+        exit(1);
+    }
+    close(fds[0]);
+
+    fcntl(fds[1], O_NONBLOCK);
+
+    *fd = fds[1];
+    return pid;
 }
 
 MigrationState *exec_start_outgoing_migration(const char *command,
@@ -57,29 +104,20 @@ MigrationState *exec_start_outgoing_migration(const char *command,
                                              int detach)
 {
     FdMigrationState *s;
-    FILE *f;
+    int fd, pid;
 
-    s = qemu_mallocz(sizeof(*s));
+    pid = exec_start_migration(command, &fd);
+    if(!pid) return NULL;
 
-    f = popen(command, "w");
-    if (f == NULL) {
-        dprintf("Unable to popen exec target\n");
-        goto err_after_alloc;
-    }
-
-    s->fd = fileno(f);
-    if (s->fd == -1) {
-        dprintf("Unable to retrieve file descriptor for popen'd handle\n");
-        goto err_after_open;
-    }
-
-    socket_set_nonblock(s->fd);
+    s = qemu_mallocz(sizeof(*s));
+    s->opaque = qemu_mallocz(sizeof(ExecMigrationState));
 
-    s->opaque = qemu_popen(f, "w");
+    ((ExecMigrationState*)(s->opaque))->pid = pid;
 
+    s->fd = fd;
+    s->get_error = exec_errno;
+    s->write = exec_write;
     s->close = exec_close;
-    s->get_error = file_errno;
-    s->write = file_write;
     s->mig_state.cancel = migrate_fd_cancel;
     s->mig_state.get_status = migrate_fd_get_status;
     s->mig_state.release = migrate_fd_release;
@@ -93,14 +131,9 @@ MigrationState *exec_start_outgoing_migration(const char *command,
 
     migrate_fd_connect(s);
     return &s->mig_state;
-
-err_after_open:
-    pclose(f);
-err_after_alloc:
-    qemu_free(s);
-    return NULL;
 }
 
+/* helper for incoming case */
 static void exec_accept_incoming_migration(void *opaque)
 {
     QEMUFile *f = opaque;
diff --git a/qemu-common.h b/qemu-common.h
index c8fb315..aeb1d78 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -24,6 +24,8 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include "config-host.h"
 
 #ifndef O_LARGEFILE
-- 
1.6.4


[-- Attachment #3: 0002-stop-using-popen-for-incoming-migrations.patch --]
[-- Type: text/x-patch, Size: 3641 bytes --]

>From e7066ce85e969e43c8142f4845bc843e9d53f5e4 Mon Sep 17 00:00:00 2001
From: Charles Duffy <Charles_Duffy@dell.com>
Date: Fri, 28 Aug 2009 23:18:49 -0500
Subject: [PATCH 2/2] stop using popen for incoming migrations

---
 migration-exec.c |   51 +++++++++++++++++++++++++++++++--------------------
 1 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/migration-exec.c b/migration-exec.c
index c36e756..3dfea18 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -31,10 +31,10 @@
     do { } while (0)
 #endif
 
-// opaque is pid
 typedef struct ExecMigrationState
 {
     pid_t pid;
+    int fd; /* only used for incoming */
 } ExecMigrationState;
 
 static int exec_errno(FdMigrationState *s)
@@ -68,9 +68,9 @@ static int exec_close(FdMigrationState *s)
     return status;
 }
 
-static pid_t exec_start_migration(const char *command, int *fd) {
+static pid_t exec_start_migration(const char *command, int *fd, unsigned char incoming) {
     const char *argv[] = { "sh", "-c", command, NULL };
-    int fds[2];
+    int fds[2], parent_fd, child_fd;
     pid_t pid;
 
     if (pipe(fds) == -1) {
@@ -78,6 +78,16 @@ static pid_t exec_start_migration(const char *command, int *fd) {
         return 0;
     }
 
+    if(incoming) {
+        /* child writes, parent reads */
+        parent_fd = fds[0];
+        child_fd = fds[1];
+    } else {
+        /* parent writes, child reads */
+        parent_fd = fds[1];
+        child_fd = fds[0];
+    }
+
     pid = fork();
     if(pid == -1) {
         close(fds[0]);
@@ -86,16 +96,14 @@ static pid_t exec_start_migration(const char *command, int *fd) {
         return 0;
     } else if (pid == 0) {
         /* child process */
-        close(fds[1]);
-        dup2(fds[0], STDIN_FILENO);
+        close(parent_fd);
+        dup2(child_fd, incoming ? STDOUT_FILENO : STDIN_FILENO);
         execv("/bin/sh", (char **)argv);
         exit(1);
     }
-    close(fds[0]);
-
-    fcntl(fds[1], O_NONBLOCK);
-
-    *fd = fds[1];
+    close(child_fd);
+    fcntl(parent_fd, O_NONBLOCK);
+    *fd = parent_fd;
     return pid;
 }
 
@@ -106,7 +114,7 @@ MigrationState *exec_start_outgoing_migration(const char *command,
     FdMigrationState *s;
     int fd, pid;
 
-    pid = exec_start_migration(command, &fd);
+    pid = exec_start_migration(command, &fd, 0);
     if(!pid) return NULL;
 
     s = qemu_mallocz(sizeof(*s));
@@ -136,7 +144,8 @@ MigrationState *exec_start_outgoing_migration(const char *command,
 /* helper for incoming case */
 static void exec_accept_incoming_migration(void *opaque)
 {
-    QEMUFile *f = opaque;
+    ExecMigrationState *s = opaque;
+    QEMUFile *f = qemu_popen(fdopen(s->fd, "rb"), "r");
     int ret;
 
     ret = qemu_loadvm_state(f);
@@ -153,22 +162,24 @@ static void exec_accept_incoming_migration(void *opaque)
 
 err:
     qemu_fclose(f);
+    do {
+        waitpid(s->pid, NULL, 0);
+    } while (ret == -1 && errno == EINTR);
+    qemu_free(s);
 }
 
 int exec_start_incoming_migration(const char *command)
 {
-    QEMUFile *f;
+    ExecMigrationState *s;
+
+    s = qemu_mallocz(sizeof(*s));
 
-    dprintf("Attempting to start an incoming migration\n");
-    f = qemu_popen_cmd(command, "r");
-    if(f == NULL) {
-        dprintf("Unable to apply qemu wrapper to popen file\n");
+    s->pid = exec_start_migration(command, &(s->fd), 1);
+    if(!s->pid) {
         return -errno;
     }
 
-    qemu_set_fd_handler2(qemu_stdio_fd(f), NULL,
-			 exec_accept_incoming_migration, NULL,
-			 (void *)(unsigned long)f);
+    qemu_set_fd_handler2(s->fd, NULL, exec_accept_incoming_migration, NULL, (void*)s);
 
     return 0;
 }
-- 
1.6.4


  reply	other threads:[~2009-08-31 22:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-27  9:19 [Qemu-devel] [BUG] Regression of exec migration Pierre Riteau
2009-08-27 14:13 ` Anthony Liguori
2009-08-27 16:16   ` Pierre Riteau
2009-08-27 16:24     ` Anthony Liguori
2009-08-28 13:04       ` Pierre Riteau
2009-08-28 15:41         ` Anthony Liguori
2009-08-31 22:55           ` Charles Duffy [this message]
2009-09-01 11:57             ` [Qemu-devel] " Pierre Riteau
2009-09-01 20:37               ` Charles Duffy
     [not found] <B2D4B7D8-CF34-4E6D-9772-266E5B1A75C8@irisa.fr>
2009-08-27 13:31 ` Chris Lalancette

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='h7hke3$3o8$1@ger.gmane.org' \
    --to=charles@dyfis.net \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.