qemu/migration/global_state.c
<<
>>
Prefs
   1/*
   2 * Global State configuration
   3 *
   4 * Copyright (c) 2014-2017 Red Hat Inc
   5 *
   6 * Authors:
   7 *  Juan Quintela <quintela@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "qemu/cutils.h"
  15#include "qemu/error-report.h"
  16#include "sysemu/runstate.h"
  17#include "qapi/error.h"
  18#include "migration.h"
  19#include "migration/global_state.h"
  20#include "migration/vmstate.h"
  21#include "trace.h"
  22
  23typedef struct {
  24    uint32_t size;
  25    uint8_t runstate[100];
  26    RunState state;
  27    bool received;
  28} GlobalState;
  29
  30static GlobalState global_state;
  31
  32int global_state_store(void)
  33{
  34    if (!runstate_store((char *)global_state.runstate,
  35                        sizeof(global_state.runstate))) {
  36        error_report("runstate name too big: %s", global_state.runstate);
  37        trace_migrate_state_too_big();
  38        return -EINVAL;
  39    }
  40    return 0;
  41}
  42
  43void global_state_store_running(void)
  44{
  45    const char *state = RunState_str(RUN_STATE_RUNNING);
  46    assert(strlen(state) < sizeof(global_state.runstate));
  47    strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate),
  48              state, '\0');
  49}
  50
  51bool global_state_received(void)
  52{
  53    return global_state.received;
  54}
  55
  56RunState global_state_get_runstate(void)
  57{
  58    return global_state.state;
  59}
  60
  61static bool global_state_needed(void *opaque)
  62{
  63    GlobalState *s = opaque;
  64    char *runstate = (char *)s->runstate;
  65
  66    /* If it is not optional, it is mandatory */
  67
  68    if (migrate_get_current()->store_global_state) {
  69        return true;
  70    }
  71
  72    /* If state is running or paused, it is not needed */
  73
  74    if (strcmp(runstate, "running") == 0 ||
  75        strcmp(runstate, "paused") == 0) {
  76        return false;
  77    }
  78
  79    /* for any other state it is needed */
  80    return true;
  81}
  82
  83static int global_state_post_load(void *opaque, int version_id)
  84{
  85    GlobalState *s = opaque;
  86    Error *local_err = NULL;
  87    int r;
  88    char *runstate = (char *)s->runstate;
  89
  90    s->received = true;
  91    trace_migrate_global_state_post_load(runstate);
  92
  93    if (strnlen((char *)s->runstate,
  94                sizeof(s->runstate)) == sizeof(s->runstate)) {
  95        /*
  96         * This condition should never happen during migration, because
  97         * all runstate names are shorter than 100 bytes (the size of
  98         * s->runstate). However, a malicious stream could overflow
  99         * the qapi_enum_parse() call, so we force the last character
 100         * to a NUL byte.
 101         */
 102        s->runstate[sizeof(s->runstate) - 1] = '\0';
 103    }
 104    r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
 105
 106    if (r == -1) {
 107        if (local_err) {
 108            error_report_err(local_err);
 109        }
 110        return -EINVAL;
 111    }
 112    s->state = r;
 113
 114    return 0;
 115}
 116
 117static int global_state_pre_save(void *opaque)
 118{
 119    GlobalState *s = opaque;
 120
 121    trace_migrate_global_state_pre_save((char *)s->runstate);
 122    s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
 123    assert(s->size <= sizeof(s->runstate));
 124
 125    return 0;
 126}
 127
 128static const VMStateDescription vmstate_globalstate = {
 129    .name = "globalstate",
 130    .version_id = 1,
 131    .minimum_version_id = 1,
 132    .post_load = global_state_post_load,
 133    .pre_save = global_state_pre_save,
 134    .needed = global_state_needed,
 135    .fields = (VMStateField[]) {
 136        VMSTATE_UINT32(size, GlobalState),
 137        VMSTATE_BUFFER(runstate, GlobalState),
 138        VMSTATE_END_OF_LIST()
 139    },
 140};
 141
 142void register_global_state(void)
 143{
 144    /* We would use it independently that we receive it */
 145    strcpy((char *)&global_state.runstate, "");
 146    global_state.received = false;
 147    vmstate_register(NULL, 0, &vmstate_globalstate, &global_state);
 148}
 149