xref: /openbmc/qemu/migration/multifd-nocomp.c (revision 68e0fca6)
140c9471eSFabiano Rosas /*
240c9471eSFabiano Rosas  * Multifd RAM migration without compression
340c9471eSFabiano Rosas  *
440c9471eSFabiano Rosas  * Copyright (c) 2019-2020 Red Hat Inc
540c9471eSFabiano Rosas  *
640c9471eSFabiano Rosas  * Authors:
740c9471eSFabiano Rosas  *  Juan Quintela <quintela@redhat.com>
840c9471eSFabiano Rosas  *
940c9471eSFabiano Rosas  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1040c9471eSFabiano Rosas  * See the COPYING file in the top-level directory.
1140c9471eSFabiano Rosas  */
1240c9471eSFabiano Rosas 
1340c9471eSFabiano Rosas #include "qemu/osdep.h"
1440c9471eSFabiano Rosas #include "exec/ramblock.h"
1540c9471eSFabiano Rosas #include "exec/target_page.h"
1640c9471eSFabiano Rosas #include "file.h"
1740c9471eSFabiano Rosas #include "multifd.h"
1840c9471eSFabiano Rosas #include "options.h"
1940c9471eSFabiano Rosas #include "qapi/error.h"
20*68e0fca6SFabiano Rosas #include "qemu/cutils.h"
2140c9471eSFabiano Rosas #include "qemu/error-report.h"
2240c9471eSFabiano Rosas #include "trace.h"
2340c9471eSFabiano Rosas 
2440c9471eSFabiano Rosas static MultiFDSendData *multifd_ram_send;
2540c9471eSFabiano Rosas 
multifd_ram_payload_size(void)2640c9471eSFabiano Rosas size_t multifd_ram_payload_size(void)
2740c9471eSFabiano Rosas {
2840c9471eSFabiano Rosas     uint32_t n = multifd_ram_page_count();
2940c9471eSFabiano Rosas 
3040c9471eSFabiano Rosas     /*
3140c9471eSFabiano Rosas      * We keep an array of page offsets at the end of MultiFDPages_t,
3240c9471eSFabiano Rosas      * add space for it in the allocation.
3340c9471eSFabiano Rosas      */
3440c9471eSFabiano Rosas     return sizeof(MultiFDPages_t) + n * sizeof(ram_addr_t);
3540c9471eSFabiano Rosas }
3640c9471eSFabiano Rosas 
multifd_ram_save_setup(void)3740c9471eSFabiano Rosas void multifd_ram_save_setup(void)
3840c9471eSFabiano Rosas {
3940c9471eSFabiano Rosas     multifd_ram_send = multifd_send_data_alloc();
4040c9471eSFabiano Rosas }
4140c9471eSFabiano Rosas 
multifd_ram_save_cleanup(void)4240c9471eSFabiano Rosas void multifd_ram_save_cleanup(void)
4340c9471eSFabiano Rosas {
4440c9471eSFabiano Rosas     g_free(multifd_ram_send);
4540c9471eSFabiano Rosas     multifd_ram_send = NULL;
4640c9471eSFabiano Rosas }
4740c9471eSFabiano Rosas 
multifd_set_file_bitmap(MultiFDSendParams * p)4840c9471eSFabiano Rosas static void multifd_set_file_bitmap(MultiFDSendParams *p)
4940c9471eSFabiano Rosas {
5040c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
5140c9471eSFabiano Rosas 
5240c9471eSFabiano Rosas     assert(pages->block);
5340c9471eSFabiano Rosas 
5440c9471eSFabiano Rosas     for (int i = 0; i < pages->normal_num; i++) {
5540c9471eSFabiano Rosas         ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], true);
5640c9471eSFabiano Rosas     }
5740c9471eSFabiano Rosas 
5840c9471eSFabiano Rosas     for (int i = pages->normal_num; i < pages->num; i++) {
5940c9471eSFabiano Rosas         ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], false);
6040c9471eSFabiano Rosas     }
6140c9471eSFabiano Rosas }
6240c9471eSFabiano Rosas 
multifd_nocomp_send_setup(MultiFDSendParams * p,Error ** errp)6340c9471eSFabiano Rosas static int multifd_nocomp_send_setup(MultiFDSendParams *p, Error **errp)
6440c9471eSFabiano Rosas {
6540c9471eSFabiano Rosas     uint32_t page_count = multifd_ram_page_count();
6640c9471eSFabiano Rosas 
6740c9471eSFabiano Rosas     if (migrate_zero_copy_send()) {
6840c9471eSFabiano Rosas         p->write_flags |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
6940c9471eSFabiano Rosas     }
7040c9471eSFabiano Rosas 
7140c9471eSFabiano Rosas     if (!migrate_mapped_ram()) {
7240c9471eSFabiano Rosas         /* We need one extra place for the packet header */
7340c9471eSFabiano Rosas         p->iov = g_new0(struct iovec, page_count + 1);
7440c9471eSFabiano Rosas     } else {
7540c9471eSFabiano Rosas         p->iov = g_new0(struct iovec, page_count);
7640c9471eSFabiano Rosas     }
7740c9471eSFabiano Rosas 
7840c9471eSFabiano Rosas     return 0;
7940c9471eSFabiano Rosas }
8040c9471eSFabiano Rosas 
multifd_nocomp_send_cleanup(MultiFDSendParams * p,Error ** errp)8140c9471eSFabiano Rosas static void multifd_nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
8240c9471eSFabiano Rosas {
8340c9471eSFabiano Rosas     g_free(p->iov);
8440c9471eSFabiano Rosas     p->iov = NULL;
8540c9471eSFabiano Rosas     return;
8640c9471eSFabiano Rosas }
8740c9471eSFabiano Rosas 
multifd_send_prepare_iovs(MultiFDSendParams * p)8840c9471eSFabiano Rosas static void multifd_send_prepare_iovs(MultiFDSendParams *p)
8940c9471eSFabiano Rosas {
9040c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
9140c9471eSFabiano Rosas     uint32_t page_size = multifd_ram_page_size();
9240c9471eSFabiano Rosas 
9340c9471eSFabiano Rosas     for (int i = 0; i < pages->normal_num; i++) {
9440c9471eSFabiano Rosas         p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
9540c9471eSFabiano Rosas         p->iov[p->iovs_num].iov_len = page_size;
9640c9471eSFabiano Rosas         p->iovs_num++;
9740c9471eSFabiano Rosas     }
9840c9471eSFabiano Rosas 
9940c9471eSFabiano Rosas     p->next_packet_size = pages->normal_num * page_size;
10040c9471eSFabiano Rosas }
10140c9471eSFabiano Rosas 
multifd_nocomp_send_prepare(MultiFDSendParams * p,Error ** errp)10240c9471eSFabiano Rosas static int multifd_nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
10340c9471eSFabiano Rosas {
10440c9471eSFabiano Rosas     bool use_zero_copy_send = migrate_zero_copy_send();
10540c9471eSFabiano Rosas     int ret;
10640c9471eSFabiano Rosas 
10740c9471eSFabiano Rosas     multifd_send_zero_page_detect(p);
10840c9471eSFabiano Rosas 
10940c9471eSFabiano Rosas     if (migrate_mapped_ram()) {
11040c9471eSFabiano Rosas         multifd_send_prepare_iovs(p);
11140c9471eSFabiano Rosas         multifd_set_file_bitmap(p);
11240c9471eSFabiano Rosas 
11340c9471eSFabiano Rosas         return 0;
11440c9471eSFabiano Rosas     }
11540c9471eSFabiano Rosas 
11640c9471eSFabiano Rosas     if (!use_zero_copy_send) {
11740c9471eSFabiano Rosas         /*
11840c9471eSFabiano Rosas          * Only !zerocopy needs the header in IOV; zerocopy will
11940c9471eSFabiano Rosas          * send it separately.
12040c9471eSFabiano Rosas          */
12140c9471eSFabiano Rosas         multifd_send_prepare_header(p);
12240c9471eSFabiano Rosas     }
12340c9471eSFabiano Rosas 
12440c9471eSFabiano Rosas     multifd_send_prepare_iovs(p);
12540c9471eSFabiano Rosas     p->flags |= MULTIFD_FLAG_NOCOMP;
12640c9471eSFabiano Rosas 
12740c9471eSFabiano Rosas     multifd_send_fill_packet(p);
12840c9471eSFabiano Rosas 
12940c9471eSFabiano Rosas     if (use_zero_copy_send) {
13040c9471eSFabiano Rosas         /* Send header first, without zerocopy */
13140c9471eSFabiano Rosas         ret = qio_channel_write_all(p->c, (void *)p->packet,
13240c9471eSFabiano Rosas                                     p->packet_len, errp);
13340c9471eSFabiano Rosas         if (ret != 0) {
13440c9471eSFabiano Rosas             return -1;
13540c9471eSFabiano Rosas         }
13640c9471eSFabiano Rosas     }
13740c9471eSFabiano Rosas 
13840c9471eSFabiano Rosas     return 0;
13940c9471eSFabiano Rosas }
14040c9471eSFabiano Rosas 
multifd_nocomp_recv_setup(MultiFDRecvParams * p,Error ** errp)14140c9471eSFabiano Rosas static int multifd_nocomp_recv_setup(MultiFDRecvParams *p, Error **errp)
14240c9471eSFabiano Rosas {
14340c9471eSFabiano Rosas     p->iov = g_new0(struct iovec, multifd_ram_page_count());
14440c9471eSFabiano Rosas     return 0;
14540c9471eSFabiano Rosas }
14640c9471eSFabiano Rosas 
multifd_nocomp_recv_cleanup(MultiFDRecvParams * p)14740c9471eSFabiano Rosas static void multifd_nocomp_recv_cleanup(MultiFDRecvParams *p)
14840c9471eSFabiano Rosas {
14940c9471eSFabiano Rosas     g_free(p->iov);
15040c9471eSFabiano Rosas     p->iov = NULL;
15140c9471eSFabiano Rosas }
15240c9471eSFabiano Rosas 
multifd_nocomp_recv(MultiFDRecvParams * p,Error ** errp)15340c9471eSFabiano Rosas static int multifd_nocomp_recv(MultiFDRecvParams *p, Error **errp)
15440c9471eSFabiano Rosas {
15540c9471eSFabiano Rosas     uint32_t flags;
15640c9471eSFabiano Rosas 
15740c9471eSFabiano Rosas     if (migrate_mapped_ram()) {
15840c9471eSFabiano Rosas         return multifd_file_recv_data(p, errp);
15940c9471eSFabiano Rosas     }
16040c9471eSFabiano Rosas 
16140c9471eSFabiano Rosas     flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
16240c9471eSFabiano Rosas 
16340c9471eSFabiano Rosas     if (flags != MULTIFD_FLAG_NOCOMP) {
16440c9471eSFabiano Rosas         error_setg(errp, "multifd %u: flags received %x flags expected %x",
16540c9471eSFabiano Rosas                    p->id, flags, MULTIFD_FLAG_NOCOMP);
16640c9471eSFabiano Rosas         return -1;
16740c9471eSFabiano Rosas     }
16840c9471eSFabiano Rosas 
16940c9471eSFabiano Rosas     multifd_recv_zero_page_process(p);
17040c9471eSFabiano Rosas 
17140c9471eSFabiano Rosas     if (!p->normal_num) {
17240c9471eSFabiano Rosas         return 0;
17340c9471eSFabiano Rosas     }
17440c9471eSFabiano Rosas 
17540c9471eSFabiano Rosas     for (int i = 0; i < p->normal_num; i++) {
17640c9471eSFabiano Rosas         p->iov[i].iov_base = p->host + p->normal[i];
17740c9471eSFabiano Rosas         p->iov[i].iov_len = multifd_ram_page_size();
17840c9471eSFabiano Rosas         ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
17940c9471eSFabiano Rosas     }
18040c9471eSFabiano Rosas     return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
18140c9471eSFabiano Rosas }
18240c9471eSFabiano Rosas 
multifd_pages_reset(MultiFDPages_t * pages)18340c9471eSFabiano Rosas static void multifd_pages_reset(MultiFDPages_t *pages)
18440c9471eSFabiano Rosas {
18540c9471eSFabiano Rosas     /*
18640c9471eSFabiano Rosas      * We don't need to touch offset[] array, because it will be
18740c9471eSFabiano Rosas      * overwritten later when reused.
18840c9471eSFabiano Rosas      */
18940c9471eSFabiano Rosas     pages->num = 0;
19040c9471eSFabiano Rosas     pages->normal_num = 0;
19140c9471eSFabiano Rosas     pages->block = NULL;
19240c9471eSFabiano Rosas }
19340c9471eSFabiano Rosas 
multifd_ram_fill_packet(MultiFDSendParams * p)19440c9471eSFabiano Rosas void multifd_ram_fill_packet(MultiFDSendParams *p)
19540c9471eSFabiano Rosas {
19640c9471eSFabiano Rosas     MultiFDPacket_t *packet = p->packet;
19740c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
19840c9471eSFabiano Rosas     uint32_t zero_num = pages->num - pages->normal_num;
19940c9471eSFabiano Rosas 
20040c9471eSFabiano Rosas     packet->pages_alloc = cpu_to_be32(multifd_ram_page_count());
20140c9471eSFabiano Rosas     packet->normal_pages = cpu_to_be32(pages->normal_num);
20240c9471eSFabiano Rosas     packet->zero_pages = cpu_to_be32(zero_num);
20340c9471eSFabiano Rosas 
20440c9471eSFabiano Rosas     if (pages->block) {
205*68e0fca6SFabiano Rosas         pstrcpy(packet->ramblock, sizeof(packet->ramblock),
206*68e0fca6SFabiano Rosas                 pages->block->idstr);
20740c9471eSFabiano Rosas     }
20840c9471eSFabiano Rosas 
20940c9471eSFabiano Rosas     for (int i = 0; i < pages->num; i++) {
21040c9471eSFabiano Rosas         /* there are architectures where ram_addr_t is 32 bit */
21140c9471eSFabiano Rosas         uint64_t temp = pages->offset[i];
21240c9471eSFabiano Rosas 
21340c9471eSFabiano Rosas         packet->offset[i] = cpu_to_be64(temp);
21440c9471eSFabiano Rosas     }
21540c9471eSFabiano Rosas 
21640c9471eSFabiano Rosas     trace_multifd_send_ram_fill(p->id, pages->normal_num,
21740c9471eSFabiano Rosas                                 zero_num);
21840c9471eSFabiano Rosas }
21940c9471eSFabiano Rosas 
multifd_ram_unfill_packet(MultiFDRecvParams * p,Error ** errp)22040c9471eSFabiano Rosas int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp)
22140c9471eSFabiano Rosas {
22240c9471eSFabiano Rosas     MultiFDPacket_t *packet = p->packet;
22340c9471eSFabiano Rosas     uint32_t page_count = multifd_ram_page_count();
22440c9471eSFabiano Rosas     uint32_t page_size = multifd_ram_page_size();
22581b0ed8aSFabiano Rosas     uint32_t pages_per_packet = be32_to_cpu(packet->pages_alloc);
22640c9471eSFabiano Rosas     int i;
22740c9471eSFabiano Rosas 
22881b0ed8aSFabiano Rosas     if (pages_per_packet > page_count) {
22981b0ed8aSFabiano Rosas         error_setg(errp, "multifd: received packet with %u pages, expected %u",
23081b0ed8aSFabiano Rosas                    pages_per_packet, page_count);
23140c9471eSFabiano Rosas         return -1;
23240c9471eSFabiano Rosas     }
23340c9471eSFabiano Rosas 
23440c9471eSFabiano Rosas     p->normal_num = be32_to_cpu(packet->normal_pages);
23581b0ed8aSFabiano Rosas     if (p->normal_num > pages_per_packet) {
23681b0ed8aSFabiano Rosas         error_setg(errp, "multifd: received packet with %u non-zero pages, "
23781b0ed8aSFabiano Rosas                    "which exceeds maximum expected pages %u",
23881b0ed8aSFabiano Rosas                    p->normal_num, pages_per_packet);
23940c9471eSFabiano Rosas         return -1;
24040c9471eSFabiano Rosas     }
24140c9471eSFabiano Rosas 
24240c9471eSFabiano Rosas     p->zero_num = be32_to_cpu(packet->zero_pages);
24381b0ed8aSFabiano Rosas     if (p->zero_num > pages_per_packet - p->normal_num) {
24481b0ed8aSFabiano Rosas         error_setg(errp,
24581b0ed8aSFabiano Rosas                    "multifd: received packet with %u zero pages, expected maximum %u",
24681b0ed8aSFabiano Rosas                    p->zero_num, pages_per_packet - p->normal_num);
24740c9471eSFabiano Rosas         return -1;
24840c9471eSFabiano Rosas     }
24940c9471eSFabiano Rosas 
25040c9471eSFabiano Rosas     if (p->normal_num == 0 && p->zero_num == 0) {
25140c9471eSFabiano Rosas         return 0;
25240c9471eSFabiano Rosas     }
25340c9471eSFabiano Rosas 
25440c9471eSFabiano Rosas     /* make sure that ramblock is 0 terminated */
25540c9471eSFabiano Rosas     packet->ramblock[255] = 0;
25640c9471eSFabiano Rosas     p->block = qemu_ram_block_by_name(packet->ramblock);
25740c9471eSFabiano Rosas     if (!p->block) {
25840c9471eSFabiano Rosas         error_setg(errp, "multifd: unknown ram block %s",
25940c9471eSFabiano Rosas                    packet->ramblock);
26040c9471eSFabiano Rosas         return -1;
26140c9471eSFabiano Rosas     }
26240c9471eSFabiano Rosas 
26340c9471eSFabiano Rosas     p->host = p->block->host;
26440c9471eSFabiano Rosas     for (i = 0; i < p->normal_num; i++) {
26540c9471eSFabiano Rosas         uint64_t offset = be64_to_cpu(packet->offset[i]);
26640c9471eSFabiano Rosas 
26740c9471eSFabiano Rosas         if (offset > (p->block->used_length - page_size)) {
26840c9471eSFabiano Rosas             error_setg(errp, "multifd: offset too long %" PRIu64
26940c9471eSFabiano Rosas                        " (max " RAM_ADDR_FMT ")",
27040c9471eSFabiano Rosas                        offset, p->block->used_length);
27140c9471eSFabiano Rosas             return -1;
27240c9471eSFabiano Rosas         }
27340c9471eSFabiano Rosas         p->normal[i] = offset;
27440c9471eSFabiano Rosas     }
27540c9471eSFabiano Rosas 
27640c9471eSFabiano Rosas     for (i = 0; i < p->zero_num; i++) {
27740c9471eSFabiano Rosas         uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
27840c9471eSFabiano Rosas 
27940c9471eSFabiano Rosas         if (offset > (p->block->used_length - page_size)) {
28040c9471eSFabiano Rosas             error_setg(errp, "multifd: offset too long %" PRIu64
28140c9471eSFabiano Rosas                        " (max " RAM_ADDR_FMT ")",
28240c9471eSFabiano Rosas                        offset, p->block->used_length);
28340c9471eSFabiano Rosas             return -1;
28440c9471eSFabiano Rosas         }
28540c9471eSFabiano Rosas         p->zero[i] = offset;
28640c9471eSFabiano Rosas     }
28740c9471eSFabiano Rosas 
28840c9471eSFabiano Rosas     return 0;
28940c9471eSFabiano Rosas }
29040c9471eSFabiano Rosas 
multifd_queue_empty(MultiFDPages_t * pages)29140c9471eSFabiano Rosas static inline bool multifd_queue_empty(MultiFDPages_t *pages)
29240c9471eSFabiano Rosas {
29340c9471eSFabiano Rosas     return pages->num == 0;
29440c9471eSFabiano Rosas }
29540c9471eSFabiano Rosas 
multifd_queue_full(MultiFDPages_t * pages)29640c9471eSFabiano Rosas static inline bool multifd_queue_full(MultiFDPages_t *pages)
29740c9471eSFabiano Rosas {
29840c9471eSFabiano Rosas     return pages->num == multifd_ram_page_count();
29940c9471eSFabiano Rosas }
30040c9471eSFabiano Rosas 
multifd_enqueue(MultiFDPages_t * pages,ram_addr_t offset)30140c9471eSFabiano Rosas static inline void multifd_enqueue(MultiFDPages_t *pages, ram_addr_t offset)
30240c9471eSFabiano Rosas {
30340c9471eSFabiano Rosas     pages->offset[pages->num++] = offset;
30440c9471eSFabiano Rosas }
30540c9471eSFabiano Rosas 
30640c9471eSFabiano Rosas /* Returns true if enqueue successful, false otherwise */
multifd_queue_page(RAMBlock * block,ram_addr_t offset)30740c9471eSFabiano Rosas bool multifd_queue_page(RAMBlock *block, ram_addr_t offset)
30840c9471eSFabiano Rosas {
30940c9471eSFabiano Rosas     MultiFDPages_t *pages;
31040c9471eSFabiano Rosas 
31140c9471eSFabiano Rosas retry:
31240c9471eSFabiano Rosas     pages = &multifd_ram_send->u.ram;
31340c9471eSFabiano Rosas 
31440c9471eSFabiano Rosas     if (multifd_payload_empty(multifd_ram_send)) {
31540c9471eSFabiano Rosas         multifd_pages_reset(pages);
31640c9471eSFabiano Rosas         multifd_set_payload_type(multifd_ram_send, MULTIFD_PAYLOAD_RAM);
31740c9471eSFabiano Rosas     }
31840c9471eSFabiano Rosas 
31940c9471eSFabiano Rosas     /* If the queue is empty, we can already enqueue now */
32040c9471eSFabiano Rosas     if (multifd_queue_empty(pages)) {
32140c9471eSFabiano Rosas         pages->block = block;
32240c9471eSFabiano Rosas         multifd_enqueue(pages, offset);
32340c9471eSFabiano Rosas         return true;
32440c9471eSFabiano Rosas     }
32540c9471eSFabiano Rosas 
32640c9471eSFabiano Rosas     /*
32740c9471eSFabiano Rosas      * Not empty, meanwhile we need a flush.  It can because of either:
32840c9471eSFabiano Rosas      *
32940c9471eSFabiano Rosas      * (1) The page is not on the same ramblock of previous ones, or,
33040c9471eSFabiano Rosas      * (2) The queue is full.
33140c9471eSFabiano Rosas      *
33240c9471eSFabiano Rosas      * After flush, always retry.
33340c9471eSFabiano Rosas      */
33440c9471eSFabiano Rosas     if (pages->block != block || multifd_queue_full(pages)) {
33540c9471eSFabiano Rosas         if (!multifd_send(&multifd_ram_send)) {
33640c9471eSFabiano Rosas             return false;
33740c9471eSFabiano Rosas         }
33840c9471eSFabiano Rosas         goto retry;
33940c9471eSFabiano Rosas     }
34040c9471eSFabiano Rosas 
34140c9471eSFabiano Rosas     /* Not empty, and we still have space, do it! */
34240c9471eSFabiano Rosas     multifd_enqueue(pages, offset);
34340c9471eSFabiano Rosas     return true;
34440c9471eSFabiano Rosas }
34540c9471eSFabiano Rosas 
multifd_ram_flush_and_sync(void)34640c9471eSFabiano Rosas int multifd_ram_flush_and_sync(void)
34740c9471eSFabiano Rosas {
34840c9471eSFabiano Rosas     if (!migrate_multifd()) {
34940c9471eSFabiano Rosas         return 0;
35040c9471eSFabiano Rosas     }
35140c9471eSFabiano Rosas 
35240c9471eSFabiano Rosas     if (!multifd_payload_empty(multifd_ram_send)) {
35340c9471eSFabiano Rosas         if (!multifd_send(&multifd_ram_send)) {
35440c9471eSFabiano Rosas             error_report("%s: multifd_send fail", __func__);
35540c9471eSFabiano Rosas             return -1;
35640c9471eSFabiano Rosas         }
35740c9471eSFabiano Rosas     }
35840c9471eSFabiano Rosas 
35940c9471eSFabiano Rosas     return multifd_send_sync_main();
36040c9471eSFabiano Rosas }
36140c9471eSFabiano Rosas 
multifd_send_prepare_common(MultiFDSendParams * p)36240c9471eSFabiano Rosas bool multifd_send_prepare_common(MultiFDSendParams *p)
36340c9471eSFabiano Rosas {
36440c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
36540c9471eSFabiano Rosas     multifd_send_zero_page_detect(p);
36640c9471eSFabiano Rosas 
36740c9471eSFabiano Rosas     if (!pages->normal_num) {
36840c9471eSFabiano Rosas         p->next_packet_size = 0;
36940c9471eSFabiano Rosas         return false;
37040c9471eSFabiano Rosas     }
37140c9471eSFabiano Rosas 
37240c9471eSFabiano Rosas     multifd_send_prepare_header(p);
37340c9471eSFabiano Rosas 
37440c9471eSFabiano Rosas     return true;
37540c9471eSFabiano Rosas }
37640c9471eSFabiano Rosas 
377308d165cSFabiano Rosas static const MultiFDMethods multifd_nocomp_ops = {
37840c9471eSFabiano Rosas     .send_setup = multifd_nocomp_send_setup,
37940c9471eSFabiano Rosas     .send_cleanup = multifd_nocomp_send_cleanup,
38040c9471eSFabiano Rosas     .send_prepare = multifd_nocomp_send_prepare,
38140c9471eSFabiano Rosas     .recv_setup = multifd_nocomp_recv_setup,
38240c9471eSFabiano Rosas     .recv_cleanup = multifd_nocomp_recv_cleanup,
38340c9471eSFabiano Rosas     .recv = multifd_nocomp_recv
38440c9471eSFabiano Rosas };
38540c9471eSFabiano Rosas 
multifd_nocomp_register(void)38640c9471eSFabiano Rosas static void multifd_nocomp_register(void)
38740c9471eSFabiano Rosas {
38840c9471eSFabiano Rosas     multifd_register_ops(MULTIFD_COMPRESSION_NONE, &multifd_nocomp_ops);
38940c9471eSFabiano Rosas }
39040c9471eSFabiano Rosas 
39140c9471eSFabiano Rosas migration_init(multifd_nocomp_register);
392