123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- /*
- * Multifd common functions
- *
- * Copyright (c) 2019-2020 Red Hat Inc
- *
- * Authors:
- * Juan Quintela <quintela@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
- #ifndef QEMU_MIGRATION_MULTIFD_H
- #define QEMU_MIGRATION_MULTIFD_H
- #include "exec/target_page.h"
- #include "ram.h"
- typedef struct MultiFDRecvData MultiFDRecvData;
- typedef struct MultiFDSendData MultiFDSendData;
- typedef enum {
- /* No sync request */
- MULTIFD_SYNC_NONE = 0,
- /* Sync locally on the sender threads without pushing messages */
- MULTIFD_SYNC_LOCAL,
- /*
- * Sync not only on the sender threads, but also push MULTIFD_FLAG_SYNC
- * message to the wire for each iochannel (which is for a remote sync).
- *
- * When remote sync is used, need to be paired with a follow up
- * RAM_SAVE_FLAG_EOS / RAM_SAVE_FLAG_MULTIFD_FLUSH message on the main
- * channel.
- */
- MULTIFD_SYNC_ALL,
- } MultiFDSyncReq;
- bool multifd_send_setup(void);
- void multifd_send_shutdown(void);
- void multifd_send_channel_created(void);
- int multifd_recv_setup(Error **errp);
- void multifd_recv_cleanup(void);
- void multifd_recv_shutdown(void);
- bool multifd_recv_all_channels_created(void);
- void multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
- void multifd_recv_sync_main(void);
- int multifd_send_sync_main(MultiFDSyncReq req);
- bool multifd_queue_page(RAMBlock *block, ram_addr_t offset);
- bool multifd_recv(void);
- MultiFDRecvData *multifd_get_recv_data(void);
- /* Multifd Compression flags */
- #define MULTIFD_FLAG_SYNC (1 << 0)
- /* We reserve 5 bits for compression methods */
- #define MULTIFD_FLAG_COMPRESSION_MASK (0x1f << 1)
- /* we need to be compatible. Before compression value was 0 */
- #define MULTIFD_FLAG_NOCOMP (0 << 1)
- #define MULTIFD_FLAG_ZLIB (1 << 1)
- #define MULTIFD_FLAG_ZSTD (2 << 1)
- #define MULTIFD_FLAG_QPL (4 << 1)
- #define MULTIFD_FLAG_UADK (8 << 1)
- #define MULTIFD_FLAG_QATZIP (16 << 1)
- /*
- * If set it means that this packet contains device state
- * (MultiFDPacketDeviceState_t), not RAM data (MultiFDPacket_t).
- */
- #define MULTIFD_FLAG_DEVICE_STATE (32 << 1)
- /* This value needs to be a multiple of qemu_target_page_size() */
- #define MULTIFD_PACKET_SIZE (512 * 1024)
- typedef struct {
- uint32_t magic;
- uint32_t version;
- uint32_t flags;
- } __attribute__((packed)) MultiFDPacketHdr_t;
- typedef struct {
- MultiFDPacketHdr_t hdr;
- /* maximum number of allocated pages */
- uint32_t pages_alloc;
- /* non zero pages */
- uint32_t normal_pages;
- /* size of the next packet that contains pages */
- uint32_t next_packet_size;
- uint64_t packet_num;
- /* zero pages */
- uint32_t zero_pages;
- uint32_t unused32[1]; /* Reserved for future use */
- uint64_t unused64[3]; /* Reserved for future use */
- char ramblock[256];
- /*
- * This array contains the pointers to:
- * - normal pages (initial normal_pages entries)
- * - zero pages (following zero_pages entries)
- */
- uint64_t offset[];
- } __attribute__((packed)) MultiFDPacket_t;
- typedef struct {
- MultiFDPacketHdr_t hdr;
- char idstr[256];
- uint32_t instance_id;
- /* size of the next packet that contains the actual data */
- uint32_t next_packet_size;
- } __attribute__((packed)) MultiFDPacketDeviceState_t;
- typedef struct {
- /* number of used pages */
- uint32_t num;
- /* number of normal pages */
- uint32_t normal_num;
- /*
- * Pointer to the ramblock. NOTE: it's caller's responsibility to make
- * sure the pointer is always valid!
- */
- RAMBlock *block;
- /* offset array of each page, managed by multifd */
- ram_addr_t *offset;
- } MultiFDPages_t;
- struct MultiFDRecvData {
- void *opaque;
- size_t size;
- /* for preadv */
- off_t file_offset;
- };
- typedef struct {
- char *idstr;
- uint32_t instance_id;
- char *buf;
- size_t buf_len;
- } MultiFDDeviceState_t;
- typedef enum {
- MULTIFD_PAYLOAD_NONE,
- MULTIFD_PAYLOAD_RAM,
- MULTIFD_PAYLOAD_DEVICE_STATE,
- } MultiFDPayloadType;
- typedef struct MultiFDPayload {
- MultiFDPages_t ram;
- MultiFDDeviceState_t device_state;
- } MultiFDPayload;
- struct MultiFDSendData {
- MultiFDPayloadType type;
- MultiFDPayload u;
- };
- static inline bool multifd_payload_empty(MultiFDSendData *data)
- {
- return data->type == MULTIFD_PAYLOAD_NONE;
- }
- static inline bool multifd_payload_device_state(MultiFDSendData *data)
- {
- return data->type == MULTIFD_PAYLOAD_DEVICE_STATE;
- }
- static inline void multifd_set_payload_type(MultiFDSendData *data,
- MultiFDPayloadType type)
- {
- assert(multifd_payload_empty(data));
- assert(type != MULTIFD_PAYLOAD_NONE);
- data->type = type;
- }
- typedef struct {
- /* Fields are only written at creating/deletion time */
- /* No lock required for them, they are read only */
- /* channel number */
- uint8_t id;
- /* channel thread name */
- char *name;
- /* channel thread id */
- QemuThread thread;
- bool thread_created;
- QemuThread tls_thread;
- bool tls_thread_created;
- /* communication channel */
- QIOChannel *c;
- /* packet allocated len */
- uint32_t packet_len;
- /* multifd flags for sending ram */
- int write_flags;
- /* sem where to wait for more work */
- QemuSemaphore sem;
- /* syncs main thread and channels */
- QemuSemaphore sem_sync;
- /* multifd flags for each packet */
- uint32_t flags;
- /*
- * The sender thread has work to do if either of below field is set.
- *
- * @pending_job: a job is pending
- * @pending_sync: a sync request is pending
- *
- * For both of these fields, they're only set by the requesters, and
- * cleared by the multifd sender threads.
- */
- bool pending_job;
- MultiFDSyncReq pending_sync;
- MultiFDSendData *data;
- /* thread local variables. No locking required */
- /* pointers to the possible packet types */
- MultiFDPacket_t *packet;
- MultiFDPacketDeviceState_t *packet_device_state;
- /* size of the next packet that contains pages */
- uint32_t next_packet_size;
- /* packets sent through this channel */
- uint64_t packets_sent;
- /* buffers to send */
- struct iovec *iov;
- /* number of iovs used */
- uint32_t iovs_num;
- /* used for compression methods */
- void *compress_data;
- } MultiFDSendParams;
- typedef struct {
- /* Fields are only written at creating/deletion time */
- /* No lock required for them, they are read only */
- /* channel number */
- uint8_t id;
- /* channel thread name */
- char *name;
- /* channel thread id */
- QemuThread thread;
- bool thread_created;
- /* communication channel */
- QIOChannel *c;
- /* packet allocated len */
- uint32_t packet_len;
- /* syncs main thread and channels */
- QemuSemaphore sem_sync;
- /* sem where to wait for more work */
- QemuSemaphore sem;
- /* this mutex protects the following parameters */
- QemuMutex mutex;
- /* should this thread finish */
- bool quit;
- /* multifd flags for each packet */
- uint32_t flags;
- /* global number of generated multifd packets */
- uint64_t packet_num;
- int pending_job;
- MultiFDRecvData *data;
- /* thread local variables. No locking required */
- /* pointers to the possible packet types */
- MultiFDPacket_t *packet;
- MultiFDPacketDeviceState_t *packet_dev_state;
- /* size of the next packet that contains pages */
- uint32_t next_packet_size;
- /* packets received through this channel */
- uint64_t packets_recved;
- /* ramblock */
- RAMBlock *block;
- /* ramblock host address */
- uint8_t *host;
- /* buffers to recv */
- struct iovec *iov;
- /* Pages that are not zero */
- ram_addr_t *normal;
- /* num of non zero pages */
- uint32_t normal_num;
- /* Pages that are zero */
- ram_addr_t *zero;
- /* num of zero pages */
- uint32_t zero_num;
- /* used for de-compression methods */
- void *compress_data;
- /* Flags for the QIOChannel */
- int read_flags;
- } MultiFDRecvParams;
- typedef struct {
- /*
- * The send_setup, send_cleanup, send_prepare are only called on
- * the QEMU instance at the migration source.
- */
- /*
- * Setup for sending side. Called once per channel during channel
- * setup phase.
- *
- * Must allocate p->iov. If packets are in use (default), one
- * extra iovec must be allocated for the packet header. Any memory
- * allocated in this hook must be released at send_cleanup.
- *
- * p->write_flags may be used for passing flags to the QIOChannel.
- *
- * p->compression_data may be used by compression methods to store
- * compression data.
- */
- int (*send_setup)(MultiFDSendParams *p, Error **errp);
- /*
- * Cleanup for sending side. Called once per channel during
- * channel cleanup phase.
- */
- void (*send_cleanup)(MultiFDSendParams *p, Error **errp);
- /*
- * Prepare the send packet. Called as a result of multifd_send()
- * on the client side, with p pointing to the MultiFDSendParams of
- * a channel that is currently idle.
- *
- * Must populate p->iov with the data to be sent, increment
- * p->iovs_num to match the amount of iovecs used and set
- * p->next_packet_size with the amount of data currently present
- * in p->iov.
- *
- * Must indicate whether this is a compression packet by setting
- * p->flags.
- *
- * As a last step, if packets are in use (default), must prepare
- * the packet by calling multifd_send_fill_packet().
- */
- int (*send_prepare)(MultiFDSendParams *p, Error **errp);
- /*
- * The recv_setup, recv_cleanup, recv are only called on the QEMU
- * instance at the migration destination.
- */
- /*
- * Setup for receiving side. Called once per channel during
- * channel setup phase. May be empty.
- *
- * May allocate data structures for the receiving of data. May use
- * p->iov. Compression methods may use p->compress_data.
- */
- int (*recv_setup)(MultiFDRecvParams *p, Error **errp);
- /*
- * Cleanup for receiving side. Called once per channel during
- * channel cleanup phase. May be empty.
- */
- void (*recv_cleanup)(MultiFDRecvParams *p);
- /*
- * Data receive method. Called as a result of multifd_recv() on
- * the client side, with p pointing to the MultiFDRecvParams of a
- * channel that is currently idle. Only called if there is data
- * available to receive.
- *
- * Must validate p->flags according to what was set at
- * send_prepare.
- *
- * Must read the data from the QIOChannel p->c.
- */
- int (*recv)(MultiFDRecvParams *p, Error **errp);
- } MultiFDMethods;
- void multifd_register_ops(int method, const MultiFDMethods *ops);
- void multifd_send_fill_packet(MultiFDSendParams *p);
- bool multifd_send_prepare_common(MultiFDSendParams *p);
- void multifd_send_zero_page_detect(MultiFDSendParams *p);
- void multifd_recv_zero_page_process(MultiFDRecvParams *p);
- void multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc);
- bool multifd_send(MultiFDSendData **send_data);
- MultiFDSendData *multifd_send_data_alloc(void);
- void multifd_send_data_clear(MultiFDSendData *data);
- void multifd_send_data_free(MultiFDSendData *data);
- static inline uint32_t multifd_ram_page_size(void)
- {
- return qemu_target_page_size();
- }
- static inline uint32_t multifd_ram_page_count(void)
- {
- return MULTIFD_PACKET_SIZE / qemu_target_page_size();
- }
- void multifd_ram_save_setup(void);
- void multifd_ram_save_cleanup(void);
- int multifd_ram_flush_and_sync(QEMUFile *f);
- bool multifd_ram_sync_per_round(void);
- bool multifd_ram_sync_per_section(void);
- void multifd_ram_payload_alloc(MultiFDPages_t *pages);
- void multifd_ram_payload_free(MultiFDPages_t *pages);
- void multifd_ram_fill_packet(MultiFDSendParams *p);
- int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp);
- void multifd_send_data_clear_device_state(MultiFDDeviceState_t *device_state);
- void multifd_device_state_send_setup(void);
- void multifd_device_state_send_cleanup(void);
- void multifd_device_state_send_prepare(MultiFDSendParams *p);
- #endif
|