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
migrate_hook_start_mapped_ram(QTestState * from,QTestState * to)110 static void *migrate_hook_start_mapped_ram(QTestState *from,
111 QTestState *to)
112 {
113 migrate_set_capability(from, "mapped-ram", true);
114 migrate_set_capability(to, "mapped-ram", true);
115
116 return NULL;
117 }
118
test_precopy_file_mapped_ram_live(void)119 static void test_precopy_file_mapped_ram_live(void)
120 {
121 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
122 FILE_TEST_FILENAME);
123 MigrateCommon args = {
124 .connect_uri = uri,
125 .listen_uri = "defer",
126 .start_hook = migrate_hook_start_mapped_ram,
127 };
128
129 test_file_common(&args, false);
130 }
131
test_precopy_file_mapped_ram(void)132 static void test_precopy_file_mapped_ram(void)
133 {
134 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
135 FILE_TEST_FILENAME);
136 MigrateCommon args = {
137 .connect_uri = uri,
138 .listen_uri = "defer",
139 .start_hook = migrate_hook_start_mapped_ram,
140 };
141
142 test_file_common(&args, true);
143 }
144
migrate_hook_start_multifd_mapped_ram(QTestState * from,QTestState * to)145 static void *migrate_hook_start_multifd_mapped_ram(QTestState *from,
146 QTestState *to)
147 {
148 migrate_hook_start_mapped_ram(from, to);
149
150 migrate_set_parameter_int(from, "multifd-channels", 4);
151 migrate_set_parameter_int(to, "multifd-channels", 4);
152
153 migrate_set_capability(from, "multifd", true);
154 migrate_set_capability(to, "multifd", true);
155
156 return NULL;
157 }
158
test_multifd_file_mapped_ram_live(void)159 static void test_multifd_file_mapped_ram_live(void)
160 {
161 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
162 FILE_TEST_FILENAME);
163 MigrateCommon args = {
164 .connect_uri = uri,
165 .listen_uri = "defer",
166 .start_hook = migrate_hook_start_multifd_mapped_ram,
167 };
168
169 test_file_common(&args, false);
170 }
171
test_multifd_file_mapped_ram(void)172 static void test_multifd_file_mapped_ram(void)
173 {
174 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
175 FILE_TEST_FILENAME);
176 MigrateCommon args = {
177 .connect_uri = uri,
178 .listen_uri = "defer",
179 .start_hook = migrate_hook_start_multifd_mapped_ram,
180 };
181
182 test_file_common(&args, true);
183 }
184
migrate_hook_start_multifd_mapped_ram_dio(QTestState * from,QTestState * to)185 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
186 QTestState *to)
187 {
188 migrate_hook_start_multifd_mapped_ram(from, to);
189
190 migrate_set_parameter_bool(from, "direct-io", true);
191 migrate_set_parameter_bool(to, "direct-io", true);
192
193 return NULL;
194 }
195
test_multifd_file_mapped_ram_dio(void)196 static void test_multifd_file_mapped_ram_dio(void)
197 {
198 g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
199 FILE_TEST_FILENAME);
200 MigrateCommon args = {
201 .connect_uri = uri,
202 .listen_uri = "defer",
203 .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
204 };
205
206 if (!probe_o_direct_support(tmpfs)) {
207 g_test_skip("Filesystem does not support O_DIRECT");
208 return;
209 }
210
211 test_file_common(&args, true);
212 }
213
214 #ifndef _WIN32
migrate_hook_end_multifd_mapped_ram_fdset(QTestState * from,QTestState * to,void * opaque)215 static void migrate_hook_end_multifd_mapped_ram_fdset(QTestState *from,
216 QTestState *to,
217 void *opaque)
218 {
219 QDict *resp;
220 QList *fdsets;
221
222 /*
223 * Remove the fdsets after migration, otherwise a second migration
224 * would fail due fdset reuse.
225 */
226 qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
227 "'arguments': { 'fdset-id': 1}}");
228
229 /*
230 * Make sure no fdsets are left after migration, otherwise a
231 * second migration would fail due fdset reuse.
232 */
233 resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
234 "'arguments': {}}");
235 g_assert(qdict_haskey(resp, "return"));
236 fdsets = qdict_get_qlist(resp, "return");
237 g_assert(fdsets && qlist_empty(fdsets));
238 qobject_unref(resp);
239 }
240
migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState * from,QTestState * to)241 static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
242 QTestState *to)
243 {
244 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
245
246 fdset_add_fds(from, file, O_WRONLY, 2, true);
247 fdset_add_fds(to, file, O_RDONLY, 2, true);
248
249 migrate_hook_start_multifd_mapped_ram(from, to);
250 migrate_set_parameter_bool(from, "direct-io", true);
251 migrate_set_parameter_bool(to, "direct-io", true);
252
253 return NULL;
254 }
255
migrate_hook_start_multifd_mapped_ram_fdset(QTestState * from,QTestState * to)256 static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from,
257 QTestState *to)
258 {
259 g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
260
261 fdset_add_fds(from, file, O_WRONLY, 2, false);
262 fdset_add_fds(to, file, O_RDONLY, 2, false);
263
264 migrate_hook_start_multifd_mapped_ram(from, to);
265
266 return NULL;
267 }
268
test_multifd_file_mapped_ram_fdset(void)269 static void test_multifd_file_mapped_ram_fdset(void)
270 {
271 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
272 FILE_TEST_OFFSET);
273 MigrateCommon args = {
274 .connect_uri = uri,
275 .listen_uri = "defer",
276 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
277 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
278 };
279
280 test_file_common(&args, true);
281 }
282
test_multifd_file_mapped_ram_fdset_dio(void)283 static void test_multifd_file_mapped_ram_fdset_dio(void)
284 {
285 g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
286 FILE_TEST_OFFSET);
287 MigrateCommon args = {
288 .connect_uri = uri,
289 .listen_uri = "defer",
290 .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
291 .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
292 };
293
294 if (!probe_o_direct_support(tmpfs)) {
295 g_test_skip("Filesystem does not support O_DIRECT");
296 return;
297 }
298
299 test_file_common(&args, true);
300 }
301 #endif /* !_WIN32 */
302
migration_test_add_file_smoke(MigrationTestEnv * env)303 static void migration_test_add_file_smoke(MigrationTestEnv *env)
304 {
305 migration_test_add("/migration/precopy/file",
306 test_precopy_file);
307
308 migration_test_add("/migration/multifd/file/mapped-ram/dio",
309 test_multifd_file_mapped_ram_dio);
310 }
311
migration_test_add_file(MigrationTestEnv * env)312 void migration_test_add_file(MigrationTestEnv *env)
313 {
314 tmpfs = env->tmpfs;
315
316 migration_test_add_file_smoke(env);
317
318 if (!env->full_set) {
319 return;
320 }
321
322 migration_test_add("/migration/precopy/file/offset",
323 test_precopy_file_offset);
324 #ifndef _WIN32
325 migration_test_add("/migration/precopy/file/offset/fdset",
326 test_precopy_file_offset_fdset);
327 #endif
328 migration_test_add("/migration/precopy/file/offset/bad",
329 test_precopy_file_offset_bad);
330
331 migration_test_add("/migration/precopy/file/mapped-ram",
332 test_precopy_file_mapped_ram);
333 migration_test_add("/migration/precopy/file/mapped-ram/live",
334 test_precopy_file_mapped_ram_live);
335
336 migration_test_add("/migration/multifd/file/mapped-ram",
337 test_multifd_file_mapped_ram);
338 migration_test_add("/migration/multifd/file/mapped-ram/live",
339 test_multifd_file_mapped_ram_live);
340
341 #ifndef _WIN32
342 migration_test_add("/migration/multifd/file/mapped-ram/fdset",
343 test_multifd_file_mapped_ram_fdset);
344 migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
345 test_multifd_file_mapped_ram_fdset_dio);
346 #endif
347 }
348