xref: /qemu/migration/cpr.c (revision 563ac3d18129a2770a285cc16c20ad50c8adc7c0)
1 /*
2  * Copyright (c) 2021-2024 Oracle and/or its affiliates.
3  *
4  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7 
8 #include "qemu/osdep.h"
9 #include "qapi/error.h"
10 #include "hw/vfio/vfio-device.h"
11 #include "migration/cpr.h"
12 #include "migration/misc.h"
13 #include "migration/options.h"
14 #include "migration/qemu-file.h"
15 #include "migration/savevm.h"
16 #include "migration/vmstate.h"
17 #include "monitor/monitor.h"
18 #include "system/runstate.h"
19 #include "trace.h"
20 
21 /*************************************************************************/
22 /* cpr state container for all information to be saved. */
23 
24 CprState cpr_state;
25 
26 /****************************************************************************/
27 
28 typedef struct CprFd {
29     char *name;
30     unsigned int namelen;
31     int id;
32     int fd;
33     QLIST_ENTRY(CprFd) next;
34 } CprFd;
35 
36 static const VMStateDescription vmstate_cpr_fd = {
37     .name = "cpr fd",
38     .version_id = 1,
39     .minimum_version_id = 1,
40     .fields = (VMStateField[]) {
41         VMSTATE_UINT32(namelen, CprFd),
42         VMSTATE_VBUFFER_ALLOC_UINT32(name, CprFd, 0, NULL, namelen),
43         VMSTATE_INT32(id, CprFd),
44         VMSTATE_FD(fd, CprFd),
45         VMSTATE_END_OF_LIST()
46     }
47 };
48 
cpr_save_fd(const char * name,int id,int fd)49 void cpr_save_fd(const char *name, int id, int fd)
50 {
51     CprFd *elem = g_new0(CprFd, 1);
52 
53     trace_cpr_save_fd(name, id, fd);
54     elem->name = g_strdup(name);
55     elem->namelen = strlen(name) + 1;
56     elem->id = id;
57     elem->fd = fd;
58     QLIST_INSERT_HEAD(&cpr_state.fds, elem, next);
59 }
60 
find_fd(CprFdList * head,const char * name,int id)61 static CprFd *find_fd(CprFdList *head, const char *name, int id)
62 {
63     CprFd *elem;
64 
65     QLIST_FOREACH(elem, head, next) {
66         if (!strcmp(elem->name, name) && elem->id == id) {
67             return elem;
68         }
69     }
70     return NULL;
71 }
72 
cpr_delete_fd(const char * name,int id)73 void cpr_delete_fd(const char *name, int id)
74 {
75     CprFd *elem = find_fd(&cpr_state.fds, name, id);
76 
77     if (elem) {
78         QLIST_REMOVE(elem, next);
79         g_free(elem->name);
80         g_free(elem);
81     }
82 
83     trace_cpr_delete_fd(name, id);
84 }
85 
cpr_find_fd(const char * name,int id)86 int cpr_find_fd(const char *name, int id)
87 {
88     CprFd *elem = find_fd(&cpr_state.fds, name, id);
89     int fd = elem ? elem->fd : -1;
90 
91     trace_cpr_find_fd(name, id, fd);
92     return fd;
93 }
94 
cpr_resave_fd(const char * name,int id,int fd)95 void cpr_resave_fd(const char *name, int id, int fd)
96 {
97     CprFd *elem = find_fd(&cpr_state.fds, name, id);
98     int old_fd = elem ? elem->fd : -1;
99 
100     if (old_fd < 0) {
101         cpr_save_fd(name, id, fd);
102     } else if (old_fd != fd) {
103         error_setg(&error_fatal,
104                    "internal error: cpr fd '%s' id %d value %d "
105                    "already saved with a different value %d",
106                    name, id, fd, old_fd);
107     }
108 }
109 
cpr_open_fd(const char * path,int flags,const char * name,int id,Error ** errp)110 int cpr_open_fd(const char *path, int flags, const char *name, int id,
111                 Error **errp)
112 {
113     int fd = cpr_find_fd(name, id);
114 
115     if (fd < 0) {
116         fd = qemu_open(path, flags, errp);
117         if (fd >= 0) {
118             cpr_save_fd(name, id, fd);
119         }
120     }
121     return fd;
122 }
123 
124 /*************************************************************************/
125 static const VMStateDescription vmstate_cpr_state = {
126     .name = CPR_STATE,
127     .version_id = 1,
128     .minimum_version_id = 1,
129     .fields = (VMStateField[]) {
130         VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next),
131         VMSTATE_END_OF_LIST()
132     },
133     .subsections = (const VMStateDescription * const []) {
134         &vmstate_cpr_vfio_devices,
135         NULL
136     }
137 };
138 /*************************************************************************/
139 
140 static QEMUFile *cpr_state_file;
141 
cpr_state_ioc(void)142 QIOChannel *cpr_state_ioc(void)
143 {
144     return qemu_file_get_ioc(cpr_state_file);
145 }
146 
147 static MigMode incoming_mode = MIG_MODE_NONE;
148 
cpr_get_incoming_mode(void)149 MigMode cpr_get_incoming_mode(void)
150 {
151     return incoming_mode;
152 }
153 
cpr_set_incoming_mode(MigMode mode)154 void cpr_set_incoming_mode(MigMode mode)
155 {
156     incoming_mode = mode;
157 }
158 
cpr_is_incoming(void)159 bool cpr_is_incoming(void)
160 {
161     return incoming_mode != MIG_MODE_NONE;
162 }
163 
cpr_state_save(MigrationChannel * channel,Error ** errp)164 int cpr_state_save(MigrationChannel *channel, Error **errp)
165 {
166     int ret;
167     QEMUFile *f;
168     MigMode mode = migrate_mode();
169 
170     trace_cpr_state_save(MigMode_str(mode));
171 
172     if (mode == MIG_MODE_CPR_TRANSFER) {
173         g_assert(channel);
174         f = cpr_transfer_output(channel, errp);
175     } else {
176         return 0;
177     }
178     if (!f) {
179         return -1;
180     }
181 
182     qemu_put_be32(f, QEMU_CPR_FILE_MAGIC);
183     qemu_put_be32(f, QEMU_CPR_FILE_VERSION);
184 
185     ret = vmstate_save_state(f, &vmstate_cpr_state, &cpr_state, 0);
186     if (ret) {
187         error_setg(errp, "vmstate_save_state error %d", ret);
188         qemu_fclose(f);
189         return ret;
190     }
191 
192     /*
193      * Close the socket only partially so we can later detect when the other
194      * end closes by getting a HUP event.
195      */
196     qemu_fflush(f);
197     qio_channel_shutdown(qemu_file_get_ioc(f), QIO_CHANNEL_SHUTDOWN_WRITE,
198                          NULL);
199     cpr_state_file = f;
200     return 0;
201 }
202 
cpr_state_load(MigrationChannel * channel,Error ** errp)203 int cpr_state_load(MigrationChannel *channel, Error **errp)
204 {
205     int ret;
206     uint32_t v;
207     QEMUFile *f;
208     MigMode mode = 0;
209 
210     if (channel) {
211         mode = MIG_MODE_CPR_TRANSFER;
212         cpr_set_incoming_mode(mode);
213         f = cpr_transfer_input(channel, errp);
214     } else {
215         return 0;
216     }
217     if (!f) {
218         return -1;
219     }
220 
221     trace_cpr_state_load(MigMode_str(mode));
222 
223     v = qemu_get_be32(f);
224     if (v != QEMU_CPR_FILE_MAGIC) {
225         error_setg(errp, "Not a migration stream (bad magic %x)", v);
226         qemu_fclose(f);
227         return -EINVAL;
228     }
229     v = qemu_get_be32(f);
230     if (v != QEMU_CPR_FILE_VERSION) {
231         error_setg(errp, "Unsupported migration stream version %d", v);
232         qemu_fclose(f);
233         return -ENOTSUP;
234     }
235 
236     ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
237     if (ret) {
238         error_setg(errp, "vmstate_load_state error %d", ret);
239         qemu_fclose(f);
240         return ret;
241     }
242 
243     /*
244      * Let the caller decide when to close the socket (and generate a HUP event
245      * for the sending side).
246      */
247     cpr_state_file = f;
248 
249     return ret;
250 }
251 
cpr_state_close(void)252 void cpr_state_close(void)
253 {
254     if (cpr_state_file) {
255         qemu_fclose(cpr_state_file);
256         cpr_state_file = NULL;
257     }
258 }
259 
cpr_incoming_needed(void * opaque)260 bool cpr_incoming_needed(void *opaque)
261 {
262     MigMode mode = migrate_mode();
263     return mode == MIG_MODE_CPR_TRANSFER;
264 }
265 
266 /*
267  * cpr_get_fd_param: find a descriptor and return its value.
268  *
269  * @name: CPR name for the descriptor
270  * @fdname: An integer-valued string, or a name passed to a getfd command
271  * @index: CPR index of the descriptor
272  * @errp: returned error message
273  *
274  * If CPR is not being performed, then use @fdname to find the fd.
275  * If CPR is being performed, then ignore @fdname, and look for @name
276  * and @index in CPR state.
277  *
278  * On success returns the fd value, else returns -1.
279  */
cpr_get_fd_param(const char * name,const char * fdname,int index,Error ** errp)280 int cpr_get_fd_param(const char *name, const char *fdname, int index,
281                      Error **errp)
282 {
283     ERRP_GUARD();
284     int fd;
285 
286     if (cpr_is_incoming()) {
287         fd = cpr_find_fd(name, index);
288         if (fd < 0) {
289             error_setg(errp, "cannot find saved value for fd %s", fdname);
290         }
291     } else {
292         fd = monitor_fd_param(monitor_cur(), fdname, errp);
293         if (fd >= 0) {
294             cpr_save_fd(name, index, fd);
295         } else {
296             error_prepend(errp, "Could not parse object fd %s:", fdname);
297         }
298     }
299     return fd;
300 }
301