From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46869) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awn0L-0006FQ-6W for qemu-devel@nongnu.org; Sun, 01 May 2016 04:45:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1awn07-0001AR-On for qemu-devel@nongnu.org; Sun, 01 May 2016 04:45:23 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41303) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awn07-00014B-G3 for qemu-devel@nongnu.org; Sun, 01 May 2016 04:45:15 -0400 References: <1461941263-9523-1-git-send-email-dgilbert@redhat.com> <1461941263-9523-5-git-send-email-dgilbert@redhat.com> From: Marcel Apfelbaum Message-ID: <5725C206.3020304@redhat.com> Date: Sun, 1 May 2016 11:44:54 +0300 MIME-Version: 1.0 In-Reply-To: <1461941263-9523-5-git-send-email-dgilbert@redhat.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v2 4/5] test: Postcopy List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: "Dr. David Alan Gilbert (git)" , qemu-devel@nongnu.org, quintela@redhat.com, amit.shah@redhat.com Cc: aarcange@redhat.com, den@openvz.org, marcel.a@redhat.com, eblake@redhat.com Hi David, On 04/29/2016 05:47 PM, Dr. David Alan Gilbert (git) wrote: > From: "Dr. David Alan Gilbert" > > This is a postcopy test (x86 only) that actually runs the guest > and checks the memory contents. > > The test runs from an x86 boot block with the hex embedded in the test; > the source for this is: > > ........... > > .code16 > .org 0x7c00 > .file "fill.s" > .text > .globl start > .type start, @function > start: # at 0x7c00 ? > cli > lgdt gdtdesc > mov $1,%eax > mov %eax,%cr0 # Protected mode enable > data32 ljmp $8,$0x7c20 > > .org 0x7c20 > .code32 > # A20 enable - not sure I actually need this > inb $0x92,%al > or $2,%al > outb %al, $0x92 > > # set up DS for the whole of RAM (needed on KVM) > mov $16,%eax > mov %eax,%ds > > mov $65,%ax > mov $0x3f8,%dx > outb %al,%dx > > # bl keeps a counter so we limit the output speed > mov $0, %bl > mainloop: > # Start from 1MB > mov $(1024*1024),%eax > innerloop: > incb (%eax) > add $4096,%eax > cmp $(100*1024*1024),%eax > jl innerloop > > inc %bl > jnz mainloop > > mov $66,%ax > mov $0x3f8,%dx > outb %al,%dx > > jmp mainloop > > # GDT magic from old (GPLv2) Grub startup.S > .p2align 2 /* force 4-byte alignment */ > gdt: > .word 0, 0 > .byte 0, 0, 0, 0 > > /* -- code segment -- > * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present > * type = 32bit code execute/read, DPL = 0 > */ > .word 0xFFFF, 0 > .byte 0, 0x9A, 0xCF, 0 > > /* -- data segment -- > * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present > * type = 32 bit data read/write, DPL = 0 > */ > .word 0xFFFF, 0 > .byte 0, 0x92, 0xCF, 0 > > gdtdesc: > .word 0x27 /* limit */ > .long gdt /* addr */ > > /* I'm a bootable disk */ > .org 0x7dfe > .byte 0x55 > .byte 0xAA > > ........... > > and that can be assembled by the following magic: > as --32 -march=i486 fill.s -o fill.o > objcopy -O binary fill.o fill.boot > dd if=fill.boot of=bootsect bs=256 count=2 skip=124 > xxd -i bootsect > I suppose you can use this a source file and compile it as part of make check, but I am not sure if is worth it. > Signed-off-by: Dr. David Alan Gilbert > --- > tests/Makefile | 2 + > tests/postcopy-test.c | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 457 insertions(+) > create mode 100644 tests/postcopy-test.c > > diff --git a/tests/Makefile b/tests/Makefile > index 9194f18..f356f4a 100644 > --- a/tests/Makefile > +++ b/tests/Makefile > @@ -224,6 +224,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)) > @@ -579,6 +580,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/postcopy-test.c b/tests/postcopy-test.c > new file mode 100644 > index 0000000..3712a50 > --- /dev/null > +++ b/tests/postcopy-test.c > @@ -0,0 +1,455 @@ > +/* > + * 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 > + > +#include "libqtest.h" > +#include "qemu/option.h" > +#include "qemu/range.h" > +#include "sysemu/char.h" > +#include "sysemu/sysemu.h" > + > +#include > +#include > +#include > + > +#if defined(__linux__) > +#include > +#endif > + > +#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD) > +#include > +#include > +#include > + > +const unsigned start_address = 1024 * 1024; > +const unsigned end_address = 100 * 1024 * 1024; > +bool got_stop; > + > +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); > + assert(0); Maybe g_assert_not_reached ? just to be consistent. > + } > + } 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; > + assert(strcmp(status, "failed")); maybe g_assert/g_assert_cmpstr() > + QDECREF(rsp); > + usleep(1000 * 100); > + } while (!completed); > +} It is possible that the migration will not finish (from some reason) ? Do you expect the test runner to stop the test? > + > +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; > + } > + assert(!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; > + assert(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); > + assert(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"; I would not explicitly use /tmp/ > + 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); > + How much time does this test takes? If is too long, maybe we should not run it automatically as part of make check, but using an environment variable. Thanks, Marcel > + 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; > +} >