xref: /qemu/migration/multifd-device-state.c (revision a1131aa94256d1007b4267ff9e79c3b4ada6e2b9)
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