1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Stefan Reiter <s.reiter@proxmox.com>
3 Date: Thu, 22 Oct 2020 17:34:18 +0200
4 Subject: [PATCH] PVE: Migrate dirty bitmap state via savevm
6 QEMU provides 'savevm' registrations as a mechanism for arbitrary state
7 to be migrated along with a VM. Use this to send a serialized version of
8 dirty bitmap state data from proxmox-backup-qemu, and restore it on the
11 Also add a flag to query-proxmox-support so qemu-server can determine if
12 safe migration is possible and makes sense.
14 Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
15 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
16 [FE: split up state_pending for 8.0]
17 Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
19 include/migration/misc.h | 3 ++
20 migration/meson.build | 2 +
21 migration/migration.c | 1 +
22 migration/pbs-state.c | 104 +++++++++++++++++++++++++++++++++++++++
24 qapi/block-core.json | 6 +++
25 6 files changed, 117 insertions(+)
26 create mode 100644 migration/pbs-state.c
28 diff --git a/include/migration/misc.h b/include/migration/misc.h
29 index 7dcc0b5c2c..4c940b2475 100644
30 --- a/include/migration/misc.h
31 +++ b/include/migration/misc.h
32 @@ -77,4 +77,7 @@ bool migration_in_bg_snapshot(void);
33 /* migration/block-dirty-bitmap.c */
34 void dirty_bitmap_mig_init(void);
36 +/* migration/pbs-state.c */
37 +void pbs_state_mig_init(void);
40 diff --git a/migration/meson.build b/migration/meson.build
41 index 07f6057acc..343994d891 100644
42 --- a/migration/meson.build
43 +++ b/migration/meson.build
44 @@ -7,7 +7,9 @@ migration_files = files(
50 +system_ss.add(libproxmox_backup_qemu)
53 'block-dirty-bitmap.c',
54 diff --git a/migration/migration.c b/migration/migration.c
55 index 7a4c8beb5d..0a955a2a18 100644
56 --- a/migration/migration.c
57 +++ b/migration/migration.c
58 @@ -162,6 +162,7 @@ void migration_object_init(void)
61 dirty_bitmap_mig_init();
62 + pbs_state_mig_init();
65 void migration_cancel(const Error *error)
66 diff --git a/migration/pbs-state.c b/migration/pbs-state.c
68 index 0000000000..887e998b9e
70 +++ b/migration/pbs-state.c
73 + * PBS (dirty-bitmap) state migration
76 +#include "qemu/osdep.h"
77 +#include "migration/misc.h"
78 +#include "qemu-file.h"
79 +#include "migration/vmstate.h"
80 +#include "migration/register.h"
81 +#include "proxmox-backup-qemu.h"
83 +typedef struct PBSState {
87 +/* state is accessed via this static variable directly, 'opaque' is NULL */
88 +static PBSState pbs_state;
90 +static void pbs_state_pending(void *opaque, uint64_t *must_precopy,
91 + uint64_t *can_postcopy)
93 + /* we send everything in save_setup, so nothing is ever pending */
96 +/* receive PBS state via f and deserialize, called on target */
97 +static int pbs_state_load(QEMUFile *f, void *opaque, int version_id)
99 + /* safe cast, we cannot migrate to target with less bits than source */
100 + size_t buf_size = (size_t)qemu_get_be64(f);
102 + uint8_t *buf = (uint8_t *)malloc(buf_size);
103 + size_t read = qemu_get_buffer(f, buf, buf_size);
105 + if (read < buf_size) {
106 + fprintf(stderr, "error receiving PBS state: not enough data\n");
110 + proxmox_import_state(buf, buf_size);
116 +/* serialize PBS state and send to target via f, called on source */
117 +static int pbs_state_save_setup(QEMUFile *f, void *opaque)
120 + uint8_t *buf = proxmox_export_state(&buf_size);
123 + qemu_put_be64(f, buf_size);
124 + qemu_put_buffer(f, buf, buf_size);
126 + proxmox_free_state_buf(buf);
127 + pbs_state.active = false;
131 +static bool pbs_state_is_active(void *opaque)
133 + /* we need to return active exactly once, else .save_setup is never called,
134 + * but if we'd just return true the migration doesn't make progress since
135 + * it'd be waiting for us */
136 + return pbs_state.active;
139 +static bool pbs_state_is_active_iterate(void *opaque)
141 + /* we don't iterate, everything is sent in save_setup */
142 + return pbs_state_is_active(opaque);
145 +static bool pbs_state_has_postcopy(void *opaque)
147 + /* PBS state can't change during a migration (since that's blocking any
148 + * potential backups), so we can copy everything before the VM is stopped */
152 +static void pbs_state_save_cleanup(void *opaque)
154 + /* reset active after migration succeeds or fails */
155 + pbs_state.active = false;
158 +static SaveVMHandlers savevm_pbs_state_handlers = {
159 + .save_setup = pbs_state_save_setup,
160 + .has_postcopy = pbs_state_has_postcopy,
161 + .state_pending_exact = pbs_state_pending,
162 + .state_pending_estimate = pbs_state_pending,
163 + .is_active_iterate = pbs_state_is_active_iterate,
164 + .load_state = pbs_state_load,
165 + .is_active = pbs_state_is_active,
166 + .save_cleanup = pbs_state_save_cleanup,
169 +void pbs_state_mig_init(void)
171 + pbs_state.active = true;
172 + register_savevm_live("pbs-state", 0, 1,
173 + &savevm_pbs_state_handlers,
176 diff --git a/pve-backup.c b/pve-backup.c
177 index 5ed3c6a310..6720e985bc 100644
180 @@ -1065,6 +1065,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
181 ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version());
182 ret->pbs_dirty_bitmap = true;
183 ret->pbs_dirty_bitmap_savevm = true;
184 + ret->pbs_dirty_bitmap_migration = true;
185 ret->query_bitmap_info = true;
186 ret->pbs_masterkey = true;
187 ret->backup_max_workers = true;
188 diff --git a/qapi/block-core.json b/qapi/block-core.json
189 index d67a6d448a..09de550c95 100644
190 --- a/qapi/block-core.json
191 +++ b/qapi/block-core.json
193 # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can
194 # safely be set for savevm-async.
196 +# @pbs-dirty-bitmap-migration: True if safe migration of dirty-bitmaps including
197 +# PBS state is supported. Enabling 'dirty-bitmaps'
198 +# migration cap if this is false/unset may lead
199 +# to crashes on migration!
201 # @pbs-masterkey: True if the QMP backup call supports the 'master_keyfile'
204 @@ -1001,6 +1006,7 @@
205 'data': { 'pbs-dirty-bitmap': 'bool',
206 'query-bitmap-info': 'bool',
207 'pbs-dirty-bitmap-savevm': 'bool',
208 + 'pbs-dirty-bitmap-migration': 'bool',
209 'pbs-masterkey': 'bool',
210 'pbs-library-version': 'str',
211 'backup-max-workers': 'bool' } }