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
--- /dev/null
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * 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;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * 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
+
#include "disas.h"
#include <dirent.h>
#include "qemu-timer.h"
+#include "migration.h"
//#define DEBUG
//#define DEBUG_COMPLETION
{ "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, },
};
{ "slirp", "", do_info_slirp,
"", "show SLIRP statistics", },
#endif
+ { "migrate", "", do_info_migrate, "", "show migration status" },
{ NULL, NULL, },
};
#endif /* !_WIN32 */
void socket_set_nonblock(int fd);
+int parse_host_port(struct sockaddr_in *saddr, const char *str);
#endif /* QEMU_SOCKET_H */
#include "qemu-char.h"
#include "block.h"
#include "audio/audio.h"
+#include "migration.h"
#include <unistd.h>
#include <fcntl.h>
}
}
-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
saved_vm_running = vm_running;
vm_stop(0);
+ bdrv_flush_all();
+
ret = qemu_savevm_state_begin(f);
if (ret < 0)
goto out;
QEMU_OPTION_tb_size,
QEMU_OPTION_icount,
QEMU_OPTION_uuid,
+ QEMU_OPTION_incoming,
};
typedef struct QEMUOption {
{ "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 },
};
const char *pid_file = NULL;
VLANState *vlan;
int autostart;
+ const char *incoming = NULL;
LIST_INIT (&vm_change_state_head);
#ifndef _WIN32
icount_time_shift = strtol(optarg, NULL, 0);
}
break;
+ case QEMU_OPTION_incoming:
+ incoming = optarg;
+ break;
}
}
}
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();