diff --git a/Makefile.target b/Makefile.target index c0af5ecb31..a11957dd70 100644 --- a/Makefile.target +++ b/Makefile.target @@ -474,7 +474,7 @@ endif #CONFIG_DARWIN_USER ifndef CONFIG_USER_ONLY OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o -OBJS+=fw_cfg.o aio.o buffered_file.o +OBJS+=fw_cfg.o aio.o buffered_file.o migration.o ifdef CONFIG_WIN32 OBJS+=block-raw-win32.o else diff --git a/migration.c b/migration.c new file mode 100644 index 0000000000..732fe3fe4c --- /dev/null +++ b/migration.c @@ -0,0 +1,83 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "migration.h" +#include "console.h" + +/* Migration speed throttling */ +static uint32_t max_throttle = (32 << 20); + +static MigrationState *current_migration; + +void qemu_start_incoming_migration(const char *uri) +{ + fprintf(stderr, "unknown migration protocol: %s\n", uri); +} + +void do_migrate(int detach, const char *uri) +{ + term_printf("unknown migration protocol: %s\n", uri); +} + +void do_migrate_cancel(void) +{ + MigrationState *s = current_migration; + + if (s) + s->cancel(s); +} + +void do_migrate_set_speed(const char *value) +{ + double d; + char *ptr; + + d = strtod(value, &ptr); + switch (*ptr) { + case 'G': case 'g': + d *= 1024; + case 'M': case 'm': + d *= 1024; + case 'K': case 'k': + d *= 1024; + default: + break; + } + + max_throttle = (uint32_t)d; +} + +void do_info_migrate(void) +{ + MigrationState *s = current_migration; + + if (s) { + term_printf("Migration status: "); + switch (s->get_status(s)) { + case MIG_STATE_ACTIVE: + term_printf("active\n"); + break; + case MIG_STATE_COMPLETED: + term_printf("completed\n"); + break; + case MIG_STATE_ERROR: + term_printf("failed\n"); + break; + case MIG_STATE_CANCELLED: + term_printf("cancelled\n"); + break; + } + } +} + diff --git a/migration.h b/migration.h new file mode 100644 index 0000000000..61f77bd89a --- /dev/null +++ b/migration.h @@ -0,0 +1,43 @@ +/* + * QEMU live migration + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MIGRATION_H +#define QEMU_MIGRATION_H + +#define MIG_STATE_ERROR -1 +#define MIG_STATE_COMPLETED 0 +#define MIG_STATE_CANCELLED 1 +#define MIG_STATE_ACTIVE 2 + +typedef struct MigrationState MigrationState; + +struct MigrationState +{ + /* FIXME: add more accessors to print migration info */ + void (*cancel)(MigrationState *s); + int (*get_status)(MigrationState *s); + void (*release)(MigrationState *s); +}; + +void qemu_start_incoming_migration(const char *uri); + +void do_migrate(int detach, const char *uri); + +void do_migrate_cancel(void); + +void do_migrate_set_speed(const char *value); + +void do_info_migrate(void); + +#endif + diff --git a/monitor.c b/monitor.c index dd2e770e68..4d7c782bca 100644 --- a/monitor.c +++ b/monitor.c @@ -36,6 +36,7 @@ #include "disas.h" #include #include "qemu-timer.h" +#include "migration.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -1454,6 +1455,12 @@ static const term_cmd_t term_cmds[] = { { "nmi", "i", do_inject_nmi, "cpu", "inject an NMI on the given CPU", }, #endif + { "migrate", "-ds", do_migrate, + "[-d] uri", "migrate to URI (using -d to not wait for completion)" }, + { "migrate_cancel", "", do_migrate_cancel, + "", "cancel the current VM migration" }, + { "migrate_set_speed", "s", do_migrate_set_speed, + "value", "set maximum speed (in bytes) for migrations" }, { NULL, NULL, }, }; @@ -1516,6 +1523,7 @@ static const term_cmd_t info_cmds[] = { { "slirp", "", do_info_slirp, "", "show SLIRP statistics", }, #endif + { "migrate", "", do_info_migrate, "", "show migration status" }, { NULL, NULL, }, }; diff --git a/qemu_socket.h b/qemu_socket.h index ef2d88bfe9..f8817bf86b 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -31,5 +31,6 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif /* !_WIN32 */ void socket_set_nonblock(int fd); +int parse_host_port(struct sockaddr_in *saddr, const char *str); #endif /* QEMU_SOCKET_H */ diff --git a/vl.c b/vl.c index c31f972aa0..190a408014 100644 --- a/vl.c +++ b/vl.c @@ -38,6 +38,7 @@ #include "qemu-char.h" #include "block.h" #include "audio/audio.h" +#include "migration.h" #include #include @@ -3364,7 +3365,6 @@ static void udp_chr_update_read_handler(CharDriverState *chr) } } -int parse_host_port(struct sockaddr_in *saddr, const char *str); #ifndef _WIN32 static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); #endif @@ -6766,6 +6766,8 @@ int qemu_savevm_state(QEMUFile *f) saved_vm_running = vm_running; vm_stop(0); + bdrv_flush_all(); + ret = qemu_savevm_state_begin(f); if (ret < 0) goto out; @@ -8338,6 +8340,7 @@ enum { QEMU_OPTION_tb_size, QEMU_OPTION_icount, QEMU_OPTION_uuid, + QEMU_OPTION_incoming, }; typedef struct QEMUOption { @@ -8450,6 +8453,7 @@ static const QEMUOption qemu_options[] = { { "startdate", HAS_ARG, QEMU_OPTION_startdate }, { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, { "icount", HAS_ARG, QEMU_OPTION_icount }, + { "incoming", HAS_ARG, QEMU_OPTION_incoming }, { NULL }, }; @@ -8742,6 +8746,7 @@ int main(int argc, char **argv) const char *pid_file = NULL; VLANState *vlan; int autostart; + const char *incoming = NULL; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -9349,6 +9354,9 @@ int main(int argc, char **argv) icount_time_shift = strtol(optarg, NULL, 0); } break; + case QEMU_OPTION_incoming: + incoming = optarg; + break; } } } @@ -9691,6 +9699,11 @@ int main(int argc, char **argv) if (loadvm) do_loadvm(loadvm); + if (incoming) { + autostart = 0; /* fixme how to deal with -daemonize */ + qemu_start_incoming_migration(incoming); + } + { /* XXX: simplify init */ read_passwords();