xref: /qemu/migration/global_state.c (revision d3c86c99)
184a899deSJuan Quintela /*
284a899deSJuan Quintela  * Global State configuration
384a899deSJuan Quintela  *
484a899deSJuan Quintela  * Copyright (c) 2014-2017 Red Hat Inc
584a899deSJuan Quintela  *
684a899deSJuan Quintela  * Authors:
784a899deSJuan Quintela  *  Juan Quintela <quintela@redhat.com>
884a899deSJuan Quintela  *
984a899deSJuan Quintela  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1084a899deSJuan Quintela  * See the COPYING file in the top-level directory.
1184a899deSJuan Quintela  */
1284a899deSJuan Quintela 
1384a899deSJuan Quintela #include "qemu/osdep.h"
1484a899deSJuan Quintela #include "qemu/cutils.h"
1584a899deSJuan Quintela #include "qemu/error-report.h"
1654d31236SMarkus Armbruster #include "sysemu/runstate.h"
1784a899deSJuan Quintela #include "qapi/error.h"
185272298cSPeter Xu #include "migration.h"
1984a899deSJuan Quintela #include "migration/global_state.h"
2084a899deSJuan Quintela #include "migration/vmstate.h"
2184a899deSJuan Quintela #include "trace.h"
2284a899deSJuan Quintela 
2384a899deSJuan Quintela typedef struct {
2484a899deSJuan Quintela     uint32_t size;
25*d3c86c99SSteve Sistare 
26*d3c86c99SSteve Sistare     /*
27*d3c86c99SSteve Sistare      * runstate was 100 bytes, zero padded, but we trimmed it to add a
28*d3c86c99SSteve Sistare      * few fields and maintain backwards compatibility.
29*d3c86c99SSteve Sistare      */
30*d3c86c99SSteve Sistare     uint8_t runstate[32];
31*d3c86c99SSteve Sistare     uint8_t has_vm_was_suspended;
32*d3c86c99SSteve Sistare     uint8_t vm_was_suspended;
33*d3c86c99SSteve Sistare     uint8_t unused[66];
34*d3c86c99SSteve Sistare 
3584a899deSJuan Quintela     RunState state;
3684a899deSJuan Quintela     bool received;
3784a899deSJuan Quintela } GlobalState;
3884a899deSJuan Quintela 
3984a899deSJuan Quintela static GlobalState global_state;
4084a899deSJuan Quintela 
global_state_do_store(RunState state)41c33f1829SVladimir Sementsov-Ogievskiy static void global_state_do_store(RunState state)
4284a899deSJuan Quintela {
43c33f1829SVladimir Sementsov-Ogievskiy     const char *state_str = RunState_str(state);
44c33f1829SVladimir Sementsov-Ogievskiy     assert(strlen(state_str) < sizeof(global_state.runstate));
45c33f1829SVladimir Sementsov-Ogievskiy     strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate),
46c33f1829SVladimir Sementsov-Ogievskiy               state_str, '\0');
47*d3c86c99SSteve Sistare     global_state.has_vm_was_suspended = true;
48*d3c86c99SSteve Sistare     global_state.vm_was_suspended = vm_get_suspended();
49*d3c86c99SSteve Sistare 
50*d3c86c99SSteve Sistare     memset(global_state.unused, 0, sizeof(global_state.unused));
5184a899deSJuan Quintela }
52c33f1829SVladimir Sementsov-Ogievskiy 
global_state_store(void)53c33f1829SVladimir Sementsov-Ogievskiy void global_state_store(void)
54c33f1829SVladimir Sementsov-Ogievskiy {
55c33f1829SVladimir Sementsov-Ogievskiy     global_state_do_store(runstate_get());
5684a899deSJuan Quintela }
5784a899deSJuan Quintela 
global_state_store_running(void)5884a899deSJuan Quintela void global_state_store_running(void)
5984a899deSJuan Quintela {
60c33f1829SVladimir Sementsov-Ogievskiy     global_state_do_store(RUN_STATE_RUNNING);
6184a899deSJuan Quintela }
6284a899deSJuan Quintela 
global_state_received(void)6384a899deSJuan Quintela bool global_state_received(void)
6484a899deSJuan Quintela {
6584a899deSJuan Quintela     return global_state.received;
6684a899deSJuan Quintela }
6784a899deSJuan Quintela 
global_state_get_runstate(void)6884a899deSJuan Quintela RunState global_state_get_runstate(void)
6984a899deSJuan Quintela {
7084a899deSJuan Quintela     return global_state.state;
7184a899deSJuan Quintela }
7284a899deSJuan Quintela 
global_state_needed(void * opaque)7384a899deSJuan Quintela static bool global_state_needed(void *opaque)
7484a899deSJuan Quintela {
75*d3c86c99SSteve Sistare     return migrate_get_current()->store_global_state;
7684a899deSJuan Quintela }
7784a899deSJuan Quintela 
global_state_post_load(void * opaque,int version_id)7884a899deSJuan Quintela static int global_state_post_load(void *opaque, int version_id)
7984a899deSJuan Quintela {
8084a899deSJuan Quintela     GlobalState *s = opaque;
8184a899deSJuan Quintela     Error *local_err = NULL;
8284a899deSJuan Quintela     int r;
8384a899deSJuan Quintela     char *runstate = (char *)s->runstate;
8484a899deSJuan Quintela 
8584a899deSJuan Quintela     s->received = true;
8684a899deSJuan Quintela     trace_migrate_global_state_post_load(runstate);
8784a899deSJuan Quintela 
88a346af9cSPhilippe Mathieu-Daudé     if (strnlen((char *)s->runstate,
89a346af9cSPhilippe Mathieu-Daudé                 sizeof(s->runstate)) == sizeof(s->runstate)) {
90a346af9cSPhilippe Mathieu-Daudé         /*
91a346af9cSPhilippe Mathieu-Daudé          * This condition should never happen during migration, because
92*d3c86c99SSteve Sistare          * all runstate names are shorter than 32 bytes (the size of
93a346af9cSPhilippe Mathieu-Daudé          * s->runstate). However, a malicious stream could overflow
94a346af9cSPhilippe Mathieu-Daudé          * the qapi_enum_parse() call, so we force the last character
95a346af9cSPhilippe Mathieu-Daudé          * to a NUL byte.
96a346af9cSPhilippe Mathieu-Daudé          */
97a346af9cSPhilippe Mathieu-Daudé         s->runstate[sizeof(s->runstate) - 1] = '\0';
98a346af9cSPhilippe Mathieu-Daudé     }
99f7abe0ecSMarc-André Lureau     r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
10084a899deSJuan Quintela 
10184a899deSJuan Quintela     if (r == -1) {
10284a899deSJuan Quintela         if (local_err) {
10384a899deSJuan Quintela             error_report_err(local_err);
10484a899deSJuan Quintela         }
10584a899deSJuan Quintela         return -EINVAL;
10684a899deSJuan Quintela     }
10784a899deSJuan Quintela     s->state = r;
10884a899deSJuan Quintela 
109*d3c86c99SSteve Sistare     /*
110*d3c86c99SSteve Sistare      * global_state is saved on the outgoing side before forcing a stopped
111*d3c86c99SSteve Sistare      * state, so it may have saved state=suspended and vm_was_suspended=0.
112*d3c86c99SSteve Sistare      * Now we are in a paused state, and when we later call vm_start, it must
113*d3c86c99SSteve Sistare      * restore the suspended state, so we must set vm_was_suspended=1 here.
114*d3c86c99SSteve Sistare      */
115*d3c86c99SSteve Sistare     vm_set_suspended(s->vm_was_suspended || r == RUN_STATE_SUSPENDED);
116*d3c86c99SSteve Sistare 
11784a899deSJuan Quintela     return 0;
11884a899deSJuan Quintela }
11984a899deSJuan Quintela 
global_state_pre_save(void * opaque)12044b1ff31SDr. David Alan Gilbert static int global_state_pre_save(void *opaque)
12184a899deSJuan Quintela {
12284a899deSJuan Quintela     GlobalState *s = opaque;
12384a899deSJuan Quintela 
12484a899deSJuan Quintela     trace_migrate_global_state_pre_save((char *)s->runstate);
125a346af9cSPhilippe Mathieu-Daudé     s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
126a346af9cSPhilippe Mathieu-Daudé     assert(s->size <= sizeof(s->runstate));
12744b1ff31SDr. David Alan Gilbert 
12844b1ff31SDr. David Alan Gilbert     return 0;
12984a899deSJuan Quintela }
13084a899deSJuan Quintela 
13184a899deSJuan Quintela static const VMStateDescription vmstate_globalstate = {
13284a899deSJuan Quintela     .name = "globalstate",
13384a899deSJuan Quintela     .version_id = 1,
13484a899deSJuan Quintela     .minimum_version_id = 1,
13584a899deSJuan Quintela     .post_load = global_state_post_load,
13684a899deSJuan Quintela     .pre_save = global_state_pre_save,
13784a899deSJuan Quintela     .needed = global_state_needed,
13884a899deSJuan Quintela     .fields = (const VMStateField[]) {
13984a899deSJuan Quintela         VMSTATE_UINT32(size, GlobalState),
14084a899deSJuan Quintela         VMSTATE_BUFFER(runstate, GlobalState),
141*d3c86c99SSteve Sistare         VMSTATE_UINT8(has_vm_was_suspended, GlobalState),
142*d3c86c99SSteve Sistare         VMSTATE_UINT8(vm_was_suspended, GlobalState),
143*d3c86c99SSteve Sistare         VMSTATE_BUFFER(unused, GlobalState),
14484a899deSJuan Quintela         VMSTATE_END_OF_LIST()
14584a899deSJuan Quintela     },
14684a899deSJuan Quintela };
14784a899deSJuan Quintela 
register_global_state(void)14884a899deSJuan Quintela void register_global_state(void)
14984a899deSJuan Quintela {
15084a899deSJuan Quintela     /* We would use it independently that we receive it */
15184a899deSJuan Quintela     strcpy((char *)&global_state.runstate, "");
15284a899deSJuan Quintela     global_state.received = false;
15384a899deSJuan Quintela     vmstate_register(NULL, 0, &vmstate_globalstate, &global_state);
15484a899deSJuan Quintela }
155