static void tcp_wait_for_connect(void *opaque) { FdMigrationState *s = opaque; int val, ret; socklen_t valsize = sizeof(val); dprintf("connect completed\n"); do { ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (char *)&val, &valsize); } while (ret == -1 && (s->get_error(s)) == EINTR); if (ret < 0) { migrate_fd_error(s); return; } qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); if (val == 0) migrate_fd_connect(s); else { dprintf("error connecting %d\n", val); migrate_fd_error(s); } }
static void migrate_fd_put_ready(void *opaque) { MigrationState *s = opaque; int ret; if (s->state != MIG_STATE_ACTIVE) { DPRINTF("put_ready returning because of non-active state\n"); return; } DPRINTF("iterate\n"); ret = qemu_savevm_state_iterate(s->mon, s->file); if (ret < 0) { migrate_fd_error(s); } else if (ret == 1) { int old_vm_running = runstate_is_running(); DPRINTF("done iterating\n"); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (qemu_savevm_state_complete(s->mon, s->file) < 0) { migrate_fd_error(s); } else { migrate_fd_completed(s); } if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); } } } }
void qmp_migrate(const char *uri, bool has_blk, bool blk, bool has_inc, bool inc, bool has_detach, bool detach, Error **errp) { Error *local_err = NULL; MigrationState *s = migrate_get_current(); MigrationParams params; const char *p; params.blk = has_blk && blk; params.shared = has_inc && inc; 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 (migration_blockers) { *errp = error_copy(migration_blockers->data); return; } s = migrate_init(¶ms); if (strstart(uri, "tcp:", &p)) { tcp_start_outgoing_migration(s, p, &local_err); #ifdef CONFIG_RDMA } else if (strstart(uri, "rdma:", &p)) { rdma_start_outgoing_migration(s, p, &local_err); #endif #if !defined(WIN32) } else if (strstart(uri, "exec:", &p)) { exec_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "unix:", &p)) { unix_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); #endif } else { error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); s->state = MIG_STATE_ERROR; return; } if (local_err) { migrate_fd_error(s); error_propagate(errp, local_err); return; } }
static void migrate_fd_put_notify(void *opaque) { MigrationState *s = opaque; qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); qemu_file_put_notify(s->file); if (s->file && qemu_file_get_error(s->file)) { migrate_fd_error(s); } }
static void migrate_ft_trans_error(FdMigrationState *s) { ft_mode = FT_ERROR; qemu_savevm_state_cancel(s->mon, s->file); migrate_fd_error(s); /* we need to set vm running to avoid assert in virtio-net */ vm_start(); event_tap_unregister(); vm_stop(0); }
static void migrate_fd_put_notify(void *opaque) { MigrationState *s = opaque; int ret; qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ret = qemu_file_put_notify(s->file); if (ret) { migrate_fd_error(s); } }
void qmp_migrate(const char *uri, bool has_blk, bool blk, bool has_inc, bool inc, bool has_detach, bool detach, Error **errp) { Error *local_err = NULL; MigrationState *s = migrate_get_current(); MigrationParams params; const char *p; params.blk = blk; params.shared = inc; if (s->state == MIG_STATE_ACTIVE) { error_set(errp, QERR_MIGRATION_ACTIVE); return; } if (qemu_savevm_state_blocked(errp)) { return; } if (migration_blockers) { *errp = error_copy(migration_blockers->data); return; } s = migrate_init(¶ms); if (strstart(uri, "tcp:", &p)) { tcp_start_outgoing_migration(s, p, &local_err); #if !defined(WIN32) } else if (strstart(uri, "exec:", &p)) { exec_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "unix:", &p)) { unix_start_outgoing_migration(s, p, &local_err); } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); #endif } else { error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); return; } if (local_err) { migrate_fd_error(s); error_propagate(errp, local_err); return; } notifier_list_notify(&migration_state_notifiers, s); }
static void tcp_wait_for_connect(int fd, void *opaque) { FdMigrationState *s = opaque; if (fd < 0) { DPRINTF("migrate connect error\n"); s->fd = -1; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); s->fd = fd; migrate_fd_connect(s); } }
static void unix_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; if (fd < 0) { DPRINTF("migrate connect error\n"); s->file = NULL; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); s->file = qemu_fopen_socket(fd, "wb"); migrate_fd_connect(s); } }
void migrate_fd_put_ready(MigrationState *s) { int ret; if (s->state != MIG_STATE_ACTIVE) { DPRINTF("put_ready returning because of non-active state\n"); return; } DPRINTF("iterate\n"); ret = qemu_savevm_state_iterate(s->file); if (ret < 0) { migrate_fd_error(s); } else if (ret == 1) { int old_vm_running = runstate_is_running(); int64_t start_time, end_time; DPRINTF("done iterating\n"); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (qemu_savevm_state_complete(s->file) < 0) { migrate_fd_error(s); } else { migrate_fd_completed(s); } end_time = qemu_get_clock_ms(rt_clock); s->total_time = end_time - s->total_time; s->downtime = end_time - start_time; if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); } } } }
static void unix_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; if (fd < 0) { DPRINTF("migrate connect error\n"); s->fd = -1; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); s->fd = fd; qemu_set_block(s->fd); migrate_fd_connect(s); } }
void migrate_fd_connect(MigrationState *s) { int ret; s->state = MIG_STATE_ACTIVE; s->file = qemu_fopen_ops_buffered(s); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file, &s->params); if (ret < 0) { DPRINTF("failed, %d\n", ret); migrate_fd_error(s); return; } migrate_fd_put_ready(s); }
static void migration_tls_outgoing_handshake(Object *src, Error *err, gpointer opaque) { MigrationState *s = opaque; QIOChannel *ioc = QIO_CHANNEL(src); if (err) { trace_migration_tls_outgoing_handshake_error(error_get_pretty(err)); s->to_dst_file = NULL; migrate_fd_error(s, err); } else { trace_migration_tls_outgoing_handshake_complete(); migration_set_outgoing_channel(s, ioc, NULL); } object_unref(OBJECT(ioc)); }
static void tcp_wait_for_connect(void *opaque) { FdMigrationState *s = opaque; int ret; dprintf("connect completed\n"); ret = socket_get_error(s->fd); if (ret < 0) { dprintf("error connecting %d\n", val); migrate_fd_error(s); return; } qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); migrate_fd_connect(s); }
static void socket_outgoing_migration(QIOTask *task, gpointer opaque) { struct SocketConnectData *data = opaque; QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); Error *err = NULL; if (qio_task_propagate_error(task, &err)) { trace_migration_socket_outgoing_error(error_get_pretty(err)); data->s->to_dst_file = NULL; migrate_fd_error(data->s, err); error_free(err); } else { trace_migration_socket_outgoing_connected(data->hostname); migration_channel_connect(data->s, sioc, data->hostname); } object_unref(OBJECT(sioc)); }
MigrationState *tcp_start_outgoing_migration(Monitor *mon, const char *host_port, int64_t bandwidth_limit, int detach, int blk, int inc, Error **errp) { FdMigrationState *s; s = qemu_mallocz(sizeof(*s)); s->get_error = socket_errno; s->write = socket_write; s->close = tcp_close; s->mig_state.cancel = migrate_fd_cancel; s->mig_state.get_status = migrate_fd_get_status; s->mig_state.release = migrate_fd_release; s->mig_state.blk = blk; s->mig_state.shared = inc; s->state = MIG_STATE_ACTIVE; trace_migrate_set_state(MIG_STATE_ACTIVE); s->mon = NULL; s->bandwidth_limit = bandwidth_limit; if (!detach) { migrate_fd_monitor_suspend(s, mon); } s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp); if (error_is_set(errp)) { migrate_fd_error(s); qemu_free(s); return NULL; } return &s->mig_state; }
void migrate_fd_connect(FdMigrationState *s) { int ret; s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit, migrate_fd_put_buffer, migrate_fd_put_ready, migrate_fd_wait_for_unfreeze, migrate_fd_close); dprintf("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file); if (ret < 0) { dprintf("failed, %d\n", ret); migrate_fd_error(s); return; } migrate_fd_put_ready(s); }
void migrate_fd_connect(MigrationState *s) { int ret; s->state = MIG_STATE_ACTIVE; s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit, migrate_fd_put_buffer, migrate_fd_put_ready, migrate_fd_wait_for_unfreeze, migrate_fd_close); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared); if (ret < 0) { DPRINTF("failed, %d\n", ret); migrate_fd_error(s); return; } migrate_fd_put_ready(s); }
static void *buffered_file_thread(void *opaque) { MigrationState *s = opaque; int64_t initial_time = qemu_get_clock_ms(rt_clock); int64_t max_size = 0; bool last_round = false; int ret; qemu_mutex_lock_iothread(); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file, &s->params); if (ret < 0) { DPRINTF("failed, %d\n", ret); qemu_mutex_unlock_iothread(); goto out; } qemu_mutex_unlock_iothread(); while (true) { int64_t current_time = qemu_get_clock_ms(rt_clock); uint64_t pending_size; qemu_mutex_lock_iothread(); if (s->state != MIG_STATE_ACTIVE) { DPRINTF("put_ready returning because of non-active state\n"); qemu_mutex_unlock_iothread(); break; } if (s->complete) { qemu_mutex_unlock_iothread(); break; } if (s->bytes_xfer < s->xfer_limit) { DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); if (pending_size && pending_size >= max_size) { ret = qemu_savevm_state_iterate(s->file); if (ret < 0) { qemu_mutex_unlock_iothread(); break; } } else { int old_vm_running = runstate_is_running(); int64_t start_time, end_time; DPRINTF("done iterating\n"); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); if (old_vm_running) { vm_stop(RUN_STATE_FINISH_MIGRATE); } else { vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); } ret = qemu_savevm_state_complete(s->file); if (ret < 0) { qemu_mutex_unlock_iothread(); break; } else { migrate_fd_completed(s); } end_time = qemu_get_clock_ms(rt_clock); s->total_time = end_time - s->total_time; s->downtime = end_time - start_time; if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); } } last_round = true; } } qemu_mutex_unlock_iothread(); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; uint64_t time_spent = current_time - initial_time; double bandwidth = transferred_bytes / time_spent; max_size = bandwidth * migrate_max_downtime() / 1000000; DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %g max_size %" PRId64 "\n", transferred_bytes, time_spent, bandwidth, max_size); s->bytes_xfer = 0; initial_time = current_time; } if (!last_round && (s->bytes_xfer >= s->xfer_limit)) { /* usleep expects microseconds */ g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); } ret = buffered_flush(s); if (ret < 0) { break; } } out: if (ret < 0) { migrate_fd_error(s); } g_free(s->buffer); return NULL; }