]>
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> | |
15 | --- | |
16 | include/migration/misc.h | 3 ++ | |
17 | migration/Makefile.objs | 1 + | |
66eae0ae | 18 | migration/pbs-state.c | 97 ++++++++++++++++++++++++++++++++++++++++ |
d95ad93e | 19 | pve-backup.c | 1 + |
32ee4115 | 20 | qapi/block-core.json | 6 +++ |
d95ad93e | 21 | softmmu/vl.c | 1 + |
32ee4115 | 22 | 6 files changed, 109 insertions(+) |
d95ad93e TL |
23 | create mode 100644 migration/pbs-state.c |
24 | ||
25 | diff --git a/include/migration/misc.h b/include/migration/misc.h | |
26 | index 34e7d75713..f83816dd3c 100644 | |
27 | --- a/include/migration/misc.h | |
28 | +++ b/include/migration/misc.h | |
29 | @@ -75,4 +75,7 @@ bool migration_in_incoming_postcopy(void); | |
30 | /* migration/block-dirty-bitmap.c */ | |
31 | void dirty_bitmap_mig_init(void); | |
32 | ||
33 | +/* migration/pbs-state.c */ | |
34 | +void pbs_state_mig_init(void); | |
35 | + | |
36 | #endif | |
37 | diff --git a/migration/Makefile.objs b/migration/Makefile.objs | |
38 | index 0fc619e380..20b3792599 100644 | |
39 | --- a/migration/Makefile.objs | |
40 | +++ b/migration/Makefile.objs | |
41 | @@ -9,6 +9,7 @@ common-obj-y += qjson.o | |
42 | common-obj-y += block-dirty-bitmap.o | |
43 | common-obj-y += multifd.o | |
44 | common-obj-y += multifd-zlib.o | |
45 | +common-obj-y += pbs-state.o | |
46 | common-obj-$(CONFIG_ZSTD) += multifd-zstd.o | |
47 | ||
48 | common-obj-$(CONFIG_RDMA) += rdma.o | |
49 | diff --git a/migration/pbs-state.c b/migration/pbs-state.c | |
50 | new file mode 100644 | |
66eae0ae | 51 | index 0000000000..c711498c3e |
d95ad93e TL |
52 | --- /dev/null |
53 | +++ b/migration/pbs-state.c | |
66eae0ae | 54 | @@ -0,0 +1,97 @@ |
d95ad93e TL |
55 | +/* |
56 | + * PBS (dirty-bitmap) state migration | |
57 | + */ | |
58 | + | |
59 | +#include "qemu/osdep.h" | |
60 | +#include "migration/misc.h" | |
61 | +#include "qemu-file.h" | |
62 | +#include "migration/vmstate.h" | |
63 | +#include "migration/register.h" | |
64 | +#include "proxmox-backup-qemu.h" | |
65 | + | |
66eae0ae TL |
66 | +typedef struct PBSState { |
67 | + bool active; | |
68 | +} PBSState; | |
69 | + | |
70 | +static PBSState pbs_state; | |
71 | + | |
d95ad93e TL |
72 | +static void pbs_state_save_pending(QEMUFile *f, void *opaque, |
73 | + uint64_t max_size, | |
74 | + uint64_t *res_precopy_only, | |
75 | + uint64_t *res_compatible, | |
76 | + uint64_t *res_postcopy_only) | |
77 | +{ | |
78 | + /* we send everything in save_setup, so nothing is ever pending */ | |
d95ad93e TL |
79 | +} |
80 | + | |
81 | +/* receive PBS state via f and deserialize, called on target */ | |
82 | +static int pbs_state_load(QEMUFile *f, void *opaque, int version_id) | |
83 | +{ | |
84 | + /* safe cast, we cannot migrate to target with less bits than source */ | |
85 | + size_t buf_size = (size_t)qemu_get_be64(f); | |
86 | + | |
87 | + uint8_t *buf = (uint8_t *)malloc(buf_size); | |
88 | + size_t read = qemu_get_buffer(f, buf, buf_size); | |
89 | + | |
90 | + if (read < buf_size) { | |
91 | + fprintf(stderr, "error receiving PBS state: not enough data\n"); | |
92 | + return -EIO; | |
93 | + } | |
94 | + | |
95 | + proxmox_import_state(buf, buf_size); | |
96 | + | |
97 | + free(buf); | |
98 | + return 0; | |
99 | +} | |
100 | + | |
101 | +/* serialize PBS state and send to target via f, called on source */ | |
102 | +static int pbs_state_save_setup(QEMUFile *f, void *opaque) | |
103 | +{ | |
104 | + size_t buf_size; | |
105 | + uint8_t *buf = proxmox_export_state(&buf_size); | |
106 | + | |
107 | + /* LV encoding */ | |
108 | + qemu_put_be64(f, buf_size); | |
109 | + qemu_put_buffer(f, buf, buf_size); | |
110 | + | |
111 | + proxmox_free_state_buf(buf); | |
66eae0ae | 112 | + pbs_state.active = false; |
d95ad93e TL |
113 | + return 0; |
114 | +} | |
115 | + | |
116 | +static bool pbs_state_is_active(void *opaque) | |
117 | +{ | |
66eae0ae TL |
118 | + // we need to be return active once, else .save_setup is never called, but, |
119 | + // if we'd just would return true, we'd freeze the migration for ~ 5 - 10s | |
120 | + return pbs_state.active; | |
d95ad93e TL |
121 | +} |
122 | + | |
123 | +static bool pbs_state_is_active_iterate(void *opaque) | |
124 | +{ | |
125 | + /* we don't iterate, everything is sent in save_setup */ | |
66eae0ae | 126 | + return pbs_state_is_active(opaque); |
d95ad93e TL |
127 | +} |
128 | + | |
129 | +static bool pbs_state_has_postcopy(void *opaque) | |
130 | +{ | |
131 | + /* PBS state can't change during a migration (since that's blocking any | |
132 | + * potential backups), so we can copy everything before the VM is stopped */ | |
133 | + return false; | |
134 | +} | |
135 | + | |
136 | +static SaveVMHandlers savevm_pbs_state_handlers = { | |
137 | + .save_setup = pbs_state_save_setup, | |
138 | + .has_postcopy = pbs_state_has_postcopy, | |
139 | + .save_live_pending = pbs_state_save_pending, | |
140 | + .is_active_iterate = pbs_state_is_active_iterate, | |
141 | + .load_state = pbs_state_load, | |
142 | + .is_active = pbs_state_is_active, | |
143 | +}; | |
144 | + | |
145 | +void pbs_state_mig_init(void) | |
146 | +{ | |
66eae0ae | 147 | + pbs_state.active = true; |
d95ad93e TL |
148 | + register_savevm_live("pbs-state", 0, 1, |
149 | + &savevm_pbs_state_handlers, | |
66eae0ae | 150 | + &pbs_state); |
d95ad93e TL |
151 | +} |
152 | diff --git a/pve-backup.c b/pve-backup.c | |
32ee4115 | 153 | index c7cde0fb0e..f65f1dda26 100644 |
d95ad93e TL |
154 | --- a/pve-backup.c |
155 | +++ b/pve-backup.c | |
32ee4115 SR |
156 | @@ -1130,5 +1130,6 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp) |
157 | ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version()); | |
d95ad93e TL |
158 | ret->pbs_dirty_bitmap = true; |
159 | ret->query_bitmap_info = true; | |
160 | + ret->pbs_dirty_bitmap_migration = true; | |
161 | return ret; | |
162 | } | |
163 | diff --git a/qapi/block-core.json b/qapi/block-core.json | |
32ee4115 | 164 | index 29650896e2..0da4b35028 100644 |
d95ad93e TL |
165 | --- a/qapi/block-core.json |
166 | +++ b/qapi/block-core.json | |
32ee4115 | 167 | @@ -890,12 +890,18 @@ |
d95ad93e TL |
168 | # |
169 | # @query-bitmap-info: True if the 'query-pbs-bitmap-info' QMP call is supported. | |
170 | # | |
171 | +# @pbs-dirty-bitmap-migration: True if safe migration of dirty-bitmaps including | |
172 | +# PBS state is supported. Enabling 'dirty-bitmaps' | |
173 | +# migration cap if this is false/unset may lead | |
174 | +# to crashes on migration! | |
175 | +# | |
32ee4115 SR |
176 | # @pbs-library-version: Running version of libproxmox-backup-qemu0 library. |
177 | # | |
d95ad93e TL |
178 | ## |
179 | { 'struct': 'ProxmoxSupportStatus', | |
32ee4115 SR |
180 | 'data': { 'pbs-dirty-bitmap': 'bool', |
181 | 'query-bitmap-info': 'bool', | |
182 | + 'pbs-dirty-bitmap-migration': 'bool', | |
183 | 'pbs-library-version': 'str' } } | |
d95ad93e TL |
184 | |
185 | ## | |
d95ad93e TL |
186 | diff --git a/softmmu/vl.c b/softmmu/vl.c |
187 | index 16aa2186b0..88b13871fd 100644 | |
188 | --- a/softmmu/vl.c | |
189 | +++ b/softmmu/vl.c | |
190 | @@ -4288,6 +4288,7 @@ void qemu_init(int argc, char **argv, char **envp) | |
191 | blk_mig_init(); | |
192 | ram_mig_init(); | |
193 | dirty_bitmap_mig_init(); | |
194 | + pbs_state_mig_init(); | |
195 | ||
196 | qemu_opts_foreach(qemu_find_opts("mon"), | |
197 | mon_init_func, NULL, &error_fatal); |