@@ -1190,6 +1190,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
return ret;
}
+/* RAM's always up for postcopying */
+static bool ram_can_postcopy(void *opaque)
+{
+ return true;
+}
+
static SaveVMHandlers savevm_ram_handlers = {
.save_live_setup = ram_save_setup,
.save_live_iterate = ram_save_iterate,
@@ -1197,6 +1203,7 @@ static SaveVMHandlers savevm_ram_handlers = {
.save_live_pending = ram_save_pending,
.load_state = ram_load,
.cancel = ram_migration_cancel,
+ .can_postcopy = ram_can_postcopy,
};
void ram_mig_init(void)
@@ -54,7 +54,7 @@ typedef struct SaveVMHandlers {
/* This runs outside the iothread lock! */
int (*save_live_setup)(QEMUFile *f, void *opaque);
uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size);
-
+ bool (*can_postcopy)(void *opaque);
LoadStateHandler *load_state;
} SaveVMHandlers;
@@ -109,7 +109,9 @@ void qemu_savevm_state_begin(QEMUFile *f,
int qemu_savevm_state_iterate(QEMUFile *f);
void qemu_savevm_state_complete(QEMUFile *f);
void qemu_savevm_state_cancel(void);
-uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
+void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
+ uint64_t *res_non_postcopiable,
+ uint64_t *res_postcopiable);
void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
uint16_t len, uint8_t *data);
void qemu_savevm_send_reqack(QEMUFile *f, uint32_t value);
@@ -840,8 +840,15 @@ static void *migration_thread(void *opaque)
uint64_t pending_size;
if (!qemu_file_rate_limit(s->file)) {
- pending_size = qemu_savevm_state_pending(s->file, max_size);
+ uint64_t pend_post, pend_nonpost;
+ DPRINTF("iterate\n");
+ qemu_savevm_state_pending(s->file, max_size, &pend_nonpost,
+ &pend_post);
+ pending_size = pend_nonpost + pend_post;
trace_migrate_pending(pending_size, max_size);
+ DPRINTF("pending size %" PRIu64 " max %" PRIu64 " (post=%" PRIu64
+ " nonpost=%" PRIu64 ")\n",
+ pending_size, max_size, pend_post, pend_nonpost);
if (pending_size && pending_size >= max_size) {
qemu_savevm_state_iterate(s->file);
} else {
@@ -903,10 +903,18 @@ void qemu_savevm_state_complete(QEMUFile *f)
qemu_fflush(f);
}
-uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
+/* Give an estimate of the amount left to be transferred,
+ * the result is split into the amount for units that can and
+ * for units that can't do postcopy.
+ */
+void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
+ uint64_t *res_non_postcopiable,
+ uint64_t *res_postcopiable)
{
SaveStateEntry *se;
- uint64_t ret = 0;
+ uint64_t res_nonpc = 0;
+ uint64_t res_pc = 0;
+ uint64_t tmp;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!se->ops || !se->ops->save_live_pending) {
@@ -917,9 +925,16 @@ uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
continue;
}
}
- ret += se->ops->save_live_pending(f, se->opaque, max_size);
+ tmp = se->ops->save_live_pending(f, se->opaque, max_size);
+
+ if (se->ops->can_postcopy(se->opaque)) {
+ res_pc += tmp;
+ } else {
+ res_nonpc += tmp;
+ }
}
- return ret;
+ *res_non_postcopiable = res_nonpc;
+ *res_postcopiable = res_pc;
}
void qemu_savevm_state_cancel(void)