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 16cde85c37SPeter Xu int multifd_send_setup(Error **errp); 17cde85c37SPeter Xu void multifd_send_shutdown(void); 18cde85c37SPeter Xu int multifd_recv_setup(Error **errp); 19cde85c37SPeter Xu void multifd_recv_cleanup(void); 20cde85c37SPeter Xu void multifd_recv_shutdown(void); 21d32ca5adSJuan Quintela bool multifd_recv_all_channels_created(void); 226720c2b3Smanish.mishra void multifd_recv_new_channel(QIOChannel *ioc, Error **errp); 23d32ca5adSJuan Quintela void multifd_recv_sync_main(void); 249346fa18SFabiano Rosas int multifd_send_sync_main(void); 25d6556d17SPeter Xu bool multifd_queue_page(RAMBlock *block, ram_addr_t offset); 26d32ca5adSJuan Quintela 277ec2c2b3SJuan Quintela /* Multifd Compression flags */ 28d32ca5adSJuan Quintela #define MULTIFD_FLAG_SYNC (1 << 0) 29d32ca5adSJuan Quintela 30ab7cbb0bSJuan Quintela /* We reserve 3 bits for compression methods */ 31ab7cbb0bSJuan Quintela #define MULTIFD_FLAG_COMPRESSION_MASK (7 << 1) 32ab7cbb0bSJuan Quintela /* we need to be compatible. Before compression value was 0 */ 33ab7cbb0bSJuan Quintela #define MULTIFD_FLAG_NOCOMP (0 << 1) 347ec2c2b3SJuan Quintela #define MULTIFD_FLAG_ZLIB (1 << 1) 3587dc6f5fSJuan Quintela #define MULTIFD_FLAG_ZSTD (2 << 1) 36ab7cbb0bSJuan Quintela 37d32ca5adSJuan Quintela /* This value needs to be a multiple of qemu_target_page_size() */ 38d32ca5adSJuan Quintela #define MULTIFD_PACKET_SIZE (512 * 1024) 39d32ca5adSJuan Quintela 40d32ca5adSJuan Quintela typedef struct { 41d32ca5adSJuan Quintela uint32_t magic; 42d32ca5adSJuan Quintela uint32_t version; 43d32ca5adSJuan Quintela uint32_t flags; 44d32ca5adSJuan Quintela /* maximum number of allocated pages */ 45d32ca5adSJuan Quintela uint32_t pages_alloc; 468c0ec0b2SJuan Quintela /* non zero pages */ 478c0ec0b2SJuan Quintela uint32_t normal_pages; 48d32ca5adSJuan Quintela /* size of the next packet that contains pages */ 49d32ca5adSJuan Quintela uint32_t next_packet_size; 50d32ca5adSJuan Quintela uint64_t packet_num; 51d32ca5adSJuan Quintela uint64_t unused[4]; /* Reserved for future use */ 52d32ca5adSJuan Quintela char ramblock[256]; 53d32ca5adSJuan Quintela uint64_t offset[]; 54d32ca5adSJuan Quintela } __attribute__((packed)) MultiFDPacket_t; 55d32ca5adSJuan Quintela 56d32ca5adSJuan Quintela typedef struct { 57d32ca5adSJuan Quintela /* number of used pages */ 5890a3d2f9SJuan Quintela uint32_t num; 59d32ca5adSJuan Quintela /* number of allocated pages */ 60d32ca5adSJuan Quintela uint32_t allocated; 61d32ca5adSJuan Quintela /* offset of each page */ 62d32ca5adSJuan Quintela ram_addr_t *offset; 63d32ca5adSJuan Quintela RAMBlock *block; 64d32ca5adSJuan Quintela } MultiFDPages_t; 65d32ca5adSJuan Quintela 66d32ca5adSJuan Quintela typedef struct { 674a8f19c9SJuan Quintela /* Fields are only written at creating/deletion time */ 684a8f19c9SJuan Quintela /* No lock required for them, they are read only */ 694a8f19c9SJuan Quintela 70d32ca5adSJuan Quintela /* channel number */ 71d32ca5adSJuan Quintela uint8_t id; 72d32ca5adSJuan Quintela /* channel thread name */ 73d32ca5adSJuan Quintela char *name; 74d32ca5adSJuan Quintela /* channel thread id */ 75d32ca5adSJuan Quintela QemuThread thread; 76*a2a63c4aSFabiano Rosas bool thread_created; 77e1921f10SFabiano Rosas QemuThread tls_thread; 78e1921f10SFabiano Rosas bool tls_thread_created; 79d32ca5adSJuan Quintela /* communication channel */ 80d32ca5adSJuan Quintela QIOChannel *c; 814a8f19c9SJuan Quintela /* is the yank function registered */ 824a8f19c9SJuan Quintela bool registered_yank; 834a8f19c9SJuan Quintela /* packet allocated len */ 844a8f19c9SJuan Quintela uint32_t packet_len; 85ddec20f8SJuan Quintela /* guest page size */ 86ddec20f8SJuan Quintela uint32_t page_size; 87d6f45ebaSJuan Quintela /* number of pages in a full packet */ 88d6f45ebaSJuan Quintela uint32_t page_count; 894a8f19c9SJuan Quintela /* multifd flags for sending ram */ 904a8f19c9SJuan Quintela int write_flags; 914a8f19c9SJuan Quintela 92d32ca5adSJuan Quintela /* sem where to wait for more work */ 93d32ca5adSJuan Quintela QemuSemaphore sem; 944a8f19c9SJuan Quintela /* syncs main thread and channels */ 954a8f19c9SJuan Quintela QemuSemaphore sem_sync; 964a8f19c9SJuan Quintela 97d32ca5adSJuan Quintela /* multifd flags for each packet */ 98d32ca5adSJuan Quintela uint32_t flags; 99f5f48a78SPeter Xu /* 100f5f48a78SPeter Xu * The sender thread has work to do if either of below boolean is set. 101f5f48a78SPeter Xu * 102f5f48a78SPeter Xu * @pending_job: a job is pending 103f5f48a78SPeter Xu * @pending_sync: a sync request is pending 104f5f48a78SPeter Xu * 105f5f48a78SPeter Xu * For both of these fields, they're only set by the requesters, and 106f5f48a78SPeter Xu * cleared by the multifd sender threads. 107f5f48a78SPeter Xu */ 108f5f48a78SPeter Xu bool pending_job; 109f5f48a78SPeter Xu bool pending_sync; 1104a8f19c9SJuan Quintela /* array of pages to sent. 1114a8f19c9SJuan Quintela * The owner of 'pages' depends of 'pending_job' value: 1124a8f19c9SJuan Quintela * pending_job == 0 -> migration_thread can use it. 1134a8f19c9SJuan Quintela * pending_job != 0 -> multifd_channel can use it. 1144a8f19c9SJuan Quintela */ 1154a8f19c9SJuan Quintela MultiFDPages_t *pages; 1164a8f19c9SJuan Quintela 1174a8f19c9SJuan Quintela /* thread local variables. No locking required */ 1184a8f19c9SJuan Quintela 1194a8f19c9SJuan Quintela /* pointer to the packet */ 1204a8f19c9SJuan Quintela MultiFDPacket_t *packet; 1214a8f19c9SJuan Quintela /* size of the next packet that contains pages */ 1224a8f19c9SJuan Quintela uint32_t next_packet_size; 123d32ca5adSJuan Quintela /* packets sent through this channel */ 12405b7ec18SPeter Xu uint64_t packets_sent; 125815956f0SJuan Quintela /* non zero pages sent through this channel */ 126815956f0SJuan Quintela uint64_t total_normal_pages; 127226468baSJuan Quintela /* buffers to send */ 128226468baSJuan Quintela struct iovec *iov; 129226468baSJuan Quintela /* number of iovs used */ 130226468baSJuan Quintela uint32_t iovs_num; 131ab7cbb0bSJuan Quintela /* used for compression methods */ 132ab7cbb0bSJuan Quintela void *data; 133d32ca5adSJuan Quintela } MultiFDSendParams; 134d32ca5adSJuan Quintela 135d32ca5adSJuan Quintela typedef struct { 1364a8f19c9SJuan Quintela /* Fields are only written at creating/deletion time */ 1374a8f19c9SJuan Quintela /* No lock required for them, they are read only */ 1384a8f19c9SJuan Quintela 139d32ca5adSJuan Quintela /* channel number */ 140d32ca5adSJuan Quintela uint8_t id; 141d32ca5adSJuan Quintela /* channel thread name */ 142d32ca5adSJuan Quintela char *name; 143d32ca5adSJuan Quintela /* channel thread id */ 144d32ca5adSJuan Quintela QemuThread thread; 145*a2a63c4aSFabiano Rosas bool thread_created; 146d32ca5adSJuan Quintela /* communication channel */ 147d32ca5adSJuan Quintela QIOChannel *c; 1484a8f19c9SJuan Quintela /* packet allocated len */ 1494a8f19c9SJuan Quintela uint32_t packet_len; 150ddec20f8SJuan Quintela /* guest page size */ 151ddec20f8SJuan Quintela uint32_t page_size; 152d6f45ebaSJuan Quintela /* number of pages in a full packet */ 153d6f45ebaSJuan Quintela uint32_t page_count; 1544a8f19c9SJuan Quintela 1554a8f19c9SJuan Quintela /* syncs main thread and channels */ 1564a8f19c9SJuan Quintela QemuSemaphore sem_sync; 1574a8f19c9SJuan Quintela 158d32ca5adSJuan Quintela /* this mutex protects the following parameters */ 159d32ca5adSJuan Quintela QemuMutex mutex; 160d32ca5adSJuan Quintela /* should this thread finish */ 161d32ca5adSJuan Quintela bool quit; 162d32ca5adSJuan Quintela /* multifd flags for each packet */ 163d32ca5adSJuan Quintela uint32_t flags; 164d32ca5adSJuan Quintela /* global number of generated multifd packets */ 165d32ca5adSJuan Quintela uint64_t packet_num; 1664a8f19c9SJuan Quintela 1674a8f19c9SJuan Quintela /* thread local variables. No locking required */ 1684a8f19c9SJuan Quintela 1694a8f19c9SJuan Quintela /* pointer to the packet */ 1704a8f19c9SJuan Quintela MultiFDPacket_t *packet; 171d32ca5adSJuan Quintela /* size of the next packet that contains pages */ 172d32ca5adSJuan Quintela uint32_t next_packet_size; 17305b7ec18SPeter Xu /* packets received through this channel */ 17405b7ec18SPeter Xu uint64_t packets_recved; 1755d1d1fcfSLukas Straub /* ramblock */ 1765d1d1fcfSLukas Straub RAMBlock *block; 1774a8f19c9SJuan Quintela /* ramblock host address */ 1784a8f19c9SJuan Quintela uint8_t *host; 179cf2d4aa8SJuan Quintela /* non zero pages recv through this channel */ 180cf2d4aa8SJuan Quintela uint64_t total_normal_pages; 181226468baSJuan Quintela /* buffers to recv */ 182226468baSJuan Quintela struct iovec *iov; 183cf2d4aa8SJuan Quintela /* Pages that are not zero */ 184cf2d4aa8SJuan Quintela ram_addr_t *normal; 185cf2d4aa8SJuan Quintela /* num of non zero pages */ 186cf2d4aa8SJuan Quintela uint32_t normal_num; 187ab7cbb0bSJuan Quintela /* used for de-compression methods */ 188ab7cbb0bSJuan Quintela void *data; 189d32ca5adSJuan Quintela } MultiFDRecvParams; 190d32ca5adSJuan Quintela 191ab7cbb0bSJuan Quintela typedef struct { 192ab7cbb0bSJuan Quintela /* Setup for sending side */ 193ab7cbb0bSJuan Quintela int (*send_setup)(MultiFDSendParams *p, Error **errp); 194ab7cbb0bSJuan Quintela /* Cleanup for sending side */ 195ab7cbb0bSJuan Quintela void (*send_cleanup)(MultiFDSendParams *p, Error **errp); 196ab7cbb0bSJuan Quintela /* Prepare the send packet */ 19702fb8104SJuan Quintela int (*send_prepare)(MultiFDSendParams *p, Error **errp); 198ab7cbb0bSJuan Quintela /* Setup for receiving side */ 199ab7cbb0bSJuan Quintela int (*recv_setup)(MultiFDRecvParams *p, Error **errp); 200ab7cbb0bSJuan Quintela /* Cleanup for receiving side */ 201ab7cbb0bSJuan Quintela void (*recv_cleanup)(MultiFDRecvParams *p); 202ab7cbb0bSJuan Quintela /* Read all pages */ 20340a4bfe9SJuan Quintela int (*recv_pages)(MultiFDRecvParams *p, Error **errp); 204ab7cbb0bSJuan Quintela } MultiFDMethods; 205ab7cbb0bSJuan Quintela 2067ec2c2b3SJuan Quintela void multifd_register_ops(int method, MultiFDMethods *ops); 20725a1f878SPeter Xu void multifd_send_fill_packet(MultiFDSendParams *p); 2087ec2c2b3SJuan Quintela 209452b2057SPeter Xu static inline void multifd_send_prepare_header(MultiFDSendParams *p) 210452b2057SPeter Xu { 211452b2057SPeter Xu p->iov[0].iov_len = p->packet_len; 212452b2057SPeter Xu p->iov[0].iov_base = p->packet; 213452b2057SPeter Xu p->iovs_num++; 214452b2057SPeter Xu } 215452b2057SPeter Xu 216452b2057SPeter Xu 217d32ca5adSJuan Quintela #endif 218