static void check_all_finished(libxl__egc *egc, libxl__stream_read_state *stream, int rc) { STATE_AO_GC(stream->ao); /* * In the case of a failure, the _abort()'s below might cancel * synchronously on top of us, or asynchronously at a later point. * * We must avoid the situation where all _abort() cancel * synchronously and the completion_callback() gets called twice; * once by the first error and once by the final stacked abort(), * both of whom will find that all of the tasks have stopped. * * To avoid this problem, any stacked re-entry into this function is * ineligible to fire the completion callback. The outermost * instance will take care of completing, once the stack has * unwound. */ if (stream->sync_teardown) return; if (!stream->rc && rc) { /* First reported failure. Tear everything down. */ stream->rc = rc; stream->sync_teardown = true; libxl__stream_read_abort(egc, stream, rc); libxl__save_helper_abort(egc, &stream->shs); libxl__conversion_helper_abort(egc, &stream->chs, rc); stream->sync_teardown = false; } /* Don't fire the callback until all our parallel tasks have stopped. */ if (libxl__stream_read_inuse(stream) || libxl__save_helper_inuse(&stream->shs) || libxl__conversion_helper_inuse(&stream->chs)) return; stream->completion_callback(egc, stream, stream->rc); }
void libxl__colo_save_teardown(libxl__egc *egc, libxl__colo_save_state *css, int rc) { libxl__domain_save_state *dss = CONTAINER_OF(css, *dss, css); EGC_GC; LOGD(WARN, dss->domid, "COLO: Domain suspend terminated with rc %d," " teardown COLO devices...", rc); libxl__stream_read_abort(egc, &css->srs, 1); if (css->qdisk_setuped) { libxl__qmp_stop_replication(gc, dss->domid, true); css->qdisk_setuped = false; } dss->cds.callback = colo_teardown_done; libxl__checkpoint_devices_teardown(egc, &dss->cds); return; }