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 596 ifdef CONFIG_WIN32
597 597 OBJS+=block-raw-win32.o
598 598 else
599   -OBJS+=block-raw-posix.o
  599 +OBJS+=block-raw-posix.o migration-exec.o
600 600 endif
601 601  
602 602 LIBS+=-lz
... ...
... ... @@ -35,6 +35,8 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
35 35 QEMUFileRateLimit *rate_limit);
36 36 QEMUFile *qemu_fopen(const char *filename, const char *mode);
37 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 40 void qemu_fflush(QEMUFile *f);
39 41 int qemu_fclose(QEMUFile *f);
40 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 22  
23 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 25 #ifdef DEBUG_MIGRATION_TCP
36 26 #define dprintf(fmt, ...) \
37 27 do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
... ... @@ -40,64 +30,19 @@ typedef struct FdMigrationState
40 30 do { } while (0)
41 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 46 if (s->fd != -1) {
102 47 close(s->fd);
103 48 s->fd = -1;
... ... @@ -105,67 +50,6 @@ static int fd_close(void *opaque)
105 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 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 dprintf("connect completed\n");
177 61 do {
178 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 65 if (ret < 0) {
182   - tcp_error(s);
  66 + migrate_fd_error(s);
183 67 return;
184 68 }
185 69  
186 70 qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
187 71  
188 72 if (val == 0)
189   - tcp_connect_migrate(s);
  73 + migrate_fd_connect(s);
190 74 else {
191 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 80 MigrationState *tcp_start_outgoing_migration(const char *host_port,
... ... @@ -247,9 +92,12 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
247 92 if (s == NULL)
248 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 102 s->state = MIG_STATE_ACTIVE;
255 103 s->detach = !async;
... ... @@ -271,7 +119,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
271 119 do {
272 120 ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
273 121 if (ret == -1)
274   - ret = -socket_error();
  122 + ret = -(s->get_error(s));
275 123  
276 124 if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
277 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 131 qemu_free(s);
284 132 return NULL;
285 133 } else if (ret >= 0)
286   - tcp_connect_migrate(s);
  134 + migrate_fd_connect(s);
287 135  
288 136 return &s->mig_state;
289 137 }
... ...
migration.c
... ... @@ -14,6 +14,20 @@
14 14 #include "qemu-common.h"
15 15 #include "migration.h"
16 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 32 /* Migration speed throttling */
19 33 static uint32_t max_throttle = (32 << 20);
... ... @@ -26,6 +40,10 @@ void qemu_start_incoming_migration(const char *uri)
26 40  
27 41 if (strstart(uri, "tcp:", &p))
28 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 47 else
30 48 fprintf(stderr, "unknown migration protocol: %s\n", uri);
31 49 }
... ... @@ -37,6 +55,10 @@ void do_migrate(int detach, const char *uri)
37 55  
38 56 if (strstart(uri, "tcp:", &p))
39 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 62 else
41 63 term_printf("unknown migration protocol: %s\n", uri);
42 64  
... ... @@ -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 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 48 void qemu_start_incoming_migration(const char *uri);
33 49  
34 50 void do_migrate(int detach, const char *uri);
... ... @@ -39,11 +55,44 @@ void do_migrate_set_speed(const char *value);
39 55  
40 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 64 int tcp_start_incoming_migration(const char *host_port);
43 65  
44 66 MigrationState *tcp_start_outgoing_migration(const char *host_port,
45 67 int64_t bandwidth_limit,
46 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 97 #endif
49 98  
... ...
... ... @@ -2964,6 +2964,12 @@ struct QEMUFile {
2964 2964 int has_error;
2965 2965 };
2966 2966  
  2967 +typedef struct QEMUFilePopen
  2968 +{
  2969 + FILE *popen_file;
  2970 + QEMUFile *file;
  2971 +} QEMUFilePopen;
  2972 +
2967 2973 typedef struct QEMUFileSocket
2968 2974 {
2969 2975 int fd;
... ... @@ -2992,6 +2998,64 @@ static int socket_close(void *opaque)
2992 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 3059 QEMUFile *qemu_fopen_socket(int fd)
2996 3060 {
2997 3061 QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
... ...