void migrate_fd_put_ready(void *opaque) { FdMigrationState *s = opaque; if (s->state != MIG_STATE_ACTIVE) { DPRINTF("put_ready returning because of non-active state\n"); return; } DPRINTF("iterate\n"); if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { int state; int old_vm_running = vm_running; DPRINTF("done iterating\n"); vm_stop(VMSTOP_MIGRATE); if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { vm_start(); } state = MIG_STATE_ERROR; } else { state = MIG_STATE_COMPLETED; } if (migrate_fd_cleanup(s) < 0) { if (old_vm_running) { vm_start(); } state = MIG_STATE_ERROR; } s->state = state; notifier_list_notify(&migration_state_notifiers); } }
static void migrate_ft_trans_connect(FdMigrationState *s, int old_vm_running) { /* close buffered_file and open ft_trans_file * NB: fd won't get closed, and reused by ft_trans_file */ qemu_fclose(s->file); s->file = qemu_fopen_ops_ft_trans(s, migrate_fd_put_buffer, migrate_fd_get_buffer, migrate_ft_trans_put_ready, migrate_ft_trans_get_ready, migrate_fd_wait_for_unfreeze, migrate_fd_close, 1); socket_set_nodelay(s->fd); /* events are tapped from now */ if (event_tap_register(migrate_ft_trans_put_ready) < 0) { migrate_ft_trans_error(s); } event_tap_schedule_suspend(); if (old_vm_running) { vm_start(); } }
MigrationState *migrate_get_current(void) { static MigrationState current_migration = { .state = MIG_STATE_NONE, .bandwidth_limit = MAX_THROTTLE, .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE, .mbps = -1, }; return ¤t_migration; } void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p; if (strstart(uri, "tcp:", &p)) tcp_start_incoming_migration(p, errp); #ifdef CONFIG_RDMA else if (strstart(uri, "rdma:", &p)) rdma_start_incoming_migration(p, errp); #endif #if !defined(WIN32) else if (strstart(uri, "exec:", &p)) exec_start_incoming_migration(p, errp); else if (strstart(uri, "unix:", &p)) unix_start_incoming_migration(p, errp); else if (strstart(uri, "fd:", &p)) fd_start_incoming_migration(p, errp); #endif else { error_setg(errp, "unknown migration protocol: %s", uri); } } static void process_incoming_migration_co(void *opaque) { QEMUFile *f = opaque; int ret; ret = qemu_loadvm_state(f); qemu_fclose(f); free_xbzrle_decoded_buf(); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); 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(); if (autostart) { vm_start(); } else { runstate_set(RUN_STATE_PAUSED); } }
static void process_incoming_migration_co(void *opaque) { QEMUFile *f = opaque; int ret; ret = qemu_loadvm_state(f); qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL); qemu_fclose(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); exit(0); } 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(); if (autostart) { vm_start(); } else { runstate_set(RUN_STATE_PAUSED); } }
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 migrate_fd_put_ready(void *opaque) { FdMigrationState *s = opaque; if (s->state != MIG_STATE_ACTIVE) { dprintf("put_ready returning because of non-active state\n"); return; } dprintf("iterate\n"); if (qemu_savevm_state_iterate(s->file) == 1) { int state; dprintf("done iterating\n"); vm_stop(0); bdrv_flush_all(); if ((qemu_savevm_state_complete(s->file)) < 0) { vm_start(); state = MIG_STATE_ERROR; } else { state = MIG_STATE_COMPLETED; } migrate_fd_cleanup(s); s->state = state; } }
void qmp_cont(Error **errp) { Error *local_err = NULL; BlockBackend *blk; BlockDriverState *bs; if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); return; } else if (runstate_check(RUN_STATE_SUSPENDED)) { return; } for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { blk_iostatus_reset(blk); } for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { bdrv_add_key(bs, NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; } } if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 1; } else { vm_start(); } }
int exec_start_incoming_migration(const char *command) { int ret; QEMUFile *f; dprintf("Attempting to start an incoming migration\n"); f = qemu_popen_cmd(command, "r"); if(f == NULL) { dprintf("Unable to apply qemu wrapper to popen file\n"); return -errno; } vm_stop(0); /* just in case */ ret = qemu_loadvm_state(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); goto err; } qemu_announce_self(); dprintf("successfully loaded vm state\n"); vm_start(); qemu_fclose(f); return 0; err: qemu_fclose(f); return -errno; }
void do_savevm(const char *name) { QEMUFile *f; int saved_vm_running, ret; f = qemu_fopen(name, "wb"); /* ??? Should this occur after vm_stop? */ qemu_aio_flush(); saved_vm_running = vm_running; vm_stop(0); if (!f) { fprintf(logfile, "Failed to open savevm file '%s'\n", name); goto the_end; } ret = qemu_savevm_state(f); qemu_fclose(f); if (ret < 0) fprintf(logfile, "Error %d while writing VM to savevm file '%s'\n", ret, name); the_end: if (saved_vm_running) vm_start(); return; }
int main(int argc, char** argv) { int fp = open(argv[1], O_RDONLY); if(fp < 0) { perror("Error opening file"); return 1; } VmFile vmfile = vmfile_open(fp); if(vmfile == NULL) { printf("Error: %d\n", vmerrno); return vmerrno; } printf("Header: %s\n", vmfile_header_get(vmfile)); printf("Version : %d.%d\n", vmfile_version_major_get(vmfile),\ vmfile_version_minor_get(vmfile)); printf("Start Of Code Segment: %d\n", vmfile_entry_get(vmfile)); printf("Instructions: %d\n", vmfile_size_get(vmfile)); printf("Instruction Dump:\n"); vmfile_inst_print(vmfile); printf("Output of Program\n"); VmState state = vmstate_new(vmfile); Vm vm = vm_new(vmfile, state); vm_start(vm); vmfile_close(vmfile); vmstate_del(state); vm_del(vm); return 0; }
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 int migrate_ft_trans_get_ready(void *opaque) { FdMigrationState *s = opaque; int ret = -1; if (ft_mode != FT_TRANSACTION_RECV) { fprintf(stderr, "migrate_ft_trans_get_ready: invalid ft_mode %d\n", ft_mode); goto error_out; } /* flush and check if events are remaining */ vm_start(); ret = event_tap_flush_one(); if (ret < 0) { fprintf(stderr, "event_tap_flush_one failed\n"); goto error_out; } if (ret) { ft_mode = FT_TRANSACTION_BEGIN; } else { ft_mode = FT_TRANSACTION_ATOMIC; ret = migrate_ft_trans_commit(s); if (ret < 0) { goto error_out; } if (ret) { goto out; } } vm_start(); ret = 0; goto out; error_out: migrate_ft_trans_error(s); out: return ret; }
/* Resume execution. */ static inline void gdb_continue(GDBState *s) { #ifdef CONFIG_USER_ONLY s->running_state = 1; #else if (!runstate_needs_reset()) { vm_start(); } #endif }
void process_incoming_migration(QEMUFile *f) { if (qemu_loadvm_state(f) < 0) { fprintf(stderr, "load of migration failed\n"); exit(0); } qemu_announce_self(); DPRINTF("successfully loaded vm state\n"); if (autostart) vm_start(); }
void qmp_cont(Error **errp) { Error *local_err = NULL; BlockBackend *blk; BlockDriverState *bs; BdrvNextIterator *it; /* if there is a dump in background, we should wait until the dump * finished */ if (dump_in_progress()) { error_setg(errp, "There is a dump in process, please wait."); return; } if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); return; } else if (runstate_check(RUN_STATE_SUSPENDED)) { return; } for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { blk_iostatus_reset(blk); } it = NULL; while ((it = bdrv_next(it, &bs))) { bdrv_add_key(bs, NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; } } /* Continuing after completed migration. Images have been inactivated to * allow the destination to take control. Need to get control back now. */ if (runstate_check(RUN_STATE_FINISH_MIGRATE) || runstate_check(RUN_STATE_POSTMIGRATE)) { bdrv_invalidate_cache_all(&local_err); if (local_err) { error_propagate(errp, local_err); return; } } if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 1; } else { vm_start(); } }
/* Resume execution. */ static inline void gdb_continue(GDBState *s) { #ifdef CONFIG_USER_ONLY s->running_state = 1; #else if (runstate_check(RUN_STATE_GUEST_PANICKED)) { runstate_set(RUN_STATE_DEBUG); } if (!runstate_needs_reset()) { vm_start(); } #endif }
void start_hypervisor() { int i; uint8_t nr_vcpus = 1; // TODO: It will be read from configuration file. uint32_t pcpu = smp_processor_id(); if (pcpu == 0) { timemanager_init(); sched_init(); vm_setup(); for (i = 0; i < NUM_GUESTS_STATIC; i++) { vmid_t vmid; if ((vmid = vm_create(nr_vcpus)) == VM_CREATE_FAILED) { printf("vm_create(vm[%d]) is failed\n", i); goto error; } if (vm_init(vmid) != HALTED) { printf("vm_init(vm[%d]) is failed\n", i); goto error; } if (vm_start(vmid) != RUNNING) { printf("vm_start(vm[%d]) is failed\n", i); goto error; } } smp_pen = 1; } else { while (!smp_pen) ; printf("cpu[%d] is enabled\n", pcpu); } /* * TODO: Add a function - return vmid or vcpu_id to execute for the first time. * TODO: Rename guest_sched_start to do_schedule or something others. * do_schedule(vmid) or do_schedule(vcpu_id) */ printf("sched_start!!!\n"); sched_start(); /* The code flow must not reach here */ error: printf("-------- [%s] ERROR: K-Hypervisor must not reach here\n", __func__); abort(); }
static void tcp_accept_incoming_migration(void *opaque) { struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); int s = (unsigned long)opaque; QEMUFile *f; int c, ret; do { c = accept(s, (struct sockaddr *)&addr, &addrlen); } while (c == -1 && socket_error() == EINTR); dprintf("accepted migration\n"); if (c == -1) { fprintf(stderr, "could not accept migration connection\n"); return; } f = qemu_fopen_socket(c); if (f == NULL) { fprintf(stderr, "could not qemu_fopen socket\n"); goto out; } vm_stop(0); /* just in case */ ret = qemu_loadvm_state(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); goto out_fopen; } qemu_announce_self(); dprintf("successfully loaded vm state\n"); /* we've successfully migrated, close the server socket */ qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); close(s); vm_start(); out_fopen: qemu_fclose(f); out: close(c); }
void process_incoming_migration(QEMUFile *f) { if (qemu_loadvm_state(f) < 0) { fprintf(stderr, "load of migration failed\n"); exit(0); } qemu_announce_self(); DPRINTF("successfully loaded vm state\n"); /* Make sure all file formats flush their mutable metadata */ bdrv_invalidate_cache_all(); if (autostart) { vm_start(); } else { runstate_set(RUN_STATE_PRELAUNCH); } }
void qmp_cont(Error **errp) { Error *local_err = NULL; BlockBackend *blk; BlockDriverState *bs; if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); return; } else if (runstate_check(RUN_STATE_SUSPENDED)) { return; } for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { blk_iostatus_reset(blk); } for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { bdrv_add_key(bs, NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return; } } /* Continuing after completed migration. Images have been inactivated to * allow the destination to take control. Need to get control back now. */ if (runstate_check(RUN_STATE_FINISH_MIGRATE) || runstate_check(RUN_STATE_POSTMIGRATE)) { bdrv_invalidate_cache_all(&local_err); if (local_err) { error_propagate(errp, local_err); return; } } if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 1; } else { vm_start(); } }
static void exec_accept_incoming_migration(void *opaque) { QEMUFile *f = opaque; int ret; ret = qemu_loadvm_state(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); goto err; } qemu_announce_self(); dprintf("successfully loaded vm state\n"); /* we've successfully migrated, close the fd */ qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL); if (autostart) vm_start(); err: qemu_fclose(f); }
void qmp_cont(Error **errp) { BlockBackend *blk; Error *local_err = NULL; /* if there is a dump in background, we should wait until the dump * finished */ if (dump_in_progress()) { error_setg(errp, "There is a dump in process, please wait."); return; } if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); return; } else if (runstate_check(RUN_STATE_SUSPENDED)) { return; } for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { blk_iostatus_reset(blk); } /* Continuing after completed migration. Images have been inactivated to * allow the destination to take control. Need to get control back now. * * If there are no inactive block nodes (e.g. because the VM was just * paused rather than completing a migration), bdrv_inactivate_all() simply * doesn't do anything. */ bdrv_invalidate_cache_all(&local_err); if (local_err) { error_propagate(errp, local_err); return; } if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 1; } else { vm_start(); } }
static void tcp_accept_incoming_migration(void *opaque) { SockAddress addr; int s = (unsigned long)opaque; QEMUFile *f; int c, ret; c = socket_accept(s, &addr); dprintf("accepted migration\n"); if (c == -1) { fprintf(stderr, "could not accept migration connection\n"); return; } f = qemu_fopen_socket(c); if (f == NULL) { fprintf(stderr, "could not qemu_fopen socket\n"); goto out; } vm_stop(0); /* just in case */ ret = qemu_loadvm_state(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); goto out_fopen; } qemu_announce_self(); dprintf("successfully loaded vm state\n"); /* we've successfully migrated, close the server socket */ qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL); socket_close(s); vm_start(); out_fopen: qemu_fclose(f); out: socket_close(c); }
void do_loadvm(const char *name) { QEMUFile *f; int saved_vm_running, ret; /* Flush all IO requests so they don't interfere with the new state. */ qemu_aio_flush(); saved_vm_running = vm_running; vm_stop(0); /* restore the VM state */ f = qemu_fopen(name, "rb"); if (!f) { fprintf(logfile, "Could not open VM state file\n"); goto the_end; } ret = qemu_loadvm_state(f); qemu_fclose(f); if (ret < 0) { fprintf(logfile, "Error %d while loading savevm file '%s'\n", ret, name); goto the_end; } #if 0 /* del tmp file */ if (unlink(name) == -1) fprintf(stderr, "delete tmp qemu state file failed.\n"); #endif the_end: if (saved_vm_running) vm_start(); }
static int vm_reboot_cb(vm_t* vm, void* token) { struct pwr_token* pwr_token = (struct pwr_token*)token; uint32_t dtb_addr; void* entry; int err; printf("Received reboot from linux\n"); //pwm_vmsig(0); vm_sem_wait(); return 0; // pwm_linux_action(1); return -1; #if 0 entry = install_linux_kernel(vm, pwr_token->linux_bin); dtb_addr = install_linux_dtb(vm, pwr_token->device_tree); if (entry == NULL || dtb_addr == 0) { printf("Failed to reload linux\n"); return -1; } err = vm_set_bootargs(vm, entry, MACH_TYPE, dtb_addr); if (err) { printf("Failed to set boot args\n"); return -1; } err = vm_start(vm); if (err) { printf("Failed to restart linux\n"); return -1; } printf("VM restarted\n"); return 0; #endif }
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 colo_process_checkpoint(MigrationState *s) { QIOChannelBuffer *bioc; QEMUFile *fb = NULL; int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); Error *local_err = NULL; int ret; failover_init_state(); s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file); if (!s->rp_state.from_dst_file) { error_report("Open QEMUFile from_dst_file failed"); goto out; } /* * Wait for Secondary finish loading VM states and enter COLO * restore. */ colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_CHECKPOINT_READY, &local_err); if (local_err) { goto out; } bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); vm_start(); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("stop", "run"); timer_mod(s->colo_delay_timer, current_time + s->parameters.x_checkpoint_delay); while (s->state == MIGRATION_STATUS_COLO) { if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); goto out; } qemu_sem_wait(&s->colo_checkpoint_sem); ret = colo_do_checkpoint_transaction(s, bioc, fb); if (ret < 0) { goto out; } } out: /* Throw the unreported error message after exited from loop */ if (local_err) { error_report_err(local_err); } if (fb) { qemu_fclose(fb); } timer_del(s->colo_delay_timer); /* Hope this not to be too long to wait here */ qemu_sem_wait(&s->colo_exit_sem); qemu_sem_destroy(&s->colo_exit_sem); /* * Must be called after failover BH is completed, * Or the failover BH may shutdown the wrong fd that * re-used by other threads after we release here. */ if (s->rp_state.from_dst_file) { qemu_fclose(s->rp_state.from_dst_file); } }
static int colo_do_checkpoint_transaction(MigrationState *s, QIOChannelBuffer *bioc, QEMUFile *fb) { Error *local_err = NULL; int ret = -1; colo_send_message(s->to_dst_file, COLO_MESSAGE_CHECKPOINT_REQUEST, &local_err); if (local_err) { goto out; } colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_CHECKPOINT_REPLY, &local_err); if (local_err) { goto out; } /* Reset channel-buffer directly */ qio_channel_io_seek(QIO_CHANNEL(bioc), 0, 0, NULL); bioc->usage = 0; qemu_mutex_lock_iothread(); if (failover_get_state() != FAILOVER_STATUS_NONE) { qemu_mutex_unlock_iothread(); goto out; } vm_stop_force_state(RUN_STATE_COLO); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("run", "stop"); /* * Failover request bh could be called after vm_stop_force_state(), * So we need check failover_request_is_active() again. */ if (failover_get_state() != FAILOVER_STATUS_NONE) { goto out; } /* Disable block migration */ s->params.blk = 0; s->params.shared = 0; qemu_savevm_state_header(fb); qemu_savevm_state_begin(fb, &s->params); qemu_mutex_lock_iothread(); qemu_savevm_state_complete_precopy(fb, false); qemu_mutex_unlock_iothread(); qemu_fflush(fb); colo_send_message(s->to_dst_file, COLO_MESSAGE_VMSTATE_SEND, &local_err); if (local_err) { goto out; } /* * We need the size of the VMstate data in Secondary side, * With which we can decide how much data should be read. */ colo_send_message_value(s->to_dst_file, COLO_MESSAGE_VMSTATE_SIZE, bioc->usage, &local_err); if (local_err) { goto out; } qemu_put_buffer(s->to_dst_file, bioc->data, bioc->usage); qemu_fflush(s->to_dst_file); ret = qemu_file_get_error(s->to_dst_file); if (ret < 0) { goto out; } colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_VMSTATE_RECEIVED, &local_err); if (local_err) { goto out; } colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_VMSTATE_LOADED, &local_err); if (local_err) { goto out; } ret = 0; qemu_mutex_lock_iothread(); vm_start(); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("stop", "run"); out: if (local_err) { error_report_err(local_err); } return ret; }
void *colo_process_incoming_thread(void *opaque) { MigrationIncomingState *mis = opaque; QEMUFile *fb = NULL; QIOChannelBuffer *bioc = NULL; /* Cache incoming device state */ uint64_t total_size; uint64_t value; Error *local_err = NULL; int ret; rcu_register_thread(); qemu_sem_init(&mis->colo_incoming_sem, 0); migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_COLO); failover_init_state(); mis->to_src_file = qemu_file_get_return_path(mis->from_src_file); if (!mis->to_src_file) { error_report("COLO incoming thread: Open QEMUFile to_src_file failed"); goto out; } /* * Note: the communication between Primary side and Secondary side * should be sequential, we set the fd to unblocked in migration incoming * coroutine, and here we are in the COLO incoming thread, so it is ok to * set the fd back to blocked. */ qemu_file_set_blocking(mis->from_src_file, true); bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); fb = qemu_fopen_channel_input(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); #ifdef CONFIG_REPLICATION replication_start_all(REPLICATION_MODE_SECONDARY, &local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } #else abort(); #endif vm_start(); trace_colo_vm_state_change("stop", "run"); qemu_mutex_unlock_iothread(); colo_send_message(mis->to_src_file, COLO_MESSAGE_CHECKPOINT_READY, &local_err); if (local_err) { goto out; } while (mis->state == MIGRATION_STATUS_COLO) { int request = 0; colo_wait_handle_message(mis->from_src_file, &request, &local_err); if (local_err) { goto out; } assert(request); if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); goto out; } qemu_mutex_lock_iothread(); vm_stop_force_state(RUN_STATE_COLO); trace_colo_vm_state_change("run", "stop"); qemu_mutex_unlock_iothread(); /* FIXME: This is unnecessary for periodic checkpoint mode */ colo_send_message(mis->to_src_file, COLO_MESSAGE_CHECKPOINT_REPLY, &local_err); if (local_err) { goto out; } colo_receive_check_message(mis->from_src_file, COLO_MESSAGE_VMSTATE_SEND, &local_err); if (local_err) { goto out; } qemu_mutex_lock_iothread(); cpu_synchronize_all_pre_loadvm(); ret = qemu_loadvm_state_main(mis->from_src_file, mis); qemu_mutex_unlock_iothread(); if (ret < 0) { error_report("Load VM's live state (ram) error"); goto out; } value = colo_receive_message_value(mis->from_src_file, COLO_MESSAGE_VMSTATE_SIZE, &local_err); if (local_err) { goto out; } /* * Read VM device state data into channel buffer, * It's better to re-use the memory allocated. * Here we need to handle the channel buffer directly. */ if (value > bioc->capacity) { bioc->capacity = value; bioc->data = g_realloc(bioc->data, bioc->capacity); } total_size = qemu_get_buffer(mis->from_src_file, bioc->data, value); if (total_size != value) { error_report("Got %" PRIu64 " VMState data, less than expected" " %" PRIu64, total_size, value); goto out; } bioc->usage = total_size; qio_channel_io_seek(QIO_CHANNEL(bioc), 0, 0, NULL); colo_send_message(mis->to_src_file, COLO_MESSAGE_VMSTATE_RECEIVED, &local_err); if (local_err) { goto out; } qemu_mutex_lock_iothread(); vmstate_loading = true; ret = qemu_load_device_state(fb); if (ret < 0) { error_report("COLO: load device state failed"); qemu_mutex_unlock_iothread(); goto out; } #ifdef CONFIG_REPLICATION replication_get_error_all(&local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } /* discard colo disk buffer */ replication_do_checkpoint_all(&local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } #else abort(); #endif /* Notify all filters of all NIC to do checkpoint */ colo_notify_filters_event(COLO_EVENT_CHECKPOINT, &local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } vmstate_loading = false; vm_start(); trace_colo_vm_state_change("stop", "run"); qemu_mutex_unlock_iothread(); if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) { failover_set_state(FAILOVER_STATUS_RELAUNCH, FAILOVER_STATUS_NONE); failover_request_active(NULL); goto out; } colo_send_message(mis->to_src_file, COLO_MESSAGE_VMSTATE_LOADED, &local_err); if (local_err) { goto out; } } out: vmstate_loading = false; /* Throw the unreported error message after exited from loop */ if (local_err) { error_report_err(local_err); } switch (failover_get_state()) { case FAILOVER_STATUS_NONE: qapi_event_send_colo_exit(COLO_MODE_SECONDARY, COLO_EXIT_REASON_ERROR); break; case FAILOVER_STATUS_REQUIRE: qapi_event_send_colo_exit(COLO_MODE_SECONDARY, COLO_EXIT_REASON_REQUEST); break; default: abort(); } if (fb) { qemu_fclose(fb); } /* Hope this not to be too long to loop here */ qemu_sem_wait(&mis->colo_incoming_sem); qemu_sem_destroy(&mis->colo_incoming_sem); /* Must be called after failover BH is completed */ if (mis->to_src_file) { qemu_fclose(mis->to_src_file); } migration_incoming_disable_colo(); rcu_unregister_thread(); return NULL; }
static void colo_process_checkpoint(MigrationState *s) { QIOChannelBuffer *bioc; QEMUFile *fb = NULL; int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); Error *local_err = NULL; int ret; failover_init_state(); s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file); if (!s->rp_state.from_dst_file) { error_report("Open QEMUFile from_dst_file failed"); goto out; } packets_compare_notifier.notify = colo_compare_notify_checkpoint; colo_compare_register_notifier(&packets_compare_notifier); /* * Wait for Secondary finish loading VM states and enter COLO * restore. */ colo_receive_check_message(s->rp_state.from_dst_file, COLO_MESSAGE_CHECKPOINT_READY, &local_err); if (local_err) { goto out; } bioc = qio_channel_buffer_new(COLO_BUFFER_BASE_SIZE); fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc)); object_unref(OBJECT(bioc)); qemu_mutex_lock_iothread(); #ifdef CONFIG_REPLICATION replication_start_all(REPLICATION_MODE_PRIMARY, &local_err); if (local_err) { qemu_mutex_unlock_iothread(); goto out; } #else abort(); #endif vm_start(); qemu_mutex_unlock_iothread(); trace_colo_vm_state_change("stop", "run"); timer_mod(s->colo_delay_timer, current_time + s->parameters.x_checkpoint_delay); while (s->state == MIGRATION_STATUS_COLO) { if (failover_get_state() != FAILOVER_STATUS_NONE) { error_report("failover request"); goto out; } qemu_sem_wait(&s->colo_checkpoint_sem); if (s->state != MIGRATION_STATUS_COLO) { goto out; } ret = colo_do_checkpoint_transaction(s, bioc, fb); if (ret < 0) { goto out; } } out: /* Throw the unreported error message after exited from loop */ if (local_err) { error_report_err(local_err); } if (fb) { qemu_fclose(fb); } /* * There are only two reasons we can get here, some error happened * or the user triggered failover. */ switch (failover_get_state()) { case FAILOVER_STATUS_NONE: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_ERROR); break; case FAILOVER_STATUS_REQUIRE: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_REQUEST); break; default: abort(); } /* Hope this not to be too long to wait here */ qemu_sem_wait(&s->colo_exit_sem); qemu_sem_destroy(&s->colo_exit_sem); /* * It is safe to unregister notifier after failover finished. * Besides, colo_delay_timer and colo_checkpoint_sem can't be * released befor unregister notifier, or there will be use-after-free * error. */ colo_compare_unregister_notifier(&packets_compare_notifier); timer_del(s->colo_delay_timer); timer_free(s->colo_delay_timer); qemu_sem_destroy(&s->colo_checkpoint_sem); /* * Must be called after failover BH is completed, * Or the failover BH may shutdown the wrong fd that * re-used by other threads after we release here. */ if (s->rp_state.from_dst_file) { qemu_fclose(s->rp_state.from_dst_file); } }