Commit 5bb7910af031cce09cc619b982d39dc889776f65
1 parent
39b65c2e
Introduce UI for live migration
This patch introduces a command line parameter and monitor command for starting a live migration. The next patch will provide an example of how to use these parameters. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5476 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
150 additions
and
2 deletions
Makefile.target
| @@ -474,7 +474,7 @@ endif #CONFIG_DARWIN_USER | @@ -474,7 +474,7 @@ endif #CONFIG_DARWIN_USER | ||
| 474 | ifndef CONFIG_USER_ONLY | 474 | ifndef CONFIG_USER_ONLY |
| 475 | 475 | ||
| 476 | OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o | 476 | OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o |
| 477 | -OBJS+=fw_cfg.o aio.o buffered_file.o | 477 | +OBJS+=fw_cfg.o aio.o buffered_file.o migration.o |
| 478 | ifdef CONFIG_WIN32 | 478 | ifdef CONFIG_WIN32 |
| 479 | OBJS+=block-raw-win32.o | 479 | OBJS+=block-raw-win32.o |
| 480 | else | 480 | else |
migration.c
0 → 100644
| 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 | + | ||
| 18 | +/* Migration speed throttling */ | ||
| 19 | +static uint32_t max_throttle = (32 << 20); | ||
| 20 | + | ||
| 21 | +static MigrationState *current_migration; | ||
| 22 | + | ||
| 23 | +void qemu_start_incoming_migration(const char *uri) | ||
| 24 | +{ | ||
| 25 | + fprintf(stderr, "unknown migration protocol: %s\n", uri); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +void do_migrate(int detach, const char *uri) | ||
| 29 | +{ | ||
| 30 | + term_printf("unknown migration protocol: %s\n", uri); | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +void do_migrate_cancel(void) | ||
| 34 | +{ | ||
| 35 | + MigrationState *s = current_migration; | ||
| 36 | + | ||
| 37 | + if (s) | ||
| 38 | + s->cancel(s); | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +void do_migrate_set_speed(const char *value) | ||
| 42 | +{ | ||
| 43 | + double d; | ||
| 44 | + char *ptr; | ||
| 45 | + | ||
| 46 | + d = strtod(value, &ptr); | ||
| 47 | + switch (*ptr) { | ||
| 48 | + case 'G': case 'g': | ||
| 49 | + d *= 1024; | ||
| 50 | + case 'M': case 'm': | ||
| 51 | + d *= 1024; | ||
| 52 | + case 'K': case 'k': | ||
| 53 | + d *= 1024; | ||
| 54 | + default: | ||
| 55 | + break; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + max_throttle = (uint32_t)d; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +void do_info_migrate(void) | ||
| 62 | +{ | ||
| 63 | + MigrationState *s = current_migration; | ||
| 64 | + | ||
| 65 | + if (s) { | ||
| 66 | + term_printf("Migration status: "); | ||
| 67 | + switch (s->get_status(s)) { | ||
| 68 | + case MIG_STATE_ACTIVE: | ||
| 69 | + term_printf("active\n"); | ||
| 70 | + break; | ||
| 71 | + case MIG_STATE_COMPLETED: | ||
| 72 | + term_printf("completed\n"); | ||
| 73 | + break; | ||
| 74 | + case MIG_STATE_ERROR: | ||
| 75 | + term_printf("failed\n"); | ||
| 76 | + break; | ||
| 77 | + case MIG_STATE_CANCELLED: | ||
| 78 | + term_printf("cancelled\n"); | ||
| 79 | + break; | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | +} | ||
| 83 | + |
migration.h
0 → 100644
| 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 | +#ifndef QEMU_MIGRATION_H | ||
| 15 | +#define QEMU_MIGRATION_H | ||
| 16 | + | ||
| 17 | +#define MIG_STATE_ERROR -1 | ||
| 18 | +#define MIG_STATE_COMPLETED 0 | ||
| 19 | +#define MIG_STATE_CANCELLED 1 | ||
| 20 | +#define MIG_STATE_ACTIVE 2 | ||
| 21 | + | ||
| 22 | +typedef struct MigrationState MigrationState; | ||
| 23 | + | ||
| 24 | +struct MigrationState | ||
| 25 | +{ | ||
| 26 | + /* FIXME: add more accessors to print migration info */ | ||
| 27 | + void (*cancel)(MigrationState *s); | ||
| 28 | + int (*get_status)(MigrationState *s); | ||
| 29 | + void (*release)(MigrationState *s); | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +void qemu_start_incoming_migration(const char *uri); | ||
| 33 | + | ||
| 34 | +void do_migrate(int detach, const char *uri); | ||
| 35 | + | ||
| 36 | +void do_migrate_cancel(void); | ||
| 37 | + | ||
| 38 | +void do_migrate_set_speed(const char *value); | ||
| 39 | + | ||
| 40 | +void do_info_migrate(void); | ||
| 41 | + | ||
| 42 | +#endif | ||
| 43 | + |
monitor.c
| @@ -36,6 +36,7 @@ | @@ -36,6 +36,7 @@ | ||
| 36 | #include "disas.h" | 36 | #include "disas.h" |
| 37 | #include <dirent.h> | 37 | #include <dirent.h> |
| 38 | #include "qemu-timer.h" | 38 | #include "qemu-timer.h" |
| 39 | +#include "migration.h" | ||
| 39 | 40 | ||
| 40 | //#define DEBUG | 41 | //#define DEBUG |
| 41 | //#define DEBUG_COMPLETION | 42 | //#define DEBUG_COMPLETION |
| @@ -1454,6 +1455,12 @@ static const term_cmd_t term_cmds[] = { | @@ -1454,6 +1455,12 @@ static const term_cmd_t term_cmds[] = { | ||
| 1454 | { "nmi", "i", do_inject_nmi, | 1455 | { "nmi", "i", do_inject_nmi, |
| 1455 | "cpu", "inject an NMI on the given CPU", }, | 1456 | "cpu", "inject an NMI on the given CPU", }, |
| 1456 | #endif | 1457 | #endif |
| 1458 | + { "migrate", "-ds", do_migrate, | ||
| 1459 | + "[-d] uri", "migrate to URI (using -d to not wait for completion)" }, | ||
| 1460 | + { "migrate_cancel", "", do_migrate_cancel, | ||
| 1461 | + "", "cancel the current VM migration" }, | ||
| 1462 | + { "migrate_set_speed", "s", do_migrate_set_speed, | ||
| 1463 | + "value", "set maximum speed (in bytes) for migrations" }, | ||
| 1457 | { NULL, NULL, }, | 1464 | { NULL, NULL, }, |
| 1458 | }; | 1465 | }; |
| 1459 | 1466 | ||
| @@ -1516,6 +1523,7 @@ static const term_cmd_t info_cmds[] = { | @@ -1516,6 +1523,7 @@ static const term_cmd_t info_cmds[] = { | ||
| 1516 | { "slirp", "", do_info_slirp, | 1523 | { "slirp", "", do_info_slirp, |
| 1517 | "", "show SLIRP statistics", }, | 1524 | "", "show SLIRP statistics", }, |
| 1518 | #endif | 1525 | #endif |
| 1526 | + { "migrate", "", do_info_migrate, "", "show migration status" }, | ||
| 1519 | { NULL, NULL, }, | 1527 | { NULL, NULL, }, |
| 1520 | }; | 1528 | }; |
| 1521 | 1529 |
qemu_socket.h
| @@ -31,5 +31,6 @@ int inet_aton(const char *cp, struct in_addr *ia); | @@ -31,5 +31,6 @@ int inet_aton(const char *cp, struct in_addr *ia); | ||
| 31 | #endif /* !_WIN32 */ | 31 | #endif /* !_WIN32 */ |
| 32 | 32 | ||
| 33 | void socket_set_nonblock(int fd); | 33 | void socket_set_nonblock(int fd); |
| 34 | +int parse_host_port(struct sockaddr_in *saddr, const char *str); | ||
| 34 | 35 | ||
| 35 | #endif /* QEMU_SOCKET_H */ | 36 | #endif /* QEMU_SOCKET_H */ |
vl.c
| @@ -38,6 +38,7 @@ | @@ -38,6 +38,7 @@ | ||
| 38 | #include "qemu-char.h" | 38 | #include "qemu-char.h" |
| 39 | #include "block.h" | 39 | #include "block.h" |
| 40 | #include "audio/audio.h" | 40 | #include "audio/audio.h" |
| 41 | +#include "migration.h" | ||
| 41 | 42 | ||
| 42 | #include <unistd.h> | 43 | #include <unistd.h> |
| 43 | #include <fcntl.h> | 44 | #include <fcntl.h> |
| @@ -3364,7 +3365,6 @@ static void udp_chr_update_read_handler(CharDriverState *chr) | @@ -3364,7 +3365,6 @@ static void udp_chr_update_read_handler(CharDriverState *chr) | ||
| 3364 | } | 3365 | } |
| 3365 | } | 3366 | } |
| 3366 | 3367 | ||
| 3367 | -int parse_host_port(struct sockaddr_in *saddr, const char *str); | ||
| 3368 | #ifndef _WIN32 | 3368 | #ifndef _WIN32 |
| 3369 | static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); | 3369 | static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); |
| 3370 | #endif | 3370 | #endif |
| @@ -6766,6 +6766,8 @@ int qemu_savevm_state(QEMUFile *f) | @@ -6766,6 +6766,8 @@ int qemu_savevm_state(QEMUFile *f) | ||
| 6766 | saved_vm_running = vm_running; | 6766 | saved_vm_running = vm_running; |
| 6767 | vm_stop(0); | 6767 | vm_stop(0); |
| 6768 | 6768 | ||
| 6769 | + bdrv_flush_all(); | ||
| 6770 | + | ||
| 6769 | ret = qemu_savevm_state_begin(f); | 6771 | ret = qemu_savevm_state_begin(f); |
| 6770 | if (ret < 0) | 6772 | if (ret < 0) |
| 6771 | goto out; | 6773 | goto out; |
| @@ -8338,6 +8340,7 @@ enum { | @@ -8338,6 +8340,7 @@ enum { | ||
| 8338 | QEMU_OPTION_tb_size, | 8340 | QEMU_OPTION_tb_size, |
| 8339 | QEMU_OPTION_icount, | 8341 | QEMU_OPTION_icount, |
| 8340 | QEMU_OPTION_uuid, | 8342 | QEMU_OPTION_uuid, |
| 8343 | + QEMU_OPTION_incoming, | ||
| 8341 | }; | 8344 | }; |
| 8342 | 8345 | ||
| 8343 | typedef struct QEMUOption { | 8346 | typedef struct QEMUOption { |
| @@ -8450,6 +8453,7 @@ static const QEMUOption qemu_options[] = { | @@ -8450,6 +8453,7 @@ static const QEMUOption qemu_options[] = { | ||
| 8450 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, | 8453 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, |
| 8451 | { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, | 8454 | { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, |
| 8452 | { "icount", HAS_ARG, QEMU_OPTION_icount }, | 8455 | { "icount", HAS_ARG, QEMU_OPTION_icount }, |
| 8456 | + { "incoming", HAS_ARG, QEMU_OPTION_incoming }, | ||
| 8453 | { NULL }, | 8457 | { NULL }, |
| 8454 | }; | 8458 | }; |
| 8455 | 8459 | ||
| @@ -8742,6 +8746,7 @@ int main(int argc, char **argv) | @@ -8742,6 +8746,7 @@ int main(int argc, char **argv) | ||
| 8742 | const char *pid_file = NULL; | 8746 | const char *pid_file = NULL; |
| 8743 | VLANState *vlan; | 8747 | VLANState *vlan; |
| 8744 | int autostart; | 8748 | int autostart; |
| 8749 | + const char *incoming = NULL; | ||
| 8745 | 8750 | ||
| 8746 | LIST_INIT (&vm_change_state_head); | 8751 | LIST_INIT (&vm_change_state_head); |
| 8747 | #ifndef _WIN32 | 8752 | #ifndef _WIN32 |
| @@ -9349,6 +9354,9 @@ int main(int argc, char **argv) | @@ -9349,6 +9354,9 @@ int main(int argc, char **argv) | ||
| 9349 | icount_time_shift = strtol(optarg, NULL, 0); | 9354 | icount_time_shift = strtol(optarg, NULL, 0); |
| 9350 | } | 9355 | } |
| 9351 | break; | 9356 | break; |
| 9357 | + case QEMU_OPTION_incoming: | ||
| 9358 | + incoming = optarg; | ||
| 9359 | + break; | ||
| 9352 | } | 9360 | } |
| 9353 | } | 9361 | } |
| 9354 | } | 9362 | } |
| @@ -9691,6 +9699,11 @@ int main(int argc, char **argv) | @@ -9691,6 +9699,11 @@ int main(int argc, char **argv) | ||
| 9691 | if (loadvm) | 9699 | if (loadvm) |
| 9692 | do_loadvm(loadvm); | 9700 | do_loadvm(loadvm); |
| 9693 | 9701 | ||
| 9702 | + if (incoming) { | ||
| 9703 | + autostart = 0; /* fixme how to deal with -daemonize */ | ||
| 9704 | + qemu_start_incoming_migration(incoming); | ||
| 9705 | + } | ||
| 9706 | + | ||
| 9694 | { | 9707 | { |
| 9695 | /* XXX: simplify init */ | 9708 | /* XXX: simplify init */ |
| 9696 | read_passwords(); | 9709 | read_passwords(); |