master
c 363 lines 10.8 KB
Raw
1 /*
2 * QTest testcases for migration to file
3 *
4 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5 * based on the vhost-user-test.c that is:
6 * Copyright (c) 2014 Virtual Open Systems Sarl.
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
10 *
11 */
12
13 #include "qemu/osdep.h"
14 #include "libqtest.h"
15 #include "migration/framework.h"
16 #include "migration/migration-qmp.h"
17 #include "migration/migration-util.h"
18 #include "qobject/qlist.h"
19
20
21 static char *tmpfs;
22
23 static int count_proc_fds(pid_t pid)
24 {
25 g_autofree char *fddir = g_strdup_printf("/proc/%d/fd", (int)pid);
26 GDir *dir = g_dir_open(fddir, 0, NULL);
27 int count = 0;
28
29 if (!dir) {
30 return -1;
31 }
32 while (g_dir_read_name(dir)) {
33 count++;
34 }
35 g_dir_close(dir);
36 return count;
37 }
38
39 static void test_file_connect_outgoing_fd_leak(char *name, MigrateCommon *args)
40 {
41 QTestState *from, *to;
42 int fd_before, fd_after;
43 const int retries = 5;
44 int i;
45 if (!g_file_test("/dev/full", G_FILE_TEST_EXISTS)) {
46 g_test_skip("/dev/full not available");
47 return;
48 }
49
50 if (migrate_start(&from, &to, &args->start)) {
51 return;
52 }
53
54 fd_before = count_proc_fds(qtest_pid(from));
55 g_assert_cmpint(fd_before, >, 0);
56 for (i = 0; i < retries; i++) {
57 migrate_qmp_fail(from, "file:/dev/full", NULL, "{}");
58 migration_event_wait(from, "failed");
59 }
60
61 fd_after = count_proc_fds(qtest_pid(from));
62 g_assert_cmpint(fd_after, >, 0);
63 g_assert_cmpint(fd_after, ==, fd_before);
64 migrate_end(from, to, false);
65 }
66
67 static void test_precopy_file(char *name, MigrateCommon *args)
68 {
69 test_file_common(args, true);
70 }
71
72 #ifndef _WIN32
73 static void fdset_add_fds(QTestState *qts, const char *file, int flags,
74 int num_fds, bool direct_io)
75 {
76 for (int i = 0; i < num_fds; i++) {
77 int fd;
78
79 #ifdef O_DIRECT
80 /* only secondary channels can use direct-io */
81 if (direct_io && i != 0) {
82 flags |= O_DIRECT;
83 }
84 #endif
85
86 fd = open(file, flags, 0660);
87 assert(fd != -1);
88
89 qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', "
90 "'arguments': {'fdset-id': 1}}");
91 close(fd);
92 }
93 }
94
95 static void *migrate_hook_start_file_offset_fdset(QTestState *from,
96 QTestState *to)
97 {
98 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
99
100 fdset_add_fds(from, file, O_WRONLY, 1, false);
101 fdset_add_fds(to, file, O_RDONLY, 1, false);
102
103 return NULL;
104 }
105
106 static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args)
107 {
108 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
109 FILE_TEST_OFFSET);
110 args->uri = uri;
111 args->start_hook = migrate_hook_start_file_offset_fdset;
112
113 test_file_common(args, false);
114 }
115 #endif
116
117 static void test_precopy_file_offset(char *name, MigrateCommon *args)
118 {
119 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
120 FILE_TEST_FILENAME,
121 FILE_TEST_OFFSET);
122
123 args->uri = uri;
124 test_file_common(args, false);
125 }
126
127 static void test_precopy_file_offset_bad(char *name, MigrateCommon *args)
128 {
129 /* using a value not supported by qemu_strtosz() */
130 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
131 tmpfs, FILE_TEST_FILENAME);
132
133 args->uri = uri;
134 args->result = MIG_TEST_QMP_ERROR;
135
136 test_file_common(args, false);
137 }
138
139 static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
140 {
141 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
142
143 test_file_common(args, false);
144 }
145
146 static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
147 {
148 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
149
150 test_file_common(args, true);
151 }
152
153 static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
154 {
155 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
156 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
157
158 test_file_common(args, false);
159 }
160
161 static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
162 {
163 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
164 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
165
166 test_file_common(args, true);
167 }
168
169 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
170 QTestState *to)
171 {
172 migrate_set_parameter_bool(from, "direct-io", true);
173 migrate_set_parameter_bool(to, "direct-io", true);
174
175 return NULL;
176 }
177
178 static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
179 {
180 args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
181
182 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
183 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
184
185 if (!probe_o_direct_support(tmpfs)) {
186 g_test_skip("Filesystem does not support O_DIRECT");
187 return;
188 }
189
190 test_file_common(args, true);
191 }
192
193 static void *migrate_hook_start_postcopy_mapped_ram(QTestState *from,
194 QTestState *to)
195 {
196 migrate_set_capability(
197 to, MigrationCapability_lookup.array[MIGRATION_CAPABILITY_POSTCOPY_RAM],
198 true);
199
200 return NULL;
201 }
202
203 static void test_postcopy_file_mapped_ram(char *name, MigrateCommon *args)
204 {
205 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
206
207 args->start_hook = migrate_hook_start_postcopy_mapped_ram;
208
209 test_file_common(args, false);
210 }
211
212 #ifndef _WIN32
213 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from,
214 QTestState *to,
215 void *opaque)
216 {
217 QDict *resp;
218 QList *fdsets;
219
220 /*
221 * Remove the fdsets after migration, otherwise a second migration
222 * would fail due fdset reuse.
223 */
224 qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
225 "'arguments': { 'fdset-id': 1}}");
226
227 /*
228 * Make sure no fdsets are left after migration, otherwise a
229 * second migration would fail due fdset reuse.
230 */
231 resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
232 "'arguments': {}}");
233 g_assert(qdict_haskey(resp, "return"));
234 fdsets = qdict_get_qlist(resp, "return");
235 g_assert(fdsets && qlist_empty(fdsets));
236 qobject_unref(resp);
237 }
238
239 static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
240 QTestState *to)
241 {
242 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
243
244 fdset_add_fds(from, file, O_WRONLY, 2, true);
245 fdset_add_fds(to, file, O_RDONLY, 2, true);
246
247 migrate_set_parameter_bool(from, "direct-io", true);
248 migrate_set_parameter_bool(to, "direct-io", true);
249
250 return NULL;
251 }
252
253 static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from,
254 QTestState *to)
255 {
256 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
257
258 fdset_add_fds(from, file, O_WRONLY, 2, false);
259 fdset_add_fds(to, file, O_RDONLY, 2, false);
260
261 return NULL;
262 }
263
264 static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
265 {
266 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
267 FILE_TEST_OFFSET);
268
269 args->uri = uri;
270 args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset;
271 args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
272
273 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
274 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
275
276 test_file_common(args, true);
277 }
278
279 static void test_multifd_file_mapped_ram_fdset_dio(char *name,
280 MigrateCommon *args)
281 {
282 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
283 FILE_TEST_OFFSET);
284 args->uri = uri;
285 args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio;
286 args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
287
288 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
289 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
290
291 if (!probe_o_direct_support(tmpfs)) {
292 g_test_skip("Filesystem does not support O_DIRECT");
293 return;
294 }
295
296 test_file_common(args, true);
297 }
298 #endif /* !_WIN32 */
299
300 static void migration_test_add_file_smoke(MigrationTestEnv *env)
301 {
302 migration_test_add("/migration/precopy/file",
303 test_precopy_file);
304
305 migration_test_add("/migration/multifd/file/mapped-ram/dio",
306 test_multifd_file_mapped_ram_dio);
307 }
308
309 static void
310 test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args)
311 {
312 args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
313 args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
314
315 test_file_common(args, true);
316 }
317
318 void migration_test_add_file(MigrationTestEnv *env)
319 {
320 tmpfs = env->tmpfs;
321
322 migration_test_add_file_smoke(env);
323
324 if (!env->full_set) {
325 return;
326 }
327
328 migration_test_add("/migration/precopy/file/offset",
329 test_precopy_file_offset);
330 #ifndef _WIN32
331 migration_test_add("/migration/precopy/file/offset/fdset",
332 test_precopy_file_offset_fdset);
333 #endif
334 migration_test_add("/migration/precopy/file/offset/bad",
335 test_precopy_file_offset_bad);
336
337 migration_test_add("/migration/precopy/file/connect-outgoing-fd-leak",
338 test_file_connect_outgoing_fd_leak);
339
340 migration_test_add("/migration/precopy/file/mapped-ram",
341 test_precopy_file_mapped_ram);
342 migration_test_add("/migration/precopy/file/mapped-ram/live",
343 test_precopy_file_mapped_ram_live);
344
345 migration_test_add("/migration/multifd/file/mapped-ram",
346 test_multifd_file_mapped_ram);
347 migration_test_add("/migration/multifd/file/mapped-ram/ignore-shared",
348 test_precopy_file_mapped_ram_ignore_shared);
349 migration_test_add("/migration/multifd/file/mapped-ram/live",
350 test_multifd_file_mapped_ram_live);
351
352 if (env->has_uffd) {
353 migration_test_add("/migration/postcopy/file/mapped-ram",
354 test_postcopy_file_mapped_ram);
355 }
356
357 #ifndef _WIN32
358 migration_test_add("/migration/multifd/file/mapped-ram/fdset",
359 test_multifd_file_mapped_ram_fdset);
360 migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
361 test_multifd_file_mapped_ram_fdset_dio);
362 #endif
363 }