master
c 476 lines 12.2 KB
Raw
1 /*
2 * Multifd RAM migration without compression
3 *
4 * Copyright (c) 2019-2020 Red Hat Inc
5 *
6 * Authors:
7 * Juan Quintela <quintela@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13 #include "qemu/osdep.h"
14 #include "system/ramblock.h"
15 #include "exec/target_page.h"
16 #include "file.h"
17 #include "migration-stats.h"
18 #include "multifd.h"
19 #include "multifd-colo.h"
20 #include "options.h"
21 #include "migration.h"
22 #include "qapi/error.h"
23 #include "qemu/cutils.h"
24 #include "qemu/error-report.h"
25 #include "trace.h"
26 #include "qemu-file.h"
27
28 static MultiFDSendData *multifd_ram_send;
29
30 void multifd_ram_payload_alloc(MultiFDPages_t *pages)
31 {
32 pages->offset = g_new0(ram_addr_t, multifd_ram_page_count());
33 }
34
35 void multifd_ram_payload_free(MultiFDPages_t *pages)
36 {
37 g_clear_pointer(&pages->offset, g_free);
38 }
39
40 void multifd_ram_save_setup(void)
41 {
42 multifd_ram_send = multifd_send_data_alloc();
43 }
44
45 void multifd_ram_save_cleanup(void)
46 {
47 g_clear_pointer(&multifd_ram_send, multifd_send_data_free);
48 }
49
50 static void multifd_set_file_bitmap(MultiFDSendParams *p)
51 {
52 MultiFDPages_t *pages = &p->data->u.ram;
53
54 assert(pages->block);
55
56 for (int i = 0; i < pages->normal_num; i++) {
57 ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], true);
58 }
59
60 for (int i = pages->normal_num; i < pages->num; i++) {
61 ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], false);
62 }
63 }
64
65 static int multifd_nocomp_send_setup(MultiFDSendParams *p, Error **errp)
66 {
67 uint32_t page_count = multifd_ram_page_count();
68
69 if (migrate_zero_copy_send()) {
70 p->write_flags |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
71 }
72
73 if (!migrate_mapped_ram()) {
74 /* We need one extra place for the packet header */
75 p->iov = g_new0(struct iovec, page_count + 1);
76 } else {
77 p->iov = g_new0(struct iovec, page_count);
78 }
79
80 return 0;
81 }
82
83 static void multifd_nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
84 {
85 g_free(p->iov);
86 p->iov = NULL;
87 }
88
89 static void multifd_ram_prepare_header(MultiFDSendParams *p)
90 {
91 p->iov[0].iov_len = p->packet_len;
92 p->iov[0].iov_base = p->packet;
93 p->iovs_num++;
94 }
95
96 static void multifd_send_prepare_iovs(MultiFDSendParams *p)
97 {
98 MultiFDPages_t *pages = &p->data->u.ram;
99 uint32_t page_size = multifd_ram_page_size();
100
101 for (int i = 0; i < pages->normal_num; i++) {
102 p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
103 p->iov[p->iovs_num].iov_len = page_size;
104 p->iovs_num++;
105 }
106
107 p->next_packet_size = pages->normal_num * page_size;
108 }
109
110 static int multifd_nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
111 {
112 bool use_zero_copy_send = migrate_zero_copy_send();
113 int ret;
114
115 multifd_send_zero_page_detect(p);
116
117 if (migrate_mapped_ram()) {
118 multifd_send_prepare_iovs(p);
119 multifd_set_file_bitmap(p);
120
121 return 0;
122 }
123
124 if (!use_zero_copy_send) {
125 /*
126 * Only !zerocopy needs the header in IOV; zerocopy will
127 * send it separately.
128 */
129 multifd_ram_prepare_header(p);
130 }
131
132 multifd_send_prepare_iovs(p);
133 p->flags |= MULTIFD_FLAG_NOCOMP;
134
135 multifd_send_fill_packet(p);
136
137 if (use_zero_copy_send) {
138 /* Send header first, without zerocopy */
139 ret = qio_channel_write_all(p->c, (void *)p->packet,
140 p->packet_len, errp);
141 if (ret != 0) {
142 return -1;
143 }
144
145 qatomic_add(&mig_stats.multifd_bytes, p->packet_len);
146 }
147
148 return 0;
149 }
150
151 static int multifd_nocomp_recv_setup(MultiFDRecvParams *p, Error **errp)
152 {
153 p->iov = g_new0(struct iovec, multifd_ram_page_count());
154 return 0;
155 }
156
157 static void multifd_nocomp_recv_cleanup(MultiFDRecvParams *p)
158 {
159 g_free(p->iov);
160 p->iov = NULL;
161 }
162
163 static int multifd_nocomp_recv(MultiFDRecvParams *p, Error **errp)
164 {
165 uint32_t flags;
166
167 if (migrate_mapped_ram()) {
168 return multifd_file_recv_data(p, errp);
169 }
170
171 flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
172
173 if (flags != MULTIFD_FLAG_NOCOMP) {
174 error_setg(errp, "multifd %u: flags received %x flags expected %x",
175 p->id, flags, MULTIFD_FLAG_NOCOMP);
176 return -1;
177 }
178
179 multifd_recv_zero_page_process(p);
180
181 if (!p->normal_num) {
182 return 0;
183 }
184
185 for (int i = 0; i < p->normal_num; i++) {
186 p->iov[i].iov_base = p->host + p->normal[i];
187 p->iov[i].iov_len = multifd_ram_page_size();
188 ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
189 }
190 return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
191 }
192
193 static void multifd_pages_reset(MultiFDPages_t *pages)
194 {
195 /*
196 * We don't need to touch offset[] array, because it will be
197 * overwritten later when reused.
198 */
199 pages->num = 0;
200 pages->normal_num = 0;
201 pages->block = NULL;
202 }
203
204 void multifd_ram_fill_packet(MultiFDSendParams *p)
205 {
206 MultiFDPacket_t *packet = p->packet;
207 MultiFDPages_t *pages = &p->data->u.ram;
208 uint32_t zero_num = pages->num - pages->normal_num;
209
210 packet->pages_alloc = cpu_to_be32(multifd_ram_page_count());
211 packet->normal_pages = cpu_to_be32(pages->normal_num);
212 packet->zero_pages = cpu_to_be32(zero_num);
213
214 if (pages->block) {
215 pstrcpy(packet->ramblock, sizeof(packet->ramblock),
216 pages->block->idstr);
217 }
218
219 for (int i = 0; i < pages->num; i++) {
220 /* there are architectures where ram_addr_t is 32 bit */
221 uint64_t temp = pages->offset[i];
222
223 packet->offset[i] = cpu_to_be64(temp);
224 }
225
226 trace_multifd_send_ram_fill(p->id, pages->normal_num,
227 zero_num);
228 }
229
230 int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp)
231 {
232 MultiFDPacket_t *packet = p->packet;
233 uint32_t page_count = multifd_ram_page_count();
234 uint32_t page_size = multifd_ram_page_size();
235 uint32_t pages_per_packet = be32_to_cpu(packet->pages_alloc);
236 int i;
237
238 if (pages_per_packet > page_count) {
239 error_setg(errp, "multifd: received packet with %u pages, expected %u",
240 pages_per_packet, page_count);
241 return -1;
242 }
243
244 p->normal_num = be32_to_cpu(packet->normal_pages);
245 if (p->normal_num > pages_per_packet) {
246 error_setg(errp, "multifd: received packet with %u non-zero pages, "
247 "which exceeds maximum expected pages %u",
248 p->normal_num, pages_per_packet);
249 return -1;
250 }
251
252 p->zero_num = be32_to_cpu(packet->zero_pages);
253 if (p->zero_num > pages_per_packet - p->normal_num) {
254 error_setg(errp,
255 "multifd: received packet with %u zero pages, expected maximum %u",
256 p->zero_num, pages_per_packet - p->normal_num);
257 return -1;
258 }
259
260 if (p->normal_num == 0 && p->zero_num == 0) {
261 return 0;
262 }
263
264 /* make sure that ramblock is 0 terminated */
265 packet->ramblock[255] = 0;
266 p->block = qemu_ram_block_by_name(packet->ramblock);
267 if (!p->block) {
268 error_setg(errp, "multifd: unknown ram block %s",
269 packet->ramblock);
270 return -1;
271 }
272
273 for (i = 0; i < p->normal_num; i++) {
274 uint64_t offset = be64_to_cpu(packet->offset[i]);
275
276 if (offset > (p->block->used_length - page_size)) {
277 error_setg(errp, "multifd: offset too long %" PRIu64
278 " (max " RAM_ADDR_FMT ")",
279 offset, p->block->used_length);
280 return -1;
281 }
282 p->normal[i] = offset;
283 }
284
285 for (i = 0; i < p->zero_num; i++) {
286 uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
287
288 if (offset > (p->block->used_length - page_size)) {
289 error_setg(errp, "multifd: offset too long %" PRIu64
290 " (max " RAM_ADDR_FMT ")",
291 offset, p->block->used_length);
292 return -1;
293 }
294 p->zero[i] = offset;
295 }
296
297 if (migrate_colo()) {
298 multifd_colo_prepare_recv(p);
299 assert(p->block->colo_cache);
300 p->host = p->block->colo_cache;
301 } else {
302 p->host = p->block->host;
303 }
304
305 return 0;
306 }
307
308 static inline bool multifd_queue_empty(MultiFDPages_t *pages)
309 {
310 return pages->num == 0;
311 }
312
313 static inline bool multifd_queue_full(MultiFDPages_t *pages)
314 {
315 return pages->num == multifd_ram_page_count();
316 }
317
318 static inline void multifd_enqueue(MultiFDPages_t *pages, ram_addr_t offset)
319 {
320 pages->offset[pages->num++] = offset;
321 }
322
323 /* Returns true if enqueue successful, false otherwise */
324 bool multifd_queue_page(RAMBlock *block, ram_addr_t offset)
325 {
326 MultiFDPages_t *pages;
327
328 retry:
329 pages = &multifd_ram_send->u.ram;
330
331 if (multifd_payload_empty(multifd_ram_send)) {
332 multifd_pages_reset(pages);
333 multifd_set_payload_type(multifd_ram_send, MULTIFD_PAYLOAD_RAM);
334 }
335
336 /* If the queue is empty, we can already enqueue now */
337 if (multifd_queue_empty(pages)) {
338 pages->block = block;
339 multifd_enqueue(pages, offset);
340 return true;
341 }
342
343 /*
344 * Not empty, meanwhile we need a flush. It can because of either:
345 *
346 * (1) The page is not on the same ramblock of previous ones, or,
347 * (2) The queue is full.
348 *
349 * After flush, always retry.
350 */
351 if (pages->block != block || multifd_queue_full(pages)) {
352 if (!multifd_send(&multifd_ram_send)) {
353 return false;
354 }
355 goto retry;
356 }
357
358 /* Not empty, and we still have space, do it! */
359 multifd_enqueue(pages, offset);
360 return true;
361 }
362
363 /*
364 * We have two modes for multifd flushes:
365 *
366 * - Per-section mode: this is the legacy way to flush, it requires one
367 * MULTIFD_FLAG_SYNC message for each RAM_SAVE_FLAG_EOS.
368 *
369 * - Per-round mode: this is the modern way to flush, it requires one
370 * MULTIFD_FLAG_SYNC message only for each round of RAM scan. Normally
371 * it's paired with a new RAM_SAVE_FLAG_MULTIFD_FLUSH message in network
372 * based migrations.
373 *
374 * One thing to mention is mapped-ram always use the modern way to sync.
375 */
376
377 /* Do we need a per-section multifd flush (legacy way)? */
378 bool multifd_ram_sync_per_section(void)
379 {
380 if (!migrate_multifd()) {
381 return false;
382 }
383
384 if (migrate_mapped_ram()) {
385 return false;
386 }
387
388 return migrate_multifd_flush_after_each_section();
389 }
390
391 /* Do we need a per-round multifd flush (modern way)? */
392 bool multifd_ram_sync_per_round(void)
393 {
394 if (!migrate_multifd()) {
395 return false;
396 }
397
398 if (migrate_mapped_ram()) {
399 return true;
400 }
401
402 return !migrate_multifd_flush_after_each_section();
403 }
404
405 int multifd_ram_flush_and_sync(QEMUFile *f)
406 {
407 MultiFDSyncReq req;
408 int ret;
409
410 if (!migrate_multifd() || migration_in_postcopy()) {
411 return 0;
412 }
413
414 if (!multifd_payload_empty(multifd_ram_send)) {
415 if (!multifd_send(&multifd_ram_send)) {
416 error_report("%s: multifd_send fail", __func__);
417 return -1;
418 }
419 }
420
421 /* File migrations only need to sync with threads */
422 req = migrate_mapped_ram() ? MULTIFD_SYNC_LOCAL : MULTIFD_SYNC_ALL;
423
424 ret = multifd_send_sync_main(req);
425 if (ret) {
426 return ret;
427 }
428
429 /* If we don't need to sync with remote at all, nothing else to do */
430 if (req == MULTIFD_SYNC_LOCAL) {
431 return 0;
432 }
433
434 /*
435 * Old QEMUs don't understand RAM_SAVE_FLAG_MULTIFD_FLUSH, it relies
436 * on RAM_SAVE_FLAG_EOS instead.
437 */
438 if (migrate_multifd_flush_after_each_section()) {
439 return 0;
440 }
441
442 qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH);
443 qemu_fflush(f);
444
445 return 0;
446 }
447
448 bool multifd_send_prepare_common(MultiFDSendParams *p)
449 {
450 MultiFDPages_t *pages = &p->data->u.ram;
451 multifd_ram_prepare_header(p);
452 multifd_send_zero_page_detect(p);
453
454 if (!pages->normal_num) {
455 p->next_packet_size = 0;
456 return false;
457 }
458
459 return true;
460 }
461
462 static const MultiFDMethods multifd_nocomp_ops = {
463 .send_setup = multifd_nocomp_send_setup,
464 .send_cleanup = multifd_nocomp_send_cleanup,
465 .send_prepare = multifd_nocomp_send_prepare,
466 .recv_setup = multifd_nocomp_recv_setup,
467 .recv_cleanup = multifd_nocomp_recv_cleanup,
468 .recv = multifd_nocomp_recv
469 };
470
471 static void multifd_nocomp_register(void)
472 {
473 multifd_register_ops(MULTIFD_COMPRESSION_NONE, &multifd_nocomp_ops);
474 }
475
476 migration_init(multifd_nocomp_register);