qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [BUG] Regression of exec migration


From: Charles Duffy
Subject: [Qemu-devel] Re: [BUG] Regression of exec migration
Date: Mon, 31 Aug 2009 17:55:46 -0500
User-agent: Thunderbird 2.0.0.22 (X11/20090608)

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 <address@hidden>
>From c48ba672cd92d1d173fe9cb93f8e268d0d7952bc Mon Sep 17 00:00:00 2001
From: Charles Duffy <address@hidden>
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

>From e7066ce85e969e43c8142f4845bc843e9d53f5e4 Mon Sep 17 00:00:00 2001
From: Charles Duffy <address@hidden>
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 via email to

[Prev in Thread] Current Thread [Next in Thread]