MIG_ITERATE_BREAK, /* Break the loop */
} MigIterateState;
+/* Are we ready to move to the next iteration phase? */
+static bool migration_iteration_next_ready(MigrationState *s,
+ MigPendingData *pending)
+{
+ /*
+ * If the estimated values already suggest us to switchover, mark this
+ * iteration finished, time to do a slow sync.
+ */
+ if (pending->total_bytes <= s->threshold_size) {
+ return true;
+ }
+
+ /*
+ * Since we may have modules reporting stop-only data, we also want to
+ * re-query with slow mode if all precopy data is moved over. This
+ * will also mark the current iteration done.
+ *
+ * This could happen when e.g. a module (like, VFIO) reports stopcopy
+ * size too large so it will never yet satisfy the downtime with the
+ * current setup (above check). Here, slow version of re-query helps
+ * because we keep trying the best to move whatever we have.
+ */
+ if (pending->precopy_bytes == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static void migration_iteration_go_next(MigPendingData *pending)
+{
+ /*
+ * Do a slow sync will achieve this. TODO: move RAM iteration code
+ * into the core layer.
+ */
+ qemu_savevm_query_pending(pending, true);
+}
+
+static bool postcopy_should_start(MigrationState *s, MigPendingData *pending)
+{
+ /* If postcopy's switchver will violate user specified downtime, stop */
+ if (pending->precopy_bytes + pending->stopcopy_bytes > s->threshold_size) {
+ return false;
+ }
+
+ return qatomic_read(&s->start_postcopy);
+}
+
/*
* Return true if continue to the next iteration directly, false
* otherwise.
s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE);
bool can_switchover = migration_can_switchover(s);
MigPendingData pending = { };
- uint64_t pending_size;
bool complete_ready;
/* Fast path - get the estimated amount of pending data */
qemu_savevm_query_pending(&pending, false);
- pending_size = pending.precopy_bytes + pending.postcopy_bytes;
if (in_postcopy) {
/*
* postcopy completion doesn't rely on can_switchover, because when
* POSTCOPY_ACTIVE it means switchover already happened.
*/
- complete_ready = !pending_size;
+ complete_ready = !pending.total_bytes;
if (s->state == MIGRATION_STATUS_POSTCOPY_DEVICE &&
(s->postcopy_package_loaded || complete_ready)) {
/*
* postcopy started, so ESTIMATE should always match with EXACT
* during postcopy phase.
*/
- if (pending_size <= s->threshold_size) {
- qemu_savevm_query_pending(&pending, true);
- pending_size = pending.precopy_bytes + pending.postcopy_bytes;
+ if (migration_iteration_next_ready(s, &pending)) {
+ migration_iteration_go_next(&pending);
}
/* Should we switch to postcopy now? */
- if (pending.precopy_bytes <= s->threshold_size &&
- can_switchover && qatomic_read(&s->start_postcopy)) {
+ if (can_switchover && postcopy_should_start(s, &pending)) {
if (postcopy_start(s, &local_err)) {
migrate_error_propagate(s, error_copy(local_err));
error_report_err(local_err);
* (2) Pending size is no more than the threshold specified
* (which was calculated from expected downtime)
*/
- complete_ready = can_switchover && (pending_size <= s->threshold_size);
+ complete_ready = can_switchover &&
+ (pending.total_bytes <= s->threshold_size);
}
if (complete_ready) {
- trace_migration_thread_low_pending(pending_size);
+ trace_migration_thread_low_pending(pending.total_bytes);
migration_completion(s);
return MIG_ITERATE_BREAK;
}
{
SaveStateEntry *se;
- pending->precopy_bytes = 0;
- pending->postcopy_bytes = 0;
+ memset(pending, 0, sizeof(*pending));
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
if (!se->ops || !se->ops->save_query_pending) {
se->ops->save_query_pending(se->opaque, pending, exact);
}
+ pending->total_bytes = pending->precopy_bytes +
+ pending->stopcopy_bytes + pending->postcopy_bytes;
+
trace_qemu_savevm_query_pending(exact, pending->precopy_bytes,
- pending->postcopy_bytes);
+ pending->stopcopy_bytes,
+ pending->postcopy_bytes,
+ pending->total_bytes);
}
void qemu_savevm_state_cleanup(void)
qemu_loadvm_state_post_main(int ret) "%d"
qemu_loadvm_state_section_startfull(uint32_t section_id, const char *idstr, uint32_t instance_id, uint32_t version_id) "%u(%s) %u %u"
qemu_savevm_send_packaged(void) ""
-qemu_savevm_query_pending(bool exact, uint64_t precopy, uint64_t postcopy) "exact=%d, precopy=%"PRIu64", postcopy=%"PRIu64
+qemu_savevm_query_pending(bool exact, uint64_t precopy, uint64_t stopcopy, uint64_t postcopy, uint64_t total) "exact=%d, precopy=%"PRIu64", stopcopy=%"PRIu64", postcopy=%"PRIu64", total=%"PRIu64
loadvm_state_switchover_ack_needed(unsigned int switchover_ack_pending_num) "Switchover ack pending num=%u"
loadvm_state_setup(void) ""
loadvm_state_cleanup(void) ""