1 /*
2 * Copyright (C) 2016 FUJITSU LIMITED
3 * Author: Wen Congyang <wency@cn.fujitsu.com>
4 * Yang Hongyang <hongyang.yang@easystack.cn>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; version 2.1 only. with the special
9 * exception on linking described in file LICENSE.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 */
16
17 #include "libxl_osdeps.h" /* must come before any other headers */
18
19 #include "libxl_internal.h"
20
21 extern const libxl__checkpoint_device_instance_ops colo_save_device_nic;
22 extern const libxl__checkpoint_device_instance_ops colo_save_device_qdisk;
23
24 static const libxl__checkpoint_device_instance_ops *colo_ops[] = {
25 &colo_save_device_nic,
26 &colo_save_device_qdisk,
27 NULL,
28 };
29
30 /* ================= helper functions ================= */
31
init_device_subkind(libxl__checkpoint_devices_state * cds)32 static int init_device_subkind(libxl__checkpoint_devices_state *cds)
33 {
34 /* init device subkind-specific state in the libxl ctx */
35 int rc;
36 STATE_AO_GC(cds->ao);
37
38 rc = init_subkind_colo_nic(cds);
39 if (rc) goto out;
40
41 rc = init_subkind_qdisk(cds);
42 if (rc) {
43 cleanup_subkind_colo_nic(cds);
44 goto out;
45 }
46
47 rc = 0;
48 out:
49 return rc;
50 }
51
cleanup_device_subkind(libxl__checkpoint_devices_state * cds)52 static void cleanup_device_subkind(libxl__checkpoint_devices_state *cds)
53 {
54 /* cleanup device subkind-specific state in the libxl ctx */
55 STATE_AO_GC(cds->ao);
56
57 cleanup_subkind_colo_nic(cds);
58 cleanup_subkind_qdisk(cds);
59 }
60
61 /* ================= colo: setup save environment ================= */
62
63 static void colo_save_setup_done(libxl__egc *egc,
64 libxl__checkpoint_devices_state *cds,
65 int rc);
66 static void colo_save_setup_failed(libxl__egc *egc,
67 libxl__checkpoint_devices_state *cds,
68 int rc);
69 /*
70 * checkpoint callbacks are called in the following order:
71 * 1. suspend
72 * 2. checkpoint
73 * 3. resume
74 * 4. wait checkpoint
75 */
76 static void libxl__colo_save_domain_suspend_callback(void *data);
77 static void libxl__colo_save_domain_checkpoint_callback(void *data);
78 static void libxl__colo_save_domain_resume_callback(void *data);
79 static void libxl__colo_save_domain_wait_checkpoint_callback(void *data);
80
libxl__colo_save_setup(libxl__egc * egc,libxl__colo_save_state * css)81 void libxl__colo_save_setup(libxl__egc *egc, libxl__colo_save_state *css)
82 {
83 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
84
85 /* Convenience aliases */
86 libxl__checkpoint_devices_state *const cds = &dss->cds;
87 libxl__srm_save_autogen_callbacks *const callbacks =
88 &dss->sws.shs.callbacks.save.a;
89
90 STATE_AO_GC(dss->ao);
91
92 if (dss->type != LIBXL_DOMAIN_TYPE_HVM) {
93 LOGD(ERROR, dss->domid, "COLO only supports hvm now");
94 goto out;
95 }
96
97 css->send_fd = dss->fd;
98 css->recv_fd = dss->recv_fd;
99 css->svm_running = false;
100 css->paused = true;
101 css->qdisk_setuped = false;
102 css->qdisk_used = false;
103 libxl__ev_child_init(&css->child);
104 css->cps.is_userspace_proxy =
105 libxl_defbool_val(dss->remus->userspace_colo_proxy);
106
107 if (dss->remus->netbufscript)
108 css->colo_proxy_script = libxl__strdup(gc, dss->remus->netbufscript);
109 else
110 css->colo_proxy_script = GCSPRINTF("%s/colo-proxy-setup",
111 libxl__xen_script_dir_path());
112
113 cds->ops = colo_ops;
114 cds->callback = colo_save_setup_done;
115 cds->ao = ao;
116 cds->domid = dss->domid;
117 cds->concrete_data = css;
118
119 /* If enable userspace proxy mode, we don't need VIF */
120 if (css->cps.is_userspace_proxy) {
121 cds->device_kind_flags = (1 << LIBXL__DEVICE_KIND_VBD);
122
123 /* Use this args we can connect to qemu colo-compare */
124 cds->nics = libxl__device_list(gc, &libxl__nic_devtype,
125 cds->domid, &cds->num_nics);
126 if (cds->num_nics > 0) {
127 css->cps.checkpoint_host = cds->nics[0].colo_checkpoint_host;
128 css->cps.checkpoint_port = cds->nics[0].colo_checkpoint_port;
129 }
130 } else {
131 cds->device_kind_flags = (1 << LIBXL__DEVICE_KIND_VIF) |
132 (1 << LIBXL__DEVICE_KIND_VBD);
133 }
134
135 css->srs.ao = ao;
136 css->srs.fd = css->recv_fd;
137 css->srs.back_channel = true;
138 libxl__stream_read_start(egc, &css->srs);
139 css->cps.ao = ao;
140 if (colo_proxy_setup(&css->cps)) {
141 LOGD(ERROR, cds->domid, "COLO: failed to setup colo proxy for guest");
142 goto out;
143 }
144
145 if (init_device_subkind(cds))
146 goto out;
147
148 callbacks->suspend = libxl__colo_save_domain_suspend_callback;
149 callbacks->checkpoint = libxl__colo_save_domain_checkpoint_callback;
150 callbacks->postcopy = libxl__colo_save_domain_resume_callback;
151 callbacks->wait_checkpoint = libxl__colo_save_domain_wait_checkpoint_callback;
152
153 libxl__checkpoint_devices_setup(egc, &dss->cds);
154
155 return;
156
157 out:
158 dss->callback(egc, dss, ERROR_FAIL);
159 }
160
colo_save_setup_done(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)161 static void colo_save_setup_done(libxl__egc *egc,
162 libxl__checkpoint_devices_state *cds,
163 int rc)
164 {
165 libxl__colo_save_state *css = cds->concrete_data;
166 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
167 EGC_GC;
168
169 if (!rc) {
170 libxl__domain_save(egc, dss);
171 return;
172 }
173
174 LOGD(ERROR, dss->domid, "COLO: failed to setup device for guest");
175 cds->callback = colo_save_setup_failed;
176 libxl__checkpoint_devices_teardown(egc, cds);
177 }
178
colo_save_setup_failed(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)179 static void colo_save_setup_failed(libxl__egc *egc,
180 libxl__checkpoint_devices_state *cds,
181 int rc)
182 {
183 libxl__colo_save_state *css = cds->concrete_data;
184 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
185 STATE_AO_GC(cds->ao);
186
187 if (rc)
188 LOGD(ERROR, cds->domid,
189 "COLO: failed to teardown device after setup failed"
190 " for guest, rc %d", rc);
191
192 cleanup_device_subkind(cds);
193 dss->callback(egc, dss, rc);
194 }
195
196 /* ================= colo: teardown save environment ================= */
197
198 static void colo_teardown_done(libxl__egc *egc,
199 libxl__checkpoint_devices_state *cds,
200 int rc);
201
libxl__colo_save_teardown(libxl__egc * egc,libxl__colo_save_state * css,int rc)202 void libxl__colo_save_teardown(libxl__egc *egc,
203 libxl__colo_save_state *css,
204 int rc)
205 {
206 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
207
208 EGC_GC;
209
210 LOGD(WARN, dss->domid,
211 "COLO: Domain suspend terminated with rc %d,"
212 " teardown COLO devices...", rc);
213
214 libxl__stream_read_abort(egc, &css->srs, 1);
215
216 if (css->qdisk_setuped) {
217 libxl__qmp_stop_replication(gc, dss->domid, true);
218 css->qdisk_setuped = false;
219 }
220
221 dss->cds.callback = colo_teardown_done;
222 libxl__checkpoint_devices_teardown(egc, &dss->cds);
223 return;
224 }
225
colo_teardown_done(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)226 static void colo_teardown_done(libxl__egc *egc,
227 libxl__checkpoint_devices_state *cds,
228 int rc)
229 {
230 libxl__colo_save_state *css = cds->concrete_data;
231 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
232
233 cleanup_device_subkind(cds);
234 colo_proxy_teardown(&css->cps);
235 dss->callback(egc, dss, rc);
236 }
237
238 static void colo_common_write_stream_done(libxl__egc *egc,
239 libxl__stream_write_state *stream,
240 int rc);
241 static void colo_common_read_stream_done(libxl__egc *egc,
242 libxl__stream_read_state *stream,
243 int rc);
244
245 /* ===================== colo: suspend primary vm ===================== */
246
247 static void colo_read_svm_suspended_done(libxl__egc *egc,
248 libxl__colo_save_state *css,
249 int id);
250 /*
251 * Do the following things when suspending primary vm:
252 * 1. suspend primary vm
253 * 2. do postsuspend
254 * 3. read CHECKPOINT_SVM_SUSPENDED
255 * 4. read secondary vm's dirty pages
256 */
257 static void colo_suspend_primary_vm_done(libxl__egc *egc,
258 libxl__domain_suspend_state *dsps,
259 int ok);
260 static void colo_postsuspend_cb(libxl__egc *egc,
261 libxl__checkpoint_devices_state *cds,
262 int rc);
263
libxl__colo_save_domain_suspend_callback(void * data)264 static void libxl__colo_save_domain_suspend_callback(void *data)
265 {
266 libxl__save_helper_state *shs = data;
267 libxl__egc *egc = shs->egc;
268 libxl__stream_write_state *sws = CONTAINER_OF(shs, *sws, shs);
269 libxl__domain_save_state *dss = sws->dss;
270
271 /* Convenience aliases */
272 libxl__domain_suspend_state *dsps = &dss->dsps;
273
274 dsps->callback_common_done = colo_suspend_primary_vm_done;
275 libxl__domain_suspend(egc, dsps);
276 }
277
colo_suspend_primary_vm_done(libxl__egc * egc,libxl__domain_suspend_state * dsps,int rc)278 static void colo_suspend_primary_vm_done(libxl__egc *egc,
279 libxl__domain_suspend_state *dsps,
280 int rc)
281 {
282 libxl__domain_save_state *dss = CONTAINER_OF(dsps, *dss, dsps);
283
284 EGC_GC;
285
286 if (rc) {
287 LOGD(ERROR, dss->domid, "cannot suspend primary vm");
288 goto out;
289 }
290
291 /* Convenience aliases */
292 libxl__checkpoint_devices_state *const cds = &dss->cds;
293
294 cds->callback = colo_postsuspend_cb;
295 libxl__checkpoint_devices_postsuspend(egc, cds);
296 return;
297
298 out:
299 dss->rc = rc;
300 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, !rc);
301 }
302
colo_postsuspend_cb(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)303 static void colo_postsuspend_cb(libxl__egc *egc,
304 libxl__checkpoint_devices_state *cds,
305 int rc)
306 {
307 libxl__colo_save_state *css = cds->concrete_data;
308 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
309
310 EGC_GC;
311
312 if (rc) {
313 LOGD(ERROR, dss->domid, "postsuspend fails");
314 goto out;
315 }
316
317 if (!css->svm_running) {
318 rc = 0;
319 goto out;
320 }
321
322 /*
323 * read CHECKPOINT_SVM_SUSPENDED
324 */
325 css->callback = colo_read_svm_suspended_done;
326 css->srs.checkpoint_callback = colo_common_read_stream_done;
327 libxl__stream_read_checkpoint_state(egc, &css->srs);
328
329 return;
330
331 out:
332 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, !rc);
333 }
334
colo_read_svm_suspended_done(libxl__egc * egc,libxl__colo_save_state * css,int id)335 static void colo_read_svm_suspended_done(libxl__egc *egc,
336 libxl__colo_save_state *css,
337 int id)
338 {
339 int ok = 0;
340 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
341
342 EGC_GC;
343
344 if (id != CHECKPOINT_SVM_SUSPENDED) {
345 LOGD(ERROR, dss->domid, "invalid section: %d, expected: %d", id,
346 CHECKPOINT_SVM_SUSPENDED);
347 goto out;
348 }
349
350 if (!css->paused &&
351 libxl__qmp_query_xen_replication_status(gc, dss->domid)) {
352 LOGD(ERROR, dss->domid,
353 "replication error occurs when primary vm is running");
354 goto out;
355 }
356
357 ok = 1;
358
359 out:
360 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, ok);
361 }
362
363 /* ===================== colo: send tailbuf ========================== */
364
libxl__colo_save_domain_checkpoint_callback(void * data)365 static void libxl__colo_save_domain_checkpoint_callback(void *data)
366 {
367 libxl__save_helper_state *shs = data;
368 libxl__stream_write_state *sws = CONTAINER_OF(shs, *sws, shs);
369 libxl__domain_save_state *dss = sws->dss;
370
371 /* Convenience aliases */
372 libxl__colo_save_state *const css = &dss->css;
373
374 /* write emulator xenstore data, emulator context, and checkpoint end */
375 css->callback = NULL;
376 dss->sws.checkpoint_callback = colo_common_write_stream_done;
377 libxl__stream_write_start_checkpoint(shs->egc, &dss->sws);
378 }
379
380 /* ===================== colo: resume primary vm ===================== */
381
382 /*
383 * Do the following things when resuming primary vm:
384 * 1. read CHECKPOINT_SVM_READY
385 * 2. do preresume
386 * 3. resume primary vm
387 * 4. read CHECKPOINT_SVM_RESUMED
388 */
389 static void colo_read_svm_ready_done(libxl__egc *egc,
390 libxl__colo_save_state *css,
391 int id);
392 static void colo_preresume_cb(libxl__egc *egc,
393 libxl__checkpoint_devices_state *cds,
394 int rc);
395 static void colo_read_svm_resumed_done(libxl__egc *egc,
396 libxl__colo_save_state *css,
397 int id);
398
libxl__colo_save_domain_resume_callback(void * data)399 static void libxl__colo_save_domain_resume_callback(void *data)
400 {
401 libxl__save_helper_state *shs = data;
402 libxl__egc *egc = shs->egc;
403 libxl__stream_write_state *sws = CONTAINER_OF(shs, *sws, shs);
404 libxl__domain_save_state *dss = sws->dss;
405
406 /* Convenience aliases */
407 libxl__colo_save_state *const css = &dss->css;
408
409 EGC_GC;
410
411 /* read CHECKPOINT_SVM_READY */
412 css->callback = colo_read_svm_ready_done;
413 css->srs.checkpoint_callback = colo_common_read_stream_done;
414 libxl__stream_read_checkpoint_state(egc, &css->srs);
415 }
416
colo_read_svm_ready_done(libxl__egc * egc,libxl__colo_save_state * css,int id)417 static void colo_read_svm_ready_done(libxl__egc *egc,
418 libxl__colo_save_state *css,
419 int id)
420 {
421 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
422
423 EGC_GC;
424
425 if (id != CHECKPOINT_SVM_READY) {
426 LOGD(ERROR, dss->domid, "invalid section: %d, expected: %d", id,
427 CHECKPOINT_SVM_READY);
428 goto out;
429 }
430
431 colo_proxy_preresume(&css->cps);
432
433 css->svm_running = true;
434 dss->cds.callback = colo_preresume_cb;
435 libxl__checkpoint_devices_preresume(egc, &dss->cds);
436
437 return;
438
439 out:
440 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, 0);
441 }
442
colo_preresume_cb(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)443 static void colo_preresume_cb(libxl__egc *egc,
444 libxl__checkpoint_devices_state *cds,
445 int rc)
446 {
447 libxl__colo_save_state *css = cds->concrete_data;
448 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
449
450 EGC_GC;
451
452 if (rc) {
453 LOGD(ERROR, dss->domid, "preresume fails");
454 goto out;
455 }
456
457 if (css->qdisk_used && !css->qdisk_setuped) {
458 if (libxl__qmp_start_replication(gc, dss->domid, true)) {
459 LOGD(ERROR, dss->domid, "starting replication fails");
460 goto out;
461 }
462 css->qdisk_setuped = true;
463 }
464
465 if (!css->paused) {
466 if (libxl__qmp_colo_do_checkpoint(gc, dss->domid)) {
467 LOGD(ERROR, dss->domid, "doing checkpoint fails");
468 goto out;
469 }
470 }
471
472 /* Resumes the domain and the device model */
473 if (libxl__domain_resume_deprecated(gc, dss->domid, /* Fast Suspend */1)) {
474 LOGD(ERROR, dss->domid, "cannot resume primary vm");
475 goto out;
476 }
477
478 /*
479 * The guest should be paused before doing colo because there is
480 * no disk migration.
481 */
482 if (css->paused) {
483 rc = libxl__domain_unpause_deprecated(gc, dss->domid);
484 if (rc) {
485 LOGD(ERROR, dss->domid, "cannot unpause primary vm");
486 goto out;
487 }
488 css->paused = false;
489 }
490
491 /* read CHECKPOINT_SVM_RESUMED */
492 css->callback = colo_read_svm_resumed_done;
493 css->srs.checkpoint_callback = colo_common_read_stream_done;
494 libxl__stream_read_checkpoint_state(egc, &css->srs);
495
496 return;
497
498 out:
499 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, 0);
500 }
501
colo_read_svm_resumed_done(libxl__egc * egc,libxl__colo_save_state * css,int id)502 static void colo_read_svm_resumed_done(libxl__egc *egc,
503 libxl__colo_save_state *css,
504 int id)
505 {
506 int ok = 0;
507 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
508
509 EGC_GC;
510
511 if (id != CHECKPOINT_SVM_RESUMED) {
512 LOGD(ERROR, dss->domid, "invalid section: %d, expected: %d", id,
513 CHECKPOINT_SVM_RESUMED);
514 goto out;
515 }
516
517 colo_proxy_postresume(&css->cps);
518
519 ok = 1;
520
521 out:
522 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, ok);
523 }
524
525 /* ===================== colo: wait new checkpoint ===================== */
526
527 static void colo_start_new_checkpoint(libxl__egc *egc,
528 libxl__checkpoint_devices_state *cds,
529 int rc);
530 static void colo_proxy_async_wait_for_checkpoint(libxl__colo_save_state *css);
531 static void colo_proxy_async_call_done(libxl__egc *egc,
532 libxl__ev_child *child,
533 int pid,
534 int status);
535
colo_proxy_wait_for_checkpoint(libxl__egc * egc,libxl__colo_save_state * css)536 static void colo_proxy_wait_for_checkpoint(libxl__egc *egc,
537 libxl__colo_save_state *css)
538 {
539 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
540
541 ASYNC_CALL(egc, dss->cds.ao, &css->child, css,
542 colo_proxy_async_wait_for_checkpoint,
543 colo_proxy_async_call_done);
544 }
545
colo_proxy_async_wait_for_checkpoint(libxl__colo_save_state * css)546 static void colo_proxy_async_wait_for_checkpoint(libxl__colo_save_state *css)
547 {
548 int req;
549
550 req = colo_proxy_checkpoint(&css->cps, COLO_PROXY_CHECKPOINT_TIMEOUT);
551 if (req < 0) {
552 /* some error happens */
553 _exit(1);
554 } else {
555 /* req == 0: no checkpoint is needed, do a checkpoint every 5s */
556 /* req > 0: net packets is not consistent, we need to start a
557 * checkpoint
558 */
559 _exit(0);
560 }
561 }
562
colo_proxy_async_call_done(libxl__egc * egc,libxl__ev_child * child,int pid,int status)563 static void colo_proxy_async_call_done(libxl__egc *egc,
564 libxl__ev_child *child,
565 int pid,
566 int status)
567 {
568 libxl__colo_save_state *css = CONTAINER_OF(child, *css, child);
569 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
570
571 EGC_GC;
572
573 if (status) {
574 LOGD(ERROR, dss->domid, "failed to wait for new checkpoint");
575 colo_start_new_checkpoint(egc, &dss->cds, ERROR_FAIL);
576 return;
577 }
578
579 colo_start_new_checkpoint(egc, &dss->cds, 0);
580 }
581
582 /*
583 * Do the following things:
584 * 1. do commit
585 * 2. wait for a new checkpoint
586 * 3. write CHECKPOINT_NEW
587 */
588 static void colo_device_commit_cb(libxl__egc *egc,
589 libxl__checkpoint_devices_state *cds,
590 int rc);
591
libxl__colo_save_domain_wait_checkpoint_callback(void * data)592 static void libxl__colo_save_domain_wait_checkpoint_callback(void *data)
593 {
594 libxl__save_helper_state *shs = data;
595 libxl__stream_write_state *sws = CONTAINER_OF(shs, *sws, shs);
596 libxl__domain_save_state *dss = sws->dss;
597 libxl__egc *egc = dss->sws.shs.egc;
598
599 /* Convenience aliases */
600 libxl__checkpoint_devices_state *const cds = &dss->cds;
601
602 cds->callback = colo_device_commit_cb;
603 libxl__checkpoint_devices_commit(egc, cds);
604 }
605
colo_device_commit_cb(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)606 static void colo_device_commit_cb(libxl__egc *egc,
607 libxl__checkpoint_devices_state *cds,
608 int rc)
609 {
610 libxl__colo_save_state *css = cds->concrete_data;
611 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
612
613 EGC_GC;
614
615 if (rc) {
616 LOGD(ERROR, dss->domid, "commit fails");
617 goto out;
618 }
619
620 colo_proxy_wait_for_checkpoint(egc, css);
621 return;
622
623 out:
624 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, 0);
625 }
626
colo_start_new_checkpoint(libxl__egc * egc,libxl__checkpoint_devices_state * cds,int rc)627 static void colo_start_new_checkpoint(libxl__egc *egc,
628 libxl__checkpoint_devices_state *cds,
629 int rc)
630 {
631 libxl__colo_save_state *css = cds->concrete_data;
632 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
633 libxl_sr_checkpoint_state srcs = { .id = CHECKPOINT_NEW };
634
635 if (rc)
636 goto out;
637
638 /* write CHECKPOINT_NEW */
639 css->callback = NULL;
640 dss->sws.checkpoint_callback = colo_common_write_stream_done;
641 libxl__stream_write_checkpoint_state(egc, &dss->sws, &srcs);
642
643 return;
644
645 out:
646 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, 0);
647 }
648
649 /* ===================== colo: common callback ===================== */
650
colo_common_write_stream_done(libxl__egc * egc,libxl__stream_write_state * stream,int rc)651 static void colo_common_write_stream_done(libxl__egc *egc,
652 libxl__stream_write_state *stream,
653 int rc)
654 {
655 libxl__domain_save_state *dss = CONTAINER_OF(stream, *dss, sws);
656 int ok;
657
658 /* Convenience aliases */
659 libxl__colo_save_state *const css = &dss->css;
660
661 EGC_GC;
662
663 if (rc < 0) {
664 /* TODO: it may be a internal error, but we don't know */
665 LOGD(ERROR, dss->domid, "sending data fails");
666 ok = 0;
667 goto out;
668 }
669
670 if (!css->callback) {
671 /* Everythins is OK */
672 ok = 1;
673 goto out;
674 }
675
676 css->callback(egc, css, 0);
677
678 return;
679
680 out:
681 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, ok);
682 }
683
colo_common_read_stream_done(libxl__egc * egc,libxl__stream_read_state * stream,int rc)684 static void colo_common_read_stream_done(libxl__egc *egc,
685 libxl__stream_read_state *stream,
686 int rc)
687 {
688 libxl__colo_save_state *css = CONTAINER_OF(stream, *css, srs);
689 libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css);
690 int ok;
691
692 EGC_GC;
693
694 if (rc < 0) {
695 /* TODO: it may be a internal error, but we don't know */
696 LOGD(ERROR, dss->domid, "reading data fails");
697 ok = 0;
698 goto out;
699 }
700
701 if (!css->callback) {
702 /* Everythins is OK */
703 ok = 1;
704 goto out;
705 }
706
707 /* rc contains the id */
708 css->callback(egc, css, rc);
709
710 return;
711
712 out:
713 libxl__xc_domain_saverestore_async_callback_done(egc, &dss->sws.shs, ok);
714 }
715