xref: /qemu/migration/multifd.h (revision 303e6f54)
1d32ca5adSJuan Quintela /*
2d32ca5adSJuan Quintela  * Multifd common functions
3d32ca5adSJuan Quintela  *
4d32ca5adSJuan Quintela  * Copyright (c) 2019-2020 Red Hat Inc
5d32ca5adSJuan Quintela  *
6d32ca5adSJuan Quintela  * Authors:
7d32ca5adSJuan Quintela  *  Juan Quintela <quintela@redhat.com>
8d32ca5adSJuan Quintela  *
9d32ca5adSJuan Quintela  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10d32ca5adSJuan Quintela  * See the COPYING file in the top-level directory.
11d32ca5adSJuan Quintela  */
12d32ca5adSJuan Quintela 
13d32ca5adSJuan Quintela #ifndef QEMU_MIGRATION_MULTIFD_H
14d32ca5adSJuan Quintela #define QEMU_MIGRATION_MULTIFD_H
15d32ca5adSJuan Quintela 
16a49d15a3SFabiano Rosas #include "ram.h"
17a49d15a3SFabiano Rosas 
18d117ed06SFabiano Rosas typedef struct MultiFDRecvData MultiFDRecvData;
19d117ed06SFabiano Rosas 
20bd8b0a8fSFabiano Rosas bool multifd_send_setup(void);
21cde85c37SPeter Xu void multifd_send_shutdown(void);
22a8a3e710SFabiano Rosas void multifd_send_channel_created(void);
23cde85c37SPeter Xu int multifd_recv_setup(Error **errp);
24cde85c37SPeter Xu void multifd_recv_cleanup(void);
25cde85c37SPeter Xu void multifd_recv_shutdown(void);
26d32ca5adSJuan Quintela bool multifd_recv_all_channels_created(void);
276720c2b3Smanish.mishra void multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
28d32ca5adSJuan Quintela void multifd_recv_sync_main(void);
299346fa18SFabiano Rosas int multifd_send_sync_main(void);
30d6556d17SPeter Xu bool multifd_queue_page(RAMBlock *block, ram_addr_t offset);
31d117ed06SFabiano Rosas bool multifd_recv(void);
32d117ed06SFabiano Rosas MultiFDRecvData *multifd_get_recv_data(void);
33d32ca5adSJuan Quintela 
347ec2c2b3SJuan Quintela /* Multifd Compression flags */
35d32ca5adSJuan Quintela #define MULTIFD_FLAG_SYNC (1 << 0)
36d32ca5adSJuan Quintela 
37ab7cbb0bSJuan Quintela /* We reserve 3 bits for compression methods */
38ab7cbb0bSJuan Quintela #define MULTIFD_FLAG_COMPRESSION_MASK (7 << 1)
39ab7cbb0bSJuan Quintela /* we need to be compatible. Before compression value was 0 */
40ab7cbb0bSJuan Quintela #define MULTIFD_FLAG_NOCOMP (0 << 1)
417ec2c2b3SJuan Quintela #define MULTIFD_FLAG_ZLIB (1 << 1)
4287dc6f5fSJuan Quintela #define MULTIFD_FLAG_ZSTD (2 << 1)
43ab7cbb0bSJuan Quintela 
44d32ca5adSJuan Quintela /* This value needs to be a multiple of qemu_target_page_size() */
45d32ca5adSJuan Quintela #define MULTIFD_PACKET_SIZE (512 * 1024)
46d32ca5adSJuan Quintela 
47d32ca5adSJuan Quintela typedef struct {
48d32ca5adSJuan Quintela     uint32_t magic;
49d32ca5adSJuan Quintela     uint32_t version;
50d32ca5adSJuan Quintela     uint32_t flags;
51d32ca5adSJuan Quintela     /* maximum number of allocated pages */
52d32ca5adSJuan Quintela     uint32_t pages_alloc;
538c0ec0b2SJuan Quintela     /* non zero pages */
548c0ec0b2SJuan Quintela     uint32_t normal_pages;
55d32ca5adSJuan Quintela     /* size of the next packet that contains pages */
56d32ca5adSJuan Quintela     uint32_t next_packet_size;
57d32ca5adSJuan Quintela     uint64_t packet_num;
58303e6f54SHao Xiang     /* zero pages */
59303e6f54SHao Xiang     uint32_t zero_pages;
60303e6f54SHao Xiang     uint32_t unused32[1];    /* Reserved for future use */
61303e6f54SHao Xiang     uint64_t unused64[3];    /* Reserved for future use */
62d32ca5adSJuan Quintela     char ramblock[256];
63303e6f54SHao Xiang     /*
64303e6f54SHao Xiang      * This array contains the pointers to:
65303e6f54SHao Xiang      *  - normal pages (initial normal_pages entries)
66303e6f54SHao Xiang      *  - zero pages (following zero_pages entries)
67303e6f54SHao Xiang      */
68d32ca5adSJuan Quintela     uint64_t offset[];
69d32ca5adSJuan Quintela } __attribute__((packed)) MultiFDPacket_t;
70d32ca5adSJuan Quintela 
71d32ca5adSJuan Quintela typedef struct {
72d32ca5adSJuan Quintela     /* number of used pages */
7390a3d2f9SJuan Quintela     uint32_t num;
74303e6f54SHao Xiang     /* number of normal pages */
75303e6f54SHao Xiang     uint32_t normal_num;
76d32ca5adSJuan Quintela     /* number of allocated pages */
77d32ca5adSJuan Quintela     uint32_t allocated;
78d32ca5adSJuan Quintela     /* offset of each page */
79d32ca5adSJuan Quintela     ram_addr_t *offset;
80d32ca5adSJuan Quintela     RAMBlock *block;
81d32ca5adSJuan Quintela } MultiFDPages_t;
82d32ca5adSJuan Quintela 
83d117ed06SFabiano Rosas struct MultiFDRecvData {
84d117ed06SFabiano Rosas     void *opaque;
85d117ed06SFabiano Rosas     size_t size;
86d117ed06SFabiano Rosas     /* for preadv */
87d117ed06SFabiano Rosas     off_t file_offset;
88d117ed06SFabiano Rosas };
89d117ed06SFabiano Rosas 
90d32ca5adSJuan Quintela typedef struct {
914a8f19c9SJuan Quintela     /* Fields are only written at creating/deletion time */
924a8f19c9SJuan Quintela     /* No lock required for them, they are read only */
934a8f19c9SJuan Quintela 
94d32ca5adSJuan Quintela     /* channel number */
95d32ca5adSJuan Quintela     uint8_t id;
96d32ca5adSJuan Quintela     /* channel thread name */
97d32ca5adSJuan Quintela     char *name;
98d32ca5adSJuan Quintela     /* channel thread id */
99d32ca5adSJuan Quintela     QemuThread thread;
100a2a63c4aSFabiano Rosas     bool thread_created;
101e1921f10SFabiano Rosas     QemuThread tls_thread;
102e1921f10SFabiano Rosas     bool tls_thread_created;
103d32ca5adSJuan Quintela     /* communication channel */
104d32ca5adSJuan Quintela     QIOChannel *c;
1054a8f19c9SJuan Quintela     /* packet allocated len */
1064a8f19c9SJuan Quintela     uint32_t packet_len;
107ddec20f8SJuan Quintela     /* guest page size */
108ddec20f8SJuan Quintela     uint32_t page_size;
109d6f45ebaSJuan Quintela     /* number of pages in a full packet */
110d6f45ebaSJuan Quintela     uint32_t page_count;
1114a8f19c9SJuan Quintela     /* multifd flags for sending ram */
1124a8f19c9SJuan Quintela     int write_flags;
1134a8f19c9SJuan Quintela 
114d32ca5adSJuan Quintela     /* sem where to wait for more work */
115d32ca5adSJuan Quintela     QemuSemaphore sem;
1164a8f19c9SJuan Quintela     /* syncs main thread and channels */
1174a8f19c9SJuan Quintela     QemuSemaphore sem_sync;
1184a8f19c9SJuan Quintela 
119d32ca5adSJuan Quintela     /* multifd flags for each packet */
120d32ca5adSJuan Quintela     uint32_t flags;
121f5f48a78SPeter Xu     /*
122f5f48a78SPeter Xu      * The sender thread has work to do if either of below boolean is set.
123f5f48a78SPeter Xu      *
124f5f48a78SPeter Xu      * @pending_job:  a job is pending
125f5f48a78SPeter Xu      * @pending_sync: a sync request is pending
126f5f48a78SPeter Xu      *
127f5f48a78SPeter Xu      * For both of these fields, they're only set by the requesters, and
128f5f48a78SPeter Xu      * cleared by the multifd sender threads.
129f5f48a78SPeter Xu      */
130f5f48a78SPeter Xu     bool pending_job;
131f5f48a78SPeter Xu     bool pending_sync;
1324a8f19c9SJuan Quintela     /* array of pages to sent.
1334a8f19c9SJuan Quintela      * The owner of 'pages' depends of 'pending_job' value:
1344a8f19c9SJuan Quintela      * pending_job == 0 -> migration_thread can use it.
1354a8f19c9SJuan Quintela      * pending_job != 0 -> multifd_channel can use it.
1364a8f19c9SJuan Quintela      */
1374a8f19c9SJuan Quintela     MultiFDPages_t *pages;
1384a8f19c9SJuan Quintela 
1394a8f19c9SJuan Quintela     /* thread local variables. No locking required */
1404a8f19c9SJuan Quintela 
1414a8f19c9SJuan Quintela     /* pointer to the packet */
1424a8f19c9SJuan Quintela     MultiFDPacket_t *packet;
1434a8f19c9SJuan Quintela     /* size of the next packet that contains pages */
1444a8f19c9SJuan Quintela     uint32_t next_packet_size;
145d32ca5adSJuan Quintela     /* packets sent through this channel */
14605b7ec18SPeter Xu     uint64_t packets_sent;
147815956f0SJuan Quintela     /* non zero pages sent through this channel */
148815956f0SJuan Quintela     uint64_t total_normal_pages;
149303e6f54SHao Xiang     /* zero pages sent through this channel */
150303e6f54SHao Xiang     uint64_t total_zero_pages;
151226468baSJuan Quintela     /* buffers to send */
152226468baSJuan Quintela     struct iovec *iov;
153226468baSJuan Quintela     /* number of iovs used */
154226468baSJuan Quintela     uint32_t iovs_num;
155ab7cbb0bSJuan Quintela     /* used for compression methods */
156402dd7acSFabiano Rosas     void *compress_data;
157d32ca5adSJuan Quintela }  MultiFDSendParams;
158d32ca5adSJuan Quintela 
159d32ca5adSJuan Quintela typedef struct {
1604a8f19c9SJuan Quintela     /* Fields are only written at creating/deletion time */
1614a8f19c9SJuan Quintela     /* No lock required for them, they are read only */
1624a8f19c9SJuan Quintela 
163d32ca5adSJuan Quintela     /* channel number */
164d32ca5adSJuan Quintela     uint8_t id;
165d32ca5adSJuan Quintela     /* channel thread name */
166d32ca5adSJuan Quintela     char *name;
167d32ca5adSJuan Quintela     /* channel thread id */
168d32ca5adSJuan Quintela     QemuThread thread;
169a2a63c4aSFabiano Rosas     bool thread_created;
170d32ca5adSJuan Quintela     /* communication channel */
171d32ca5adSJuan Quintela     QIOChannel *c;
1724a8f19c9SJuan Quintela     /* packet allocated len */
1734a8f19c9SJuan Quintela     uint32_t packet_len;
174ddec20f8SJuan Quintela     /* guest page size */
175ddec20f8SJuan Quintela     uint32_t page_size;
176d6f45ebaSJuan Quintela     /* number of pages in a full packet */
177d6f45ebaSJuan Quintela     uint32_t page_count;
1784a8f19c9SJuan Quintela 
1794a8f19c9SJuan Quintela     /* syncs main thread and channels */
1804a8f19c9SJuan Quintela     QemuSemaphore sem_sync;
181d117ed06SFabiano Rosas     /* sem where to wait for more work */
182d117ed06SFabiano Rosas     QemuSemaphore sem;
1834a8f19c9SJuan Quintela 
184d32ca5adSJuan Quintela     /* this mutex protects the following parameters */
185d32ca5adSJuan Quintela     QemuMutex mutex;
186d32ca5adSJuan Quintela     /* should this thread finish */
187d32ca5adSJuan Quintela     bool quit;
188d32ca5adSJuan Quintela     /* multifd flags for each packet */
189d32ca5adSJuan Quintela     uint32_t flags;
190d32ca5adSJuan Quintela     /* global number of generated multifd packets */
191d32ca5adSJuan Quintela     uint64_t packet_num;
192d117ed06SFabiano Rosas     int pending_job;
193d117ed06SFabiano Rosas     MultiFDRecvData *data;
1944a8f19c9SJuan Quintela 
1954a8f19c9SJuan Quintela     /* thread local variables. No locking required */
1964a8f19c9SJuan Quintela 
1974a8f19c9SJuan Quintela     /* pointer to the packet */
1984a8f19c9SJuan Quintela     MultiFDPacket_t *packet;
199d32ca5adSJuan Quintela     /* size of the next packet that contains pages */
200d32ca5adSJuan Quintela     uint32_t next_packet_size;
20105b7ec18SPeter Xu     /* packets received through this channel */
20205b7ec18SPeter Xu     uint64_t packets_recved;
2035d1d1fcfSLukas Straub     /* ramblock */
2045d1d1fcfSLukas Straub     RAMBlock *block;
2054a8f19c9SJuan Quintela     /* ramblock host address */
2064a8f19c9SJuan Quintela     uint8_t *host;
207cf2d4aa8SJuan Quintela     /* non zero pages recv through this channel */
208cf2d4aa8SJuan Quintela     uint64_t total_normal_pages;
209303e6f54SHao Xiang     /* zero pages recv through this channel */
210303e6f54SHao Xiang     uint64_t total_zero_pages;
211226468baSJuan Quintela     /* buffers to recv */
212226468baSJuan Quintela     struct iovec *iov;
213cf2d4aa8SJuan Quintela     /* Pages that are not zero */
214cf2d4aa8SJuan Quintela     ram_addr_t *normal;
215cf2d4aa8SJuan Quintela     /* num of non zero pages */
216cf2d4aa8SJuan Quintela     uint32_t normal_num;
217303e6f54SHao Xiang     /* Pages that are zero */
218303e6f54SHao Xiang     ram_addr_t *zero;
219303e6f54SHao Xiang     /* num of zero pages */
220303e6f54SHao Xiang     uint32_t zero_num;
221ab7cbb0bSJuan Quintela     /* used for de-compression methods */
222402dd7acSFabiano Rosas     void *compress_data;
223d32ca5adSJuan Quintela } MultiFDRecvParams;
224d32ca5adSJuan Quintela 
225ab7cbb0bSJuan Quintela typedef struct {
226ab7cbb0bSJuan Quintela     /* Setup for sending side */
227ab7cbb0bSJuan Quintela     int (*send_setup)(MultiFDSendParams *p, Error **errp);
228ab7cbb0bSJuan Quintela     /* Cleanup for sending side */
229ab7cbb0bSJuan Quintela     void (*send_cleanup)(MultiFDSendParams *p, Error **errp);
230ab7cbb0bSJuan Quintela     /* Prepare the send packet */
23102fb8104SJuan Quintela     int (*send_prepare)(MultiFDSendParams *p, Error **errp);
232ab7cbb0bSJuan Quintela     /* Setup for receiving side */
233ab7cbb0bSJuan Quintela     int (*recv_setup)(MultiFDRecvParams *p, Error **errp);
234ab7cbb0bSJuan Quintela     /* Cleanup for receiving side */
235ab7cbb0bSJuan Quintela     void (*recv_cleanup)(MultiFDRecvParams *p);
2369db19125SFabiano Rosas     /* Read all data */
2379db19125SFabiano Rosas     int (*recv)(MultiFDRecvParams *p, Error **errp);
238ab7cbb0bSJuan Quintela } MultiFDMethods;
239ab7cbb0bSJuan Quintela 
2407ec2c2b3SJuan Quintela void multifd_register_ops(int method, MultiFDMethods *ops);
24125a1f878SPeter Xu void multifd_send_fill_packet(MultiFDSendParams *p);
242303e6f54SHao Xiang bool multifd_send_prepare_common(MultiFDSendParams *p);
243303e6f54SHao Xiang void multifd_send_zero_page_detect(MultiFDSendParams *p);
244303e6f54SHao Xiang void multifd_recv_zero_page_process(MultiFDRecvParams *p);
2457ec2c2b3SJuan Quintela 
multifd_send_prepare_header(MultiFDSendParams * p)246452b2057SPeter Xu static inline void multifd_send_prepare_header(MultiFDSendParams *p)
247452b2057SPeter Xu {
248452b2057SPeter Xu     p->iov[0].iov_len = p->packet_len;
249452b2057SPeter Xu     p->iov[0].iov_base = p->packet;
250452b2057SPeter Xu     p->iovs_num++;
251452b2057SPeter Xu }
252452b2057SPeter Xu 
253b7b03eb6SFabiano Rosas void multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc);
254452b2057SPeter Xu 
255d32ca5adSJuan Quintela #endif
256