Пример #1
0
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);
    }
}
Пример #2
0
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();
    }
}
Пример #3
0
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 &current_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);
    }
}
Пример #4
0
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);
    }
}
Пример #5
0
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();
            }
        }
    }
}
Пример #6
0
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;
    }
}
Пример #7
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
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);
}
Пример #12
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;
}
Пример #13
0
/* 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
}
Пример #14
0
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();
}
Пример #15
0
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();
    }
}
Пример #16
0
/* 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
}
Пример #17
0
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);
}
Пример #19
0
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);
    }
}
Пример #20
0
Файл: qmp.c Проект: jjykh/qemu
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();
    }
}
Пример #21
0
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);
}
Пример #22
0
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();
    }
}
Пример #23
0
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);
}
Пример #24
0
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();
}
Пример #25
0
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
}
Пример #26
0
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();
            }
        }
    }
}
Пример #27
0
Файл: colo.c Проект: mmuman/qemu
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);
    }
}
Пример #28
0
Файл: colo.c Проект: mmuman/qemu
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;
}
Пример #29
0
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;
}
Пример #30
0
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);
    }
}