This will help on next patch to split vcpu-dirty-limit-test.c Signed-off-by: Juan Quintela <quint...@redhat.com> --- tests/qtest/migration-helpers.h | 39 +++++ tests/qtest/migration-helpers.c | 242 +++++++++++++++++++++++++++++ tests/qtest/migration-test.c | 260 -------------------------------- 3 files changed, 281 insertions(+), 260 deletions(-)
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h index 009e250e90..6096ffd82a 100644 --- a/tests/qtest/migration-helpers.h +++ b/tests/qtest/migration-helpers.h @@ -15,6 +15,8 @@ #include "libqtest.h" +extern char *tmpfs; + bool migrate_watch_for_stop(QTestState *who, const char *name, QDict *event, void *opaque); bool migrate_watch_for_resume(QTestState *who, const char *name, @@ -33,4 +35,41 @@ void wait_for_migration_complete(QTestState *who); void wait_for_migration_fail(QTestState *from, bool allow_active); +typedef struct { + QTestState *qs; + /* options for source and target */ + gchar *arch_opts; + gchar *arch_source; + gchar *arch_target; + const gchar *extra_opts; + const gchar *hide_stderr; + gchar *kvm_opts; + const gchar *memory_size; + /* + * name must *not* contain "target" if it is the target of a + * migration. + */ + const gchar *name; + gchar *serial_path; + gchar *shmem_opts; + gchar *shmem_path; + gchar *unix_socket; + gchar *uri; + unsigned start_address; + unsigned end_address; + bool got_event; +} GuestState; + +GuestState *guest_create(const char *name); +void guest_destroy(GuestState *vm); +void guest_realize(GuestState *who); +void guest_use_dirty_ring(GuestState *vm); + +void wait_for_serial(GuestState *vm); + +void bootfile_create(char *dir); +void bootfile_delete(void); + +bool kvm_dirty_ring_supported(void); + #endif /* MIGRATION_HELPERS_H */ diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c index be00c52d00..ffdc689a88 100644 --- a/tests/qtest/migration-helpers.c +++ b/tests/qtest/migration-helpers.c @@ -13,8 +13,23 @@ #include "qemu/osdep.h" #include "qapi/qmp/qjson.h" +#include "tests/migration/migration-test.h" #include "migration-helpers.h" +#if defined(__linux__) +#include <sys/syscall.h> +#include <sys/ioctl.h> +#include <sys/vfs.h> +#endif + +/* For dirty ring test; so far only x86_64 is supported */ +#if defined(__linux__) && defined(HOST_X86_64) +#include "linux/kvm.h" +#endif + +char *tmpfs; +static char *bootpath; + /* * Number of seconds we wait when looking for migration * status changes, to avoid test suite hanging forever @@ -180,3 +195,230 @@ void wait_for_migration_fail(QTestState *from, bool allow_active) g_assert(qdict_get_bool(rsp_return, "running")); qobject_unref(rsp_return); } + +/* The boot file modifies memory area in [start_address, end_address) + * repeatedly. It outputs a 'B' at a fixed rate while it's still running. + */ +#include "tests/migration/i386/a-b-bootblock.h" +#include "tests/migration/aarch64/a-b-kernel.h" +#include "tests/migration/s390x/a-b-bios.h" + +void bootfile_create(char *dir) +{ + const char *arch = qtest_get_arch(); + unsigned char *content; + size_t len; + + bootpath = g_strdup_printf("%s/bootsect", dir); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + /* the assembled x86 boot sector should be exactly one sector large */ + g_assert(sizeof(x86_bootsect) == 512); + content = x86_bootsect; + len = sizeof(x86_bootsect); + } else if (g_str_equal(arch, "s390x")) { + content = s390x_elf; + len = sizeof(s390x_elf); + } else if (strcmp(arch, "ppc64") == 0) { + /* + * sane architectures can be programmed at the boot prompt + */ + return; + } else if (strcmp(arch, "aarch64") == 0) { + content = aarch64_kernel; + len = sizeof(aarch64_kernel); + g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); + } else { + g_assert_not_reached(); + } + + FILE *bootfile = fopen(bootpath, "wb"); + + g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1); + fclose(bootfile); +} + +void bootfile_delete(void) +{ + unlink(bootpath); + g_free(bootpath); + bootpath = NULL; +} + +GuestState *guest_create(const char *name) +{ + GuestState *vm = g_new0(GuestState, 1); + const char *arch = qtest_get_arch(); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + vm->memory_size = "150M"; + vm->arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); + vm->start_address = X86_TEST_MEM_START; + vm->end_address = X86_TEST_MEM_END; + } else if (g_str_equal(arch, "s390x")) { + vm->memory_size = "128M"; + vm->arch_opts = g_strdup_printf("-bios %s", bootpath); + vm->start_address = S390_TEST_MEM_START; + vm->end_address = S390_TEST_MEM_END; + } else if (strcmp(arch, "ppc64") == 0) { + vm->memory_size = "256M"; + vm->start_address = PPC_TEST_MEM_START; + vm->end_address = PPC_TEST_MEM_END; + vm->arch_source = g_strdup_printf( + "-prom-env 'use-nvramrc?=true' -prom-env " + "'nvramrc=hex .\" _\" begin %x %x " + "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " + "until'", vm->end_address, vm->start_address); + vm->arch_opts = g_strdup("-nodefaults -machine vsmt=8"); + } else if (strcmp(arch, "aarch64") == 0) { + vm->memory_size = "150M"; + vm->arch_opts = g_strdup_printf( + "-machine virt,gic-version=max -cpu max -kernel %s", bootpath); + vm->start_address = ARM_TEST_MEM_START; + vm->end_address = ARM_TEST_MEM_END; + } else { + g_assert_not_reached(); + } + + vm->name = name; + vm->serial_path = g_strdup_printf("%s/%s", tmpfs, vm->name); + return vm; +} + +void guest_destroy(GuestState *vm) +{ + qtest_quit(vm->qs); + g_free(vm->arch_opts); + g_free(vm->arch_source); + g_free(vm->arch_target); + g_free(vm->kvm_opts); + unlink(vm->serial_path); + g_free(vm->serial_path); + g_free(vm->shmem_opts); + unlink(vm->shmem_path); + g_free(vm->shmem_path); + if (vm->unix_socket) { + unlink(vm->unix_socket); + g_free(vm->unix_socket); + } + g_free(vm->uri); + g_free(vm); +} + +void guest_realize(GuestState *who) +{ + bool target = false; + if (strncmp(who->name, "target", strlen("target")) == 0) { + target = true; + } + gchar * + cmd = g_strdup_printf("-accel kvm%s -accel tcg " + "-name %s,debug-threads=on " + "-m %s " + "-serial file:%s " + "%s %s " + "%s %s %s %s %s", + who->kvm_opts ? who->kvm_opts : "", + who->name, + who->memory_size, + who->serial_path, + target ? "-incoming" : "", + target ? who->uri ? who->uri : "defer" + : "", + who->arch_opts ? who->arch_opts : "", + target ? who->arch_target ? who->arch_target : "" + : who->arch_source ? who->arch_source : "", + who->shmem_opts ? who->shmem_opts : "", + who->extra_opts ? who->extra_opts : "", + who->hide_stderr ? who->hide_stderr : ""); + who->qs = qtest_init(cmd); + qtest_qmp_set_event_callback(who->qs, + target ? migrate_watch_for_resume + : migrate_watch_for_stop, + &who->got_event); +} + +void guest_use_dirty_ring(GuestState *vm) +{ + g_assert(vm->kvm_opts == NULL); + vm->kvm_opts = g_strdup(",dirty-ring-size=4096"); +} + +/* + * Wait for some output in the serial output file, + * we get an 'A' followed by an endless string of 'B's + * but on the destination we won't have the A. + */ +void wait_for_serial(GuestState *vm) +{ + FILE *serialfile = fopen(vm->serial_path, "r"); + const char *arch = qtest_get_arch(); + /* see serial_path comment on GuestState definition */ + int started = (strstr(vm->serial_path, "target") == NULL && + strcmp(arch, "ppc64") == 0) ? 0 : 1; + + do { + int readvalue = fgetc(serialfile); + + if (!started) { + /* SLOF prints its banner before starting test, + * to ignore it, mark the start of the test with '_', + * ignore all characters until this marker + */ + switch (readvalue) { + case '_': + started = 1; + break; + case EOF: + fseek(serialfile, 0, SEEK_SET); + usleep(1000); + break; + } + continue; + } + switch (readvalue) { + case 'A': + /* Fine */ + break; + + case 'B': + /* It's alive! */ + fclose(serialfile); + return; + + case EOF: + started = (strstr(vm->serial_path, "target") == NULL && + strcmp(arch, "ppc64") == 0) ? 0 : 1; + fseek(serialfile, 0, SEEK_SET); + usleep(1000); + break; + + default: + fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, + vm->serial_path); + g_assert_not_reached(); + } + } while (true); +} + +bool kvm_dirty_ring_supported(void) +{ +#if defined(__linux__) && defined(HOST_X86_64) + int ret, kvm_fd = open("/dev/kvm", O_RDONLY); + + if (kvm_fd < 0) { + return false; + } + + ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING); + close(kvm_fd); + + /* We test with 4096 slots */ + if (ret < 4096) { + return false; + } + + return true; +#else + return false; +#endif +} diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index d8479abb4a..4d3321b7b3 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -35,11 +35,6 @@ # endif /* CONFIG_TASN1 */ #endif /* CONFIG_GNUTLS */ -/* For dirty ring test; so far only x86_64 is supported */ -#if defined(__linux__) && defined(HOST_X86_64) -#include "linux/kvm.h" -#endif - static bool uffd_feature_thread_id; /* @@ -97,181 +92,6 @@ static bool ufd_version_check(void) #endif -static char *tmpfs; -static char *bootpath; - -/* The boot file modifies memory area in [start_address, end_address) - * repeatedly. It outputs a 'B' at a fixed rate while it's still running. - */ -#include "tests/migration/i386/a-b-bootblock.h" -#include "tests/migration/aarch64/a-b-kernel.h" -#include "tests/migration/s390x/a-b-bios.h" - -static void bootfile_create(char *dir) -{ - const char *arch = qtest_get_arch(); - unsigned char *content; - size_t len; - - bootpath = g_strdup_printf("%s/bootsect", dir); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - /* the assembled x86 boot sector should be exactly one sector large */ - g_assert(sizeof(x86_bootsect) == 512); - content = x86_bootsect; - len = sizeof(x86_bootsect); - } else if (g_str_equal(arch, "s390x")) { - content = s390x_elf; - len = sizeof(s390x_elf); - } else if (strcmp(arch, "ppc64") == 0) { - /* - * sane architectures can be programmed at the boot prompt - */ - return; - } else if (strcmp(arch, "aarch64") == 0) { - content = aarch64_kernel; - len = sizeof(aarch64_kernel); - g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); - } else { - g_assert_not_reached(); - } - - FILE *bootfile = fopen(bootpath, "wb"); - - g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1); - fclose(bootfile); -} - -static void bootfile_delete(void) -{ - unlink(bootpath); - g_free(bootpath); - bootpath = NULL; -} - -typedef struct { - QTestState *qs; - /* options for source and target */ - gchar *arch_opts; - gchar *arch_source; - gchar *arch_target; - const gchar *extra_opts; - const gchar *hide_stderr; - gchar *kvm_opts; - const gchar *memory_size; - /* - * name must *not* contain "target" if it is the target of a - * migration. - */ - const gchar *name; - gchar *serial_path; - gchar *shmem_opts; - gchar *shmem_path; - gchar *unix_socket; - gchar *uri; - unsigned start_address; - unsigned end_address; - bool got_event; -} GuestState; - -static GuestState *guest_create(const char *name) -{ - GuestState *vm = g_new0(GuestState, 1); - const char *arch = qtest_get_arch(); - - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - vm->memory_size = "150M"; - vm->arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); - vm->start_address = X86_TEST_MEM_START; - vm->end_address = X86_TEST_MEM_END; - } else if (g_str_equal(arch, "s390x")) { - vm->memory_size = "128M"; - vm->arch_opts = g_strdup_printf("-bios %s", bootpath); - vm->start_address = S390_TEST_MEM_START; - vm->end_address = S390_TEST_MEM_END; - } else if (strcmp(arch, "ppc64") == 0) { - vm->memory_size = "256M"; - vm->start_address = PPC_TEST_MEM_START; - vm->end_address = PPC_TEST_MEM_END; - vm->arch_source = g_strdup_printf( - "-prom-env 'use-nvramrc?=true' -prom-env " - "'nvramrc=hex .\" _\" begin %x %x " - "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " - "until'", vm->end_address, vm->start_address); - vm->arch_opts = g_strdup("-nodefaults -machine vsmt=8"); - } else if (strcmp(arch, "aarch64") == 0) { - vm->memory_size = "150M"; - vm->arch_opts = g_strdup_printf( - "-machine virt,gic-version=max -cpu max -kernel %s", bootpath); - vm->start_address = ARM_TEST_MEM_START; - vm->end_address = ARM_TEST_MEM_END; - } else { - g_assert_not_reached(); - } - - vm->name = name; - vm->serial_path = g_strdup_printf("%s/%s", tmpfs, vm->name); - return vm; -} - -static void guest_destroy(GuestState *vm) -{ - qtest_quit(vm->qs); - g_free(vm->arch_opts); - g_free(vm->arch_source); - g_free(vm->arch_target); - g_free(vm->kvm_opts); - unlink(vm->serial_path); - g_free(vm->serial_path); - g_free(vm->shmem_opts); - unlink(vm->shmem_path); - g_free(vm->shmem_path); - if (vm->unix_socket) { - unlink(vm->unix_socket); - g_free(vm->unix_socket); - } - g_free(vm->uri); - g_free(vm); -} - -static void guest_realize(GuestState *who) -{ - bool target = false; - if (strncmp(who->name, "target", strlen("target")) == 0) { - target = true; - } - gchar * - cmd = g_strdup_printf("-accel kvm%s -accel tcg " - "-name %s,debug-threads=on " - "-m %s " - "-serial file:%s " - "%s %s " - "%s %s %s %s %s", - who->kvm_opts ? who->kvm_opts : "", - who->name, - who->memory_size, - who->serial_path, - target ? "-incoming" : "", - target ? who->uri ? who->uri : "defer" - : "", - who->arch_opts ? who->arch_opts : "", - target ? who->arch_target ? who->arch_target : "" - : who->arch_source ? who->arch_source : "", - who->shmem_opts ? who->shmem_opts : "", - who->extra_opts ? who->extra_opts : "", - who->hide_stderr ? who->hide_stderr : ""); - who->qs = qtest_init(cmd); - qtest_qmp_set_event_callback(who->qs, - target ? migrate_watch_for_resume - : migrate_watch_for_stop, - &who->got_event); -} - -static void guest_use_dirty_ring(GuestState *vm) -{ - g_assert(vm->kvm_opts == NULL); - vm->kvm_opts = g_strdup(",dirty-ring-size=4096"); -} - static void guest_use_shmem(GuestState *vm) { g_assert(vm->shmem_opts == NULL); @@ -324,63 +144,6 @@ static void guest_set_uri(GuestState *vm, const gchar *uri) vm->uri = g_strdup(uri); } -/* - * Wait for some output in the serial output file, - * we get an 'A' followed by an endless string of 'B's - * but on the destination we won't have the A. - */ -static void wait_for_serial(GuestState *vm) -{ - FILE *serialfile = fopen(vm->serial_path, "r"); - const char *arch = qtest_get_arch(); - /* see serial_path comment on GuestState definition */ - int started = (strstr(vm->serial_path, "target") == NULL && - strcmp(arch, "ppc64") == 0) ? 0 : 1; - - do { - int readvalue = fgetc(serialfile); - - if (!started) { - /* SLOF prints its banner before starting test, - * to ignore it, mark the start of the test with '_', - * ignore all characters until this marker - */ - switch (readvalue) { - case '_': - started = 1; - break; - case EOF: - fseek(serialfile, 0, SEEK_SET); - usleep(1000); - break; - } - continue; - } - switch (readvalue) { - case 'A': - /* Fine */ - break; - - case 'B': - /* It's alive! */ - fclose(serialfile); - return; - - case EOF: - started = (strstr(vm->serial_path, "target") == NULL && - strcmp(arch, "ppc64") == 0) ? 0 : 1; - fseek(serialfile, 0, SEEK_SET); - usleep(1000); - break; - - default: - fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, - vm->serial_path); - g_assert_not_reached(); - } - } while (true); -} - /* * It's tricky to use qemu's migration event capability with qtest, * events suddenly appearing confuse the qmp()/hmp() responses. @@ -2615,29 +2378,6 @@ static void test_vcpu_dirty_limit(void) dirtylimit_stop_vm(vm); } -static bool kvm_dirty_ring_supported(void) -{ -#if defined(__linux__) && defined(HOST_X86_64) - int ret, kvm_fd = open("/dev/kvm", O_RDONLY); - - if (kvm_fd < 0) { - return false; - } - - ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING); - close(kvm_fd); - - /* We test with 4096 slots */ - if (ret < 4096) { - return false; - } - - return true; -#else - return false; -#endif -} - static bool shm_supported(void) { if (g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { -- 2.40.1