COLO: Add a new RunState RUN_STATE_COLO
[qemu/ar7.git] / migration / colo.c
blobfcc9047595a6a55019ac94d9d7f3a73064f0c9cd
1 /*
2 * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO)
3 * (a.k.a. Fault Tolerance or Continuous Replication)
5 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
6 * Copyright (c) 2016 FUJITSU LIMITED
7 * Copyright (c) 2016 Intel Corporation
9 * This work is licensed under the terms of the GNU GPL, version 2 or
10 * later. See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "sysemu/sysemu.h"
15 #include "migration/colo.h"
16 #include "trace.h"
17 #include "qemu/error-report.h"
18 #include "qapi/error.h"
20 bool colo_supported(void)
22 return false;
25 bool migration_in_colo_state(void)
27 MigrationState *s = migrate_get_current();
29 return (s->state == MIGRATION_STATUS_COLO);
32 bool migration_incoming_in_colo_state(void)
34 MigrationIncomingState *mis = migration_incoming_get_current();
36 return mis && (mis->state == MIGRATION_STATUS_COLO);
39 static void colo_send_message(QEMUFile *f, COLOMessage msg,
40 Error **errp)
42 int ret;
44 if (msg >= COLO_MESSAGE__MAX) {
45 error_setg(errp, "%s: Invalid message", __func__);
46 return;
48 qemu_put_be32(f, msg);
49 qemu_fflush(f);
51 ret = qemu_file_get_error(f);
52 if (ret < 0) {
53 error_setg_errno(errp, -ret, "Can't send COLO message");
55 trace_colo_send_message(COLOMessage_lookup[msg]);
58 static COLOMessage colo_receive_message(QEMUFile *f, Error **errp)
60 COLOMessage msg;
61 int ret;
63 msg = qemu_get_be32(f);
64 ret = qemu_file_get_error(f);
65 if (ret < 0) {
66 error_setg_errno(errp, -ret, "Can't receive COLO message");
67 return msg;
69 if (msg >= COLO_MESSAGE__MAX) {
70 error_setg(errp, "%s: Invalid message", __func__);
71 return msg;
73 trace_colo_receive_message(COLOMessage_lookup[msg]);
74 return msg;
77 static void colo_receive_check_message(QEMUFile *f, COLOMessage expect_msg,
78 Error **errp)
80 COLOMessage msg;
81 Error *local_err = NULL;
83 msg = colo_receive_message(f, &local_err);
84 if (local_err) {
85 error_propagate(errp, local_err);
86 return;
88 if (msg != expect_msg) {
89 error_setg(errp, "Unexpected COLO message %d, expected %d",
90 msg, expect_msg);
94 static int colo_do_checkpoint_transaction(MigrationState *s)
96 Error *local_err = NULL;
98 colo_send_message(s->to_dst_file, COLO_MESSAGE_CHECKPOINT_REQUEST,
99 &local_err);
100 if (local_err) {
101 goto out;
104 colo_receive_check_message(s->rp_state.from_dst_file,
105 COLO_MESSAGE_CHECKPOINT_REPLY, &local_err);
106 if (local_err) {
107 goto out;
110 /* TODO: suspend and save vm state to colo buffer */
112 colo_send_message(s->to_dst_file, COLO_MESSAGE_VMSTATE_SEND, &local_err);
113 if (local_err) {
114 goto out;
117 /* TODO: send vmstate to Secondary */
119 colo_receive_check_message(s->rp_state.from_dst_file,
120 COLO_MESSAGE_VMSTATE_RECEIVED, &local_err);
121 if (local_err) {
122 goto out;
125 colo_receive_check_message(s->rp_state.from_dst_file,
126 COLO_MESSAGE_VMSTATE_LOADED, &local_err);
127 if (local_err) {
128 goto out;
131 /* TODO: resume Primary */
133 return 0;
134 out:
135 if (local_err) {
136 error_report_err(local_err);
138 return -EINVAL;
141 static void colo_process_checkpoint(MigrationState *s)
143 Error *local_err = NULL;
144 int ret;
146 s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file);
147 if (!s->rp_state.from_dst_file) {
148 error_report("Open QEMUFile from_dst_file failed");
149 goto out;
153 * Wait for Secondary finish loading VM states and enter COLO
154 * restore.
156 colo_receive_check_message(s->rp_state.from_dst_file,
157 COLO_MESSAGE_CHECKPOINT_READY, &local_err);
158 if (local_err) {
159 goto out;
162 qemu_mutex_lock_iothread();
163 vm_start();
164 qemu_mutex_unlock_iothread();
165 trace_colo_vm_state_change("stop", "run");
167 while (s->state == MIGRATION_STATUS_COLO) {
168 ret = colo_do_checkpoint_transaction(s);
169 if (ret < 0) {
170 goto out;
174 out:
175 /* Throw the unreported error message after exited from loop */
176 if (local_err) {
177 error_report_err(local_err);
180 if (s->rp_state.from_dst_file) {
181 qemu_fclose(s->rp_state.from_dst_file);
185 void migrate_start_colo_process(MigrationState *s)
187 qemu_mutex_unlock_iothread();
188 migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
189 MIGRATION_STATUS_COLO);
190 colo_process_checkpoint(s);
191 qemu_mutex_lock_iothread();
194 static void colo_wait_handle_message(QEMUFile *f, int *checkpoint_request,
195 Error **errp)
197 COLOMessage msg;
198 Error *local_err = NULL;
200 msg = colo_receive_message(f, &local_err);
201 if (local_err) {
202 error_propagate(errp, local_err);
203 return;
206 switch (msg) {
207 case COLO_MESSAGE_CHECKPOINT_REQUEST:
208 *checkpoint_request = 1;
209 break;
210 default:
211 *checkpoint_request = 0;
212 error_setg(errp, "Got unknown COLO message: %d", msg);
213 break;
217 void *colo_process_incoming_thread(void *opaque)
219 MigrationIncomingState *mis = opaque;
220 Error *local_err = NULL;
222 migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
223 MIGRATION_STATUS_COLO);
225 mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
226 if (!mis->to_src_file) {
227 error_report("COLO incoming thread: Open QEMUFile to_src_file failed");
228 goto out;
231 * Note: the communication between Primary side and Secondary side
232 * should be sequential, we set the fd to unblocked in migration incoming
233 * coroutine, and here we are in the COLO incoming thread, so it is ok to
234 * set the fd back to blocked.
236 qemu_file_set_blocking(mis->from_src_file, true);
238 colo_send_message(mis->to_src_file, COLO_MESSAGE_CHECKPOINT_READY,
239 &local_err);
240 if (local_err) {
241 goto out;
244 while (mis->state == MIGRATION_STATUS_COLO) {
245 int request;
247 colo_wait_handle_message(mis->from_src_file, &request, &local_err);
248 if (local_err) {
249 goto out;
251 assert(request);
252 /* FIXME: This is unnecessary for periodic checkpoint mode */
253 colo_send_message(mis->to_src_file, COLO_MESSAGE_CHECKPOINT_REPLY,
254 &local_err);
255 if (local_err) {
256 goto out;
259 colo_receive_check_message(mis->from_src_file,
260 COLO_MESSAGE_VMSTATE_SEND, &local_err);
261 if (local_err) {
262 goto out;
265 /* TODO: read migration data into colo buffer */
267 colo_send_message(mis->to_src_file, COLO_MESSAGE_VMSTATE_RECEIVED,
268 &local_err);
269 if (local_err) {
270 goto out;
273 /* TODO: load vm state */
275 colo_send_message(mis->to_src_file, COLO_MESSAGE_VMSTATE_LOADED,
276 &local_err);
277 if (local_err) {
278 goto out;
282 out:
283 /* Throw the unreported error message after exited from loop */
284 if (local_err) {
285 error_report_err(local_err);
288 if (mis->to_src_file) {
289 qemu_fclose(mis->to_src_file);
291 migration_incoming_exit_colo();
293 return NULL;