global_state.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #include "qemu/osdep.h"
  13. #include "qemu/cutils.h"
  14. #include "qemu/error-report.h"
  15. #include "system/runstate.h"
  16. #include "qapi/error.h"
  17. #include "migration.h"
  18. #include "migration/global_state.h"
  19. #include "migration/vmstate.h"
  20. #include "trace.h"
  21. typedef struct {
  22. uint32_t size;
  23. /*
  24. * runstate was 100 bytes, zero padded, but we trimmed it to add a
  25. * few fields and maintain backwards compatibility.
  26. */
  27. uint8_t runstate[32];
  28. uint8_t has_vm_was_suspended;
  29. uint8_t vm_was_suspended;
  30. uint8_t unused[66];
  31. RunState state;
  32. bool received;
  33. } GlobalState;
  34. static GlobalState global_state;
  35. static void global_state_do_store(RunState state)
  36. {
  37. const char *state_str = RunState_str(state);
  38. assert(strlen(state_str) < sizeof(global_state.runstate));
  39. strpadcpy((char *)global_state.runstate, sizeof(global_state.runstate),
  40. state_str, '\0');
  41. global_state.has_vm_was_suspended = true;
  42. global_state.vm_was_suspended = vm_get_suspended();
  43. memset(global_state.unused, 0, sizeof(global_state.unused));
  44. }
  45. void global_state_store(void)
  46. {
  47. global_state_do_store(runstate_get());
  48. }
  49. void global_state_store_running(void)
  50. {
  51. global_state_do_store(RUN_STATE_RUNNING);
  52. }
  53. bool global_state_received(void)
  54. {
  55. return global_state.received;
  56. }
  57. RunState global_state_get_runstate(void)
  58. {
  59. return global_state.state;
  60. }
  61. static bool global_state_needed(void *opaque)
  62. {
  63. return migrate_get_current()->store_global_state;
  64. }
  65. static int global_state_post_load(void *opaque, int version_id)
  66. {
  67. GlobalState *s = opaque;
  68. Error *local_err = NULL;
  69. int r;
  70. char *runstate = (char *)s->runstate;
  71. s->received = true;
  72. trace_migrate_global_state_post_load(runstate);
  73. if (strnlen((char *)s->runstate,
  74. sizeof(s->runstate)) == sizeof(s->runstate)) {
  75. /*
  76. * This condition should never happen during migration, because
  77. * all runstate names are shorter than 32 bytes (the size of
  78. * s->runstate). However, a malicious stream could overflow
  79. * the qapi_enum_parse() call, so we force the last character
  80. * to a NUL byte.
  81. */
  82. s->runstate[sizeof(s->runstate) - 1] = '\0';
  83. }
  84. r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
  85. if (r == -1) {
  86. if (local_err) {
  87. error_report_err(local_err);
  88. }
  89. return -EINVAL;
  90. }
  91. s->state = r;
  92. /*
  93. * global_state is saved on the outgoing side before forcing a stopped
  94. * state, so it may have saved state=suspended and vm_was_suspended=0.
  95. * Now we are in a paused state, and when we later call vm_start, it must
  96. * restore the suspended state, so we must set vm_was_suspended=1 here.
  97. */
  98. vm_set_suspended(s->vm_was_suspended || r == RUN_STATE_SUSPENDED);
  99. return 0;
  100. }
  101. static int global_state_pre_save(void *opaque)
  102. {
  103. GlobalState *s = opaque;
  104. trace_migrate_global_state_pre_save((char *)s->runstate);
  105. s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
  106. assert(s->size <= sizeof(s->runstate));
  107. return 0;
  108. }
  109. static const VMStateDescription vmstate_globalstate = {
  110. .name = "globalstate",
  111. .version_id = 1,
  112. .minimum_version_id = 1,
  113. .post_load = global_state_post_load,
  114. .pre_save = global_state_pre_save,
  115. .needed = global_state_needed,
  116. .fields = (const VMStateField[]) {
  117. VMSTATE_UINT32(size, GlobalState),
  118. VMSTATE_BUFFER(runstate, GlobalState),
  119. VMSTATE_UINT8(has_vm_was_suspended, GlobalState),
  120. VMSTATE_UINT8(vm_was_suspended, GlobalState),
  121. VMSTATE_BUFFER(unused, GlobalState),
  122. VMSTATE_END_OF_LIST()
  123. },
  124. };
  125. void register_global_state(void)
  126. {
  127. /* We would use it independently that we receive it */
  128. strcpy((char *)&global_state.runstate, "");
  129. global_state.received = false;
  130. vmstate_register(NULL, 0, &vmstate_globalstate, &global_state);
  131. }