Exemplo n.º 1
0
/* Register a handler for external shared memory postcopy
 * called on the destination.
 */
void postcopy_register_shared_ufd(struct PostCopyFD *pcfd)
{
    MigrationIncomingState *mis = migration_incoming_get_current();

    mis->postcopy_remote_fds = g_array_append_val(mis->postcopy_remote_fds,
                                                  *pcfd);
}
Exemplo n.º 2
0
static uint32_t get_postcopy_total_blocktime(void)
{
    MigrationIncomingState *mis = migration_incoming_get_current();
    PostcopyBlocktimeContext *bc = mis->blocktime_ctx;

    if (!bc) {
        return 0;
    }

    return bc->total_blocktime;
}
Exemplo n.º 3
0
Arquivo: colo.c Projeto: mmuman/qemu
static void secondary_vm_do_failover(void)
{
    int old_state;
    MigrationIncomingState *mis = migration_incoming_get_current();

    /* Can not do failover during the process of VM's loading VMstate, Or
     * it will break the secondary VM.
     */
    if (vmstate_loading) {
        old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
                        FAILOVER_STATUS_RELAUNCH);
        if (old_state != FAILOVER_STATUS_ACTIVE) {
            error_report("Unknown error while do failover for secondary VM,"
                         "old_state: %s", FailoverStatus_lookup[old_state]);
        }
        return;
    }

    migrate_set_state(&mis->state, MIGRATION_STATUS_COLO,
                      MIGRATION_STATUS_COMPLETED);

    if (!autostart) {
        error_report("\"-S\" qemu option will be ignored in secondary side");
        /* recover runstate to normal migration finish state */
        autostart = true;
    }
    /*
     * Make sure COLO incoming thread not block in recv or send,
     * If mis->from_src_file and mis->to_src_file use the same fd,
     * The second shutdown() will return -1, we ignore this value,
     * It is harmless.
     */
    if (mis->from_src_file) {
        qemu_file_shutdown(mis->from_src_file);
    }
    if (mis->to_src_file) {
        qemu_file_shutdown(mis->to_src_file);
    }

    old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
                                   FAILOVER_STATUS_COMPLETED);
    if (old_state != FAILOVER_STATUS_ACTIVE) {
        error_report("Incorrect state (%s) while doing failover for "
                     "secondary VM", FailoverStatus_lookup[old_state]);
        return;
    }
    /* Notify COLO incoming thread that failover work is finished */
    qemu_sem_post(&mis->colo_incoming_sem);
    /* For Secondary VM, jump to incoming co */
    if (mis->migration_incoming_co) {
        qemu_coroutine_enter(mis->migration_incoming_co);
    }
}
Exemplo n.º 4
0
/*
 * This function just populates MigrationInfo from postcopy's
 * blocktime context. It will not populate MigrationInfo,
 * unless postcopy-blocktime capability was set.
 *
 * @info: pointer to MigrationInfo to populate
 */
void fill_destination_postcopy_migration_info(MigrationInfo *info)
{
    MigrationIncomingState *mis = migration_incoming_get_current();
    PostcopyBlocktimeContext *bc = mis->blocktime_ctx;

    if (!bc) {
        return;
    }

    info->has_postcopy_blocktime = true;
    info->postcopy_blocktime = bc->total_blocktime;
    info->has_postcopy_vcpu_blocktime = true;
    info->postcopy_vcpu_blocktime = get_vcpu_blocktime_list(bc);
}
Exemplo n.º 5
0
/* Unregister a handler for external shared memory postcopy
 */
void postcopy_unregister_shared_ufd(struct PostCopyFD *pcfd)
{
    guint i;
    MigrationIncomingState *mis = migration_incoming_get_current();
    GArray *pcrfds = mis->postcopy_remote_fds;

    for (i = 0; i < pcrfds->len; i++) {
        struct PostCopyFD *cur = &g_array_index(pcrfds, struct PostCopyFD, i);
        if (cur->fd == pcfd->fd) {
            mis->postcopy_remote_fds = g_array_remove_index(pcrfds, i);
            return;
        }
    }
}
Exemplo n.º 6
0
int postcopy_notify_shared_wake(RAMBlock *rb, uint64_t offset)
{
    int i;
    MigrationIncomingState *mis = migration_incoming_get_current();
    GArray *pcrfds = mis->postcopy_remote_fds;

    for (i = 0; i < pcrfds->len; i++) {
        struct PostCopyFD *cur = &g_array_index(pcrfds, struct PostCopyFD, i);
        int ret = cur->waker(cur, rb, offset);
        if (ret) {
            return ret;
        }
    }
    return 0;
}
Exemplo n.º 7
0
/*
 *  This function just provide calculated blocktime per cpu and trace it.
 *  Total blocktime is calculated in mark_postcopy_blocktime_end.
 *
 *
 * Assume we have 3 CPU
 *
 *      S1        E1           S1               E1
 * -----***********------------xxx***************------------------------> CPU1
 *
 *             S2                E2
 * ------------****************xxx---------------------------------------> CPU2
 *
 *                         S3            E3
 * ------------------------****xxx********-------------------------------> CPU3
 *
 * We have sequence S1,S2,E1,S3,S1,E2,E3,E1
 * S2,E1 - doesn't match condition due to sequence S1,S2,E1 doesn't include CPU3
 * S3,S1,E2 - sequence includes all CPUs, in this case overlap will be S1,E2 -
 *            it's a part of total blocktime.
 * S1 - here is last_begin
 * Legend of the picture is following:
 *              * - means blocktime per vCPU
 *              x - means overlapped blocktime (total blocktime)
 *
 * @addr: host virtual address
 */
static void mark_postcopy_blocktime_end(uintptr_t addr)
{
    MigrationIncomingState *mis = migration_incoming_get_current();
    PostcopyBlocktimeContext *dc = mis->blocktime_ctx;
    int i, affected_cpu = 0;
    bool vcpu_total_blocktime = false;
    uint32_t read_vcpu_time, low_time_offset;

    if (!dc) {
        return;
    }

    low_time_offset = get_low_time_offset(dc);
    /* lookup cpu, to clear it,
     * that algorithm looks straighforward, but it's not
     * optimal, more optimal algorithm is keeping tree or hash
     * where key is address value is a list of  */
    for (i = 0; i < smp_cpus; i++) {
        uint32_t vcpu_blocktime = 0;

        read_vcpu_time = atomic_fetch_add(&dc->page_fault_vcpu_time[i], 0);
        if (atomic_fetch_add(&dc->vcpu_addr[i], 0) != addr ||
            read_vcpu_time == 0) {
            continue;
        }
        atomic_xchg(&dc->vcpu_addr[i], 0);
        vcpu_blocktime = low_time_offset - read_vcpu_time;
        affected_cpu += 1;
        /* we need to know is that mark_postcopy_end was due to
         * faulted page, another possible case it's prefetched
         * page and in that case we shouldn't be here */
        if (!vcpu_total_blocktime &&
            atomic_fetch_add(&dc->smp_cpus_down, 0) == smp_cpus) {
            vcpu_total_blocktime = true;
        }
        /* continue cycle, due to one page could affect several vCPUs */
        dc->vcpu_blocktime[i] += vcpu_blocktime;
    }

    atomic_sub(&dc->smp_cpus_down, affected_cpu);
    if (vcpu_total_blocktime) {
        dc->total_blocktime += low_time_offset - atomic_fetch_add(
                &dc->last_begin, 0);
    }
    trace_mark_postcopy_blocktime_end(addr, dc, dc->total_blocktime,
                                      affected_cpu);
}
Exemplo n.º 8
0
/*
 * This function is being called when pagefault occurs. It
 * tracks down vCPU blocking time.
 *
 * @addr: faulted host virtual address
 * @ptid: faulted process thread id
 * @rb: ramblock appropriate to addr
 */
static void mark_postcopy_blocktime_begin(uintptr_t addr, uint32_t ptid,
                                          RAMBlock *rb)
{
    int cpu, already_received;
    MigrationIncomingState *mis = migration_incoming_get_current();
    PostcopyBlocktimeContext *dc = mis->blocktime_ctx;
    uint32_t low_time_offset;

    if (!dc || ptid == 0) {
        return;
    }
    cpu = get_mem_fault_cpu_index(ptid);
    if (cpu < 0) {
        return;
    }

    low_time_offset = get_low_time_offset(dc);
    if (dc->vcpu_addr[cpu] == 0) {
        atomic_inc(&dc->smp_cpus_down);
    }

    atomic_xchg(&dc->last_begin, low_time_offset);
    atomic_xchg(&dc->page_fault_vcpu_time[cpu], low_time_offset);
    atomic_xchg(&dc->vcpu_addr[cpu], addr);

    /* check it here, not at the begining of the function,
     * due to, check could accur early than bitmap_set in
     * qemu_ufd_copy_ioctl */
    already_received = ramblock_recv_bitmap_test(rb, (void *)addr);
    if (already_received) {
        atomic_xchg(&dc->vcpu_addr[cpu], 0);
        atomic_xchg(&dc->page_fault_vcpu_time[cpu], 0);
        atomic_dec(&dc->smp_cpus_down);
    }
    trace_mark_postcopy_blocktime_begin(addr, dc, dc->page_fault_vcpu_time[cpu],
                                        cpu, already_received);
}
Exemplo n.º 9
0
/*
 * Callback from shared fault handlers to ask for a page,
 * the page must be specified by a RAMBlock and an offset in that rb
 * Note: Only for use by shared fault handlers (in fault thread)
 */
int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb,
                                 uint64_t client_addr, uint64_t rb_offset)
{
    size_t pagesize = qemu_ram_pagesize(rb);
    uint64_t aligned_rbo = rb_offset & ~(pagesize - 1);
    MigrationIncomingState *mis = migration_incoming_get_current();

    trace_postcopy_request_shared_page(pcfd->idstr, qemu_ram_get_idstr(rb),
                                       rb_offset);
    if (ramblock_recv_bitmap_test_byte_offset(rb, aligned_rbo)) {
        trace_postcopy_request_shared_page_present(pcfd->idstr,
                                        qemu_ram_get_idstr(rb), rb_offset);
        return postcopy_wake_shared(pcfd, client_addr, rb);
    }
    if (rb != mis->last_rb) {
        mis->last_rb = rb;
        migrate_send_rp_req_pages(mis, qemu_ram_get_idstr(rb),
                                  aligned_rbo, pagesize);
    } else {
        /* Save some space */
        migrate_send_rp_req_pages(mis, NULL, aligned_rbo, pagesize);
    }
    return 0;
}
Exemplo n.º 10
0
Arquivo: colo.c Projeto: mmuman/qemu
bool migration_incoming_in_colo_state(void)
{
    MigrationIncomingState *mis = migration_incoming_get_current();

    return mis && (mis->state == MIGRATION_STATUS_COLO);
}
Exemplo n.º 11
0
Arquivo: colo.c Projeto: CTU-IIG/qemu
static void secondary_vm_do_failover(void)
{
/* COLO needs enable block-replication */
#ifdef CONFIG_REPLICATION
    int old_state;
    MigrationIncomingState *mis = migration_incoming_get_current();
    Error *local_err = NULL;

    /* Can not do failover during the process of VM's loading VMstate, Or
     * it will break the secondary VM.
     */
    if (vmstate_loading) {
        old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
                        FAILOVER_STATUS_RELAUNCH);
        if (old_state != FAILOVER_STATUS_ACTIVE) {
            error_report("Unknown error while do failover for secondary VM,"
                         "old_state: %s", FailoverStatus_str(old_state));
        }
        return;
    }

    migrate_set_state(&mis->state, MIGRATION_STATUS_COLO,
                      MIGRATION_STATUS_COMPLETED);

    replication_stop_all(true, &local_err);
    if (local_err) {
        error_report_err(local_err);
    }

    /* Notify all filters of all NIC to do checkpoint */
    colo_notify_filters_event(COLO_EVENT_FAILOVER, &local_err);
    if (local_err) {
        error_report_err(local_err);
    }

    if (!autostart) {
        error_report("\"-S\" qemu option will be ignored in secondary side");
        /* recover runstate to normal migration finish state */
        autostart = true;
    }
    /*
     * Make sure COLO incoming thread not block in recv or send,
     * If mis->from_src_file and mis->to_src_file use the same fd,
     * The second shutdown() will return -1, we ignore this value,
     * It is harmless.
     */
    if (mis->from_src_file) {
        qemu_file_shutdown(mis->from_src_file);
    }
    if (mis->to_src_file) {
        qemu_file_shutdown(mis->to_src_file);
    }

    old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
                                   FAILOVER_STATUS_COMPLETED);
    if (old_state != FAILOVER_STATUS_ACTIVE) {
        error_report("Incorrect state (%s) while doing failover for "
                     "secondary VM", FailoverStatus_str(old_state));
        return;
    }
    /* Notify COLO incoming thread that failover work is finished */
    qemu_sem_post(&mis->colo_incoming_sem);
    /* For Secondary VM, jump to incoming co */
    if (mis->migration_incoming_co) {
        qemu_coroutine_enter(mis->migration_incoming_co);
    }
#else
    abort();
#endif
}