1 /* 2 * Multifd common functions 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 #ifndef QEMU_MIGRATION_MULTIFD_H 14 #define QEMU_MIGRATION_MULTIFD_H 15 16 #include "ram.h" 17 18 typedef struct MultiFDRecvData MultiFDRecvData; 19 20 bool multifd_send_setup(void); 21 void multifd_send_shutdown(void); 22 void multifd_send_channel_created(void); 23 int multifd_recv_setup(Error **errp); 24 void multifd_recv_cleanup(void); 25 void multifd_recv_shutdown(void); 26 bool multifd_recv_all_channels_created(void); 27 void multifd_recv_new_channel(QIOChannel *ioc, Error **errp); 28 void multifd_recv_sync_main(void); 29 int multifd_send_sync_main(void); 30 bool multifd_queue_page(RAMBlock *block, ram_addr_t offset); 31 bool multifd_recv(void); 32 MultiFDRecvData *multifd_get_recv_data(void); 33 34 /* Multifd Compression flags */ 35 #define MULTIFD_FLAG_SYNC (1 << 0) 36 37 /* We reserve 3 bits for compression methods */ 38 #define MULTIFD_FLAG_COMPRESSION_MASK (7 << 1) 39 /* we need to be compatible. Before compression value was 0 */ 40 #define MULTIFD_FLAG_NOCOMP (0 << 1) 41 #define MULTIFD_FLAG_ZLIB (1 << 1) 42 #define MULTIFD_FLAG_ZSTD (2 << 1) 43 44 /* This value needs to be a multiple of qemu_target_page_size() */ 45 #define MULTIFD_PACKET_SIZE (512 * 1024) 46 47 typedef struct { 48 uint32_t magic; 49 uint32_t version; 50 uint32_t flags; 51 /* maximum number of allocated pages */ 52 uint32_t pages_alloc; 53 /* non zero pages */ 54 uint32_t normal_pages; 55 /* size of the next packet that contains pages */ 56 uint32_t next_packet_size; 57 uint64_t packet_num; 58 uint64_t unused[4]; /* Reserved for future use */ 59 char ramblock[256]; 60 uint64_t offset[]; 61 } __attribute__((packed)) MultiFDPacket_t; 62 63 typedef struct { 64 /* number of used pages */ 65 uint32_t num; 66 /* number of allocated pages */ 67 uint32_t allocated; 68 /* offset of each page */ 69 ram_addr_t *offset; 70 RAMBlock *block; 71 } MultiFDPages_t; 72 73 struct MultiFDRecvData { 74 void *opaque; 75 size_t size; 76 /* for preadv */ 77 off_t file_offset; 78 }; 79 80 typedef struct { 81 /* Fields are only written at creating/deletion time */ 82 /* No lock required for them, they are read only */ 83 84 /* channel number */ 85 uint8_t id; 86 /* channel thread name */ 87 char *name; 88 /* channel thread id */ 89 QemuThread thread; 90 bool thread_created; 91 QemuThread tls_thread; 92 bool tls_thread_created; 93 /* communication channel */ 94 QIOChannel *c; 95 /* packet allocated len */ 96 uint32_t packet_len; 97 /* guest page size */ 98 uint32_t page_size; 99 /* number of pages in a full packet */ 100 uint32_t page_count; 101 /* multifd flags for sending ram */ 102 int write_flags; 103 104 /* sem where to wait for more work */ 105 QemuSemaphore sem; 106 /* syncs main thread and channels */ 107 QemuSemaphore sem_sync; 108 109 /* multifd flags for each packet */ 110 uint32_t flags; 111 /* 112 * The sender thread has work to do if either of below boolean is set. 113 * 114 * @pending_job: a job is pending 115 * @pending_sync: a sync request is pending 116 * 117 * For both of these fields, they're only set by the requesters, and 118 * cleared by the multifd sender threads. 119 */ 120 bool pending_job; 121 bool pending_sync; 122 /* array of pages to sent. 123 * The owner of 'pages' depends of 'pending_job' value: 124 * pending_job == 0 -> migration_thread can use it. 125 * pending_job != 0 -> multifd_channel can use it. 126 */ 127 MultiFDPages_t *pages; 128 129 /* thread local variables. No locking required */ 130 131 /* pointer to the packet */ 132 MultiFDPacket_t *packet; 133 /* size of the next packet that contains pages */ 134 uint32_t next_packet_size; 135 /* packets sent through this channel */ 136 uint64_t packets_sent; 137 /* non zero pages sent through this channel */ 138 uint64_t total_normal_pages; 139 /* buffers to send */ 140 struct iovec *iov; 141 /* number of iovs used */ 142 uint32_t iovs_num; 143 /* used for compression methods */ 144 void *compress_data; 145 } MultiFDSendParams; 146 147 typedef struct { 148 /* Fields are only written at creating/deletion time */ 149 /* No lock required for them, they are read only */ 150 151 /* channel number */ 152 uint8_t id; 153 /* channel thread name */ 154 char *name; 155 /* channel thread id */ 156 QemuThread thread; 157 bool thread_created; 158 /* communication channel */ 159 QIOChannel *c; 160 /* packet allocated len */ 161 uint32_t packet_len; 162 /* guest page size */ 163 uint32_t page_size; 164 /* number of pages in a full packet */ 165 uint32_t page_count; 166 167 /* syncs main thread and channels */ 168 QemuSemaphore sem_sync; 169 /* sem where to wait for more work */ 170 QemuSemaphore sem; 171 172 /* this mutex protects the following parameters */ 173 QemuMutex mutex; 174 /* should this thread finish */ 175 bool quit; 176 /* multifd flags for each packet */ 177 uint32_t flags; 178 /* global number of generated multifd packets */ 179 uint64_t packet_num; 180 int pending_job; 181 MultiFDRecvData *data; 182 183 /* thread local variables. No locking required */ 184 185 /* pointer to the packet */ 186 MultiFDPacket_t *packet; 187 /* size of the next packet that contains pages */ 188 uint32_t next_packet_size; 189 /* packets received through this channel */ 190 uint64_t packets_recved; 191 /* ramblock */ 192 RAMBlock *block; 193 /* ramblock host address */ 194 uint8_t *host; 195 /* non zero pages recv through this channel */ 196 uint64_t total_normal_pages; 197 /* buffers to recv */ 198 struct iovec *iov; 199 /* Pages that are not zero */ 200 ram_addr_t *normal; 201 /* num of non zero pages */ 202 uint32_t normal_num; 203 /* used for de-compression methods */ 204 void *compress_data; 205 } MultiFDRecvParams; 206 207 typedef struct { 208 /* Setup for sending side */ 209 int (*send_setup)(MultiFDSendParams *p, Error **errp); 210 /* Cleanup for sending side */ 211 void (*send_cleanup)(MultiFDSendParams *p, Error **errp); 212 /* Prepare the send packet */ 213 int (*send_prepare)(MultiFDSendParams *p, Error **errp); 214 /* Setup for receiving side */ 215 int (*recv_setup)(MultiFDRecvParams *p, Error **errp); 216 /* Cleanup for receiving side */ 217 void (*recv_cleanup)(MultiFDRecvParams *p); 218 /* Read all data */ 219 int (*recv)(MultiFDRecvParams *p, Error **errp); 220 } MultiFDMethods; 221 222 void multifd_register_ops(int method, MultiFDMethods *ops); 223 void multifd_send_fill_packet(MultiFDSendParams *p); 224 225 static inline void multifd_send_prepare_header(MultiFDSendParams *p) 226 { 227 p->iov[0].iov_len = p->packet_len; 228 p->iov[0].iov_base = p->packet; 229 p->iovs_num++; 230 } 231 232 void multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc); 233 234 #endif 235