| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Global State configuration | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2014-2017 Red Hat Inc | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *  Juan Quintela <quintela@redhat.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
					
						
							|  |  |  |  * See the COPYING file in the top-level directory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "qemu/osdep.h"
 | 
					
						
							|  |  |  | #include "qemu/cutils.h"
 | 
					
						
							|  |  |  | #include "qemu/error-report.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:59 +02:00
										 |  |  | #include "sysemu/runstate.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-27 12:10:14 +08:00
										 |  |  | #include "migration.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | #include "migration/global_state.h"
 | 
					
						
							|  |  |  | #include "migration/vmstate.h"
 | 
					
						
							|  |  |  | #include "trace.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     uint32_t size; | 
					
						
							|  |  |  |     uint8_t runstate[100]; | 
					
						
							|  |  |  |     RunState state; | 
					
						
							|  |  |  |     bool received; | 
					
						
							|  |  |  | } GlobalState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GlobalState global_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int global_state_store(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!runstate_store((char *)global_state.runstate, | 
					
						
							|  |  |  |                         sizeof(global_state.runstate))) { | 
					
						
							|  |  |  |         error_report("runstate name too big: %s", global_state.runstate); | 
					
						
							|  |  |  |         trace_migrate_state_too_big(); | 
					
						
							|  |  |  |         return -EINVAL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void global_state_store_running(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-24 10:46:08 +02:00
										 |  |  |     const char *state = RunState_str(RUN_STATE_RUNNING); | 
					
						
							| 
									
										
										
										
											2019-01-03 09:56:37 +01:00
										 |  |  |     assert(strlen(state) < sizeof(global_state.runstate)); | 
					
						
							| 
									
										
										
										
											2020-09-25 16:40:16 +01:00
										 |  |  |     strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate), | 
					
						
							|  |  |  |               state, '\0'); | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool global_state_received(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return global_state.received; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RunState global_state_get_runstate(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return global_state.state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool global_state_needed(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     GlobalState *s = opaque; | 
					
						
							|  |  |  |     char *runstate = (char *)s->runstate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* If it is not optional, it is mandatory */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 12:10:14 +08:00
										 |  |  |     if (migrate_get_current()->store_global_state) { | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* If state is running or paused, it is not needed */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (strcmp(runstate, "running") == 0 || | 
					
						
							|  |  |  |         strcmp(runstate, "paused") == 0) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* for any other state it is needed */ | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int global_state_post_load(void *opaque, int version_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     GlobalState *s = opaque; | 
					
						
							|  |  |  |     Error *local_err = NULL; | 
					
						
							|  |  |  |     int r; | 
					
						
							|  |  |  |     char *runstate = (char *)s->runstate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->received = true; | 
					
						
							|  |  |  |     trace_migrate_global_state_post_load(runstate); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-03 09:56:38 +01:00
										 |  |  |     if (strnlen((char *)s->runstate, | 
					
						
							|  |  |  |                 sizeof(s->runstate)) == sizeof(s->runstate)) { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * This condition should never happen during migration, because | 
					
						
							|  |  |  |          * all runstate names are shorter than 100 bytes (the size of | 
					
						
							|  |  |  |          * s->runstate). However, a malicious stream could overflow | 
					
						
							|  |  |  |          * the qapi_enum_parse() call, so we force the last character | 
					
						
							|  |  |  |          * to a NUL byte. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         s->runstate[sizeof(s->runstate) - 1] = '\0'; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-24 10:46:10 +02:00
										 |  |  |     r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err); | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (r == -1) { | 
					
						
							|  |  |  |         if (local_err) { | 
					
						
							|  |  |  |             error_report_err(local_err); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return -EINVAL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s->state = r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 12:29:12 +01:00
										 |  |  | static int global_state_pre_save(void *opaque) | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     GlobalState *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     trace_migrate_global_state_pre_save((char *)s->runstate); | 
					
						
							| 
									
										
										
										
											2019-01-03 09:56:38 +01:00
										 |  |  |     s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1; | 
					
						
							|  |  |  |     assert(s->size <= sizeof(s->runstate)); | 
					
						
							| 
									
										
										
										
											2017-09-25 12:29:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2017-04-24 18:53:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const VMStateDescription vmstate_globalstate = { | 
					
						
							|  |  |  |     .name = "globalstate", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .post_load = global_state_post_load, | 
					
						
							|  |  |  |     .pre_save = global_state_pre_save, | 
					
						
							|  |  |  |     .needed = global_state_needed, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_UINT32(size, GlobalState), | 
					
						
							|  |  |  |         VMSTATE_BUFFER(runstate, GlobalState), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void register_global_state(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* We would use it independently that we receive it */ | 
					
						
							|  |  |  |     strcpy((char *)&global_state.runstate, ""); | 
					
						
							|  |  |  |     global_state.received = false; | 
					
						
							|  |  |  |     vmstate_register(NULL, 0, &vmstate_globalstate, &global_state); | 
					
						
							|  |  |  | } |