master
c 202 lines 4.92 KB
Raw
1 /*
2 * Copyright (c) 2021-2025 Oracle and/or its affiliates.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "qemu/osdep.h"
8 #include "qemu/cutils.h"
9 #include "qemu/error-report.h"
10 #include "qemu/memfd.h"
11 #include "qapi/error.h"
12 #include "qapi/type-helpers.h"
13 #include "io/channel-file.h"
14 #include "io/channel-socket.h"
15 #include "block/block-global-state.h"
16 #include "qemu/main-loop.h"
17 #include "migration/cpr.h"
18 #include "migration/qemu-file.h"
19 #include "migration/migration.h"
20 #include "migration/misc.h"
21 #include "migration/vmstate.h"
22 #include "system/runstate.h"
23 #include "trace.h"
24
25 #define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE"
26
27 static QEMUFile *qemu_file_new_fd_input(int fd, const char *name)
28 {
29 g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd);
30 QIOChannel *ioc = QIO_CHANNEL(fioc);
31 qio_channel_set_name(ioc, name);
32 return qemu_file_new_input(ioc);
33 }
34
35 static QEMUFile *qemu_file_new_fd_output(int fd, const char *name)
36 {
37 g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd);
38 QIOChannel *ioc = QIO_CHANNEL(fioc);
39 qio_channel_set_name(ioc, name);
40 return qemu_file_new_output(ioc);
41 }
42
43 bool cpr_exec_persist_state(QEMUFile *f, Error **errp)
44 {
45 QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f));
46 /* coverity[leaked_storage] - mfd intentionally kept open across exec() */
47 int mfd = dup(fioc->fd);
48 char val[16];
49
50 /* Remember mfd in environment for post-exec load */
51 qemu_clear_cloexec(mfd);
52 snprintf(val, sizeof(val), "%d", mfd);
53 if (!g_setenv(CPR_EXEC_STATE_NAME, val, 1)) {
54 error_setg(errp, "Setting env %s = %s failed", CPR_EXEC_STATE_NAME, val);
55 return false;
56 }
57
58 return true;
59 }
60
61 static int cpr_exec_find_state(void)
62 {
63 const char *val = g_getenv(CPR_EXEC_STATE_NAME);
64 int mfd;
65
66 assert(val);
67 g_unsetenv(CPR_EXEC_STATE_NAME);
68 assert(!qemu_strtoi(val, NULL, 10, &mfd));
69 return mfd;
70 }
71
72 bool cpr_exec_has_state(void)
73 {
74 return g_getenv(CPR_EXEC_STATE_NAME) != NULL;
75 }
76
77 void cpr_exec_unpersist_state(void)
78 {
79 int mfd;
80 const char *val = g_getenv(CPR_EXEC_STATE_NAME);
81
82 g_unsetenv(CPR_EXEC_STATE_NAME);
83 assert(val);
84 assert(!qemu_strtoi(val, NULL, 10, &mfd));
85 close(mfd);
86 }
87
88 QEMUFile *cpr_exec_output(Error **errp)
89 {
90 int mfd;
91
92 #ifdef CONFIG_LINUX
93 mfd = qemu_memfd_create(CPR_EXEC_STATE_NAME, 0, false, 0, 0, errp);
94 #else
95 mfd = -1;
96 #endif
97
98 if (mfd < 0) {
99 return NULL;
100 }
101
102 return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME);
103 }
104
105 QEMUFile *cpr_exec_input(Error **errp)
106 {
107 int mfd = cpr_exec_find_state();
108
109 lseek(mfd, 0, SEEK_SET);
110 return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME);
111 }
112
113 static bool preserve_fd(int fd)
114 {
115 qemu_clear_cloexec(fd);
116 return true;
117 }
118
119 static bool unpreserve_fd(int fd)
120 {
121 qemu_set_cloexec(fd);
122 return true;
123 }
124
125 static void cpr_exec_preserve_fds(void)
126 {
127 cpr_walk_fd(preserve_fd);
128 }
129
130 void cpr_exec_unpreserve_fds(void)
131 {
132 cpr_walk_fd(unpreserve_fd);
133 }
134
135 static void cpr_exec_cb(void *opaque)
136 {
137 MigrationState *s = migrate_get_current();
138 char **argv = strv_from_str_list(s->parameters.cpr_exec_command);
139 Error *err = NULL;
140
141 /*
142 * Clear the close-on-exec flag for all preserved fd's. We cannot do so
143 * earlier because they should not persist across miscellaneous fork and
144 * exec calls that are performed during normal operation.
145 */
146 cpr_exec_preserve_fds();
147
148 trace_cpr_exec();
149 execvp(argv[0], argv);
150
151 /*
152 * exec should only fail if argv[0] is bogus, or has a permissions problem,
153 * or the system is very short on resources.
154 */
155 error_setg_errno(&err, errno, "execvp %s failed", argv[0]);
156 g_clear_pointer(&argv, g_strfreev);
157 cpr_exec_unpreserve_fds();
158
159 error_report_err(error_copy(err));
160 migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
161
162 migrate_error_propagate(s, err);
163 /* We must reset the error because it'll be reused later */
164 err = NULL;
165
166 /* Note, we can go from state COMPLETED to FAILED */
167 migration_call_notifiers(MIG_EVENT_FAILED, NULL);
168
169 if (!migration_block_activate(&err)) {
170 /* error was already reported */
171 error_free(err);
172 return;
173 }
174
175 if (runstate_is_live(s->vm_old_state)) {
176 vm_start();
177 }
178 }
179
180 static int cpr_exec_notifier(NotifierWithReturn *notifier, MigrationEvent *e,
181 Error **errp)
182 {
183 MigrationState *s = migrate_get_current();
184
185 if (e->type == MIG_EVENT_DONE) {
186 QEMUBH *cpr_exec_bh = qemu_bh_new(cpr_exec_cb, NULL);
187 assert(s->state == MIGRATION_STATUS_COMPLETED);
188 qemu_bh_schedule(cpr_exec_bh);
189 qemu_notify_event();
190 } else if (e->type == MIG_EVENT_FAILED) {
191 cpr_exec_unpersist_state();
192 }
193 return 0;
194 }
195
196 void cpr_exec_init(void)
197 {
198 static NotifierWithReturn exec_notifier;
199
200 migration_add_notifier_mode(&exec_notifier, cpr_exec_notifier,
201 MIG_MODE_CPR_EXEC);
202 }