From: "Maciej S. Szmigiero" <maciej.szmigiero@oracle.com>
These SaveVMHandlers allow device to provide its own asynchronous
transmission of the remaining data at the end of a precopy phase.
The save_live_complete_precopy_async handler is supposed to start such
transmission (for example, by launching appropriate threads) while the
save_live_complete_precopy_async_wait handler is supposed to wait until
such transfer has finished (for example, until the sending threads
have exited).
Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
---
include/migration/register.h | 31 +++++++++++++++++++++++++++++++
migration/savevm.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/include/migration/register.h b/include/migration/register.h
index d7b70a8be68c..9d36e35bd612 100644
--- a/include/migration/register.h
+++ b/include/migration/register.h
@@ -102,6 +102,37 @@ typedef struct SaveVMHandlers {
*/
int (*save_live_complete_precopy)(QEMUFile *f, void *opaque);
+ /**
+ * @save_live_complete_precopy_async
+ *
+ * Arranges for handler-specific asynchronous transmission of the
+ * remaining data at the end of a precopy phase. When postcopy is
+ * enabled, devices that support postcopy will skip this step.
+ *
+ * @f: QEMUFile where the handler can synchronously send data before returning
+ * @idstr: this device section idstr
+ * @instance_id: this device section instance_id
+ * @opaque: data pointer passed to register_savevm_live()
+ *
+ * Returns zero to indicate success and negative for error
+ */
+ int (*save_live_complete_precopy_async)(QEMUFile *f,
+ char *idstr, uint32_t instance_id,
+ void *opaque);
+ /**
+ * @save_live_complete_precopy_async_wait
+ *
+ * Waits for the asynchronous transmission started by the of the
+ * @save_live_complete_precopy_async handler to complete.
+ * When postcopy is enabled, devices that support postcopy will skip this step.
+ *
+ * @f: QEMUFile where the handler can synchronously send data before returning
+ * @opaque: data pointer passed to register_savevm_live()
+ *
+ * Returns zero to indicate success and negative for error
+ */
+ int (*save_live_complete_precopy_async_wait)(QEMUFile *f, void *opaque);
+
/* This runs both outside and inside the BQL. */
/**
diff --git a/migration/savevm.c b/migration/savevm.c
index 388d7af7cdd8..fa35504678bf 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1497,6 +1497,27 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
SaveStateEntry *se;
int ret;
+ QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
+ if (!se->ops || (in_postcopy && se->ops->has_postcopy &&
+ se->ops->has_postcopy(se->opaque)) ||
+ !se->ops->save_live_complete_precopy_async) {
+ continue;
+ }
+
+ save_section_header(f, se, QEMU_VM_SECTION_END);
+
+ ret = se->ops->save_live_complete_precopy_async(f,
+ se->idstr, se->instance_id,
+ se->opaque);
+
+ save_section_footer(f, se);
+
+ if (ret < 0) {
+ qemu_file_set_error(f, ret);
+ return -1;
+ }
+ }
+
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
if (!se->ops ||
(in_postcopy && se->ops->has_postcopy &&
@@ -1528,6 +1549,20 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
end_ts_each - start_ts_each);
}
+ QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
+ if (!se->ops || (in_postcopy && se->ops->has_postcopy &&
+ se->ops->has_postcopy(se->opaque)) ||
+ !se->ops->save_live_complete_precopy_async_wait) {
+ continue;
+ }
+
+ ret = se->ops->save_live_complete_precopy_async_wait(f, se->opaque);
+ if (ret < 0) {
+ qemu_file_set_error(f, ret);
+ return -1;
+ }
+ }
+
trace_vmstate_downtime_checkpoint("src-iterable-saved");
return 0;