]>
Commit | Line | Data |
---|---|---|
d95ad93e TL |
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 | |
5 | ||
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 | |
9 | target node. | |
10 | ||
11 | Also add a flag to query-proxmox-support so qemu-server can determine if | |
12 | safe migration is possible and makes sense. | |
13 | ||
14 | Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | |
ddbf7a87 | 15 | Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> |
bf251437 FE |
16 | [FE: split up state_pending for 8.0] |
17 | Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | |
d95ad93e | 18 | --- |
cfe02b3b | 19 | include/migration/misc.h | 3 ++ |
817b7667 | 20 | migration/meson.build | 2 + |
8dca018b | 21 | migration/migration.c | 1 + |
bf251437 | 22 | migration/pbs-state.c | 104 +++++++++++++++++++++++++++++++++++++++ |
cfe02b3b SR |
23 | pve-backup.c | 1 + |
24 | qapi/block-core.json | 6 +++ | |
bf251437 | 25 | 6 files changed, 117 insertions(+) |
d95ad93e TL |
26 | create mode 100644 migration/pbs-state.c |
27 | ||
28 | diff --git a/include/migration/misc.h b/include/migration/misc.h | |
10e10933 | 29 | index 7dcc0b5c2c..4c940b2475 100644 |
d95ad93e TL |
30 | --- a/include/migration/misc.h |
31 | +++ b/include/migration/misc.h | |
bf251437 | 32 | @@ -77,4 +77,7 @@ bool migration_in_bg_snapshot(void); |
d95ad93e TL |
33 | /* migration/block-dirty-bitmap.c */ |
34 | void dirty_bitmap_mig_init(void); | |
35 | ||
36 | +/* migration/pbs-state.c */ | |
37 | +void pbs_state_mig_init(void); | |
38 | + | |
39 | #endif | |
817b7667 | 40 | diff --git a/migration/meson.build b/migration/meson.build |
10e10933 | 41 | index 07f6057acc..343994d891 100644 |
817b7667 SR |
42 | --- a/migration/meson.build |
43 | +++ b/migration/meson.build | |
10e10933 | 44 | @@ -7,7 +7,9 @@ migration_files = files( |
5b15e2ec | 45 | 'vmstate.c', |
817b7667 | 46 | 'qemu-file.c', |
8dca018b | 47 | 'yank_functions.c', |
817b7667 SR |
48 | + 'pbs-state.c', |
49 | ) | |
10e10933 | 50 | +system_ss.add(libproxmox_backup_qemu) |
d95ad93e | 51 | |
10e10933 | 52 | system_ss.add(files( |
817b7667 | 53 | 'block-dirty-bitmap.c', |
8dca018b | 54 | diff --git a/migration/migration.c b/migration/migration.c |
10e10933 | 55 | index 7a4c8beb5d..0a955a2a18 100644 |
8dca018b SR |
56 | --- a/migration/migration.c |
57 | +++ b/migration/migration.c | |
10e10933 | 58 | @@ -162,6 +162,7 @@ void migration_object_init(void) |
8dca018b SR |
59 | blk_mig_init(); |
60 | ram_mig_init(); | |
61 | dirty_bitmap_mig_init(); | |
62 | + pbs_state_mig_init(); | |
63 | } | |
64 | ||
4567474e | 65 | void migration_cancel(const Error *error) |
d95ad93e TL |
66 | diff --git a/migration/pbs-state.c b/migration/pbs-state.c |
67 | new file mode 100644 | |
bf251437 | 68 | index 0000000000..887e998b9e |
d95ad93e TL |
69 | --- /dev/null |
70 | +++ b/migration/pbs-state.c | |
bf251437 | 71 | @@ -0,0 +1,104 @@ |
d95ad93e TL |
72 | +/* |
73 | + * PBS (dirty-bitmap) state migration | |
74 | + */ | |
75 | + | |
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" | |
82 | + | |
66eae0ae TL |
83 | +typedef struct PBSState { |
84 | + bool active; | |
85 | +} PBSState; | |
86 | + | |
cfe02b3b | 87 | +/* state is accessed via this static variable directly, 'opaque' is NULL */ |
66eae0ae TL |
88 | +static PBSState pbs_state; |
89 | + | |
bf251437 FE |
90 | +static void pbs_state_pending(void *opaque, uint64_t *must_precopy, |
91 | + uint64_t *can_postcopy) | |
d95ad93e TL |
92 | +{ |
93 | + /* we send everything in save_setup, so nothing is ever pending */ | |
d95ad93e TL |
94 | +} |
95 | + | |
96 | +/* receive PBS state via f and deserialize, called on target */ | |
97 | +static int pbs_state_load(QEMUFile *f, void *opaque, int version_id) | |
98 | +{ | |
99 | + /* safe cast, we cannot migrate to target with less bits than source */ | |
100 | + size_t buf_size = (size_t)qemu_get_be64(f); | |
101 | + | |
102 | + uint8_t *buf = (uint8_t *)malloc(buf_size); | |
103 | + size_t read = qemu_get_buffer(f, buf, buf_size); | |
104 | + | |
105 | + if (read < buf_size) { | |
106 | + fprintf(stderr, "error receiving PBS state: not enough data\n"); | |
107 | + return -EIO; | |
108 | + } | |
109 | + | |
110 | + proxmox_import_state(buf, buf_size); | |
111 | + | |
112 | + free(buf); | |
113 | + return 0; | |
114 | +} | |
115 | + | |
116 | +/* serialize PBS state and send to target via f, called on source */ | |
117 | +static int pbs_state_save_setup(QEMUFile *f, void *opaque) | |
118 | +{ | |
119 | + size_t buf_size; | |
120 | + uint8_t *buf = proxmox_export_state(&buf_size); | |
121 | + | |
122 | + /* LV encoding */ | |
123 | + qemu_put_be64(f, buf_size); | |
124 | + qemu_put_buffer(f, buf, buf_size); | |
125 | + | |
126 | + proxmox_free_state_buf(buf); | |
66eae0ae | 127 | + pbs_state.active = false; |
d95ad93e TL |
128 | + return 0; |
129 | +} | |
130 | + | |
131 | +static bool pbs_state_is_active(void *opaque) | |
132 | +{ | |
cfe02b3b SR |
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 */ | |
66eae0ae | 136 | + return pbs_state.active; |
d95ad93e TL |
137 | +} |
138 | + | |
139 | +static bool pbs_state_is_active_iterate(void *opaque) | |
140 | +{ | |
141 | + /* we don't iterate, everything is sent in save_setup */ | |
66eae0ae | 142 | + return pbs_state_is_active(opaque); |
d95ad93e TL |
143 | +} |
144 | + | |
145 | +static bool pbs_state_has_postcopy(void *opaque) | |
146 | +{ | |
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 */ | |
149 | + return false; | |
150 | +} | |
151 | + | |
cfe02b3b SR |
152 | +static void pbs_state_save_cleanup(void *opaque) |
153 | +{ | |
154 | + /* reset active after migration succeeds or fails */ | |
155 | + pbs_state.active = false; | |
156 | +} | |
157 | + | |
d95ad93e TL |
158 | +static SaveVMHandlers savevm_pbs_state_handlers = { |
159 | + .save_setup = pbs_state_save_setup, | |
160 | + .has_postcopy = pbs_state_has_postcopy, | |
bf251437 FE |
161 | + .state_pending_exact = pbs_state_pending, |
162 | + .state_pending_estimate = pbs_state_pending, | |
d95ad93e TL |
163 | + .is_active_iterate = pbs_state_is_active_iterate, |
164 | + .load_state = pbs_state_load, | |
165 | + .is_active = pbs_state_is_active, | |
cfe02b3b | 166 | + .save_cleanup = pbs_state_save_cleanup, |
d95ad93e TL |
167 | +}; |
168 | + | |
169 | +void pbs_state_mig_init(void) | |
170 | +{ | |
66eae0ae | 171 | + pbs_state.active = true; |
d95ad93e TL |
172 | + register_savevm_live("pbs-state", 0, 1, |
173 | + &savevm_pbs_state_handlers, | |
cfe02b3b | 174 | + NULL); |
d95ad93e TL |
175 | +} |
176 | diff --git a/pve-backup.c b/pve-backup.c | |
8dd76cc5 | 177 | index ae3d137e12..e6b17b797e 100644 |
d95ad93e TL |
178 | --- a/pve-backup.c |
179 | +++ b/pve-backup.c | |
8dd76cc5 | 180 | @@ -1082,6 +1082,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp) |
32ee4115 | 181 | ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version()); |
d95ad93e | 182 | ret->pbs_dirty_bitmap = true; |
e9b36665 | 183 | ret->pbs_dirty_bitmap_savevm = true; |
d95ad93e | 184 | + ret->pbs_dirty_bitmap_migration = true; |
e9b36665 | 185 | ret->query_bitmap_info = true; |
db5d2a4b FE |
186 | ret->pbs_masterkey = true; |
187 | ret->backup_max_workers = true; | |
d95ad93e | 188 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
4b7975e7 | 189 | index d67a6d448a..09de550c95 100644 |
d95ad93e TL |
190 | --- a/qapi/block-core.json |
191 | +++ b/qapi/block-core.json | |
10e10933 | 192 | @@ -991,6 +991,11 @@ |
e9b36665 SR |
193 | # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can |
194 | # safely be set for savevm-async. | |
d95ad93e TL |
195 | # |
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! | |
200 | +# | |
db5d2a4b FE |
201 | # @pbs-masterkey: True if the QMP backup call supports the 'master_keyfile' |
202 | # parameter. | |
32ee4115 | 203 | # |
10e10933 | 204 | @@ -1001,6 +1006,7 @@ |
32ee4115 SR |
205 | 'data': { 'pbs-dirty-bitmap': 'bool', |
206 | 'query-bitmap-info': 'bool', | |
e9b36665 | 207 | 'pbs-dirty-bitmap-savevm': 'bool', |
32ee4115 | 208 | + 'pbs-dirty-bitmap-migration': 'bool', |
db5d2a4b FE |
209 | 'pbs-masterkey': 'bool', |
210 | 'pbs-library-version': 'str', | |
211 | 'backup-max-workers': 'bool' } } |