Commit 80fda8f6 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20151119' into staging



migration/next for 20151119

# gpg: Signature made Thu 19 Nov 2015 11:17:07 GMT using RSA key ID 5872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>"
# gpg:                 aka "Juan Quintela <quintela@trasno.org>"

* remotes/juanquintela/tags/migration/20151119:
  migration: normalize locking in migration/savevm.c
  migration: implement bdrv_all_find_vmstate_bs helper
  migration: reorder processing in hmp_savevm
  snapshot: create bdrv_all_create_snapshot helper
  migration: drop find_vmstate_bs check in hmp_delvm
  snapshot: create bdrv_all_find_snapshot helper
  migration: factor our snapshottability check in load_vmstate
  snapshot: create bdrv_all_goto_snapshot helper
  snapshot: create bdrv_all_delete_snapshot helper
  snapshot: return error code from bdrv_snapshot_delete_by_id_or_name
  snapshot: create helper to test that block drivers supports snapshots
  Unneeded NULL check
  migration: Dead assignment of current_time
  Set last_sent_block

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 8f280309 79b3c12a
Loading
Loading
Loading
Loading
+131 −3
Original line number Diff line number Diff line
@@ -253,7 +253,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
    return -ENOTSUP;
}

void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
                                       const char *id_or_name,
                                       Error **errp)
{
@@ -270,6 +270,7 @@ void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
    if (ret < 0) {
        error_propagate(errp, local_err);
    }
    return ret;
}

int bdrv_snapshot_list(BlockDriverState *bs,
@@ -356,3 +357,130 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,

    return ret;
}


/* Group operations. All block drivers are involved.
 * These functions will properly handle dataplane (take aio_context_acquire
 * when appropriate for appropriate block drivers) */

bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
{
    bool ok = true;
    BlockDriverState *bs = NULL;

    while (ok && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) {
            ok = bdrv_can_snapshot(bs);
        }
        aio_context_release(ctx);
    }

    *first_bad_bs = bs;
    return ok;
}

int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
                             Error **err)
{
    int ret = 0;
    BlockDriverState *bs = NULL;
    QEMUSnapshotInfo sn1, *snapshot = &sn1;

    while (ret == 0 && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        if (bdrv_can_snapshot(bs) &&
                bdrv_snapshot_find(bs, snapshot, name) >= 0) {
            ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err);
        }
        aio_context_release(ctx);
    }

    *first_bad_bs = bs;
    return ret;
}


int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs)
{
    int err = 0;
    BlockDriverState *bs = NULL;

    while (err == 0 && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        if (bdrv_can_snapshot(bs)) {
            err = bdrv_snapshot_goto(bs, name);
        }
        aio_context_release(ctx);
    }

    *first_bad_bs = bs;
    return err;
}

int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs)
{
    QEMUSnapshotInfo sn;
    int err = 0;
    BlockDriverState *bs = NULL;

    while (err == 0 && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        if (bdrv_can_snapshot(bs)) {
            err = bdrv_snapshot_find(bs, &sn, name);
        }
        aio_context_release(ctx);
    }

    *first_bad_bs = bs;
    return err;
}

int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
                             BlockDriverState *vm_state_bs,
                             uint64_t vm_state_size,
                             BlockDriverState **first_bad_bs)
{
    int err = 0;
    BlockDriverState *bs = NULL;

    while (err == 0 && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        if (bs == vm_state_bs) {
            sn->vm_state_size = vm_state_size;
            err = bdrv_snapshot_create(bs, sn);
        } else if (bdrv_can_snapshot(bs)) {
            sn->vm_state_size = 0;
            err = bdrv_snapshot_create(bs, sn);
        }
        aio_context_release(ctx);
    }

    *first_bad_bs = bs;
    return err;
}

BlockDriverState *bdrv_all_find_vmstate_bs(void)
{
    bool not_found = true;
    BlockDriverState *bs = NULL;

    while (not_found && (bs = bdrv_next(bs))) {
        AioContext *ctx = bdrv_get_aio_context(bs);

        aio_context_acquire(ctx);
        not_found = !bdrv_can_snapshot(bs);
        aio_context_release(ctx);
    }
    return bs;
}
+21 −3
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
                         const char *snapshot_id,
                         const char *name,
                         Error **errp);
void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
                                       const char *id_or_name,
                                       Error **errp);
int bdrv_snapshot_list(BlockDriverState *bs,
@@ -75,4 +75,22 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
                                         const char *id_or_name,
                                         Error **errp);


/* Group operations. All block drivers are involved.
 * These functions will properly handle dataplane (take aio_context_acquire
 * when appropriate for appropriate block drivers */

bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs);
int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bsd_bs,
                             Error **err);
int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bsd_bs);
int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs);
int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
                             BlockDriverState *vm_state_bs,
                             uint64_t vm_state_size,
                             BlockDriverState **first_bad_bs);

BlockDriverState *bdrv_all_find_vmstate_bs(void);

#endif
+1 −2
Original line number Diff line number Diff line
@@ -1345,7 +1345,7 @@ static void *source_return_path_thread(void *opaque)
            break;
        }
    }
    if (rp && qemu_file_get_error(rp)) {
    if (qemu_file_get_error(rp)) {
        trace_source_return_path_thread_bad_end();
        mark_source_rp_bad(ms);
    }
@@ -1643,7 +1643,6 @@ static void *migration_thread(void *opaque)
            if (pending_size && pending_size >= max_size) {
                /* Still a significant amount to transfer */

                current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
                if (migrate_postcopy_ram() &&
                    s->state != MIGRATION_STATUS_POSTCOPY_ACTIVE &&
                    pend_nonpost <= max_size &&
+1 −0
Original line number Diff line number Diff line
@@ -1249,6 +1249,7 @@ static int ram_save_target_page(MigrationState *ms, QEMUFile *f,
        if (unsentmap) {
            clear_bit(dirty_ram_abs >> TARGET_PAGE_BITS, unsentmap);
        }
        last_sent_block = block;
    }

    return res;
+63 −144
Original line number Diff line number Diff line
@@ -1905,46 +1905,6 @@ int qemu_loadvm_state(QEMUFile *f)
    return ret;
}

static BlockDriverState *find_vmstate_bs(void)
{
    BlockDriverState *bs = NULL;
    while ((bs = bdrv_next(bs))) {
        if (bdrv_can_snapshot(bs)) {
            return bs;
        }
    }
    return NULL;
}

/*
 * Deletes snapshots of a given name in all opened images.
 */
static int del_existing_snapshots(Monitor *mon, const char *name)
{
    BlockDriverState *bs;
    QEMUSnapshotInfo sn1, *snapshot = &sn1;
    Error *err = NULL;

    bs = NULL;
    while ((bs = bdrv_next(bs))) {
        if (bdrv_can_snapshot(bs) &&
            bdrv_snapshot_find(bs, snapshot, name) >= 0) {
            bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
            if (err) {
                monitor_printf(mon,
                               "Error while deleting snapshot on device '%s':"
                               " %s\n",
                               bdrv_get_device_name(bs),
                               error_get_pretty(err));
                error_free(err);
                return -1;
            }
        }
    }

    return 0;
}

void hmp_savevm(Monitor *mon, const QDict *qdict)
{
    BlockDriverState *bs, *bs1;
@@ -1957,27 +1917,29 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
    struct tm tm;
    const char *name = qdict_get_try_str(qdict, "name");
    Error *local_err = NULL;
    AioContext *aio_context;

    /* Verify if there is a device that doesn't support snapshots and is writable */
    bs = NULL;
    while ((bs = bdrv_next(bs))) {

        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
            continue;
    if (!bdrv_all_can_snapshot(&bs)) {
        monitor_printf(mon, "Device '%s' is writable but does not "
                       "support snapshots.\n", bdrv_get_device_name(bs));
        return;
    }

        if (!bdrv_can_snapshot(bs)) {
            monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n",
                               bdrv_get_device_name(bs));
    /* Delete old snapshots of the same name */
    if (name && bdrv_all_delete_snapshot(name, &bs1, &local_err) < 0) {
        monitor_printf(mon,
                       "Error while deleting snapshot on device '%s': %s\n",
                       bdrv_get_device_name(bs1), error_get_pretty(local_err));
        error_free(local_err);
        return;
    }
    }

    bs = find_vmstate_bs();
    if (!bs) {
    bs = bdrv_all_find_vmstate_bs();
    if (bs == NULL) {
        monitor_printf(mon, "No block device can accept snapshots\n");
        return;
    }
    aio_context = bdrv_get_aio_context(bs);

    saved_vm_running = runstate_is_running();

@@ -1988,6 +1950,8 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
    }
    vm_stop(RUN_STATE_SAVE_VM);

    aio_context_acquire(aio_context);

    memset(sn, 0, sizeof(*sn));

    /* fill auxiliary fields */
@@ -2010,11 +1974,6 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
        strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
    }

    /* Delete old snapshots of the same name */
    if (name && del_existing_snapshots(mon, name) < 0) {
        goto the_end;
    }

    /* save the VM state */
    f = qemu_fopen_bdrv(bs, 1);
    if (!f) {
@@ -2030,22 +1989,14 @@ void hmp_savevm(Monitor *mon, const QDict *qdict)
        goto the_end;
    }

    /* create the snapshots */

    bs1 = NULL;
    while ((bs1 = bdrv_next(bs1))) {
        if (bdrv_can_snapshot(bs1)) {
            /* Write VM state size only to the image that contains the state */
            sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
            ret = bdrv_snapshot_create(bs1, sn);
    ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
    if (ret < 0) {
        monitor_printf(mon, "Error while creating snapshot on '%s'\n",
                               bdrv_get_device_name(bs1));
            }
        }
                       bdrv_get_device_name(bs));
    }

 the_end:
    aio_context_release(aio_context);
    if (saved_vm_running) {
        vm_start();
    }
@@ -2084,15 +2035,31 @@ int load_vmstate(const char *name)
    QEMUSnapshotInfo sn;
    QEMUFile *f;
    int ret;
    AioContext *aio_context;

    if (!bdrv_all_can_snapshot(&bs)) {
        error_report("Device '%s' is writable but does not support snapshots.",
                     bdrv_get_device_name(bs));
        return -ENOTSUP;
    }
    ret = bdrv_all_find_snapshot(name, &bs);
    if (ret < 0) {
        error_report("Device '%s' does not have the requested snapshot '%s'",
                     bdrv_get_device_name(bs), name);
        return ret;
    }

    bs_vm_state = find_vmstate_bs();
    bs_vm_state = bdrv_all_find_vmstate_bs();
    if (!bs_vm_state) {
        error_report("No block device supports snapshots");
        return -ENOTSUP;
    }
    aio_context = bdrv_get_aio_context(bs_vm_state);

    /* Don't even try to load empty VM states */
    aio_context_acquire(aio_context);
    ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
    aio_context_release(aio_context);
    if (ret < 0) {
        return ret;
    } else if (sn.vm_state_size == 0) {
@@ -2101,43 +2068,15 @@ int load_vmstate(const char *name)
        return -EINVAL;
    }

    /* Verify if there is any device that doesn't support snapshots and is
    writable and check if the requested snapshot is available too. */
    bs = NULL;
    while ((bs = bdrv_next(bs))) {

        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
            continue;
        }

        if (!bdrv_can_snapshot(bs)) {
            error_report("Device '%s' is writable but does not support snapshots.",
                               bdrv_get_device_name(bs));
            return -ENOTSUP;
        }

        ret = bdrv_snapshot_find(bs, &sn, name);
        if (ret < 0) {
            error_report("Device '%s' does not have the requested snapshot '%s'",
                           bdrv_get_device_name(bs), name);
            return ret;
        }
    }

    /* Flush all IO requests so they don't interfere with the new state.  */
    bdrv_drain_all();

    bs = NULL;
    while ((bs = bdrv_next(bs))) {
        if (bdrv_can_snapshot(bs)) {
            ret = bdrv_snapshot_goto(bs, name);
    ret = bdrv_all_goto_snapshot(name, &bs);
    if (ret < 0) {
        error_report("Error %d while activating snapshot '%s' on '%s'",
                     ret, name, bdrv_get_device_name(bs));
        return ret;
    }
        }
    }

    /* restore the VM state */
    f = qemu_fopen_bdrv(bs_vm_state, 0);
@@ -2148,9 +2087,12 @@ int load_vmstate(const char *name)

    qemu_system_reset(VMRESET_SILENT);
    migration_incoming_state_new(f);
    ret = qemu_loadvm_state(f);

    aio_context_acquire(aio_context);
    ret = qemu_loadvm_state(f);
    qemu_fclose(f);
    aio_context_release(aio_context);

    migration_incoming_state_destroy();
    if (ret < 0) {
        error_report("Error %d while loading VM state", ret);
@@ -2166,43 +2108,34 @@ void hmp_delvm(Monitor *mon, const QDict *qdict)
    Error *err;
    const char *name = qdict_get_str(qdict, "name");

    if (!find_vmstate_bs()) {
        monitor_printf(mon, "No block device supports snapshots\n");
        return;
    }

    bs = NULL;
    while ((bs = bdrv_next(bs))) {
        if (bdrv_can_snapshot(bs)) {
            err = NULL;
            bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
            if (err) {
    if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
        monitor_printf(mon,
                               "Error while deleting snapshot on device '%s':"
                               " %s\n",
                               bdrv_get_device_name(bs),
                               error_get_pretty(err));
                       "Error while deleting snapshot on device '%s': %s\n",
                       bdrv_get_device_name(bs), error_get_pretty(err));
        error_free(err);
    }
}
    }
}

void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
{
    BlockDriverState *bs, *bs1;
    QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
    int nb_sns, i, ret, available;
    QEMUSnapshotInfo *sn_tab, *sn;
    int nb_sns, i;
    int total;
    int *available_snapshots;
    AioContext *aio_context;

    bs = find_vmstate_bs();
    bs = bdrv_all_find_vmstate_bs();
    if (!bs) {
        monitor_printf(mon, "No available block device supports snapshots\n");
        return;
    }
    aio_context = bdrv_get_aio_context(bs);

    aio_context_acquire(aio_context);
    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
    aio_context_release(aio_context);

    if (nb_sns < 0) {
        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
        return;
@@ -2216,21 +2149,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
    available_snapshots = g_new0(int, nb_sns);
    total = 0;
    for (i = 0; i < nb_sns; i++) {
        sn = &sn_tab[i];
        available = 1;
        bs1 = NULL;

        while ((bs1 = bdrv_next(bs1))) {
            if (bdrv_can_snapshot(bs1) && bs1 != bs) {
                ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
                if (ret < 0) {
                    available = 0;
                    break;
                }
            }
        }

        if (available) {
        if (bdrv_all_find_snapshot(sn_tab[i].id_str, &bs1) == 0) {
            available_snapshots[total] = i;
            total++;
        }