xref: /qemu/tests/qtest/migration/file-tests.c (revision d64db833d6e3cbe9ea5f36342480f920f3675cea)
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 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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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