2 * Global State configuration
4 * Copyright (c) 2014-2017 Red Hat Inc
7 * Juan Quintela <quintela@redhat.com>
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.
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"
27 * runstate was 100 bytes, zero padded, but we trimmed it to add a
28 * few fields and maintain backwards compatibility.
31 uint8_t has_vm_was_suspended
;
32 uint8_t vm_was_suspended
;
39 static GlobalState global_state
;
41 static void global_state_do_store(RunState state
)
43 const char *state_str
= RunState_str(state
);
44 assert(strlen(state_str
) < sizeof(global_state
.runstate
));
45 strpadcpy((char *)global_state
.runstate
, sizeof(global_state
.runstate
),
47 global_state
.has_vm_was_suspended
= true;
48 global_state
.vm_was_suspended
= vm_get_suspended();
50 memset(global_state
.unused
, 0, sizeof(global_state
.unused
));
53 void global_state_store(void)
55 global_state_do_store(runstate_get());
58 void global_state_store_running(void)
60 global_state_do_store(RUN_STATE_RUNNING
);
63 bool global_state_received(void)
65 return global_state
.received
;
68 RunState
global_state_get_runstate(void)
70 return global_state
.state
;
73 static bool global_state_needed(void *opaque
)
75 return migrate_get_current()->store_global_state
;
78 static int global_state_post_load(void *opaque
, int version_id
)
80 GlobalState
*s
= opaque
;
81 Error
*local_err
= NULL
;
83 char *runstate
= (char *)s
->runstate
;
86 trace_migrate_global_state_post_load(runstate
);
88 if (strnlen((char *)s
->runstate
,
89 sizeof(s
->runstate
)) == sizeof(s
->runstate
)) {
91 * This condition should never happen during migration, because
92 * all runstate names are shorter than 32 bytes (the size of
93 * s->runstate). However, a malicious stream could overflow
94 * the qapi_enum_parse() call, so we force the last character
97 s
->runstate
[sizeof(s
->runstate
) - 1] = '\0';
99 r
= qapi_enum_parse(&RunState_lookup
, runstate
, -1, &local_err
);
103 error_report_err(local_err
);
110 * global_state is saved on the outgoing side before forcing a stopped
111 * state, so it may have saved state=suspended and vm_was_suspended=0.
112 * Now we are in a paused state, and when we later call vm_start, it must
113 * restore the suspended state, so we must set vm_was_suspended=1 here.
115 vm_set_suspended(s
->vm_was_suspended
|| r
== RUN_STATE_SUSPENDED
);
120 static int global_state_pre_save(void *opaque
)
122 GlobalState
*s
= opaque
;
124 trace_migrate_global_state_pre_save((char *)s
->runstate
);
125 s
->size
= strnlen((char *)s
->runstate
, sizeof(s
->runstate
)) + 1;
126 assert(s
->size
<= sizeof(s
->runstate
));
131 static const VMStateDescription vmstate_globalstate
= {
132 .name
= "globalstate",
134 .minimum_version_id
= 1,
135 .post_load
= global_state_post_load
,
136 .pre_save
= global_state_pre_save
,
137 .needed
= global_state_needed
,
138 .fields
= (const VMStateField
[]) {
139 VMSTATE_UINT32(size
, GlobalState
),
140 VMSTATE_BUFFER(runstate
, GlobalState
),
141 VMSTATE_UINT8(has_vm_was_suspended
, GlobalState
),
142 VMSTATE_UINT8(vm_was_suspended
, GlobalState
),
143 VMSTATE_BUFFER(unused
, GlobalState
),
144 VMSTATE_END_OF_LIST()
148 void register_global_state(void)
150 /* We would use it independently that we receive it */
151 strcpy((char *)&global_state
.runstate
, "");
152 global_state
.received
= false;
153 vmstate_register(NULL
, 0, &vmstate_globalstate
, &global_state
);