diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.include | 2 | ||||
-rw-r--r-- | tests/e1000e-test.c | 1 | ||||
-rw-r--r-- | tests/i440fx-test.c | 1 | ||||
-rw-r--r-- | tests/ivshmem-test.c | 1 | ||||
-rw-r--r-- | tests/libqtest.c | 2 | ||||
-rw-r--r-- | tests/postcopy-test.c | 453 | ||||
-rw-r--r-- | tests/qemu-iotests/087.out | 12 | ||||
-rwxr-xr-x | tests/qemu-iotests/095 | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/155 | 261 | ||||
-rw-r--r-- | tests/qemu-iotests/155.out | 5 | ||||
-rwxr-xr-x | tests/qemu-iotests/156 | 174 | ||||
-rw-r--r-- | tests/qemu-iotests/156.out | 48 | ||||
-rw-r--r-- | tests/qemu-iotests/README | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 2 | ||||
-rw-r--r-- | tests/qht-bench.c | 1 | ||||
-rw-r--r-- | tests/test-qdist.c | 1 | ||||
-rw-r--r-- | tests/test-qht-par.c | 1 | ||||
-rw-r--r-- | tests/test-qht.c | 1 | ||||
-rw-r--r-- | tests/vhost-user-bridge.c | 1 | ||||
-rw-r--r-- | tests/vhost-user-test.c | 1 |
20 files changed, 952 insertions, 21 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include index 4b4bfa5930..bf620b8dd4 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -234,6 +234,7 @@ endif check-qtest-i386-y += tests/test-netfilter$(EXESUF) check-qtest-i386-y += tests/test-filter-mirror$(EXESUF) check-qtest-i386-y += tests/test-filter-redirector$(EXESUF) +check-qtest-i386-y += tests/postcopy-test$(EXESUF) check-qtest-x86_64-y += $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) @@ -599,6 +600,7 @@ tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y) tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o +tests/postcopy-test$(EXESUF): tests/postcopy-test.o tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y) diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index dbf4859f88..d497b0857c 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" -#include <glib.h> #include "libqtest.h" #include "qemu-common.h" #include "libqos/pci-pc.h" diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index bff999cf12..c1d9b3eb9e 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -13,7 +13,6 @@ */ #include "qemu/osdep.h" -#include <sys/mman.h> #include "libqtest.h" #include "libqos/pci.h" diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index 010860a5b7..0957ee7555 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include <glib/gstdio.h> -#include <sys/mman.h> #include "contrib/ivshmem-server/ivshmem-server.h" #include "libqos/pci-pc.h" #include "libqtest.h" diff --git a/tests/libqtest.c b/tests/libqtest.c index 5c82348265..eb00f1392b 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -26,7 +26,7 @@ #include "qapi/qmp/qjson.h" #define MAX_IRQ 256 -#define SOCKET_TIMEOUT 5 +#define SOCKET_TIMEOUT 50 QTestState *global_qtest; diff --git a/tests/postcopy-test.c b/tests/postcopy-test.c new file mode 100644 index 0000000000..35d5180173 --- /dev/null +++ b/tests/postcopy-test.c @@ -0,0 +1,453 @@ +/* + * QTest testcase for postcopy + * + * Copyright (c) 2016 Red Hat, Inc. and/or its affiliates + * based on the vhost-user-test.c that is: + * Copyright (c) 2014 Virtual Open Systems Sarl. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "libqtest.h" +#include "qemu/option.h" +#include "qemu/range.h" +#include "sysemu/char.h" +#include "sysemu/sysemu.h" + +#include <qemu/sockets.h> + +const unsigned start_address = 1024 * 1024; +const unsigned end_address = 100 * 1024 * 1024; +bool got_stop; + +#if defined(__linux__) +#include <sys/syscall.h> +#include <sys/vfs.h> +#endif + +#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD) +#include <sys/eventfd.h> +#include <sys/ioctl.h> +#include <linux/userfaultfd.h> + +static bool ufd_version_check(void) +{ + struct uffdio_api api_struct; + uint64_t ioctl_mask; + + int ufd = ufd = syscall(__NR_userfaultfd, O_CLOEXEC); + + if (ufd == -1) { + g_test_message("Skipping test: userfaultfd not available"); + return false; + } + + api_struct.api = UFFD_API; + api_struct.features = 0; + if (ioctl(ufd, UFFDIO_API, &api_struct)) { + g_test_message("Skipping test: UFFDIO_API failed"); + return false; + } + + ioctl_mask = (__u64)1 << _UFFDIO_REGISTER | + (__u64)1 << _UFFDIO_UNREGISTER; + if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) { + g_test_message("Skipping test: Missing userfault feature"); + return false; + } + + return true; +} + +#else +static bool ufd_version_check(void) +{ + g_test_message("Skipping test: Userfault not available (builtdtime)"); + return false; +} + +#endif + +static const char *tmpfs; + +/* A simple PC boot sector that modifies memory (1-100MB) quickly + * outputing a 'B' every so often if it's still running. + */ +unsigned char bootsect[] = { + 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00, + 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02, + 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41, + 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10, + 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40, + 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66, + 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa +}; + +/* + * 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(const char *side) +{ + char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); + FILE *serialfile = fopen(serialpath, "r"); + + do { + int readvalue = fgetc(serialfile); + + switch (readvalue) { + case 'A': + /* Fine */ + break; + + case 'B': + /* It's alive! */ + fclose(serialfile); + g_free(serialpath); + return; + + case EOF: + fseek(serialfile, 0, SEEK_SET); + usleep(1000); + break; + + default: + fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side); + g_assert_not_reached(); + } + } while (true); +} + +/* + * Events can get in the way of responses we are actually waiting for. + */ +static QDict *return_or_event(QDict *response) +{ + const char *event_string; + if (!qdict_haskey(response, "event")) { + return response; + } + + /* OK, it was an event */ + event_string = qdict_get_str(response, "event"); + if (!strcmp(event_string, "STOP")) { + got_stop = true; + } + QDECREF(response); + return return_or_event(qtest_qmp_receive(global_qtest)); +} + + +/* + * It's tricky to use qemu's migration event capability with qtest, + * events suddenly appearing confuse the qmp()/hmp() responses. + * so wait for a couple of passes to have happened before + * going postcopy. + */ + +static uint64_t get_migration_pass(void) +{ + QDict *rsp, *rsp_return, *rsp_ram; + uint64_t result; + + rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }")); + rsp_return = qdict_get_qdict(rsp, "return"); + if (!qdict_haskey(rsp_return, "ram")) { + /* Still in setup */ + result = 0; + } else { + rsp_ram = qdict_get_qdict(rsp_return, "ram"); + result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0); + QDECREF(rsp); + } + return result; +} + +static void wait_for_migration_complete(void) +{ + QDict *rsp, *rsp_return; + bool completed; + + do { + const char *status; + + rsp = return_or_event(qmp("{ 'execute': 'query-migrate' }")); + rsp_return = qdict_get_qdict(rsp, "return"); + status = qdict_get_str(rsp_return, "status"); + completed = strcmp(status, "completed") == 0; + g_assert_cmpstr(status, !=, "failed"); + QDECREF(rsp); + usleep(1000 * 100); + } while (!completed); +} + +static void wait_for_migration_pass(void) +{ + uint64_t initial_pass = get_migration_pass(); + uint64_t pass; + + /* Wait for the 1st sync */ + do { + initial_pass = get_migration_pass(); + if (got_stop || initial_pass) { + break; + } + usleep(1000 * 100); + } while (true); + + do { + usleep(1000 * 100); + pass = get_migration_pass(); + } while (pass == initial_pass && !got_stop); +} + +static void check_guests_ram(void) +{ + /* Our ASM test will have been incrementing one byte from each page from + * 1MB to <100MB in order. + * This gives us a constraint that any page's byte should be equal or less + * than the previous pages byte (mod 256); and they should all be equal + * except for one transition at the point where we meet the incrementer. + * (We're running this with the guest stopped). + */ + unsigned address; + uint8_t first_byte; + uint8_t last_byte; + bool hit_edge = false; + bool bad = false; + + qtest_memread(global_qtest, start_address, &first_byte, 1); + last_byte = first_byte; + + for (address = start_address + 4096; address < end_address; address += 4096) + { + uint8_t b; + qtest_memread(global_qtest, address, &b, 1); + if (b != last_byte) { + if (((b + 1) % 256) == last_byte && !hit_edge) { + /* This is OK, the guest stopped at the point of + * incrementing the previous page but didn't get + * to us yet. + */ + hit_edge = true; + } else { + fprintf(stderr, "Memory content inconsistency at %x" + " first_byte = %x last_byte = %x current = %x" + " hit_edge = %x\n", + address, first_byte, last_byte, b, hit_edge); + bad = true; + } + } + last_byte = b; + } + g_assert_false(bad); +} + +static void cleanup(const char *filename) +{ + char *path = g_strdup_printf("%s/%s", tmpfs, filename); + + unlink(path); +} + +static void test_migrate(void) +{ + char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + QTestState *global = global_qtest, *from, *to; + unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d; + gchar *cmd; + QDict *rsp; + + char *bootpath = g_strdup_printf("%s/bootsect", tmpfs); + FILE *bootfile = fopen(bootpath, "wb"); + + got_stop = false; + g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1); + fclose(bootfile); + + cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M" + " -name pcsource,debug-threads=on" + " -serial file:%s/src_serial" + " -drive file=%s,format=raw", + tmpfs, bootpath); + from = qtest_start(cmd); + g_free(cmd); + + cmd = g_strdup_printf("-machine accel=kvm:tcg -m 150M" + " -name pcdest,debug-threads=on" + " -serial file:%s/dest_serial" + " -drive file=%s,format=raw" + " -incoming %s", + tmpfs, bootpath, uri); + to = qtest_init(cmd); + g_free(cmd); + + global_qtest = from; + rsp = qmp("{ 'execute': 'migrate-set-capabilities'," + "'arguments': { " + "'capabilities': [ {" + "'capability': 'postcopy-ram'," + "'state': true } ] } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + global_qtest = to; + rsp = qmp("{ 'execute': 'migrate-set-capabilities'," + "'arguments': { " + "'capabilities': [ {" + "'capability': 'postcopy-ram'," + "'state': true } ] } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + /* We want to pick a speed slow enough that the test completes + * quickly, but that it doesn't complete precopy even on a slow + * machine, so also set the downtime. + */ + global_qtest = from; + rsp = qmp("{ 'execute': 'migrate_set_speed'," + "'arguments': { 'value': 100000000 } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + /* 1ms downtime - it should never finish precopy */ + rsp = qmp("{ 'execute': 'migrate_set_downtime'," + "'arguments': { 'value': 0.001 } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + + /* Wait for the first serial output from the source */ + wait_for_serial("src_serial"); + + cmd = g_strdup_printf("{ 'execute': 'migrate'," + "'arguments': { 'uri': '%s' } }", + uri); + rsp = qmp(cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + wait_for_migration_pass(); + + rsp = return_or_event(qmp("{ 'execute': 'migrate-start-postcopy' }")); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + if (!got_stop) { + qmp_eventwait("STOP"); + } + + global_qtest = to; + qmp_eventwait("RESUME"); + + wait_for_serial("dest_serial"); + global_qtest = from; + wait_for_migration_complete(); + + qtest_quit(from); + + global_qtest = to; + + qtest_memread(to, start_address, &dest_byte_a, 1); + + /* Destination still running, wait for a byte to change */ + do { + qtest_memread(to, start_address, &dest_byte_b, 1); + usleep(10 * 1000); + } while (dest_byte_a == dest_byte_b); + + qmp("{ 'execute' : 'stop'}"); + /* With it stopped, check nothing changes */ + qtest_memread(to, start_address, &dest_byte_c, 1); + sleep(1); + qtest_memread(to, start_address, &dest_byte_d, 1); + g_assert_cmpint(dest_byte_c, ==, dest_byte_d); + + check_guests_ram(); + + qtest_quit(to); + g_free(uri); + + global_qtest = global; + + cleanup("bootsect"); + cleanup("migsocket"); + cleanup("src_serial"); + cleanup("dest_serial"); +} + +int main(int argc, char **argv) +{ + char template[] = "/tmp/postcopy-test-XXXXXX"; + int ret; + + g_test_init(&argc, &argv, NULL); + + if (!ufd_version_check()) { + return 0; + } + + tmpfs = mkdtemp(template); + if (!tmpfs) { + g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno)); + } + g_assert(tmpfs); + + module_call_init(MODULE_INIT_QOM); + + qtest_add_func("/postcopy", test_migrate); + + ret = g_test_run(); + + g_assert_cmpint(ret, ==, 0); + + ret = rmdir(tmpfs); + if (ret != 0) { + g_test_message("unable to rmdir: path (%s): %s\n", + tmpfs, strerror(errno)); + } + + return ret; +} diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index 055c553cdb..a95c4b0be8 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -42,22 +42,14 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION {"return": {}} -IMGFMT built-in AES encryption is deprecated -Support for it will be removed in a future release. -You can use 'qemu-img convert' to switch to an -unencrypted IMGFMT image, or a LUKS raw image. -{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}} +{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} Testing: QMP_VERSION {"return": {}} -IMGFMT built-in AES encryption is deprecated -Support for it will be removed in a future release. -You can use 'qemu-img convert' to switch to an -unencrypted IMGFMT image, or a LUKS raw image. -{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}} +{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 index dad04b9ac9..030adb22e1 100755 --- a/tests/qemu-iotests/095 +++ b/tests/qemu-iotests/095 @@ -74,6 +74,8 @@ _send_qemu_cmd $h "{ 'execute': 'block-commit', 'arguments': { 'device': 'test', 'top': '"${TEST_IMG}.snp1"' } }" "BLOCK_JOB_COMPLETED" +_cleanup_qemu + echo echo "=== Base image info after commit and resize ===" TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 new file mode 100755 index 0000000000..4057b5e2aa --- /dev/null +++ b/tests/qemu-iotests/155 @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# +# Test whether the backing BDSs are correct after completion of a +# mirror block job; in "existing" modes (drive-mirror with +# mode=existing and blockdev-mirror) the backing chain should not be +# overridden. +# +# Copyright (C) 2016 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import iotests +from iotests import qemu_img + +back0_img = os.path.join(iotests.test_dir, 'back0.' + iotests.imgfmt) +back1_img = os.path.join(iotests.test_dir, 'back1.' + iotests.imgfmt) +back2_img = os.path.join(iotests.test_dir, 'back2.' + iotests.imgfmt) +source_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt) +target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt) + + +# Class variables for controlling its behavior: +# +# existing: If True, explicitly create the target image and blockdev-add it +# target_backing: If existing is True: Use this filename as the backing file +# of the target image +# (None: no backing file) +# target_blockdev_backing: If existing is True: Pass this dict as "backing" +# for the blockdev-add command +# (None: do not pass "backing") +# target_real_backing: If existing is True: The real filename of the backing +# image during runtime, only makes sense if +# target_blockdev_backing is not None +# (None: same as target_backing) + +class BaseClass(iotests.QMPTestCase): + target_blockdev_backing = None + target_real_backing = None + + def setUp(self): + qemu_img('create', '-f', iotests.imgfmt, back0_img, '1M') + qemu_img('create', '-f', iotests.imgfmt, '-b', back0_img, back1_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back1_img, back2_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back2_img, source_img) + + self.vm = iotests.VM() + self.vm.add_drive(None, '', 'none') + self.vm.launch() + + # Add the BDS via blockdev-add so it stays around after the mirror block + # job has been completed + result = self.vm.qmp('blockdev-add', + options={'node-name': 'source', + 'driver': iotests.imgfmt, + 'file': {'driver': 'file', + 'filename': source_img}}) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('x-blockdev-insert-medium', + device='drive0', node_name='source') + self.assert_qmp(result, 'return', {}) + + self.assertIntactSourceBackingChain() + + if self.existing: + if self.target_backing: + qemu_img('create', '-f', iotests.imgfmt, + '-b', self.target_backing, target_img, '1M') + else: + qemu_img('create', '-f', iotests.imgfmt, target_img, '1M') + + if self.cmd == 'blockdev-mirror': + options = { 'node-name': 'target', + 'driver': iotests.imgfmt, + 'file': { 'driver': 'file', + 'filename': target_img } } + if self.target_blockdev_backing: + options['backing'] = self.target_blockdev_backing + + result = self.vm.qmp('blockdev-add', options=options) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + self.vm.shutdown() + os.remove(source_img) + os.remove(back2_img) + os.remove(back1_img) + os.remove(back0_img) + try: + os.remove(target_img) + except OSError: + pass + + def findBlockNode(self, node_name, id=None): + if id: + result = self.vm.qmp('query-block') + for device in result['return']: + if device['device'] == id: + if node_name: + self.assert_qmp(device, 'inserted/node-name', node_name) + return device['inserted'] + else: + result = self.vm.qmp('query-named-block-nodes') + for node in result['return']: + if node['node-name'] == node_name: + return node + + self.fail('Cannot find node %s/%s' % (id, node_name)) + + def assertIntactSourceBackingChain(self): + node = self.findBlockNode('source') + + self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename', + source_img) + self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename', + back2_img) + self.assert_qmp(node, 'image' + '/backing-image' * 2 + '/filename', + back1_img) + self.assert_qmp(node, 'image' + '/backing-image' * 3 + '/filename', + back0_img) + self.assert_qmp_absent(node, 'image' + '/backing-image' * 4) + + def assertCorrectBackingImage(self, node, default_image): + if self.existing: + if self.target_real_backing: + image = self.target_real_backing + else: + image = self.target_backing + else: + image = default_image + + if image: + self.assert_qmp(node, 'image/backing-image/filename', image) + else: + self.assert_qmp_absent(node, 'image/backing-image') + + +# Class variables for controlling its behavior: +# +# cmd: Mirroring command to execute, either drive-mirror or blockdev-mirror + +class MirrorBaseClass(BaseClass): + def runMirror(self, sync): + if self.cmd == 'blockdev-mirror': + result = self.vm.qmp(self.cmd, device='drive0', sync=sync, + target='target') + else: + if self.existing: + mode = 'existing' + else: + mode = 'absolute-paths' + result = self.vm.qmp(self.cmd, device='drive0', sync=sync, + target=target_img, format=iotests.imgfmt, + mode=mode, node_name='target') + + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_READY') + + result = self.vm.qmp('block-job-complete', device='drive0') + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_COMPLETED') + + def testFull(self): + self.runMirror('full') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, None) + self.assertIntactSourceBackingChain() + + def testTop(self): + self.runMirror('top') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, back2_img) + self.assertIntactSourceBackingChain() + + def testNone(self): + self.runMirror('none') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, source_img) + self.assertIntactSourceBackingChain() + + +class TestDriveMirrorAbsolutePaths(MirrorBaseClass): + cmd = 'drive-mirror' + existing = False + +class TestDriveMirrorExistingNoBacking(MirrorBaseClass): + cmd = 'drive-mirror' + existing = True + target_backing = None + +class TestDriveMirrorExistingBacking(MirrorBaseClass): + cmd = 'drive-mirror' + existing = True + target_backing = 'null-co://' + +class TestBlockdevMirrorNoBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = None + +class TestBlockdevMirrorBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = 'null-co://' + +class TestBlockdevMirrorForcedBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = None + target_blockdev_backing = { 'driver': 'null-co' } + target_real_backing = 'null-co://' + + +class TestCommit(BaseClass): + existing = False + + def testCommit(self): + result = self.vm.qmp('block-commit', device='drive0', base=back1_img) + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_READY') + + result = self.vm.qmp('block-job-complete', device='drive0') + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_COMPLETED') + + node = self.findBlockNode(None, 'drive0') + self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename', + back1_img) + self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename', + back0_img) + self.assert_qmp_absent(node, 'image' + '/backing-image' * 2 + + '/filename') + + self.assertIntactSourceBackingChain() + + +BaseClass = None +MirrorBaseClass = None + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/155.out b/tests/qemu-iotests/155.out new file mode 100644 index 0000000000..4176bb9402 --- /dev/null +++ b/tests/qemu-iotests/155.out @@ -0,0 +1,5 @@ +................... +---------------------------------------------------------------------- +Ran 19 tests + +OK diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 new file mode 100755 index 0000000000..cc95ff1f98 --- /dev/null +++ b/tests/qemu-iotests/156 @@ -0,0 +1,174 @@ +#!/bin/bash +# +# Tests oVirt-like storage migration: +# - Create snapshot +# - Create target image with (not yet existing) target backing chain +# (i.e. just write the name of a soon-to-be-copied-over backing file into it) +# - drive-mirror the snapshot to the target with mode=existing and sync=top +# - In the meantime, copy the original source files to the destination via +# conventional means (i.e. outside of qemu) +# - Complete the drive-mirror job +# - Delete all source images +# +# Copyright (C) 2016 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 # failure is the default! + +_cleanup() +{ + rm -f "$TEST_IMG{,.target}{,.backing,.overlay}" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 qed +_supported_proto generic +_supported_os Linux + +# Create source disk +TEST_IMG="$TEST_IMG.backing" _make_test_img 1M +_make_test_img -b "$TEST_IMG.backing" 1M + +$QEMU_IO -c 'write -P 1 0 256k' "$TEST_IMG.backing" | _filter_qemu_io +$QEMU_IO -c 'write -P 2 64k 192k' "$TEST_IMG" | _filter_qemu_io + +_launch_qemu -drive if=none,id=source,file="$TEST_IMG" + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +# Create snapshot +TEST_IMG="$TEST_IMG.overlay" _make_test_img -b "$TEST_IMG" 1M +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'source', + 'snapshot-file': '$TEST_IMG.overlay', + 'format': '$IMGFMT', + 'mode': 'existing' } }" \ + 'return' + +# Write something to the snapshot +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"write -P 3 128k 128k\"' } }" \ + 'return' + +# Create target image +TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -b "$TEST_IMG.target" 1M + +# Mirror snapshot +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'drive-mirror', + 'arguments': { 'device': 'source', + 'target': '$TEST_IMG.target.overlay', + 'mode': 'existing', + 'sync': 'top' } }" \ + 'return' + +# Wait for convergence +_send_qemu_cmd $QEMU_HANDLE \ + '' \ + 'BLOCK_JOB_READY' + +# Write some more +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"write -P 4 192k 64k\"' } }" \ + 'return' + +# Copy source backing chain to the target before completing the job +cp "$TEST_IMG.backing" "$TEST_IMG.target.backing" +cp "$TEST_IMG" "$TEST_IMG.target" +$QEMU_IMG rebase -u -b "$TEST_IMG.target.backing" "$TEST_IMG.target" + +# Complete block job +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'block-job-complete', + 'arguments': { 'device': 'source' } }" \ + '' + +_send_qemu_cmd $QEMU_HANDLE \ + '' \ + 'BLOCK_JOB_COMPLETED' + +# Remove the source images +rm -f "$TEST_IMG{,.backing,.overlay}" + +echo + +# Check online disk contents +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 1 0k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 2 64k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 3 128k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 4 192k 64k\"' } }" \ + 'return' + +echo + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'quit' }" \ + 'return' + +wait=1 _cleanup_qemu + +echo + +# Check offline disk contents +$QEMU_IO -c 'read -P 1 0k 64k' \ + -c 'read -P 2 64k 64k' \ + -c 'read -P 3 128k 64k' \ + -c 'read -P 4 192k 64k' \ + "$TEST_IMG.target.overlay" | _filter_qemu_io + +echo + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out new file mode 100644 index 0000000000..3af82ae540 --- /dev/null +++ b/tests/qemu-iotests/156.out @@ -0,0 +1,48 @@ +QA output created by 156 +Formatting 'TEST_DIR/t.IMGFMT.backing', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.backing +wrote 262144/262144 bytes at offset 0 +256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 196608/196608 bytes at offset 65536 +192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +Formatting 'TEST_DIR/t.IMGFMT.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT +{"return": {}} +wrote 131072/131072 bytes at offset 131072 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "source", "len": 131072, "offset": 131072, "speed": 0, "type": "mirror"}} +wrote 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "source", "len": 196608, "offset": 196608, "speed": 0, "type": "mirror"}} + +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} + +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} + +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +*** done diff --git a/tests/qemu-iotests/README b/tests/qemu-iotests/README index 4ccfdd1cc0..6079b401ae 100644 --- a/tests/qemu-iotests/README +++ b/tests/qemu-iotests/README @@ -17,4 +17,5 @@ additional options to test further image formats or I/O methods. * Feedback and patches Please send improvements to the test suite, general feedback or just -reports of failing tests cases to qemu-devel@savannah.nongnu.org. +reports of failing tests cases to qemu-devel@nongnu.org with a CC: +to qemu-block@nongnu.org. diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ab1d76efdf..1c6fcb6018 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -154,3 +154,5 @@ 150 rw auto quick 152 rw auto quick 154 rw auto backing quick +155 rw auto +156 rw auto quick diff --git a/tests/qht-bench.c b/tests/qht-bench.c index ad8efbca95..76360a0cf5 100644 --- a/tests/qht-bench.c +++ b/tests/qht-bench.c @@ -5,7 +5,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include <glib.h> #include "qemu/processor.h" #include "qemu/atomic.h" #include "qemu/qht.h" diff --git a/tests/test-qdist.c b/tests/test-qdist.c index a67f26057e..0298986ac9 100644 --- a/tests/test-qdist.c +++ b/tests/test-qdist.c @@ -5,7 +5,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include <glib.h> #include "qemu/qdist.h" #include <math.h> diff --git a/tests/test-qht-par.c b/tests/test-qht-par.c index f09e004ec6..d8a83caf5c 100644 --- a/tests/test-qht-par.c +++ b/tests/test-qht-par.c @@ -5,7 +5,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include <glib.h> #define TEST_QHT_STRING "tests/qht-bench 1>/dev/null 2>&1 -R -S0.1 -D10000 -N1 " diff --git a/tests/test-qht.c b/tests/test-qht.c index c8eb9305ed..f1d628371d 100644 --- a/tests/test-qht.c +++ b/tests/test-qht.c @@ -5,7 +5,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include <glib.h> #include "qemu/qht.h" #define N 5000 diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 36b3cd8b8c..45fa2b6148 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -33,7 +33,6 @@ #include <sys/socket.h> #include <sys/un.h> #include <sys/unistd.h> -#include <sys/mman.h> #include <sys/eventfd.h> #include <arpa/inet.h> #include <netdb.h> diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 6e3a4c0d57..8b2164b99d 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -17,7 +17,6 @@ #include "sysemu/sysemu.h" #include <linux/vhost.h> -#include <sys/mman.h> #include <sys/vfs.h> #include <qemu/sockets.h> |