Mostly minor changes, bigger ones summarized: * QEMU's internal backup code now uses a new async system, which allows parallel requests - the default max_workers settings is 64, I chose less, since 64 put enough stress on QEMU that the guest became practically unusable during the backup, and 16 still shows quite a nice measureable performance improvement. Little code changes for us though. * 'malformed' QAPI parameters/functions are now a build error (i.e. using '_' vs '-'), I chose to just whitelist our calls in the name of backwards compatibility. * monitor OOB race fix now uses the upstream variant, cherry-picked from origin/master since it's not in 6.0 by default * last patch fixes a bug with snapshot rollback related to the new yank system Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
		
			
				
	
	
		
			212 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
						|
From: Stefan Reiter <s.reiter@proxmox.com>
 | 
						|
Date: Thu, 22 Oct 2020 17:34:18 +0200
 | 
						|
Subject: [PATCH] PVE: Migrate dirty bitmap state via savevm
 | 
						|
 | 
						|
QEMU provides 'savevm' registrations as a mechanism for arbitrary state
 | 
						|
to be migrated along with a VM. Use this to send a serialized version of
 | 
						|
dirty bitmap state data from proxmox-backup-qemu, and restore it on the
 | 
						|
target node.
 | 
						|
 | 
						|
Also add a flag to query-proxmox-support so qemu-server can determine if
 | 
						|
safe migration is possible and makes sense.
 | 
						|
 | 
						|
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
 | 
						|
---
 | 
						|
 include/migration/misc.h |   3 ++
 | 
						|
 migration/meson.build    |   2 +
 | 
						|
 migration/migration.c    |   1 +
 | 
						|
 migration/pbs-state.c    | 106 +++++++++++++++++++++++++++++++++++++++
 | 
						|
 pve-backup.c             |   1 +
 | 
						|
 qapi/block-core.json     |   6 +++
 | 
						|
 6 files changed, 119 insertions(+)
 | 
						|
 create mode 100644 migration/pbs-state.c
 | 
						|
 | 
						|
diff --git a/include/migration/misc.h b/include/migration/misc.h
 | 
						|
index 738675ef52..2b89db4b8e 100644
 | 
						|
--- a/include/migration/misc.h
 | 
						|
+++ b/include/migration/misc.h
 | 
						|
@@ -76,4 +76,7 @@ bool migration_in_bg_snapshot(void);
 | 
						|
 /* migration/block-dirty-bitmap.c */
 | 
						|
 void dirty_bitmap_mig_init(void);
 | 
						|
 
 | 
						|
+/* migration/pbs-state.c */
 | 
						|
+void pbs_state_mig_init(void);
 | 
						|
+
 | 
						|
 #endif
 | 
						|
diff --git a/migration/meson.build b/migration/meson.build
 | 
						|
index c8ae813a48..49108c79ef 100644
 | 
						|
--- a/migration/meson.build
 | 
						|
+++ b/migration/meson.build
 | 
						|
@@ -7,8 +7,10 @@ migration_files = files(
 | 
						|
   'qemu-file-channel.c',
 | 
						|
   'qemu-file.c',
 | 
						|
   'yank_functions.c',
 | 
						|
+  'pbs-state.c',
 | 
						|
 )
 | 
						|
 softmmu_ss.add(migration_files)
 | 
						|
+softmmu_ss.add(libproxmox_backup_qemu)
 | 
						|
 
 | 
						|
 softmmu_ss.add(files(
 | 
						|
   'block-dirty-bitmap.c',
 | 
						|
diff --git a/migration/migration.c b/migration/migration.c
 | 
						|
index 8ca034136b..a5ce875685 100644
 | 
						|
--- a/migration/migration.c
 | 
						|
+++ b/migration/migration.c
 | 
						|
@@ -221,6 +221,7 @@ void migration_object_init(void)
 | 
						|
     blk_mig_init();
 | 
						|
     ram_mig_init();
 | 
						|
     dirty_bitmap_mig_init();
 | 
						|
+    pbs_state_mig_init();
 | 
						|
 }
 | 
						|
 
 | 
						|
 void migration_shutdown(void)
 | 
						|
diff --git a/migration/pbs-state.c b/migration/pbs-state.c
 | 
						|
new file mode 100644
 | 
						|
index 0000000000..29f2b3860d
 | 
						|
--- /dev/null
 | 
						|
+++ b/migration/pbs-state.c
 | 
						|
@@ -0,0 +1,106 @@
 | 
						|
+/*
 | 
						|
+ * PBS (dirty-bitmap) state migration
 | 
						|
+ */
 | 
						|
+
 | 
						|
+#include "qemu/osdep.h"
 | 
						|
+#include "migration/misc.h"
 | 
						|
+#include "qemu-file.h"
 | 
						|
+#include "migration/vmstate.h"
 | 
						|
+#include "migration/register.h"
 | 
						|
+#include "proxmox-backup-qemu.h"
 | 
						|
+
 | 
						|
+typedef struct PBSState {
 | 
						|
+    bool active;
 | 
						|
+} PBSState;
 | 
						|
+
 | 
						|
+/* state is accessed via this static variable directly, 'opaque' is NULL */
 | 
						|
+static PBSState pbs_state;
 | 
						|
+
 | 
						|
+static void pbs_state_save_pending(QEMUFile *f, void *opaque,
 | 
						|
+                                      uint64_t max_size,
 | 
						|
+                                      uint64_t *res_precopy_only,
 | 
						|
+                                      uint64_t *res_compatible,
 | 
						|
+                                      uint64_t *res_postcopy_only)
 | 
						|
+{
 | 
						|
+    /* we send everything in save_setup, so nothing is ever pending */
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* receive PBS state via f and deserialize, called on target */
 | 
						|
+static int pbs_state_load(QEMUFile *f, void *opaque, int version_id)
 | 
						|
+{
 | 
						|
+    /* safe cast, we cannot migrate to target with less bits than source */
 | 
						|
+    size_t buf_size = (size_t)qemu_get_be64(f);
 | 
						|
+
 | 
						|
+    uint8_t *buf = (uint8_t *)malloc(buf_size);
 | 
						|
+    size_t read = qemu_get_buffer(f, buf, buf_size);
 | 
						|
+
 | 
						|
+    if (read < buf_size) {
 | 
						|
+        fprintf(stderr, "error receiving PBS state: not enough data\n");
 | 
						|
+        return -EIO;
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    proxmox_import_state(buf, buf_size);
 | 
						|
+
 | 
						|
+    free(buf);
 | 
						|
+    return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* serialize PBS state and send to target via f, called on source */
 | 
						|
+static int pbs_state_save_setup(QEMUFile *f, void *opaque)
 | 
						|
+{
 | 
						|
+    size_t buf_size;
 | 
						|
+    uint8_t *buf = proxmox_export_state(&buf_size);
 | 
						|
+
 | 
						|
+    /* LV encoding */
 | 
						|
+    qemu_put_be64(f, buf_size);
 | 
						|
+    qemu_put_buffer(f, buf, buf_size);
 | 
						|
+
 | 
						|
+    proxmox_free_state_buf(buf);
 | 
						|
+    pbs_state.active = false;
 | 
						|
+    return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool pbs_state_is_active(void *opaque)
 | 
						|
+{
 | 
						|
+    /* we need to return active exactly once, else .save_setup is never called,
 | 
						|
+     * but if we'd just return true the migration doesn't make progress since
 | 
						|
+     * it'd be waiting for us */
 | 
						|
+    return pbs_state.active;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool pbs_state_is_active_iterate(void *opaque)
 | 
						|
+{
 | 
						|
+    /* we don't iterate, everything is sent in save_setup */
 | 
						|
+    return pbs_state_is_active(opaque);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static bool pbs_state_has_postcopy(void *opaque)
 | 
						|
+{
 | 
						|
+    /* PBS state can't change during a migration (since that's blocking any
 | 
						|
+     * potential backups), so we can copy everything before the VM is stopped */
 | 
						|
+    return false;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void pbs_state_save_cleanup(void *opaque)
 | 
						|
+{
 | 
						|
+    /* reset active after migration succeeds or fails */
 | 
						|
+    pbs_state.active = false;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static SaveVMHandlers savevm_pbs_state_handlers = {
 | 
						|
+    .save_setup = pbs_state_save_setup,
 | 
						|
+    .has_postcopy = pbs_state_has_postcopy,
 | 
						|
+    .save_live_pending = pbs_state_save_pending,
 | 
						|
+    .is_active_iterate = pbs_state_is_active_iterate,
 | 
						|
+    .load_state = pbs_state_load,
 | 
						|
+    .is_active = pbs_state_is_active,
 | 
						|
+    .save_cleanup = pbs_state_save_cleanup,
 | 
						|
+};
 | 
						|
+
 | 
						|
+void pbs_state_mig_init(void)
 | 
						|
+{
 | 
						|
+    pbs_state.active = true;
 | 
						|
+    register_savevm_live("pbs-state", 0, 1,
 | 
						|
+                         &savevm_pbs_state_handlers,
 | 
						|
+                         NULL);
 | 
						|
+}
 | 
						|
diff --git a/pve-backup.c b/pve-backup.c
 | 
						|
index 59b4034871..ecff792760 100644
 | 
						|
--- a/pve-backup.c
 | 
						|
+++ b/pve-backup.c
 | 
						|
@@ -1132,6 +1132,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | 
						|
     ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version());
 | 
						|
     ret->pbs_dirty_bitmap = true;
 | 
						|
     ret->pbs_dirty_bitmap_savevm = true;
 | 
						|
+    ret->pbs_dirty_bitmap_migration = true;
 | 
						|
     ret->query_bitmap_info = true;
 | 
						|
     return ret;
 | 
						|
 }
 | 
						|
diff --git a/qapi/block-core.json b/qapi/block-core.json
 | 
						|
index 710b8dfb2d..cf3cbf2a56 100644
 | 
						|
--- a/qapi/block-core.json
 | 
						|
+++ b/qapi/block-core.json
 | 
						|
@@ -822,6 +822,11 @@
 | 
						|
 # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can
 | 
						|
 #                           safely be set for savevm-async.
 | 
						|
 #
 | 
						|
+# @pbs-dirty-bitmap-migration: True if safe migration of dirty-bitmaps including
 | 
						|
+#                              PBS state is supported. Enabling 'dirty-bitmaps'
 | 
						|
+#                              migration cap if this is false/unset may lead
 | 
						|
+#                              to crashes on migration!
 | 
						|
+#
 | 
						|
 # @pbs-library-version: Running version of libproxmox-backup-qemu0 library.
 | 
						|
 #
 | 
						|
 ##
 | 
						|
@@ -829,6 +834,7 @@
 | 
						|
   'data': { 'pbs-dirty-bitmap': 'bool',
 | 
						|
             'query-bitmap-info': 'bool',
 | 
						|
             'pbs-dirty-bitmap-savevm': 'bool',
 | 
						|
+            'pbs-dirty-bitmap-migration': 'bool',
 | 
						|
             'pbs-library-version': 'str' } }
 | 
						|
 
 | 
						|
 ##
 |