Commit 065e281356282f59386272aa50590b566a1809d9

Authored by aliguori
1 parent a74b4d2c

Reintroduce migrate-to-exec: support (Charles Duffy)

KVM's live migration support included support for exec: URLs, allowing system
state to be written or received via an arbitrary popen()ed subprocess. This
provides a convenient way to pipe state through a compression algorithm or an
arbitrary network transport on its way to its destination, and a convenient way
to write state to disk; libvirt's qemu driver currently uses migration to exec:
targets for this latter purpose.

This version of the patch refactors now-common code from migrate-tcp.c into
migrate.c. 

Signed-off-by: Charles Duffy <Charles_Duffy@messageone.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5694 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
@@ -596,7 +596,7 @@ endif @@ -596,7 +596,7 @@ endif
596 ifdef CONFIG_WIN32 596 ifdef CONFIG_WIN32
597 OBJS+=block-raw-win32.o 597 OBJS+=block-raw-win32.o
598 else 598 else
599 -OBJS+=block-raw-posix.o 599 +OBJS+=block-raw-posix.o migration-exec.o
600 endif 600 endif
601 601
602 LIBS+=-lz 602 LIBS+=-lz
@@ -35,6 +35,8 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, @@ -35,6 +35,8 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
35 QEMUFileRateLimit *rate_limit); 35 QEMUFileRateLimit *rate_limit);
36 QEMUFile *qemu_fopen(const char *filename, const char *mode); 36 QEMUFile *qemu_fopen(const char *filename, const char *mode);
37 QEMUFile *qemu_fopen_socket(int fd); 37 QEMUFile *qemu_fopen_socket(int fd);
  38 +QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
  39 +QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
38 void qemu_fflush(QEMUFile *f); 40 void qemu_fflush(QEMUFile *f);
39 int qemu_fclose(QEMUFile *f); 41 int qemu_fclose(QEMUFile *f);
40 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); 42 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
migration-exec.c 0 → 100644
  1 +/*
  2 + * QEMU live migration
  3 + *
  4 + * Copyright IBM, Corp. 2008
  5 + * Copyright Dell MessageOne 2008
  6 + *
  7 + * Authors:
  8 + * Anthony Liguori <aliguori@us.ibm.com>
  9 + * Charles Duffy <charles_duffy@messageone.com>
  10 + *
  11 + * This work is licensed under the terms of the GNU GPL, version 2. See
  12 + * the COPYING file in the top-level directory.
  13 + *
  14 + */
  15 +
  16 +#include "qemu-common.h"
  17 +#include "qemu_socket.h"
  18 +#include "migration.h"
  19 +#include "qemu-char.h"
  20 +#include "sysemu.h"
  21 +#include "console.h"
  22 +#include "buffered_file.h"
  23 +#include "block.h"
  24 +
  25 +//#define DEBUG_MIGRATION_EXEC
  26 +
  27 +#ifdef DEBUG_MIGRATION_EXEC
  28 +#define dprintf(fmt, ...) \
  29 + do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0)
  30 +#else
  31 +#define dprintf(fmt, ...) \
  32 + do { } while (0)
  33 +#endif
  34 +
  35 +static int file_errno(FdMigrationState *s)
  36 +{
  37 + return errno;
  38 +}
  39 +
  40 +static int file_write(FdMigrationState *s, const void * buf, size_t size)
  41 +{
  42 + return write(s->fd, buf, size);
  43 +}
  44 +
  45 +static int exec_close(FdMigrationState *s)
  46 +{
  47 + dprintf("exec_close\n");
  48 + if (s->opaque) {
  49 + qemu_fclose(s->opaque);
  50 + s->opaque = NULL;
  51 + s->fd = -1;
  52 + }
  53 + return 0;
  54 +}
  55 +
  56 +MigrationState *exec_start_outgoing_migration(const char *command,
  57 + int64_t bandwidth_limit,
  58 + int async)
  59 +{
  60 + FdMigrationState *s;
  61 + FILE *f;
  62 +
  63 + s = qemu_mallocz(sizeof(*s));
  64 + if (s == NULL) {
  65 + dprintf("Unable to allocate FdMigrationState\n");
  66 + goto err;
  67 + }
  68 +
  69 + f = popen(command, "w");
  70 + if (f == NULL) {
  71 + dprintf("Unable to popen exec target\n");
  72 + goto err_after_alloc;
  73 + }
  74 +
  75 + s->fd = fileno(f);
  76 + if (s->fd == -1) {
  77 + dprintf("Unable to retrieve file descriptor for popen'd handle\n");
  78 + goto err_after_open;
  79 + }
  80 +
  81 + if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) {
  82 + dprintf("Unable to set nonblocking mode on file descriptor\n");
  83 + goto err_after_open;
  84 + }
  85 +
  86 + s->opaque = qemu_popen(f, "w");
  87 +
  88 + s->get_error = file_errno;
  89 + s->write = file_write;
  90 + s->mig_state.cancel = migrate_fd_cancel;
  91 + s->mig_state.get_status = migrate_fd_get_status;
  92 + s->mig_state.release = migrate_fd_release;
  93 +
  94 + s->state = MIG_STATE_ACTIVE;
  95 + s->detach = !async;
  96 + s->bandwidth_limit = bandwidth_limit;
  97 +
  98 + if (s->detach == 1) {
  99 + dprintf("detaching from monitor\n");
  100 + monitor_suspend();
  101 + s->detach = 2;
  102 + }
  103 +
  104 + migrate_fd_connect(s);
  105 + return &s->mig_state;
  106 +
  107 +err_after_open:
  108 + pclose(f);
  109 +err_after_alloc:
  110 + qemu_free(s);
  111 +err:
  112 + return NULL;
  113 +}
  114 +
  115 +int exec_start_incoming_migration(const char *command)
  116 +{
  117 + int ret;
  118 + QEMUFile *f;
  119 +
  120 + dprintf("Attempting to start an incoming migration\n");
  121 + f = qemu_popen_cmd(command, "r");
  122 + if(f == NULL) {
  123 + dprintf("Unable to apply qemu wrapper to popen file\n");
  124 + return -errno;
  125 + }
  126 + vm_stop(0); /* just in case */
  127 + ret = qemu_loadvm_state(f);
  128 + if (ret < 0) {
  129 + fprintf(stderr, "load of migration failed\n");
  130 + goto err;
  131 + }
  132 + qemu_announce_self();
  133 + dprintf("successfully loaded vm state\n");
  134 + vm_start();
  135 + qemu_fclose(f);
  136 + return 0;
  137 +
  138 +err:
  139 + qemu_fclose(f);
  140 + return -errno;
  141 +}
migration-tcp.c
@@ -22,16 +22,6 @@ @@ -22,16 +22,6 @@
22 22
23 //#define DEBUG_MIGRATION_TCP 23 //#define DEBUG_MIGRATION_TCP
24 24
25 -typedef struct FdMigrationState  
26 -{  
27 - MigrationState mig_state;  
28 - QEMUFile *file;  
29 - int64_t bandwidth_limit;  
30 - int fd;  
31 - int detach;  
32 - int state;  
33 -} FdMigrationState;  
34 -  
35 #ifdef DEBUG_MIGRATION_TCP 25 #ifdef DEBUG_MIGRATION_TCP
36 #define dprintf(fmt, ...) \ 26 #define dprintf(fmt, ...) \
37 do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0) 27 do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
@@ -40,64 +30,19 @@ typedef struct FdMigrationState @@ -40,64 +30,19 @@ typedef struct FdMigrationState
40 do { } while (0) 30 do { } while (0)
41 #endif 31 #endif
42 32
43 -static void tcp_cleanup(FdMigrationState *s) 33 +static int socket_errno(FdMigrationState *s)
44 { 34 {
45 - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);  
46 -  
47 - if (s->file) {  
48 - dprintf("closing file\n");  
49 - qemu_fclose(s->file);  
50 - }  
51 -  
52 - if (s->fd != -1)  
53 - close(s->fd);  
54 -  
55 - /* Don't resume monitor until we've flushed all of the buffers */  
56 - if (s->detach == 2) {  
57 - monitor_resume();  
58 - s->detach = 0;  
59 - }  
60 -  
61 - s->fd = -1;  
62 -}  
63 -  
64 -static void tcp_error(FdMigrationState *s)  
65 -{  
66 - dprintf("setting error state\n");  
67 - s->state = MIG_STATE_ERROR;  
68 - tcp_cleanup(s);  
69 -}  
70 -  
71 -static void fd_put_notify(void *opaque)  
72 -{  
73 - FdMigrationState *s = opaque;  
74 -  
75 - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);  
76 - qemu_file_put_notify(s->file); 35 + return (s->get_error(s));
77 } 36 }
78 37
79 -static ssize_t fd_put_buffer(void *opaque, const void *data, size_t size) 38 +static int socket_write(FdMigrationState *s, const void * buf, size_t size)
80 { 39 {
81 - FdMigrationState *s = opaque;  
82 - ssize_t ret;  
83 -  
84 - do {  
85 - ret = send(s->fd, data, size, 0);  
86 - } while (ret == -1 && (socket_error() == EINTR || socket_error() == EWOULDBLOCK));  
87 -  
88 - if (ret == -1)  
89 - ret = -socket_error();  
90 -  
91 - if (ret == -EAGAIN)  
92 - qemu_set_fd_handler2(s->fd, NULL, NULL, fd_put_notify, s);  
93 -  
94 - return ret; 40 + return send(s->fd, buf, size, 0);
95 } 41 }
96 42
97 -static int fd_close(void *opaque) 43 +static int tcp_close(FdMigrationState *s)
98 { 44 {
99 - FdMigrationState *s = opaque;  
100 - dprintf("fd_close\n"); 45 + dprintf("tcp_close\n");
101 if (s->fd != -1) { 46 if (s->fd != -1) {
102 close(s->fd); 47 close(s->fd);
103 s->fd = -1; 48 s->fd = -1;
@@ -105,67 +50,6 @@ static int fd_close(void *opaque) @@ -105,67 +50,6 @@ static int fd_close(void *opaque)
105 return 0; 50 return 0;
106 } 51 }
107 52
108 -static void fd_wait_for_unfreeze(void *opaque)  
109 -{  
110 - FdMigrationState *s = opaque;  
111 - int ret;  
112 -  
113 - dprintf("wait for unfreeze\n");  
114 - if (s->state != MIG_STATE_ACTIVE)  
115 - return;  
116 -  
117 - do {  
118 - fd_set wfds;  
119 -  
120 - FD_ZERO(&wfds);  
121 - FD_SET(s->fd, &wfds);  
122 -  
123 - ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);  
124 - } while (ret == -1 && socket_error() == EINTR);  
125 -}  
126 -  
127 -static void fd_put_ready(void *opaque)  
128 -{  
129 - FdMigrationState *s = opaque;  
130 -  
131 - if (s->state != MIG_STATE_ACTIVE) {  
132 - dprintf("put_ready returning because of non-active state\n");  
133 - return;  
134 - }  
135 -  
136 - dprintf("iterate\n");  
137 - if (qemu_savevm_state_iterate(s->file) == 1) {  
138 - dprintf("done iterating\n");  
139 - vm_stop(0);  
140 -  
141 - bdrv_flush_all();  
142 - qemu_savevm_state_complete(s->file);  
143 - s->state = MIG_STATE_COMPLETED;  
144 - tcp_cleanup(s);  
145 - }  
146 -}  
147 -  
148 -static void tcp_connect_migrate(FdMigrationState *s)  
149 -{  
150 - int ret;  
151 -  
152 - s->file = qemu_fopen_ops_buffered(s,  
153 - s->bandwidth_limit,  
154 - fd_put_buffer,  
155 - fd_put_ready,  
156 - fd_wait_for_unfreeze,  
157 - fd_close);  
158 -  
159 - dprintf("beginning savevm\n");  
160 - ret = qemu_savevm_state_begin(s->file);  
161 - if (ret < 0) {  
162 - dprintf("failed, %d\n", ret);  
163 - tcp_error(s);  
164 - return;  
165 - }  
166 -  
167 - fd_put_ready(s);  
168 -}  
169 53
170 static void tcp_wait_for_connect(void *opaque) 54 static void tcp_wait_for_connect(void *opaque)
171 { 55 {
@@ -176,60 +60,21 @@ static void tcp_wait_for_connect(void *opaque) @@ -176,60 +60,21 @@ static void tcp_wait_for_connect(void *opaque)
176 dprintf("connect completed\n"); 60 dprintf("connect completed\n");
177 do { 61 do {
178 ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize); 62 ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
179 - } while (ret == -1 && socket_error() == EINTR); 63 + } while (ret == -1 && (s->get_error(s)) == EINTR);
180 64
181 if (ret < 0) { 65 if (ret < 0) {
182 - tcp_error(s); 66 + migrate_fd_error(s);
183 return; 67 return;
184 } 68 }
185 69
186 qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); 70 qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
187 71
188 if (val == 0) 72 if (val == 0)
189 - tcp_connect_migrate(s); 73 + migrate_fd_connect(s);
190 else { 74 else {
191 dprintf("error connecting %d\n", val); 75 dprintf("error connecting %d\n", val);
192 - tcp_error(s);  
193 - }  
194 -}  
195 -  
196 -static FdMigrationState *to_fms(MigrationState *mig_state)  
197 -{  
198 - return container_of(mig_state, FdMigrationState, mig_state);  
199 -}  
200 -  
201 -static int tcp_get_status(MigrationState *mig_state)  
202 -{  
203 - FdMigrationState *s = to_fms(mig_state);  
204 -  
205 - return s->state;  
206 -}  
207 -  
208 -static void tcp_cancel(MigrationState *mig_state)  
209 -{  
210 - FdMigrationState *s = to_fms(mig_state);  
211 -  
212 - if (s->state != MIG_STATE_ACTIVE)  
213 - return;  
214 -  
215 - dprintf("cancelling migration\n");  
216 -  
217 - s->state = MIG_STATE_CANCELLED;  
218 -  
219 - tcp_cleanup(s);  
220 -}  
221 -  
222 -static void tcp_release(MigrationState *mig_state)  
223 -{  
224 - FdMigrationState *s = to_fms(mig_state);  
225 -  
226 - dprintf("releasing state\n");  
227 -  
228 - if (s->state == MIG_STATE_ACTIVE) {  
229 - s->state = MIG_STATE_CANCELLED;  
230 - tcp_cleanup(s); 76 + migrate_fd_error(s);
231 } 77 }
232 - free(s);  
233 } 78 }
234 79
235 MigrationState *tcp_start_outgoing_migration(const char *host_port, 80 MigrationState *tcp_start_outgoing_migration(const char *host_port,
@@ -247,9 +92,12 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, @@ -247,9 +92,12 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
247 if (s == NULL) 92 if (s == NULL)
248 return NULL; 93 return NULL;
249 94
250 - s->mig_state.cancel = tcp_cancel;  
251 - s->mig_state.get_status = tcp_get_status;  
252 - s->mig_state.release = tcp_release; 95 + s->get_error = socket_errno;
  96 + s->write = socket_write;
  97 + s->close = tcp_close;
  98 + s->mig_state.cancel = migrate_fd_cancel;
  99 + s->mig_state.get_status = migrate_fd_get_status;
  100 + s->mig_state.release = migrate_fd_release;
253 101
254 s->state = MIG_STATE_ACTIVE; 102 s->state = MIG_STATE_ACTIVE;
255 s->detach = !async; 103 s->detach = !async;
@@ -271,7 +119,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, @@ -271,7 +119,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
271 do { 119 do {
272 ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); 120 ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
273 if (ret == -1) 121 if (ret == -1)
274 - ret = -socket_error(); 122 + ret = -(s->get_error(s));
275 123
276 if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) 124 if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
277 qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); 125 qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
@@ -283,7 +131,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, @@ -283,7 +131,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
283 qemu_free(s); 131 qemu_free(s);
284 return NULL; 132 return NULL;
285 } else if (ret >= 0) 133 } else if (ret >= 0)
286 - tcp_connect_migrate(s); 134 + migrate_fd_connect(s);
287 135
288 return &s->mig_state; 136 return &s->mig_state;
289 } 137 }
migration.c
@@ -14,6 +14,20 @@ @@ -14,6 +14,20 @@
14 #include "qemu-common.h" 14 #include "qemu-common.h"
15 #include "migration.h" 15 #include "migration.h"
16 #include "console.h" 16 #include "console.h"
  17 +#include "buffered_file.h"
  18 +#include "sysemu.h"
  19 +#include "block.h"
  20 +#include "qemu_socket.h"
  21 +
  22 +//#define DEBUG_MIGRATION
  23 +
  24 +#ifdef DEBUG_MIGRATION
  25 +#define dprintf(fmt, ...) \
  26 + do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
  27 +#else
  28 +#define dprintf(fmt, ...) \
  29 + do { } while (0)
  30 +#endif
17 31
18 /* Migration speed throttling */ 32 /* Migration speed throttling */
19 static uint32_t max_throttle = (32 << 20); 33 static uint32_t max_throttle = (32 << 20);
@@ -26,6 +40,10 @@ void qemu_start_incoming_migration(const char *uri) @@ -26,6 +40,10 @@ void qemu_start_incoming_migration(const char *uri)
26 40
27 if (strstart(uri, "tcp:", &p)) 41 if (strstart(uri, "tcp:", &p))
28 tcp_start_incoming_migration(p); 42 tcp_start_incoming_migration(p);
  43 +#if !defined(WIN32)
  44 + else if (strstart(uri, "exec:", &p))
  45 + exec_start_incoming_migration(p);
  46 +#endif
29 else 47 else
30 fprintf(stderr, "unknown migration protocol: %s\n", uri); 48 fprintf(stderr, "unknown migration protocol: %s\n", uri);
31 } 49 }
@@ -37,6 +55,10 @@ void do_migrate(int detach, const char *uri) @@ -37,6 +55,10 @@ void do_migrate(int detach, const char *uri)
37 55
38 if (strstart(uri, "tcp:", &p)) 56 if (strstart(uri, "tcp:", &p))
39 s = tcp_start_outgoing_migration(p, max_throttle, detach); 57 s = tcp_start_outgoing_migration(p, max_throttle, detach);
  58 +#if !defined(WIN32)
  59 + else if (strstart(uri, "exec:", &p))
  60 + s = exec_start_outgoing_migration(p, max_throttle, detach);
  61 +#endif
40 else 62 else
41 term_printf("unknown migration protocol: %s\n", uri); 63 term_printf("unknown migration protocol: %s\n", uri);
42 64
@@ -101,3 +123,159 @@ void do_info_migrate(void) @@ -101,3 +123,159 @@ void do_info_migrate(void)
101 } 123 }
102 } 124 }
103 125
  126 +/* shared migration helpers */
  127 +
  128 +void migrate_fd_error(FdMigrationState *s)
  129 +{
  130 + dprintf("setting error state\n");
  131 + s->state = MIG_STATE_ERROR;
  132 + migrate_fd_cleanup(s);
  133 +}
  134 +
  135 +void migrate_fd_cleanup(FdMigrationState *s)
  136 +{
  137 + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  138 +
  139 + if (s->file) {
  140 + dprintf("closing file\n");
  141 + qemu_fclose(s->file);
  142 + }
  143 +
  144 + if (s->fd != -1)
  145 + close(s->fd);
  146 +
  147 + /* Don't resume monitor until we've flushed all of the buffers */
  148 + if (s->detach == 2) {
  149 + monitor_resume();
  150 + s->detach = 0;
  151 + }
  152 +
  153 + s->fd = -1;
  154 +}
  155 +
  156 +void migrate_fd_put_notify(void *opaque)
  157 +{
  158 + FdMigrationState *s = opaque;
  159 +
  160 + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  161 + qemu_file_put_notify(s->file);
  162 +}
  163 +
  164 +ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
  165 +{
  166 + FdMigrationState *s = opaque;
  167 + ssize_t ret;
  168 +
  169 + do {
  170 + ret = s->write(s, data, size);
  171 + } while (ret == -1 && ((s->get_error(s)) == EINTR || (s->get_error(s)) == EWOULDBLOCK));
  172 +
  173 + if (ret == -1)
  174 + ret = -(s->get_error(s));
  175 +
  176 + if (ret == -EAGAIN)
  177 + qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
  178 +
  179 + return ret;
  180 +}
  181 +
  182 +void migrate_fd_connect(FdMigrationState *s)
  183 +{
  184 + int ret;
  185 +
  186 + s->file = qemu_fopen_ops_buffered(s,
  187 + s->bandwidth_limit,
  188 + migrate_fd_put_buffer,
  189 + migrate_fd_put_ready,
  190 + migrate_fd_wait_for_unfreeze,
  191 + migrate_fd_close);
  192 +
  193 + dprintf("beginning savevm\n");
  194 + ret = qemu_savevm_state_begin(s->file);
  195 + if (ret < 0) {
  196 + dprintf("failed, %d\n", ret);
  197 + migrate_fd_error(s);
  198 + return;
  199 + }
  200 +
  201 + migrate_fd_put_ready(s);
  202 +}
  203 +
  204 +void migrate_fd_put_ready(void *opaque)
  205 +{
  206 + FdMigrationState *s = opaque;
  207 +
  208 + if (s->state != MIG_STATE_ACTIVE) {
  209 + dprintf("put_ready returning because of non-active state\n");
  210 + return;
  211 + }
  212 +
  213 + dprintf("iterate\n");
  214 + if (qemu_savevm_state_iterate(s->file) == 1) {
  215 + dprintf("done iterating\n");
  216 + vm_stop(0);
  217 +
  218 + bdrv_flush_all();
  219 + qemu_savevm_state_complete(s->file);
  220 + s->state = MIG_STATE_COMPLETED;
  221 + migrate_fd_cleanup(s);
  222 + }
  223 +}
  224 +
  225 +int migrate_fd_get_status(MigrationState *mig_state)
  226 +{
  227 + FdMigrationState *s = migrate_to_fms(mig_state);
  228 + return s->state;
  229 +}
  230 +
  231 +void migrate_fd_cancel(MigrationState *mig_state)
  232 +{
  233 + FdMigrationState *s = migrate_to_fms(mig_state);
  234 +
  235 + if (s->state != MIG_STATE_ACTIVE)
  236 + return;
  237 +
  238 + dprintf("cancelling migration\n");
  239 +
  240 + s->state = MIG_STATE_CANCELLED;
  241 +
  242 + migrate_fd_cleanup(s);
  243 +}
  244 +
  245 +void migrate_fd_release(MigrationState *mig_state)
  246 +{
  247 + FdMigrationState *s = migrate_to_fms(mig_state);
  248 +
  249 + dprintf("releasing state\n");
  250 +
  251 + if (s->state == MIG_STATE_ACTIVE) {
  252 + s->state = MIG_STATE_CANCELLED;
  253 + migrate_fd_cleanup(s);
  254 + }
  255 + free(s);
  256 +}
  257 +
  258 +void migrate_fd_wait_for_unfreeze(void *opaque)
  259 +{
  260 + FdMigrationState *s = opaque;
  261 + int ret;
  262 +
  263 + dprintf("wait for unfreeze\n");
  264 + if (s->state != MIG_STATE_ACTIVE)
  265 + return;
  266 +
  267 + do {
  268 + fd_set wfds;
  269 +
  270 + FD_ZERO(&wfds);
  271 + FD_SET(s->fd, &wfds);
  272 +
  273 + ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
  274 + } while (ret == -1 && (s->get_error(s)) == EINTR);
  275 +}
  276 +
  277 +int migrate_fd_close(void *opaque)
  278 +{
  279 + FdMigrationState *s = opaque;
  280 + return s->close(s);
  281 +}
migration.h
@@ -29,6 +29,22 @@ struct MigrationState @@ -29,6 +29,22 @@ struct MigrationState
29 void (*release)(MigrationState *s); 29 void (*release)(MigrationState *s);
30 }; 30 };
31 31
  32 +typedef struct FdMigrationState FdMigrationState;
  33 +
  34 +struct FdMigrationState
  35 +{
  36 + MigrationState mig_state;
  37 + int64_t bandwidth_limit;
  38 + QEMUFile *file;
  39 + int fd;
  40 + int detach;
  41 + int state;
  42 + int (*get_error)(struct FdMigrationState*);
  43 + int (*close)(struct FdMigrationState*);
  44 + int (*write)(struct FdMigrationState*, const void *, size_t);
  45 + void *opaque;
  46 +};
  47 +
32 void qemu_start_incoming_migration(const char *uri); 48 void qemu_start_incoming_migration(const char *uri);
33 49
34 void do_migrate(int detach, const char *uri); 50 void do_migrate(int detach, const char *uri);
@@ -39,11 +55,44 @@ void do_migrate_set_speed(const char *value); @@ -39,11 +55,44 @@ void do_migrate_set_speed(const char *value);
39 55
40 void do_info_migrate(void); 56 void do_info_migrate(void);
41 57
  58 +int exec_start_incoming_migration(const char *host_port);
  59 +
  60 +MigrationState *exec_start_outgoing_migration(const char *host_port,
  61 + int64_t bandwidth_limit,
  62 + int detach);
  63 +
42 int tcp_start_incoming_migration(const char *host_port); 64 int tcp_start_incoming_migration(const char *host_port);
43 65
44 MigrationState *tcp_start_outgoing_migration(const char *host_port, 66 MigrationState *tcp_start_outgoing_migration(const char *host_port,
45 int64_t bandwidth_limit, 67 int64_t bandwidth_limit,
46 int detach); 68 int detach);
47 69
  70 +void migrate_fd_error(FdMigrationState *s);
  71 +
  72 +void migrate_fd_cleanup(FdMigrationState *s);
  73 +
  74 +void migrate_fd_put_notify(void *opaque);
  75 +
  76 +ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
  77 +
  78 +void migrate_fd_connect(FdMigrationState *s);
  79 +
  80 +void migrate_fd_put_ready(void *opaque);
  81 +
  82 +int migrate_fd_get_status(MigrationState *mig_state);
  83 +
  84 +void migrate_fd_cancel(MigrationState *mig_state);
  85 +
  86 +void migrate_fd_release(MigrationState *mig_state);
  87 +
  88 +void migrate_fd_wait_for_unfreeze(void *opaque);
  89 +
  90 +int migrate_fd_close(void *opaque);
  91 +
  92 +static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
  93 +{
  94 + return container_of(mig_state, FdMigrationState, mig_state);
  95 +}
  96 +
48 #endif 97 #endif
49 98
@@ -2964,6 +2964,12 @@ struct QEMUFile { @@ -2964,6 +2964,12 @@ struct QEMUFile {
2964 int has_error; 2964 int has_error;
2965 }; 2965 };
2966 2966
  2967 +typedef struct QEMUFilePopen
  2968 +{
  2969 + FILE *popen_file;
  2970 + QEMUFile *file;
  2971 +} QEMUFilePopen;
  2972 +
2967 typedef struct QEMUFileSocket 2973 typedef struct QEMUFileSocket
2968 { 2974 {
2969 int fd; 2975 int fd;
@@ -2992,6 +2998,64 @@ static int socket_close(void *opaque) @@ -2992,6 +2998,64 @@ static int socket_close(void *opaque)
2992 return 0; 2998 return 0;
2993 } 2999 }
2994 3000
  3001 +static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
  3002 +{
  3003 + QEMUFilePopen *s = opaque;
  3004 + return fwrite(buf, 1, size, s->popen_file);
  3005 +}
  3006 +
  3007 +static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
  3008 +{
  3009 + QEMUFilePopen *s = opaque;
  3010 + return fread(buf, 1, size, s->popen_file);
  3011 +}
  3012 +
  3013 +static int popen_close(void *opaque)
  3014 +{
  3015 + QEMUFilePopen *s = opaque;
  3016 + pclose(s->popen_file);
  3017 + qemu_free(s);
  3018 + return 0;
  3019 +}
  3020 +
  3021 +QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
  3022 +{
  3023 + QEMUFilePopen *s;
  3024 +
  3025 + if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
  3026 + fprintf(stderr, "qemu_popen: Argument validity check failed\n");
  3027 + return NULL;
  3028 + }
  3029 +
  3030 + s = qemu_mallocz(sizeof(QEMUFilePopen));
  3031 + if (!s) {
  3032 + fprintf(stderr, "qemu_popen: malloc failed\n");
  3033 + return NULL;
  3034 + }
  3035 +
  3036 + s->popen_file = popen_file;
  3037 +
  3038 + if(mode[0] == 'r') {
  3039 + s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL);
  3040 + } else {
  3041 + s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL);
  3042 + }
  3043 + fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n");
  3044 + return s->file;
  3045 +}
  3046 +
  3047 +QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
  3048 +{
  3049 + FILE *popen_file;
  3050 +
  3051 + popen_file = popen(command, mode);
  3052 + if(popen_file == NULL) {
  3053 + return NULL;
  3054 + }
  3055 +
  3056 + return qemu_popen(popen_file, mode);
  3057 +}
  3058 +
2995 QEMUFile *qemu_fopen_socket(int fd) 3059 QEMUFile *qemu_fopen_socket(int fd)
2996 { 3060 {
2997 QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket)); 3061 QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));