#include "qmp-commands.h"
#include "trace.h"
-//#define DEBUG_MIGRATION
-
-#ifdef DEBUG_MIGRATION
-#define DPRINTF(fmt, ...) \
- do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
enum {
MIG_STATE_ERROR = -1,
MIG_STATE_NONE,
MIG_STATE_SETUP,
+ MIG_STATE_CANCELLING,
MIG_STATE_CANCELLED,
MIG_STATE_ACTIVE,
MIG_STATE_COMPLETED,
if (strstart(uri, "tcp:", &p))
tcp_start_incoming_migration(p, errp);
#ifdef CONFIG_RDMA
- else if (strstart(uri, "x-rdma:", &p))
+ else if (strstart(uri, "rdma:", &p))
rdma_start_incoming_migration(p, errp);
#endif
#if !defined(WIN32)
static void process_incoming_migration_co(void *opaque)
{
QEMUFile *f = opaque;
+ Error *local_err = NULL;
int ret;
ret = qemu_loadvm_state(f);
qemu_fclose(f);
+ free_xbzrle_decoded_buf();
if (ret < 0) {
- fprintf(stderr, "load of migration failed\n");
+ error_report("load of migration failed: %s", strerror(-ret));
exit(EXIT_FAILURE);
}
qemu_announce_self();
- DPRINTF("successfully loaded vm state\n");
- bdrv_clear_incoming_migration_all();
/* Make sure all file formats flush their mutable metadata */
- bdrv_invalidate_cache_all();
+ bdrv_invalidate_cache_all(&local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ exit(EXIT_FAILURE);
+ }
if (autostart) {
vm_start();
* the choice of nanoseconds is because it is the maximum resolution that
* get_clock() can achieve. It is an internal measure. All user-visible
* units must be in seconds */
-static uint64_t max_downtime = 30000000;
+static uint64_t max_downtime = 300000000;
uint64_t migrate_max_downtime(void)
{
MigrationState *s = migrate_get_current();
int i;
+ caps = NULL; /* silence compiler warning */
for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
if (head == NULL) {
head = g_malloc0(sizeof(*caps));
info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->cache_miss_rate = xbzrle_mig_cache_miss_rate();
info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
}
}
info->has_total_time = false;
break;
case MIG_STATE_ACTIVE:
+ case MIG_STATE_CANCELLING:
info->has_status = true;
info->status = g_strdup("active");
info->has_total_time = true;
info->ram->normal_bytes = norm_mig_bytes_transferred();
info->ram->dirty_pages_rate = s->dirty_pages_rate;
info->ram->mbps = s->mbps;
+ info->ram->dirty_sync_count = s->dirty_sync_count;
if (blk_mig_active()) {
info->has_disk = true;
info->ram->normal = norm_mig_pages_transferred();
info->ram->normal_bytes = norm_mig_bytes_transferred();
info->ram->mbps = s->mbps;
+ info->ram->dirty_sync_count = s->dirty_sync_count;
break;
case MIG_STATE_ERROR:
info->has_status = true;
/* shared migration helpers */
+static void migrate_set_state(MigrationState *s, int old_state, int new_state)
+{
+ if (atomic_cmpxchg(&s->state, old_state, new_state) == new_state) {
+ trace_migrate_set_state(new_state);
+ }
+}
+
static void migrate_fd_cleanup(void *opaque)
{
MigrationState *s = opaque;
s->cleanup_bh = NULL;
if (s->file) {
- DPRINTF("closing file\n");
+ trace_migrate_fd_cleanup();
qemu_mutex_unlock_iothread();
qemu_thread_join(&s->thread);
qemu_mutex_lock_iothread();
if (s->state != MIG_STATE_COMPLETED) {
qemu_savevm_state_cancel();
+ if (s->state == MIG_STATE_CANCELLING) {
+ migrate_set_state(s, MIG_STATE_CANCELLING, MIG_STATE_CANCELLED);
+ }
}
notifier_list_notify(&migration_state_notifiers, s);
}
-static void migrate_set_state(MigrationState *s, int old_state, int new_state)
-{
- if (atomic_cmpxchg(&s->state, old_state, new_state) == new_state) {
- trace_migrate_set_state(new_state);
- }
-}
-
void migrate_fd_error(MigrationState *s)
{
- DPRINTF("setting error state\n");
+ trace_migrate_fd_error();
assert(s->file == NULL);
s->state = MIG_STATE_ERROR;
trace_migrate_set_state(MIG_STATE_ERROR);
static void migrate_fd_cancel(MigrationState *s)
{
- DPRINTF("cancelling migration\n");
+ int old_state ;
+ trace_migrate_fd_cancel();
- migrate_set_state(s, s->state, MIG_STATE_CANCELLED);
+ do {
+ old_state = s->state;
+ if (old_state != MIG_STATE_SETUP && old_state != MIG_STATE_ACTIVE) {
+ break;
+ }
+ migrate_set_state(s, old_state, MIG_STATE_CANCELLING);
+ } while (s->state != MIG_STATE_CANCELLING);
}
void add_migration_state_change_notifier(Notifier *notify)
params.blk = has_blk && blk;
params.shared = has_inc && inc;
- if (s->state == MIG_STATE_ACTIVE || s->state == MIG_STATE_SETUP) {
+ if (s->state == MIG_STATE_ACTIVE || s->state == MIG_STATE_SETUP ||
+ s->state == MIG_STATE_CANCELLING) {
error_set(errp, QERR_MIGRATION_ACTIVE);
return;
}
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ error_setg(errp, "Guest is waiting for an incoming migration");
+ return;
+ }
+
if (qemu_savevm_state_blocked(errp)) {
return;
}
if (strstart(uri, "tcp:", &p)) {
tcp_start_outgoing_migration(s, p, &local_err);
#ifdef CONFIG_RDMA
- } else if (strstart(uri, "x-rdma:", &p)) {
+ } else if (strstart(uri, "rdma:", &p)) {
rdma_start_outgoing_migration(s, p, &local_err);
#endif
#if !defined(WIN32)
#endif
} else {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol");
+ s->state = MIG_STATE_ERROR;
return;
}
void qmp_migrate_set_cache_size(int64_t value, Error **errp)
{
MigrationState *s = migrate_get_current();
+ int64_t new_size;
/* Check for truncation */
if (value != (size_t)value) {
return;
}
- s->xbzrle_cache_size = xbzrle_cache_resize(value);
+ /* Cache should not be larger than guest ram size */
+ if (value > ram_bytes_total()) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "exceeds guest ram size ");
+ return;
+ }
+
+ new_size = xbzrle_cache_resize(value);
+ if (new_size < 0) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "is smaller than page size");
+ return;
+ }
+
+ s->xbzrle_cache_size = new_size;
}
int64_t qmp_query_migrate_cache_size(Error **errp)
s = migrate_get_current();
- return s->enabled_capabilities[MIGRATION_CAPABILITY_X_RDMA_PIN_ALL];
+ return s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
}
bool migrate_auto_converge(void)
int64_t start_time = initial_time;
bool old_vm_running = false;
- DPRINTF("beginning savevm\n");
qemu_savevm_state_begin(s->file, &s->params);
s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start;
migrate_set_state(s, MIG_STATE_SETUP, MIG_STATE_ACTIVE);
- DPRINTF("setup complete\n");
-
while (s->state == MIG_STATE_ACTIVE) {
int64_t current_time;
uint64_t pending_size;
if (!qemu_file_rate_limit(s->file)) {
- DPRINTF("iterate\n");
pending_size = qemu_savevm_state_pending(s->file, max_size);
- DPRINTF("pending size %" PRIu64 " max %" PRIu64 "\n",
- pending_size, max_size);
+ trace_migrate_pending(pending_size, max_size);
if (pending_size && pending_size >= max_size) {
qemu_savevm_state_iterate(s->file);
} else {
int ret;
- DPRINTF("done iterating\n");
qemu_mutex_lock_iothread();
start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
if (ret >= 0) {
- qemu_file_set_rate_limit(s->file, INT_MAX);
+ qemu_file_set_rate_limit(s->file, INT64_MAX);
qemu_savevm_state_complete(s->file);
}
qemu_mutex_unlock_iothread();
s->mbps = time_spent ? (((double) transferred_bytes * 8.0) /
((double) time_spent / 1000.0)) / 1000.0 / 1000.0 : -1;
- DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64
- " bandwidth %g max_size %" PRId64 "\n",
- transferred_bytes, time_spent, bandwidth, max_size);
+ trace_migrate_transferred(transferred_bytes, time_spent,
+ bandwidth, max_size);
/* if we haven't sent anything, we don't want to recalculate
10000 is a small enough number for our purposes */
if (s->dirty_bytes_rate && transferred_bytes > 10000) {
qemu_mutex_lock_iothread();
if (s->state == MIG_STATE_COMPLETED) {
int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+ uint64_t transferred_bytes = qemu_ftell(s->file);
s->total_time = end_time - s->total_time;
s->downtime = end_time - start_time;
+ if (s->total_time) {
+ s->mbps = (((double) transferred_bytes * 8.0) /
+ ((double) s->total_time)) / 1000;
+ }
runstate_set(RUN_STATE_POSTMIGRATE);
} else {
if (old_vm_running) {
/* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s);
- qemu_thread_create(&s->thread, migration_thread, s,
+ qemu_thread_create(&s->thread, "migration", migration_thread, s,
QEMU_THREAD_JOINABLE);
}