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