|
1 /* |
|
2 * QEMU live migration |
|
3 * |
|
4 * Copyright IBM, Corp. 2008 |
|
5 * |
|
6 * Authors: |
|
7 * Anthony Liguori <aliguori@us.ibm.com> |
|
8 * |
|
9 * This work is licensed under the terms of the GNU GPL, version 2. See |
|
10 * the COPYING file in the top-level directory. |
|
11 * |
|
12 */ |
|
13 |
|
14 #include "qemu-common.h" |
|
15 #include "migration.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 |
|
31 |
|
32 /* Migration speed throttling */ |
|
33 static uint32_t max_throttle = (32 << 20); |
|
34 |
|
35 static MigrationState *current_migration; |
|
36 |
|
37 void qemu_start_incoming_migration(const char *uri) |
|
38 { |
|
39 const char *p; |
|
40 |
|
41 if (strstart(uri, "tcp:", &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 |
|
47 else |
|
48 fprintf(stderr, "unknown migration protocol: %s\n", uri); |
|
49 } |
|
50 |
|
51 void do_migrate(int detach, const char *uri) |
|
52 { |
|
53 MigrationState *s = NULL; |
|
54 const char *p; |
|
55 |
|
56 if (strstart(uri, "tcp:", &p)) |
|
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 |
|
62 else |
|
63 term_printf("unknown migration protocol: %s\n", uri); |
|
64 |
|
65 if (s == NULL) |
|
66 term_printf("migration failed\n"); |
|
67 else { |
|
68 if (current_migration) |
|
69 current_migration->release(current_migration); |
|
70 |
|
71 current_migration = s; |
|
72 } |
|
73 } |
|
74 |
|
75 void do_migrate_cancel(void) |
|
76 { |
|
77 MigrationState *s = current_migration; |
|
78 |
|
79 if (s) |
|
80 s->cancel(s); |
|
81 } |
|
82 |
|
83 void do_migrate_set_speed(const char *value) |
|
84 { |
|
85 double d; |
|
86 char *ptr; |
|
87 |
|
88 d = strtod(value, &ptr); |
|
89 switch (*ptr) { |
|
90 case 'G': case 'g': |
|
91 d *= 1024; |
|
92 case 'M': case 'm': |
|
93 d *= 1024; |
|
94 case 'K': case 'k': |
|
95 d *= 1024; |
|
96 default: |
|
97 break; |
|
98 } |
|
99 |
|
100 max_throttle = (uint32_t)d; |
|
101 } |
|
102 |
|
103 void do_info_migrate(void) |
|
104 { |
|
105 MigrationState *s = current_migration; |
|
106 |
|
107 if (s) { |
|
108 term_printf("Migration status: "); |
|
109 switch (s->get_status(s)) { |
|
110 case MIG_STATE_ACTIVE: |
|
111 term_printf("active\n"); |
|
112 break; |
|
113 case MIG_STATE_COMPLETED: |
|
114 term_printf("completed\n"); |
|
115 break; |
|
116 case MIG_STATE_ERROR: |
|
117 term_printf("failed\n"); |
|
118 break; |
|
119 case MIG_STATE_CANCELLED: |
|
120 term_printf("cancelled\n"); |
|
121 break; |
|
122 } |
|
123 } |
|
124 } |
|
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 } |