Run the existing cpr-transfer and cpr-exec tests with a vhost-vsock-pci device attached. There's no guest involved which is driving the device, so here we only test the QEMU side of the handoff, i.e. the vhost FD is preserved, the device ownership is released on the source and re-acquired on the target.
The tests need /dev/vhost-vsock on the host and a kernel supporting VHOST_RESET_OWNER for vhost-vsock, they are skipped otherwise. Signed-off-by: Andrey Drobyshev <[email protected]> --- tests/qtest/migration/cpr-tests.c | 93 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index a5255193101..245ab39f54b 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -19,6 +19,13 @@ #include "qobject/qjson.h" #include "qobject/qlist.h" +#ifdef CONFIG_LINUX +#include <sys/ioctl.h> +#include <linux/vhost.h> +#endif + +/* We expect this CID to be unassigned on the host */ +#define VHOST_VSOCK_TEST_DEV "vhost-vsock-pci,guest-cid=4000000000" static char *tmpfs; @@ -101,14 +108,17 @@ static int test_transfer(MigrateCommon *args, const char *cpr_channel, * migration, and cannot connect synchronously to the monitor, so defer * the target connection. */ -static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer) +static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer, + const char *dev_opts) { g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs); g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs); g_autofree char *uri = g_strdup_printf("unix:%s", mig_path); g_autofree char *opts_target = NULL; - const char *opts = "-machine aux-ram-share=on -nodefaults"; + g_autofree char *opts = g_strdup_printf("-machine aux-ram-share=on " + "-nodefaults %s", + dev_opts ? dev_opts : ""); g_autofree const char *cpr_channel = g_strdup_printf( "cpr,addr.transport=socket,addr.type=unix,addr.path=%s", cpr_path); @@ -154,12 +164,12 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer) static void test_mode_transfer(char *name, MigrateCommon *args) { - test_mode_transfer_common(args, false); + test_mode_transfer_common(args, false, NULL); } static void test_mode_transfer_defer(char *name, MigrateCommon *args) { - test_mode_transfer_common(args, true); + test_mode_transfer_common(args, true, NULL); } static void set_cpr_exec_args(QTestState *who, MigrateCommon *args) @@ -276,20 +286,85 @@ static void *test_mode_exec_start(QTestState *from, QTestState *to) return NULL; } -static void test_mode_exec(char *name, MigrateCommon *args) +static void test_mode_exec_common(MigrateCommon *args, const char *dev_opts) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); + g_autofree char *opts = g_strdup_printf("-machine aux-ram-share=on " + "-nodefaults %s", + dev_opts ? dev_opts : ""); args->uri = uri; args->start_hook = test_mode_exec_start; args->start.only_source = true; - args->start.opts_source = "-machine aux-ram-share=on -nodefaults"; + args->start.opts_source = opts; args->start.mem_type = MEM_TYPE_MEMFD; test_cpr_exec(args); } +static void test_mode_exec(char *name, MigrateCommon *args) +{ + test_mode_exec_common(args, NULL); +} + +/* + * A vhost-vsock device can be handed over across CPR only if the host + * exposes /dev/vhost-vsock and its kernel supports VHOST_RESET_OWNER + * for it. Skip the test otherwise. + */ +static bool vhost_vsock_cpr_check(void) +{ +#ifdef CONFIG_LINUX + bool set_owner, reset_owner; + int fd; + + if (!qtest_has_device("vhost-vsock-pci")) { + g_test_skip("vhost-vsock-pci device is not available"); + return false; + } + + fd = open("/dev/vhost-vsock", O_RDWR); + if (fd < 0) { + g_test_skip("/dev/vhost-vsock is not available"); + return false; + } + + set_owner = ioctl(fd, VHOST_SET_OWNER) == 0; + reset_owner = ioctl(fd, VHOST_RESET_OWNER) == 0; + close(fd); + + if (!set_owner) { + g_test_skip("VHOST_SET_OWNER is not supported for vhost-vsock"); + return false; + } + + if (!reset_owner) { + g_test_skip("VHOST_RESET_OWNER is not supported for vhost-vsock"); + return false; + } + + return true; +#else + g_test_skip("vhost-vsock is Linux only"); + return false; +#endif +} + +static void test_mode_transfer_vhost_vsock(char *name, MigrateCommon *args) +{ + if (vhost_vsock_cpr_check()) { + test_mode_transfer_common(args, false, "-device " VHOST_VSOCK_TEST_DEV); + } +} + +static void test_mode_exec_vhost_vsock(char *name, MigrateCommon *args) +{ + if (vhost_vsock_cpr_check()) { + test_mode_exec_common(args, "-device " VHOST_VSOCK_TEST_DEV); + } +} + /* Snapshots must be refused while a CPR migration mode is set */ static void test_mode_no_snapshot(char *name, MigrateCommon *args) { @@ -348,4 +423,10 @@ void migration_test_add_cpr(MigrationTestEnv *env) test_mode_transfer_defer); migration_test_add("/migration/mode/exec", test_mode_exec); } + + /* The vhost-vsock handoff doesn't need KVM */ + migration_test_add("/migration/mode/transfer/vhost-vsock", + test_mode_transfer_vhost_vsock); + migration_test_add("/migration/mode/exec/vhost-vsock", + test_mode_exec_vhost_vsock); } -- 2.47.1
