1 /* 2 * Multifd device state migration 3 * 4 * Copyright (C) 2024,2025 Oracle and/or its affiliates. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 */ 11 12 #include "qemu/osdep.h" 13 #include "qemu/lockable.h" 14 #include "migration/misc.h" 15 #include "multifd.h" 16 #include "options.h" 17 18 static struct { 19 QemuMutex queue_job_mutex; 20 21 MultiFDSendData *send_data; 22 } *multifd_send_device_state; 23 24 void multifd_device_state_send_setup(void) 25 { 26 assert(!multifd_send_device_state); 27 multifd_send_device_state = g_malloc(sizeof(*multifd_send_device_state)); 28 29 qemu_mutex_init(&multifd_send_device_state->queue_job_mutex); 30 31 multifd_send_device_state->send_data = multifd_send_data_alloc(); 32 } 33 34 void multifd_device_state_send_cleanup(void) 35 { 36 g_clear_pointer(&multifd_send_device_state->send_data, 37 multifd_send_data_free); 38 39 qemu_mutex_destroy(&multifd_send_device_state->queue_job_mutex); 40 41 g_clear_pointer(&multifd_send_device_state, g_free); 42 } 43 44 void multifd_send_data_clear_device_state(MultiFDDeviceState_t *device_state) 45 { 46 g_clear_pointer(&device_state->idstr, g_free); 47 g_clear_pointer(&device_state->buf, g_free); 48 } 49 50 static void multifd_device_state_fill_packet(MultiFDSendParams *p) 51 { 52 MultiFDDeviceState_t *device_state = &p->data->u.device_state; 53 MultiFDPacketDeviceState_t *packet = p->packet_device_state; 54 55 packet->hdr.flags = cpu_to_be32(p->flags); 56 strncpy(packet->idstr, device_state->idstr, sizeof(packet->idstr) - 1); 57 packet->idstr[sizeof(packet->idstr) - 1] = 0; 58 packet->instance_id = cpu_to_be32(device_state->instance_id); 59 packet->next_packet_size = cpu_to_be32(p->next_packet_size); 60 } 61 62 static void multifd_prepare_header_device_state(MultiFDSendParams *p) 63 { 64 p->iov[0].iov_len = sizeof(*p->packet_device_state); 65 p->iov[0].iov_base = p->packet_device_state; 66 p->iovs_num++; 67 } 68 69 void multifd_device_state_send_prepare(MultiFDSendParams *p) 70 { 71 MultiFDDeviceState_t *device_state = &p->data->u.device_state; 72 73 assert(multifd_payload_device_state(p->data)); 74 75 multifd_prepare_header_device_state(p); 76 77 assert(!(p->flags & MULTIFD_FLAG_SYNC)); 78 79 p->next_packet_size = device_state->buf_len; 80 if (p->next_packet_size > 0) { 81 p->iov[p->iovs_num].iov_base = device_state->buf; 82 p->iov[p->iovs_num].iov_len = p->next_packet_size; 83 p->iovs_num++; 84 } 85 86 p->flags |= MULTIFD_FLAG_NOCOMP | MULTIFD_FLAG_DEVICE_STATE; 87 88 multifd_device_state_fill_packet(p); 89 } 90 91 bool multifd_queue_device_state(char *idstr, uint32_t instance_id, 92 char *data, size_t len) 93 { 94 /* Device state submissions can come from multiple threads */ 95 QEMU_LOCK_GUARD(&multifd_send_device_state->queue_job_mutex); 96 MultiFDDeviceState_t *device_state; 97 98 assert(multifd_payload_empty(multifd_send_device_state->send_data)); 99 100 multifd_set_payload_type(multifd_send_device_state->send_data, 101 MULTIFD_PAYLOAD_DEVICE_STATE); 102 device_state = &multifd_send_device_state->send_data->u.device_state; 103 device_state->idstr = g_strdup(idstr); 104 device_state->instance_id = instance_id; 105 device_state->buf = g_memdup2(data, len); 106 device_state->buf_len = len; 107 108 if (!multifd_send(&multifd_send_device_state->send_data)) { 109 multifd_send_data_clear(multifd_send_device_state->send_data); 110 return false; 111 } 112 113 return true; 114 } 115 116 bool multifd_device_state_supported(void) 117 { 118 return migrate_multifd() && !migrate_mapped_ram() && 119 migrate_multifd_compression() == MULTIFD_COMPRESSION_NONE; 120 } 121