cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

migration-helpers.c (4785B)


      1/*
      2 * QTest migration helpers
      3 *
      4 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
      5 *   based on the vhost-user-test.c that is:
      6 *      Copyright (c) 2014 Virtual Open Systems Sarl.
      7 *
      8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9 * See the COPYING file in the top-level directory.
     10 *
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qapi/qmp/qjson.h"
     15
     16#include "migration-helpers.h"
     17
     18bool got_stop;
     19
     20static void check_stop_event(QTestState *who)
     21{
     22    QDict *event = qtest_qmp_event_ref(who, "STOP");
     23    if (event) {
     24        got_stop = true;
     25        qobject_unref(event);
     26    }
     27}
     28
     29/*
     30 * Events can get in the way of responses we are actually waiting for.
     31 */
     32QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
     33{
     34    va_list ap;
     35    QDict *resp, *ret;
     36
     37    va_start(ap, command);
     38    qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
     39    va_end(ap);
     40
     41    resp = qtest_qmp_receive(who);
     42    check_stop_event(who);
     43
     44    g_assert(!qdict_haskey(resp, "error"));
     45    g_assert(qdict_haskey(resp, "return"));
     46
     47    ret = qdict_get_qdict(resp, "return");
     48    qobject_ref(ret);
     49    qobject_unref(resp);
     50
     51    return ret;
     52}
     53
     54/*
     55 * Events can get in the way of responses we are actually waiting for.
     56 */
     57QDict *wait_command(QTestState *who, const char *command, ...)
     58{
     59    va_list ap;
     60    QDict *resp, *ret;
     61
     62    va_start(ap, command);
     63    resp = qtest_vqmp(who, command, ap);
     64    va_end(ap);
     65
     66    check_stop_event(who);
     67
     68    g_assert(!qdict_haskey(resp, "error"));
     69    g_assert(qdict_haskey(resp, "return"));
     70
     71    ret = qdict_get_qdict(resp, "return");
     72    qobject_ref(ret);
     73    qobject_unref(resp);
     74
     75    return ret;
     76}
     77
     78/*
     79 * Send QMP command "migrate".
     80 * Arguments are built from @fmt... (formatted like
     81 * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
     82 */
     83void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
     84{
     85    va_list ap;
     86    QDict *args, *rsp;
     87
     88    va_start(ap, fmt);
     89    args = qdict_from_vjsonf_nofail(fmt, ap);
     90    va_end(ap);
     91
     92    g_assert(!qdict_haskey(args, "uri"));
     93    qdict_put_str(args, "uri", uri);
     94
     95    rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
     96
     97    g_assert(qdict_haskey(rsp, "return"));
     98    qobject_unref(rsp);
     99}
    100
    101/*
    102 * Note: caller is responsible to free the returned object via
    103 * qobject_unref() after use
    104 */
    105QDict *migrate_query(QTestState *who)
    106{
    107    return wait_command(who, "{ 'execute': 'query-migrate' }");
    108}
    109
    110/*
    111 * Note: caller is responsible to free the returned object via
    112 * g_free() after use
    113 */
    114static gchar *migrate_query_status(QTestState *who)
    115{
    116    QDict *rsp_return = migrate_query(who);
    117    gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
    118
    119    g_assert(status);
    120    qobject_unref(rsp_return);
    121
    122    return status;
    123}
    124
    125static bool check_migration_status(QTestState *who, const char *goal,
    126                                   const char **ungoals)
    127{
    128    bool ready;
    129    char *current_status;
    130    const char **ungoal;
    131
    132    current_status = migrate_query_status(who);
    133    ready = strcmp(current_status, goal) == 0;
    134    if (!ungoals) {
    135        g_assert_cmpstr(current_status, !=, "failed");
    136        /*
    137         * If looking for a state other than completed,
    138         * completion of migration would cause the test to
    139         * hang.
    140         */
    141        if (strcmp(goal, "completed") != 0) {
    142            g_assert_cmpstr(current_status, !=, "completed");
    143        }
    144    } else {
    145        for (ungoal = ungoals; *ungoal; ungoal++) {
    146            g_assert_cmpstr(current_status, !=,  *ungoal);
    147        }
    148    }
    149    g_free(current_status);
    150    return ready;
    151}
    152
    153void wait_for_migration_status(QTestState *who,
    154                               const char *goal, const char **ungoals)
    155{
    156    while (!check_migration_status(who, goal, ungoals)) {
    157        usleep(1000);
    158    }
    159}
    160
    161void wait_for_migration_complete(QTestState *who)
    162{
    163    wait_for_migration_status(who, "completed", NULL);
    164}
    165
    166void wait_for_migration_fail(QTestState *from, bool allow_active)
    167{
    168    QDict *rsp_return;
    169    char *status;
    170    bool failed;
    171
    172    do {
    173        status = migrate_query_status(from);
    174        bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
    175            (allow_active && !strcmp(status, "active"));
    176        if (!result) {
    177            fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
    178                    __func__, status, allow_active);
    179        }
    180        g_assert(result);
    181        failed = !strcmp(status, "failed");
    182        g_free(status);
    183    } while (!failed);
    184
    185    /* Is the machine currently running? */
    186    rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
    187    g_assert(qdict_haskey(rsp_return, "running"));
    188    g_assert(qdict_get_bool(rsp_return, "running"));
    189    qobject_unref(rsp_return);
    190}