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
test_precopy_file(void)23 static void test_precopy_file(void)
24 {
25 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
26 FILE_TEST_FILENAME);
27 MigrateCommon args = {
28 .connect_uri = uri,
29 .listen_uri = "defer",
30 };
31
32 test_file_common(&args, true);
33 }
34
35 #ifndef _WIN32
fdset_add_fds(QTestState * qts,const char * file,int flags,int num_fds,bool direct_io)36 static void fdset_add_fds(QTestState *qts, const char *file, int flags,
37 int num_fds, bool direct_io)
38 {
39 for (int i = 0; i < num_fds; i++) {
40 int fd;
41
42 #ifdef O_DIRECT
43 /* only secondary channels can use direct-io */
44 if (direct_io && i != 0) {
45 flags |= O_DIRECT;
46 }
47 #endif
48
49 fd = open(file, flags, 0660);
50 assert(fd != -1);
51
52 qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', "
53 "'arguments': {'fdset-id': 1}}");
54 close(fd);
55 }
56 }
57
migrate_hook_start_file_offset_fdset(QTestState * from,QTestState * to)58 static void *migrate_hook_start_file_offset_fdset(QTestState *from,
59 QTestState *to)
60 {
61 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
62
63 fdset_add_fds(from, file, O_WRONLY, 1, false);
64 fdset_add_fds(to, file, O_RDONLY, 1, false);
65
66 return NULL;
67 }
68
test_precopy_file_offset_fdset(void)69 static void test_precopy_file_offset_fdset(void)
70 {
71 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
72 FILE_TEST_OFFSET);
73 MigrateCommon args = {
74 .connect_uri = uri,
75 .listen_uri = "defer",
76 .start_hook = migrate_hook_start_file_offset_fdset,
77 };
78
79 test_file_common(&args, false);
80 }
81 #endif
82
test_precopy_file_offset(void)83 static void test_precopy_file_offset(void)
84 {
85 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
86 FILE_TEST_FILENAME,
87 FILE_TEST_OFFSET);
88 MigrateCommon args = {
89 .connect_uri = uri,
90 .listen_uri = "defer",
91 };
92
93 test_file_common(&args, false);
94 }
95
test_precopy_file_offset_bad(void)96 static void test_precopy_file_offset_bad(void)
97 {
98 /* using a value not supported by qemu_strtosz() */
99 g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
100 tmpfs, FILE_TEST_FILENAME);
101 MigrateCommon args = {
102 .connect_uri = uri,
103 .listen_uri = "defer",
104 .result = MIG_TEST_QMP_ERROR,
105 };
106
107 test_file_common(&args, false);
108 }
109
test_precopy_file_mapped_ram_live(void)110 static void test_precopy_file_mapped_ram_live(void)
111 {
112 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
113 FILE_TEST_FILENAME);
114 MigrateCommon args = {
115 .connect_uri = uri,
116 .listen_uri = "defer",
117 .start = {
118 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
119 },
120 };
121
122 test_file_common(&args, false);
123 }
124
test_precopy_file_mapped_ram(void)125 static void test_precopy_file_mapped_ram(void)
126 {
127 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
128 FILE_TEST_FILENAME);
129 MigrateCommon args = {
130 .connect_uri = uri,
131 .listen_uri = "defer",
132 .start = {
133 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
134 },
135 };
136
137 test_file_common(&args, true);
138 }
139
test_multifd_file_mapped_ram_live(void)140 static void test_multifd_file_mapped_ram_live(void)
141 {
142 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
143 FILE_TEST_FILENAME);
144 MigrateCommon args = {
145 .connect_uri = uri,
146 .listen_uri = "defer",
147 .start = {
148 .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
149 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
150 },
151 };
152
153 test_file_common(&args, false);
154 }
155
test_multifd_file_mapped_ram(void)156 static void test_multifd_file_mapped_ram(void)
157 {
158 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
159 FILE_TEST_FILENAME);
160 MigrateCommon args = {
161 .connect_uri = uri,
162 .listen_uri = "defer",
163 .start = {
164 .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
165 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
166 },
167 };
168
169 test_file_common(&args, true);
170 }
171
migrate_hook_start_multifd_mapped_ram_dio(QTestState * from,QTestState * to)172 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
173 QTestState *to)
174 {
175 migrate_set_parameter_bool(from, "direct-io", true);
176 migrate_set_parameter_bool(to, "direct-io", true);
177
178 return NULL;
179 }
180
test_multifd_file_mapped_ram_dio(void)181 static void test_multifd_file_mapped_ram_dio(void)
182 {
183 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
184 FILE_TEST_FILENAME);
185 MigrateCommon args = {
186 .connect_uri = uri,
187 .listen_uri = "defer",
188 .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
189 .start = {
190 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
191 .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
192 },
193 };
194
195 if (!probe_o_direct_support(tmpfs)) {
196 g_test_skip("Filesystem does not support O_DIRECT");
197 return;
198 }
199
200 test_file_common(&args, true);
201 }
202
203 #ifndef _WIN32
migrate_hook_end_multifd_mapped_ram_fdset(QTestState * from,QTestState * to,void * opaque)204 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from,
205 QTestState *to,
206 void *opaque)
207 {
208 QDict *resp;
209 QList *fdsets;
210
211 /*
212 * Remove the fdsets after migration, otherwise a second migration
213 * would fail due fdset reuse.
214 */
215 qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
216 "'arguments': { 'fdset-id': 1}}");
217
218 /*
219 * Make sure no fdsets are left after migration, otherwise a
220 * second migration would fail due fdset reuse.
221 */
222 resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
223 "'arguments': {}}");
224 g_assert(qdict_haskey(resp, "return"));
225 fdsets = qdict_get_qlist(resp, "return");
226 g_assert(fdsets && qlist_empty(fdsets));
227 qobject_unref(resp);
228 }
229
migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState * from,QTestState * to)230 static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
231 QTestState *to)
232 {
233 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
234
235 fdset_add_fds(from, file, O_WRONLY, 2, true);
236 fdset_add_fds(to, file, O_RDONLY, 2, true);
237
238 migrate_set_parameter_bool(from, "direct-io", true);
239 migrate_set_parameter_bool(to, "direct-io", true);
240
241 return NULL;
242 }
243
migrate_hook_start_multifd_mapped_ram_fdset(QTestState * from,QTestState * to)244 static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from,
245 QTestState *to)
246 {
247 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
248
249 fdset_add_fds(from, file, O_WRONLY, 2, false);
250 fdset_add_fds(to, file, O_RDONLY, 2, false);
251
252 return NULL;
253 }
254
test_multifd_file_mapped_ram_fdset(void)255 static void test_multifd_file_mapped_ram_fdset(void)
256 {
257 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
258 FILE_TEST_OFFSET);
259 MigrateCommon args = {
260 .connect_uri = uri,
261 .listen_uri = "defer",
262 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
263 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
264 .start = {
265 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
266 .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
267 },
268 };
269
270 test_file_common(&args, true);
271 }
272
test_multifd_file_mapped_ram_fdset_dio(void)273 static void test_multifd_file_mapped_ram_fdset_dio(void)
274 {
275 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
276 FILE_TEST_OFFSET);
277 MigrateCommon args = {
278 .connect_uri = uri,
279 .listen_uri = "defer",
280 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
281 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
282 .start = {
283 .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
284 .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
285 },
286 };
287
288 if (!probe_o_direct_support(tmpfs)) {
289 g_test_skip("Filesystem does not support O_DIRECT");
290 return;
291 }
292
293 test_file_common(&args, true);
294 }
295 #endif /* !_WIN32 */
296
migration_test_add_file_smoke(MigrationTestEnv * env)297 static void migration_test_add_file_smoke(MigrationTestEnv *env)
298 {
299 migration_test_add("/migration/precopy/file",
300 test_precopy_file);
301
302 migration_test_add("/migration/multifd/file/mapped-ram/dio",
303 test_multifd_file_mapped_ram_dio);
304 }
305
migration_test_add_file(MigrationTestEnv * env)306 void migration_test_add_file(MigrationTestEnv *env)
307 {
308 tmpfs = env->tmpfs;
309
310 migration_test_add_file_smoke(env);
311
312 if (!env->full_set) {
313 return;
314 }
315
316 migration_test_add("/migration/precopy/file/offset",
317 test_precopy_file_offset);
318 #ifndef _WIN32
319 migration_test_add("/migration/precopy/file/offset/fdset",
320 test_precopy_file_offset_fdset);
321 #endif
322 migration_test_add("/migration/precopy/file/offset/bad",
323 test_precopy_file_offset_bad);
324
325 migration_test_add("/migration/precopy/file/mapped-ram",
326 test_precopy_file_mapped_ram);
327 migration_test_add("/migration/precopy/file/mapped-ram/live",
328 test_precopy_file_mapped_ram_live);
329
330 migration_test_add("/migration/multifd/file/mapped-ram",
331 test_multifd_file_mapped_ram);
332 migration_test_add("/migration/multifd/file/mapped-ram/live",
333 test_multifd_file_mapped_ram_live);
334
335 #ifndef _WIN32
336 migration_test_add("/migration/multifd/file/mapped-ram/fdset",
337 test_multifd_file_mapped_ram_fdset);
338 migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
339 test_multifd_file_mapped_ram_fdset_dio);
340 #endif
341 }
342