tests/qtest/migration: Add a test for mapped-ram with passing of fds
Add a multifd test for mapped-ram with passing of fds into QEMU. This
is how libvirt will consume the feature.
There are a couple of details to the fdset mechanism:
- multifd needs two distinct file descriptors (not duplicated with
dup()) so it can enable O_DIRECT only on the channels that do
aligned IO. The dup() system call creates file descriptors that
share status flags, of which O_DIRECT is one.
- the open() access mode flags used for the fds passed into QEMU need
to match the flags QEMU uses to open the file. Currently O_WRONLY
for src and O_RDONLY for dst.
Note that fdset code goes under _WIN32 because fd passing is not
supported on Windows.
Reviewed-by: Peter Xu <peterx@redhat.com>
[brought back the qmp_remove_fd() call at the end of the tests]
Signed-off-by: Fabiano Rosas <farosas@suse.de>
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 5c41d1b..6207305 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -2104,11 +2104,18 @@
#ifndef _WIN32
static void fdset_add_fds(QTestState *qts, const char *file, int flags,
- int num_fds)
+ int num_fds, bool direct_io)
{
for (int i = 0; i < num_fds; i++) {
int fd;
+#ifdef O_DIRECT
+ /* only secondary channels can use direct-io */
+ if (direct_io && i != 0) {
+ flags |= O_DIRECT;
+ }
+#endif
+
fd = open(file, flags, 0660);
assert(fd != -1);
@@ -2122,8 +2129,8 @@
{
g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
- fdset_add_fds(from, file, O_WRONLY, 1);
- fdset_add_fds(to, file, O_RDONLY, 1);
+ fdset_add_fds(from, file, O_WRONLY, 1, false);
+ fdset_add_fds(to, file, O_RDONLY, 1, false);
return NULL;
}
@@ -2295,6 +2302,91 @@
test_file_common(&args, true);
}
+#ifndef _WIN32
+static void multifd_mapped_ram_fdset_end(QTestState *from, QTestState *to,
+ void *opaque)
+{
+ QDict *resp;
+ QList *fdsets;
+
+ /*
+ * Remove the fdsets after migration, otherwise a second migration
+ * would fail due fdset reuse.
+ */
+ qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
+ "'arguments': { 'fdset-id': 1}}");
+
+ /*
+ * Make sure no fdsets are left after migration, otherwise a
+ * second migration would fail due fdset reuse.
+ */
+ resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
+ "'arguments': {}}");
+ g_assert(qdict_haskey(resp, "return"));
+ fdsets = qdict_get_qlist(resp, "return");
+ g_assert(fdsets && qlist_empty(fdsets));
+}
+
+static void *multifd_mapped_ram_fdset_dio(QTestState *from, QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+
+ fdset_add_fds(from, file, O_WRONLY, 2, true);
+ fdset_add_fds(to, file, O_RDONLY, 2, true);
+
+ migrate_multifd_mapped_ram_start(from, to);
+ migrate_set_parameter_bool(from, "direct-io", true);
+ migrate_set_parameter_bool(to, "direct-io", true);
+
+ return NULL;
+}
+
+static void *multifd_mapped_ram_fdset(QTestState *from, QTestState *to)
+{
+ g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+
+ fdset_add_fds(from, file, O_WRONLY, 2, false);
+ fdset_add_fds(to, file, O_RDONLY, 2, false);
+
+ migrate_multifd_mapped_ram_start(from, to);
+
+ return NULL;
+}
+
+static void test_multifd_file_mapped_ram_fdset(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = multifd_mapped_ram_fdset,
+ .finish_hook = multifd_mapped_ram_fdset_end,
+ };
+
+ test_file_common(&args, true);
+}
+
+static void test_multifd_file_mapped_ram_fdset_dio(void)
+{
+ g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
+ FILE_TEST_OFFSET);
+ MigrateCommon args = {
+ .connect_uri = uri,
+ .listen_uri = "defer",
+ .start_hook = multifd_mapped_ram_fdset_dio,
+ .finish_hook = multifd_mapped_ram_fdset_end,
+ };
+
+ if (!probe_o_direct_support(tmpfs)) {
+ g_test_skip("Filesystem does not support O_DIRECT");
+ return;
+ }
+
+ test_file_common(&args, true);
+}
+#endif /* !_WIN32 */
+
static void test_precopy_tcp_plain(void)
{
MigrateCommon args = {
@@ -3736,6 +3828,13 @@
migration_test_add("/migration/multifd/file/mapped-ram/dio",
test_multifd_file_mapped_ram_dio);
+#ifndef _WIN32
+ migration_test_add("/migration/multifd/file/mapped-ram/fdset",
+ test_multifd_file_mapped_ram_fdset);
+ migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
+ test_multifd_file_mapped_ram_fdset_dio);
+#endif
+
#ifdef CONFIG_GNUTLS
migration_test_add("/migration/precopy/unix/tls/psk",
test_precopy_unix_tls_psk);