xref: /openbmc/qemu/migration/multifd-nocomp.c (revision 40c9471e)
1*40c9471eSFabiano Rosas /*
2*40c9471eSFabiano Rosas  * Multifd RAM migration without compression
3*40c9471eSFabiano Rosas  *
4*40c9471eSFabiano Rosas  * Copyright (c) 2019-2020 Red Hat Inc
5*40c9471eSFabiano Rosas  *
6*40c9471eSFabiano Rosas  * Authors:
7*40c9471eSFabiano Rosas  *  Juan Quintela <quintela@redhat.com>
8*40c9471eSFabiano Rosas  *
9*40c9471eSFabiano Rosas  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10*40c9471eSFabiano Rosas  * See the COPYING file in the top-level directory.
11*40c9471eSFabiano Rosas  */
12*40c9471eSFabiano Rosas 
13*40c9471eSFabiano Rosas #include "qemu/osdep.h"
14*40c9471eSFabiano Rosas #include "exec/ramblock.h"
15*40c9471eSFabiano Rosas #include "exec/target_page.h"
16*40c9471eSFabiano Rosas #include "file.h"
17*40c9471eSFabiano Rosas #include "multifd.h"
18*40c9471eSFabiano Rosas #include "options.h"
19*40c9471eSFabiano Rosas #include "qapi/error.h"
20*40c9471eSFabiano Rosas #include "qemu/error-report.h"
21*40c9471eSFabiano Rosas #include "trace.h"
22*40c9471eSFabiano Rosas 
23*40c9471eSFabiano Rosas static MultiFDSendData *multifd_ram_send;
24*40c9471eSFabiano Rosas 
25*40c9471eSFabiano Rosas size_t multifd_ram_payload_size(void)
26*40c9471eSFabiano Rosas {
27*40c9471eSFabiano Rosas     uint32_t n = multifd_ram_page_count();
28*40c9471eSFabiano Rosas 
29*40c9471eSFabiano Rosas     /*
30*40c9471eSFabiano Rosas      * We keep an array of page offsets at the end of MultiFDPages_t,
31*40c9471eSFabiano Rosas      * add space for it in the allocation.
32*40c9471eSFabiano Rosas      */
33*40c9471eSFabiano Rosas     return sizeof(MultiFDPages_t) + n * sizeof(ram_addr_t);
34*40c9471eSFabiano Rosas }
35*40c9471eSFabiano Rosas 
36*40c9471eSFabiano Rosas void multifd_ram_save_setup(void)
37*40c9471eSFabiano Rosas {
38*40c9471eSFabiano Rosas     multifd_ram_send = multifd_send_data_alloc();
39*40c9471eSFabiano Rosas }
40*40c9471eSFabiano Rosas 
41*40c9471eSFabiano Rosas void multifd_ram_save_cleanup(void)
42*40c9471eSFabiano Rosas {
43*40c9471eSFabiano Rosas     g_free(multifd_ram_send);
44*40c9471eSFabiano Rosas     multifd_ram_send = NULL;
45*40c9471eSFabiano Rosas }
46*40c9471eSFabiano Rosas 
47*40c9471eSFabiano Rosas static void multifd_set_file_bitmap(MultiFDSendParams *p)
48*40c9471eSFabiano Rosas {
49*40c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
50*40c9471eSFabiano Rosas 
51*40c9471eSFabiano Rosas     assert(pages->block);
52*40c9471eSFabiano Rosas 
53*40c9471eSFabiano Rosas     for (int i = 0; i < pages->normal_num; i++) {
54*40c9471eSFabiano Rosas         ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], true);
55*40c9471eSFabiano Rosas     }
56*40c9471eSFabiano Rosas 
57*40c9471eSFabiano Rosas     for (int i = pages->normal_num; i < pages->num; i++) {
58*40c9471eSFabiano Rosas         ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], false);
59*40c9471eSFabiano Rosas     }
60*40c9471eSFabiano Rosas }
61*40c9471eSFabiano Rosas 
62*40c9471eSFabiano Rosas static int multifd_nocomp_send_setup(MultiFDSendParams *p, Error **errp)
63*40c9471eSFabiano Rosas {
64*40c9471eSFabiano Rosas     uint32_t page_count = multifd_ram_page_count();
65*40c9471eSFabiano Rosas 
66*40c9471eSFabiano Rosas     if (migrate_zero_copy_send()) {
67*40c9471eSFabiano Rosas         p->write_flags |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
68*40c9471eSFabiano Rosas     }
69*40c9471eSFabiano Rosas 
70*40c9471eSFabiano Rosas     if (!migrate_mapped_ram()) {
71*40c9471eSFabiano Rosas         /* We need one extra place for the packet header */
72*40c9471eSFabiano Rosas         p->iov = g_new0(struct iovec, page_count + 1);
73*40c9471eSFabiano Rosas     } else {
74*40c9471eSFabiano Rosas         p->iov = g_new0(struct iovec, page_count);
75*40c9471eSFabiano Rosas     }
76*40c9471eSFabiano Rosas 
77*40c9471eSFabiano Rosas     return 0;
78*40c9471eSFabiano Rosas }
79*40c9471eSFabiano Rosas 
80*40c9471eSFabiano Rosas static void multifd_nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
81*40c9471eSFabiano Rosas {
82*40c9471eSFabiano Rosas     g_free(p->iov);
83*40c9471eSFabiano Rosas     p->iov = NULL;
84*40c9471eSFabiano Rosas     return;
85*40c9471eSFabiano Rosas }
86*40c9471eSFabiano Rosas 
87*40c9471eSFabiano Rosas static void multifd_send_prepare_iovs(MultiFDSendParams *p)
88*40c9471eSFabiano Rosas {
89*40c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
90*40c9471eSFabiano Rosas     uint32_t page_size = multifd_ram_page_size();
91*40c9471eSFabiano Rosas 
92*40c9471eSFabiano Rosas     for (int i = 0; i < pages->normal_num; i++) {
93*40c9471eSFabiano Rosas         p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
94*40c9471eSFabiano Rosas         p->iov[p->iovs_num].iov_len = page_size;
95*40c9471eSFabiano Rosas         p->iovs_num++;
96*40c9471eSFabiano Rosas     }
97*40c9471eSFabiano Rosas 
98*40c9471eSFabiano Rosas     p->next_packet_size = pages->normal_num * page_size;
99*40c9471eSFabiano Rosas }
100*40c9471eSFabiano Rosas 
101*40c9471eSFabiano Rosas static int multifd_nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
102*40c9471eSFabiano Rosas {
103*40c9471eSFabiano Rosas     bool use_zero_copy_send = migrate_zero_copy_send();
104*40c9471eSFabiano Rosas     int ret;
105*40c9471eSFabiano Rosas 
106*40c9471eSFabiano Rosas     multifd_send_zero_page_detect(p);
107*40c9471eSFabiano Rosas 
108*40c9471eSFabiano Rosas     if (migrate_mapped_ram()) {
109*40c9471eSFabiano Rosas         multifd_send_prepare_iovs(p);
110*40c9471eSFabiano Rosas         multifd_set_file_bitmap(p);
111*40c9471eSFabiano Rosas 
112*40c9471eSFabiano Rosas         return 0;
113*40c9471eSFabiano Rosas     }
114*40c9471eSFabiano Rosas 
115*40c9471eSFabiano Rosas     if (!use_zero_copy_send) {
116*40c9471eSFabiano Rosas         /*
117*40c9471eSFabiano Rosas          * Only !zerocopy needs the header in IOV; zerocopy will
118*40c9471eSFabiano Rosas          * send it separately.
119*40c9471eSFabiano Rosas          */
120*40c9471eSFabiano Rosas         multifd_send_prepare_header(p);
121*40c9471eSFabiano Rosas     }
122*40c9471eSFabiano Rosas 
123*40c9471eSFabiano Rosas     multifd_send_prepare_iovs(p);
124*40c9471eSFabiano Rosas     p->flags |= MULTIFD_FLAG_NOCOMP;
125*40c9471eSFabiano Rosas 
126*40c9471eSFabiano Rosas     multifd_send_fill_packet(p);
127*40c9471eSFabiano Rosas 
128*40c9471eSFabiano Rosas     if (use_zero_copy_send) {
129*40c9471eSFabiano Rosas         /* Send header first, without zerocopy */
130*40c9471eSFabiano Rosas         ret = qio_channel_write_all(p->c, (void *)p->packet,
131*40c9471eSFabiano Rosas                                     p->packet_len, errp);
132*40c9471eSFabiano Rosas         if (ret != 0) {
133*40c9471eSFabiano Rosas             return -1;
134*40c9471eSFabiano Rosas         }
135*40c9471eSFabiano Rosas     }
136*40c9471eSFabiano Rosas 
137*40c9471eSFabiano Rosas     return 0;
138*40c9471eSFabiano Rosas }
139*40c9471eSFabiano Rosas 
140*40c9471eSFabiano Rosas static int multifd_nocomp_recv_setup(MultiFDRecvParams *p, Error **errp)
141*40c9471eSFabiano Rosas {
142*40c9471eSFabiano Rosas     p->iov = g_new0(struct iovec, multifd_ram_page_count());
143*40c9471eSFabiano Rosas     return 0;
144*40c9471eSFabiano Rosas }
145*40c9471eSFabiano Rosas 
146*40c9471eSFabiano Rosas static void multifd_nocomp_recv_cleanup(MultiFDRecvParams *p)
147*40c9471eSFabiano Rosas {
148*40c9471eSFabiano Rosas     g_free(p->iov);
149*40c9471eSFabiano Rosas     p->iov = NULL;
150*40c9471eSFabiano Rosas }
151*40c9471eSFabiano Rosas 
152*40c9471eSFabiano Rosas static int multifd_nocomp_recv(MultiFDRecvParams *p, Error **errp)
153*40c9471eSFabiano Rosas {
154*40c9471eSFabiano Rosas     uint32_t flags;
155*40c9471eSFabiano Rosas 
156*40c9471eSFabiano Rosas     if (migrate_mapped_ram()) {
157*40c9471eSFabiano Rosas         return multifd_file_recv_data(p, errp);
158*40c9471eSFabiano Rosas     }
159*40c9471eSFabiano Rosas 
160*40c9471eSFabiano Rosas     flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
161*40c9471eSFabiano Rosas 
162*40c9471eSFabiano Rosas     if (flags != MULTIFD_FLAG_NOCOMP) {
163*40c9471eSFabiano Rosas         error_setg(errp, "multifd %u: flags received %x flags expected %x",
164*40c9471eSFabiano Rosas                    p->id, flags, MULTIFD_FLAG_NOCOMP);
165*40c9471eSFabiano Rosas         return -1;
166*40c9471eSFabiano Rosas     }
167*40c9471eSFabiano Rosas 
168*40c9471eSFabiano Rosas     multifd_recv_zero_page_process(p);
169*40c9471eSFabiano Rosas 
170*40c9471eSFabiano Rosas     if (!p->normal_num) {
171*40c9471eSFabiano Rosas         return 0;
172*40c9471eSFabiano Rosas     }
173*40c9471eSFabiano Rosas 
174*40c9471eSFabiano Rosas     for (int i = 0; i < p->normal_num; i++) {
175*40c9471eSFabiano Rosas         p->iov[i].iov_base = p->host + p->normal[i];
176*40c9471eSFabiano Rosas         p->iov[i].iov_len = multifd_ram_page_size();
177*40c9471eSFabiano Rosas         ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
178*40c9471eSFabiano Rosas     }
179*40c9471eSFabiano Rosas     return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
180*40c9471eSFabiano Rosas }
181*40c9471eSFabiano Rosas 
182*40c9471eSFabiano Rosas static void multifd_pages_reset(MultiFDPages_t *pages)
183*40c9471eSFabiano Rosas {
184*40c9471eSFabiano Rosas     /*
185*40c9471eSFabiano Rosas      * We don't need to touch offset[] array, because it will be
186*40c9471eSFabiano Rosas      * overwritten later when reused.
187*40c9471eSFabiano Rosas      */
188*40c9471eSFabiano Rosas     pages->num = 0;
189*40c9471eSFabiano Rosas     pages->normal_num = 0;
190*40c9471eSFabiano Rosas     pages->block = NULL;
191*40c9471eSFabiano Rosas }
192*40c9471eSFabiano Rosas 
193*40c9471eSFabiano Rosas void multifd_ram_fill_packet(MultiFDSendParams *p)
194*40c9471eSFabiano Rosas {
195*40c9471eSFabiano Rosas     MultiFDPacket_t *packet = p->packet;
196*40c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
197*40c9471eSFabiano Rosas     uint32_t zero_num = pages->num - pages->normal_num;
198*40c9471eSFabiano Rosas 
199*40c9471eSFabiano Rosas     packet->pages_alloc = cpu_to_be32(multifd_ram_page_count());
200*40c9471eSFabiano Rosas     packet->normal_pages = cpu_to_be32(pages->normal_num);
201*40c9471eSFabiano Rosas     packet->zero_pages = cpu_to_be32(zero_num);
202*40c9471eSFabiano Rosas 
203*40c9471eSFabiano Rosas     if (pages->block) {
204*40c9471eSFabiano Rosas         strncpy(packet->ramblock, pages->block->idstr, 256);
205*40c9471eSFabiano Rosas     }
206*40c9471eSFabiano Rosas 
207*40c9471eSFabiano Rosas     for (int i = 0; i < pages->num; i++) {
208*40c9471eSFabiano Rosas         /* there are architectures where ram_addr_t is 32 bit */
209*40c9471eSFabiano Rosas         uint64_t temp = pages->offset[i];
210*40c9471eSFabiano Rosas 
211*40c9471eSFabiano Rosas         packet->offset[i] = cpu_to_be64(temp);
212*40c9471eSFabiano Rosas     }
213*40c9471eSFabiano Rosas 
214*40c9471eSFabiano Rosas     trace_multifd_send_ram_fill(p->id, pages->normal_num,
215*40c9471eSFabiano Rosas                                 zero_num);
216*40c9471eSFabiano Rosas }
217*40c9471eSFabiano Rosas 
218*40c9471eSFabiano Rosas int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp)
219*40c9471eSFabiano Rosas {
220*40c9471eSFabiano Rosas     MultiFDPacket_t *packet = p->packet;
221*40c9471eSFabiano Rosas     uint32_t page_count = multifd_ram_page_count();
222*40c9471eSFabiano Rosas     uint32_t page_size = multifd_ram_page_size();
223*40c9471eSFabiano Rosas     int i;
224*40c9471eSFabiano Rosas 
225*40c9471eSFabiano Rosas     packet->pages_alloc = be32_to_cpu(packet->pages_alloc);
226*40c9471eSFabiano Rosas     /*
227*40c9471eSFabiano Rosas      * If we received a packet that is 100 times bigger than expected
228*40c9471eSFabiano Rosas      * just stop migration.  It is a magic number.
229*40c9471eSFabiano Rosas      */
230*40c9471eSFabiano Rosas     if (packet->pages_alloc > page_count) {
231*40c9471eSFabiano Rosas         error_setg(errp, "multifd: received packet "
232*40c9471eSFabiano Rosas                    "with size %u and expected a size of %u",
233*40c9471eSFabiano Rosas                    packet->pages_alloc, page_count) ;
234*40c9471eSFabiano Rosas         return -1;
235*40c9471eSFabiano Rosas     }
236*40c9471eSFabiano Rosas 
237*40c9471eSFabiano Rosas     p->normal_num = be32_to_cpu(packet->normal_pages);
238*40c9471eSFabiano Rosas     if (p->normal_num > packet->pages_alloc) {
239*40c9471eSFabiano Rosas         error_setg(errp, "multifd: received packet "
240*40c9471eSFabiano Rosas                    "with %u normal pages and expected maximum pages are %u",
241*40c9471eSFabiano Rosas                    p->normal_num, packet->pages_alloc) ;
242*40c9471eSFabiano Rosas         return -1;
243*40c9471eSFabiano Rosas     }
244*40c9471eSFabiano Rosas 
245*40c9471eSFabiano Rosas     p->zero_num = be32_to_cpu(packet->zero_pages);
246*40c9471eSFabiano Rosas     if (p->zero_num > packet->pages_alloc - p->normal_num) {
247*40c9471eSFabiano Rosas         error_setg(errp, "multifd: received packet "
248*40c9471eSFabiano Rosas                    "with %u zero pages and expected maximum zero pages are %u",
249*40c9471eSFabiano Rosas                    p->zero_num, packet->pages_alloc - p->normal_num) ;
250*40c9471eSFabiano Rosas         return -1;
251*40c9471eSFabiano Rosas     }
252*40c9471eSFabiano Rosas 
253*40c9471eSFabiano Rosas     if (p->normal_num == 0 && p->zero_num == 0) {
254*40c9471eSFabiano Rosas         return 0;
255*40c9471eSFabiano Rosas     }
256*40c9471eSFabiano Rosas 
257*40c9471eSFabiano Rosas     /* make sure that ramblock is 0 terminated */
258*40c9471eSFabiano Rosas     packet->ramblock[255] = 0;
259*40c9471eSFabiano Rosas     p->block = qemu_ram_block_by_name(packet->ramblock);
260*40c9471eSFabiano Rosas     if (!p->block) {
261*40c9471eSFabiano Rosas         error_setg(errp, "multifd: unknown ram block %s",
262*40c9471eSFabiano Rosas                    packet->ramblock);
263*40c9471eSFabiano Rosas         return -1;
264*40c9471eSFabiano Rosas     }
265*40c9471eSFabiano Rosas 
266*40c9471eSFabiano Rosas     p->host = p->block->host;
267*40c9471eSFabiano Rosas     for (i = 0; i < p->normal_num; i++) {
268*40c9471eSFabiano Rosas         uint64_t offset = be64_to_cpu(packet->offset[i]);
269*40c9471eSFabiano Rosas 
270*40c9471eSFabiano Rosas         if (offset > (p->block->used_length - page_size)) {
271*40c9471eSFabiano Rosas             error_setg(errp, "multifd: offset too long %" PRIu64
272*40c9471eSFabiano Rosas                        " (max " RAM_ADDR_FMT ")",
273*40c9471eSFabiano Rosas                        offset, p->block->used_length);
274*40c9471eSFabiano Rosas             return -1;
275*40c9471eSFabiano Rosas         }
276*40c9471eSFabiano Rosas         p->normal[i] = offset;
277*40c9471eSFabiano Rosas     }
278*40c9471eSFabiano Rosas 
279*40c9471eSFabiano Rosas     for (i = 0; i < p->zero_num; i++) {
280*40c9471eSFabiano Rosas         uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
281*40c9471eSFabiano Rosas 
282*40c9471eSFabiano Rosas         if (offset > (p->block->used_length - page_size)) {
283*40c9471eSFabiano Rosas             error_setg(errp, "multifd: offset too long %" PRIu64
284*40c9471eSFabiano Rosas                        " (max " RAM_ADDR_FMT ")",
285*40c9471eSFabiano Rosas                        offset, p->block->used_length);
286*40c9471eSFabiano Rosas             return -1;
287*40c9471eSFabiano Rosas         }
288*40c9471eSFabiano Rosas         p->zero[i] = offset;
289*40c9471eSFabiano Rosas     }
290*40c9471eSFabiano Rosas 
291*40c9471eSFabiano Rosas     return 0;
292*40c9471eSFabiano Rosas }
293*40c9471eSFabiano Rosas 
294*40c9471eSFabiano Rosas static inline bool multifd_queue_empty(MultiFDPages_t *pages)
295*40c9471eSFabiano Rosas {
296*40c9471eSFabiano Rosas     return pages->num == 0;
297*40c9471eSFabiano Rosas }
298*40c9471eSFabiano Rosas 
299*40c9471eSFabiano Rosas static inline bool multifd_queue_full(MultiFDPages_t *pages)
300*40c9471eSFabiano Rosas {
301*40c9471eSFabiano Rosas     return pages->num == multifd_ram_page_count();
302*40c9471eSFabiano Rosas }
303*40c9471eSFabiano Rosas 
304*40c9471eSFabiano Rosas static inline void multifd_enqueue(MultiFDPages_t *pages, ram_addr_t offset)
305*40c9471eSFabiano Rosas {
306*40c9471eSFabiano Rosas     pages->offset[pages->num++] = offset;
307*40c9471eSFabiano Rosas }
308*40c9471eSFabiano Rosas 
309*40c9471eSFabiano Rosas /* Returns true if enqueue successful, false otherwise */
310*40c9471eSFabiano Rosas bool multifd_queue_page(RAMBlock *block, ram_addr_t offset)
311*40c9471eSFabiano Rosas {
312*40c9471eSFabiano Rosas     MultiFDPages_t *pages;
313*40c9471eSFabiano Rosas 
314*40c9471eSFabiano Rosas retry:
315*40c9471eSFabiano Rosas     pages = &multifd_ram_send->u.ram;
316*40c9471eSFabiano Rosas 
317*40c9471eSFabiano Rosas     if (multifd_payload_empty(multifd_ram_send)) {
318*40c9471eSFabiano Rosas         multifd_pages_reset(pages);
319*40c9471eSFabiano Rosas         multifd_set_payload_type(multifd_ram_send, MULTIFD_PAYLOAD_RAM);
320*40c9471eSFabiano Rosas     }
321*40c9471eSFabiano Rosas 
322*40c9471eSFabiano Rosas     /* If the queue is empty, we can already enqueue now */
323*40c9471eSFabiano Rosas     if (multifd_queue_empty(pages)) {
324*40c9471eSFabiano Rosas         pages->block = block;
325*40c9471eSFabiano Rosas         multifd_enqueue(pages, offset);
326*40c9471eSFabiano Rosas         return true;
327*40c9471eSFabiano Rosas     }
328*40c9471eSFabiano Rosas 
329*40c9471eSFabiano Rosas     /*
330*40c9471eSFabiano Rosas      * Not empty, meanwhile we need a flush.  It can because of either:
331*40c9471eSFabiano Rosas      *
332*40c9471eSFabiano Rosas      * (1) The page is not on the same ramblock of previous ones, or,
333*40c9471eSFabiano Rosas      * (2) The queue is full.
334*40c9471eSFabiano Rosas      *
335*40c9471eSFabiano Rosas      * After flush, always retry.
336*40c9471eSFabiano Rosas      */
337*40c9471eSFabiano Rosas     if (pages->block != block || multifd_queue_full(pages)) {
338*40c9471eSFabiano Rosas         if (!multifd_send(&multifd_ram_send)) {
339*40c9471eSFabiano Rosas             return false;
340*40c9471eSFabiano Rosas         }
341*40c9471eSFabiano Rosas         goto retry;
342*40c9471eSFabiano Rosas     }
343*40c9471eSFabiano Rosas 
344*40c9471eSFabiano Rosas     /* Not empty, and we still have space, do it! */
345*40c9471eSFabiano Rosas     multifd_enqueue(pages, offset);
346*40c9471eSFabiano Rosas     return true;
347*40c9471eSFabiano Rosas }
348*40c9471eSFabiano Rosas 
349*40c9471eSFabiano Rosas int multifd_ram_flush_and_sync(void)
350*40c9471eSFabiano Rosas {
351*40c9471eSFabiano Rosas     if (!migrate_multifd()) {
352*40c9471eSFabiano Rosas         return 0;
353*40c9471eSFabiano Rosas     }
354*40c9471eSFabiano Rosas 
355*40c9471eSFabiano Rosas     if (!multifd_payload_empty(multifd_ram_send)) {
356*40c9471eSFabiano Rosas         if (!multifd_send(&multifd_ram_send)) {
357*40c9471eSFabiano Rosas             error_report("%s: multifd_send fail", __func__);
358*40c9471eSFabiano Rosas             return -1;
359*40c9471eSFabiano Rosas         }
360*40c9471eSFabiano Rosas     }
361*40c9471eSFabiano Rosas 
362*40c9471eSFabiano Rosas     return multifd_send_sync_main();
363*40c9471eSFabiano Rosas }
364*40c9471eSFabiano Rosas 
365*40c9471eSFabiano Rosas bool multifd_send_prepare_common(MultiFDSendParams *p)
366*40c9471eSFabiano Rosas {
367*40c9471eSFabiano Rosas     MultiFDPages_t *pages = &p->data->u.ram;
368*40c9471eSFabiano Rosas     multifd_send_zero_page_detect(p);
369*40c9471eSFabiano Rosas 
370*40c9471eSFabiano Rosas     if (!pages->normal_num) {
371*40c9471eSFabiano Rosas         p->next_packet_size = 0;
372*40c9471eSFabiano Rosas         return false;
373*40c9471eSFabiano Rosas     }
374*40c9471eSFabiano Rosas 
375*40c9471eSFabiano Rosas     multifd_send_prepare_header(p);
376*40c9471eSFabiano Rosas 
377*40c9471eSFabiano Rosas     return true;
378*40c9471eSFabiano Rosas }
379*40c9471eSFabiano Rosas 
380*40c9471eSFabiano Rosas static MultiFDMethods multifd_nocomp_ops = {
381*40c9471eSFabiano Rosas     .send_setup = multifd_nocomp_send_setup,
382*40c9471eSFabiano Rosas     .send_cleanup = multifd_nocomp_send_cleanup,
383*40c9471eSFabiano Rosas     .send_prepare = multifd_nocomp_send_prepare,
384*40c9471eSFabiano Rosas     .recv_setup = multifd_nocomp_recv_setup,
385*40c9471eSFabiano Rosas     .recv_cleanup = multifd_nocomp_recv_cleanup,
386*40c9471eSFabiano Rosas     .recv = multifd_nocomp_recv
387*40c9471eSFabiano Rosas };
388*40c9471eSFabiano Rosas 
389*40c9471eSFabiano Rosas static void multifd_nocomp_register(void)
390*40c9471eSFabiano Rosas {
391*40c9471eSFabiano Rosas     multifd_register_ops(MULTIFD_COMPRESSION_NONE, &multifd_nocomp_ops);
392*40c9471eSFabiano Rosas }
393*40c9471eSFabiano Rosas 
394*40c9471eSFabiano Rosas migration_init(multifd_nocomp_register);
395