summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include4
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py12
-rw-r--r--tests/benchmark-crypto-cipher.c12
-rw-r--r--tests/benchmark-crypto-hash.c4
-rw-r--r--tests/benchmark-crypto-hmac.c7
-rw-r--r--tests/check-qom-interface.c11
-rw-r--r--tests/check-qom-proplist.c16
-rw-r--r--tests/meson.build3
-rw-r--r--tests/plugin/hotblocks.c145
-rw-r--r--tests/plugin/hotpages.c193
-rw-r--r--tests/plugin/howvec.c362
-rw-r--r--tests/plugin/lockstep.c340
-rw-r--r--tests/plugin/meson.build4
-rwxr-xr-xtests/qemu-iotests/02044
-rw-r--r--tests/qemu-iotests/020.out10
-rwxr-xr-xtests/qemu-iotests/040238
-rw-r--r--tests/qemu-iotests/040.out4
-rwxr-xr-xtests/qemu-iotests/041146
-rw-r--r--tests/qemu-iotests/041.out4
-rwxr-xr-xtests/qemu-iotests/0494
-rw-r--r--tests/qemu-iotests/049.out5
-rw-r--r--tests/qemu-iotests/153.out2
-rwxr-xr-xtests/qemu-iotests/1843
-rw-r--r--tests/qemu-iotests/184.out14
-rw-r--r--tests/qemu-iotests/204.out1
-rwxr-xr-xtests/qemu-iotests/2286
-rw-r--r--tests/qemu-iotests/228.out6
-rwxr-xr-xtests/qemu-iotests/24449
-rw-r--r--tests/qemu-iotests/244.out7
-rwxr-xr-xtests/qemu-iotests/2454
-rw-r--r--tests/qemu-iotests/273.out4
-rwxr-xr-xtests/qemu-iotests/check2
-rw-r--r--tests/qemu-iotests/iotests.py10
-rw-r--r--tests/requirements.txt2
-rw-r--r--tests/tcg/Makefile.target3
-rw-r--r--tests/test-qdev-global-props.c13
-rw-r--r--tests/test-vmstate.c3
37 files changed, 593 insertions, 1104 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index f93e611220..40d909badc 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -50,7 +50,7 @@ RUN_TCG_TARGET_RULES=$(patsubst %,run-tcg-tests-%, $(TARGET_DIRS))
 $(foreach PROBE_TARGET,$(TARGET_DIRS), 				\
 	$(eval -include $(SRC_PATH)/tests/tcg/Makefile.prereqs))
 
-build-tcg-tests-%: $(if $(CONFIG_PLUGIN),plugins)
+build-tcg-tests-%: $(if $(CONFIG_PLUGIN),test-plugins)
 	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) \
 		-f $(SRC_PATH)/tests/tcg/Makefile.qemu \
 		SRC_PATH=$(SRC_PATH) \
@@ -127,7 +127,7 @@ check-acceptance: check-venv $(TESTS_RESULTS_DIR) get-vm-images
             --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \
             --filter-by-tags-include-empty --filter-by-tags-include-empty-key \
             $(AVOCADO_TAGS) \
-            $(if $(GITLAB_CI),,--failfast=on) tests/acceptance, \
+            $(if $(GITLAB_CI),,--failfast) tests/acceptance, \
             "AVOCADO", "tests/acceptance")
 
 # Consolidated targets
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index db9c0f5d79..4cda037187 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -192,3 +192,15 @@ class Test(avocado.Test):
     def tearDown(self):
         for vm in self._vms.values():
             vm.shutdown()
+
+    def fetch_asset(self, name,
+                    asset_hash=None, algorithm=None,
+                    locations=None, expire=None,
+                    find_only=False, cancel_on_missing=True):
+        return super(Test, self).fetch_asset(name,
+                        asset_hash=asset_hash,
+                        algorithm=algorithm,
+                        locations=locations,
+                        expire=expire,
+                        find_only=find_only,
+                        cancel_on_missing=cancel_on_missing)
diff --git a/tests/benchmark-crypto-cipher.c b/tests/benchmark-crypto-cipher.c
index 1936aa4ae0..c04f0a0fba 100644
--- a/tests/benchmark-crypto-cipher.c
+++ b/tests/benchmark-crypto-cipher.c
@@ -70,8 +70,10 @@ static void test_cipher_speed(size_t chunk_size,
     }
     g_test_timer_elapsed();
 
-    g_test_message("Enc chunk %zu bytes ", chunk_size);
-    g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
+    g_test_message("enc(%s-%s) chunk %zu bytes %.2f MB/sec ",
+                   QCryptoCipherAlgorithm_str(alg),
+                   QCryptoCipherMode_str(mode),
+                   chunk_size, (double)total / MiB / g_test_timer_last());
 
     g_test_timer_start();
     remain = total;
@@ -85,8 +87,10 @@ static void test_cipher_speed(size_t chunk_size,
     }
     g_test_timer_elapsed();
 
-    g_test_message("Dec chunk %zu bytes ", chunk_size);
-    g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
+    g_test_message("dec(%s-%s) chunk %zu bytes %.2f MB/sec ",
+                   QCryptoCipherAlgorithm_str(alg),
+                   QCryptoCipherMode_str(mode),
+                   chunk_size, (double)total / MiB / g_test_timer_last());
 
     qcrypto_cipher_free(cipher);
     g_free(plaintext);
diff --git a/tests/benchmark-crypto-hash.c b/tests/benchmark-crypto-hash.c
index 598111e75a..927b00bb4d 100644
--- a/tests/benchmark-crypto-hash.c
+++ b/tests/benchmark-crypto-hash.c
@@ -48,7 +48,9 @@ static void test_hash_speed(const void *opaque)
     }
     g_test_timer_elapsed();
 
-    g_test_message("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
+    g_test_message("hash(%s): chunk %zu bytes %.2f MB/sec",
+                   QCryptoHashAlgorithm_str(opts->alg),
+                   opts->chunk_size, total / g_test_timer_last());
 
     g_free(out);
     g_free(in);
diff --git a/tests/benchmark-crypto-hmac.c b/tests/benchmark-crypto-hmac.c
index f9fa22df95..5cca636789 100644
--- a/tests/benchmark-crypto-hmac.c
+++ b/tests/benchmark-crypto-hmac.c
@@ -55,10 +55,9 @@ static void test_hmac_speed(const void *opaque)
     } while (g_test_timer_elapsed() < 5.0);
 
     total /= MiB;
-    g_test_message("hmac(sha256): ");
-    g_test_message("Testing chunk_size %zu bytes ", chunk_size);
-    g_test_message("done: %.2f MB in %.2f secs: ", total, g_test_timer_last());
-    g_test_message("%.2f MB/sec\n", total / g_test_timer_last());
+    g_test_message("hmac(%s): chunk %zu bytes %.2f MB/sec",
+                   QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_SHA256),
+                   chunk_size, total / g_test_timer_last());
 
     g_free(out);
     g_free(in);
diff --git a/tests/check-qom-interface.c b/tests/check-qom-interface.c
index 2177f0dce5..c99be97ed8 100644
--- a/tests/check-qom-interface.c
+++ b/tests/check-qom-interface.c
@@ -16,20 +16,19 @@
 
 
 #define TYPE_TEST_IF "test-interface"
-#define TEST_IF_CLASS(klass) \
-     OBJECT_CLASS_CHECK(TestIfClass, (klass), TYPE_TEST_IF)
-#define TEST_IF_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(TestIfClass, (obj), TYPE_TEST_IF)
+typedef struct TestIfClass TestIfClass;
+DECLARE_CLASS_CHECKERS(TestIfClass, TEST_IF,
+                       TYPE_TEST_IF)
 #define TEST_IF(obj) \
      INTERFACE_CHECK(TestIf, (obj), TYPE_TEST_IF)
 
 typedef struct TestIf TestIf;
 
-typedef struct TestIfClass {
+struct TestIfClass {
     InterfaceClass parent_class;
 
     uint32_t test;
-} TestIfClass;
+};
 
 static const TypeInfo test_if_info = {
     .name          = TYPE_TEST_IF,
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index e1e0a96661..1571606c1c 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -33,8 +33,8 @@
 typedef struct DummyObject DummyObject;
 typedef struct DummyObjectClass DummyObjectClass;
 
-#define DUMMY_OBJECT(obj)                               \
-    OBJECT_CHECK(DummyObject, (obj), TYPE_DUMMY)
+DECLARE_INSTANCE_CHECKER(DummyObject, DUMMY_OBJECT,
+                         TYPE_DUMMY)
 
 typedef enum DummyAnimal DummyAnimal;
 
@@ -196,12 +196,12 @@ typedef struct DummyBackendClass DummyBackendClass;
 #define TYPE_DUMMY_BUS "qemu-dummy-bus"
 #define TYPE_DUMMY_BACKEND "qemu-dummy-backend"
 
-#define DUMMY_DEV(obj)                               \
-    OBJECT_CHECK(DummyDev, (obj), TYPE_DUMMY_DEV)
-#define DUMMY_BUS(obj)                               \
-    OBJECT_CHECK(DummyBus, (obj), TYPE_DUMMY_BUS)
-#define DUMMY_BACKEND(obj)                               \
-    OBJECT_CHECK(DummyBackend, (obj), TYPE_DUMMY_BACKEND)
+DECLARE_INSTANCE_CHECKER(DummyDev, DUMMY_DEV,
+                         TYPE_DUMMY_DEV)
+DECLARE_INSTANCE_CHECKER(DummyBus, DUMMY_BUS,
+                         TYPE_DUMMY_BUS)
+DECLARE_INSTANCE_CHECKER(DummyBackend, DUMMY_BACKEND,
+                         TYPE_DUMMY_BACKEND)
 
 struct DummyDev {
     Object parent_obj;
diff --git a/tests/meson.build b/tests/meson.build
index 998e4c48f9..dae8a77df1 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -259,8 +259,9 @@ test('decodetree', sh,
      workdir: meson.current_source_dir() / 'decode',
      suite: 'decodetree')
 
+subdir('fp')
+
 if 'CONFIG_TCG' in config_host
-  subdir('fp')
   if 'CONFIG_PLUGIN' in config_host
     subdir('plugin')
   endif
diff --git a/tests/plugin/hotblocks.c b/tests/plugin/hotblocks.c
deleted file mode 100644
index 3942a2ca54..0000000000
--- a/tests/plugin/hotblocks.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
- *
- * License: GNU GPL, version 2 or later.
- *   See the COPYING file in the top-level directory.
- */
-#include <inttypes.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <glib.h>
-
-#include <qemu-plugin.h>
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-
-static bool do_inline;
-
-/* Plugins need to take care of their own locking */
-static GMutex lock;
-static GHashTable *hotblocks;
-static guint64 limit = 20;
-
-/*
- * Counting Structure
- *
- * The internals of the TCG are not exposed to plugins so we can only
- * get the starting PC for each block. We cheat this slightly by
- * xor'ing the number of instructions to the hash to help
- * differentiate.
- */
-typedef struct {
-    uint64_t start_addr;
-    uint64_t exec_count;
-    int      trans_count;
-    unsigned long insns;
-} ExecCount;
-
-static gint cmp_exec_count(gconstpointer a, gconstpointer b)
-{
-    ExecCount *ea = (ExecCount *) a;
-    ExecCount *eb = (ExecCount *) b;
-    return ea->exec_count > eb->exec_count ? -1 : 1;
-}
-
-static void plugin_exit(qemu_plugin_id_t id, void *p)
-{
-    g_autoptr(GString) report = g_string_new("collected ");
-    GList *counts, *it;
-    int i;
-
-    g_mutex_lock(&lock);
-    g_string_append_printf(report, "%d entries in the hash table\n",
-                           g_hash_table_size(hotblocks));
-    counts = g_hash_table_get_values(hotblocks);
-    it = g_list_sort(counts, cmp_exec_count);
-
-    if (it) {
-        g_string_append_printf(report, "pc, tcount, icount, ecount\n");
-
-        for (i = 0; i < limit && it->next; i++, it = it->next) {
-            ExecCount *rec = (ExecCount *) it->data;
-            g_string_append_printf(report, "%#016"PRIx64", %d, %ld, %"PRId64"\n",
-                                   rec->start_addr, rec->trans_count,
-                                   rec->insns, rec->exec_count);
-        }
-
-        g_list_free(it);
-        g_mutex_unlock(&lock);
-    }
-
-    qemu_plugin_outs(report->str);
-}
-
-static void plugin_init(void)
-{
-    hotblocks = g_hash_table_new(NULL, g_direct_equal);
-}
-
-static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
-{
-    ExecCount *cnt;
-    uint64_t hash = (uint64_t) udata;
-
-    g_mutex_lock(&lock);
-    cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
-    /* should always succeed */
-    g_assert(cnt);
-    cnt->exec_count++;
-    g_mutex_unlock(&lock);
-}
-
-/*
- * When do_inline we ask the plugin to increment the counter for us.
- * Otherwise a helper is inserted which calls the vcpu_tb_exec
- * callback.
- */
-static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
-{
-    ExecCount *cnt;
-    uint64_t pc = qemu_plugin_tb_vaddr(tb);
-    unsigned long insns = qemu_plugin_tb_n_insns(tb);
-    uint64_t hash = pc ^ insns;
-
-    g_mutex_lock(&lock);
-    cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
-    if (cnt) {
-        cnt->trans_count++;
-    } else {
-        cnt = g_new0(ExecCount, 1);
-        cnt->start_addr = pc;
-        cnt->trans_count = 1;
-        cnt->insns = insns;
-        g_hash_table_insert(hotblocks, (gpointer) hash, (gpointer) cnt);
-    }
-
-    g_mutex_unlock(&lock);
-
-    if (do_inline) {
-        qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64,
-                                                 &cnt->exec_count, 1);
-    } else {
-        qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
-                                             QEMU_PLUGIN_CB_NO_REGS,
-                                             (void *)hash);
-    }
-}
-
-QEMU_PLUGIN_EXPORT
-int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
-                        int argc, char **argv)
-{
-    if (argc && strcmp(argv[0], "inline") == 0) {
-        do_inline = true;
-    }
-
-    plugin_init();
-
-    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
-    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
-    return 0;
-}
diff --git a/tests/plugin/hotpages.c b/tests/plugin/hotpages.c
deleted file mode 100644
index ecd6c18732..0000000000
--- a/tests/plugin/hotpages.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
- *
- * Hot Pages - show which pages saw the most memory accesses.
- *
- * License: GNU GPL, version 2 or later.
- *   See the COPYING file in the top-level directory.
- */
-
-#include <inttypes.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <glib.h>
-
-#include <qemu-plugin.h>
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-static uint64_t page_size = 4096;
-static uint64_t page_mask;
-static int limit = 50;
-static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
-static bool track_io;
-
-enum sort_type {
-    SORT_RW = 0,
-    SORT_R,
-    SORT_W,
-    SORT_A
-};
-
-static int sort_by = SORT_RW;
-
-typedef struct {
-    uint64_t page_address;
-    int cpu_read;
-    int cpu_write;
-    uint64_t reads;
-    uint64_t writes;
-} PageCounters;
-
-static GMutex lock;
-static GHashTable *pages;
-
-static gint cmp_access_count(gconstpointer a, gconstpointer b)
-{
-    PageCounters *ea = (PageCounters *) a;
-    PageCounters *eb = (PageCounters *) b;
-    int r;
-    switch (sort_by) {
-    case SORT_RW:
-        r = (ea->reads + ea->writes) > (eb->reads + eb->writes) ? -1 : 1;
-        break;
-    case SORT_R:
-        r = ea->reads > eb->reads ? -1 : 1;
-        break;
-    case SORT_W:
-        r = ea->writes > eb->writes ? -1 : 1;
-        break;
-    case SORT_A:
-        r = ea->page_address > eb->page_address ? -1 : 1;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    return r;
-}
-
-
-static void plugin_exit(qemu_plugin_id_t id, void *p)
-{
-    g_autoptr(GString) report = g_string_new("Addr, RCPUs, Reads, WCPUs, Writes\n");
-    int i;
-    GList *counts;
-
-    counts = g_hash_table_get_values(pages);
-    if (counts && g_list_next(counts)) {
-        GList *it;
-
-        it = g_list_sort(counts, cmp_access_count);
-
-        for (i = 0; i < limit && it->next; i++, it = it->next) {
-            PageCounters *rec = (PageCounters *) it->data;
-            g_string_append_printf(report,
-                                   "%#016"PRIx64", 0x%04x, %"PRId64
-                                   ", 0x%04x, %"PRId64"\n",
-                                   rec->page_address,
-                                   rec->cpu_read, rec->reads,
-                                   rec->cpu_write, rec->writes);
-        }
-        g_list_free(it);
-    }
-
-    qemu_plugin_outs(report->str);
-}
-
-static void plugin_init(void)
-{
-    page_mask = (page_size - 1);
-    pages = g_hash_table_new(NULL, g_direct_equal);
-}
-
-static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
-                       uint64_t vaddr, void *udata)
-{
-    struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
-    uint64_t page;
-    PageCounters *count;
-
-    /* We only get a hwaddr for system emulation */
-    if (track_io) {
-        if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) {
-            page = vaddr;
-        } else {
-            return;
-        }
-    } else {
-        if (hwaddr && !qemu_plugin_hwaddr_is_io(hwaddr)) {
-            page = (uint64_t) qemu_plugin_hwaddr_device_offset(hwaddr);
-        } else {
-            page = vaddr;
-        }
-    }
-    page &= ~page_mask;
-
-    g_mutex_lock(&lock);
-    count = (PageCounters *) g_hash_table_lookup(pages, GUINT_TO_POINTER(page));
-
-    if (!count) {
-        count = g_new0(PageCounters, 1);
-        count->page_address = page;
-        g_hash_table_insert(pages, GUINT_TO_POINTER(page), (gpointer) count);
-    }
-    if (qemu_plugin_mem_is_store(meminfo)) {
-        count->writes++;
-        count->cpu_write |= (1 << cpu_index);
-    } else {
-        count->reads++;
-        count->cpu_read |= (1 << cpu_index);
-    }
-
-    g_mutex_unlock(&lock);
-}
-
-static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
-{
-    size_t n = qemu_plugin_tb_n_insns(tb);
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
-        qemu_plugin_register_vcpu_mem_cb(insn, vcpu_haddr,
-                                         QEMU_PLUGIN_CB_NO_REGS,
-                                         rw, NULL);
-    }
-}
-
-QEMU_PLUGIN_EXPORT
-int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
-                        int argc, char **argv)
-{
-    int i;
-
-    for (i = 0; i < argc; i++) {
-        char *opt = argv[i];
-        if (g_strcmp0(opt, "reads") == 0) {
-            sort_by = SORT_R;
-        } else if (g_strcmp0(opt, "writes") == 0) {
-            sort_by = SORT_W;
-        } else if (g_strcmp0(opt, "address") == 0) {
-            sort_by = SORT_A;
-        } else if (g_strcmp0(opt, "io") == 0) {
-            track_io = true;
-        } else if (g_str_has_prefix(opt, "pagesize=")) {
-            page_size = g_ascii_strtoull(opt + 9, NULL, 10);
-        } else {
-            fprintf(stderr, "option parsing failed: %s\n", opt);
-            return -1;
-        }
-    }
-
-    plugin_init();
-
-    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
-    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
-    return 0;
-}
diff --git a/tests/plugin/howvec.c b/tests/plugin/howvec.c
deleted file mode 100644
index 3b9a6939f2..0000000000
--- a/tests/plugin/howvec.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2019, Alex Bennée <alex.bennee@linaro.org>
- *
- * How vectorised is this code?
- *
- * Attempt to measure the amount of vectorisation that has been done
- * on some code by counting classes of instruction.
- *
- * License: GNU GPL, version 2 or later.
- *   See the COPYING file in the top-level directory.
- */
-#include <inttypes.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <glib.h>
-
-#include <qemu-plugin.h>
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-typedef enum {
-    COUNT_CLASS,
-    COUNT_INDIVIDUAL,
-    COUNT_NONE
-} CountType;
-
-static int limit = 50;
-static bool do_inline;
-static bool verbose;
-
-static GMutex lock;
-static GHashTable *insns;
-
-typedef struct {
-    const char *class;
-    const char *opt;
-    uint32_t mask;
-    uint32_t pattern;
-    CountType what;
-    uint64_t count;
-} InsnClassExecCount;
-
-typedef struct {
-    char *insn;
-    uint32_t opcode;
-    uint64_t count;
-    InsnClassExecCount *class;
-} InsnExecCount;
-
-/*
- * Matchers for classes of instructions, order is important.
- *
- * Your most precise match must be before looser matches. If no match
- * is found in the table we can create an individual entry.
- *
- * 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0
- */
-static InsnClassExecCount aarch64_insn_classes[] = {
-    /* "Reserved"" */
-    { "  UDEF",              "udef",   0xffff0000, 0x00000000, COUNT_NONE},
-    { "  SVE",               "sve",    0x1e000000, 0x04000000, COUNT_CLASS},
-    { "Reserved",            "res",    0x1e000000, 0x00000000, COUNT_CLASS},
-    /* Data Processing Immediate */
-    { "  PCrel addr",        "pcrel",  0x1f000000, 0x10000000, COUNT_CLASS},
-    { "  Add/Sub (imm,tags)","asit",   0x1f800000, 0x11800000, COUNT_CLASS},
-    { "  Add/Sub (imm)",     "asi",    0x1f000000, 0x11000000, COUNT_CLASS},
-    { "  Logical (imm)",     "logi",   0x1f800000, 0x12000000, COUNT_CLASS},
-    { "  Move Wide (imm)",   "movwi",  0x1f800000, 0x12800000, COUNT_CLASS},
-    { "  Bitfield",          "bitf",   0x1f800000, 0x13000000, COUNT_CLASS},
-    { "  Extract",           "extr",   0x1f800000, 0x13800000, COUNT_CLASS},
-    { "Data Proc Imm",       "dpri",   0x1c000000, 0x10000000, COUNT_CLASS},
-    /* Branches */
-    { "  Cond Branch (imm)", "cndb",   0xfe000000, 0x54000000, COUNT_CLASS},
-    { "  Exception Gen",     "excp",   0xff000000, 0xd4000000, COUNT_CLASS},
-    { "    NOP",             "nop",    0xffffffff, 0xd503201f, COUNT_NONE},
-    { "  Hints",             "hint",   0xfffff000, 0xd5032000, COUNT_CLASS},
-    { "  Barriers",          "barr",   0xfffff000, 0xd5033000, COUNT_CLASS},
-    { "  PSTATE",            "psta",   0xfff8f000, 0xd5004000, COUNT_CLASS},
-    { "  System Insn",       "sins",   0xffd80000, 0xd5080000, COUNT_CLASS},
-    { "  System Reg",        "sreg",   0xffd00000, 0xd5100000, COUNT_CLASS},
-    { "  Branch (reg)",      "breg",   0xfe000000, 0xd6000000, COUNT_CLASS},
-    { "  Branch (imm)",      "bimm",   0x7c000000, 0x14000000, COUNT_CLASS},
-    { "  Cmp & Branch",      "cmpb",   0x7e000000, 0x34000000, COUNT_CLASS},
-    { "  Tst & Branch",      "tstb",   0x7e000000, 0x36000000, COUNT_CLASS},
-    { "Branches",            "branch", 0x1c000000, 0x14000000, COUNT_CLASS},
-    /* Loads and Stores */
-    { "  AdvSimd ldstmult",  "advlsm", 0xbfbf0000, 0x0c000000, COUNT_CLASS},
-    { "  AdvSimd ldstmult++","advlsmp",0xbfb00000, 0x0c800000, COUNT_CLASS},
-    { "  AdvSimd ldst",      "advlss", 0xbf9f0000, 0x0d000000, COUNT_CLASS},
-    { "  AdvSimd ldst++",    "advlssp",0xbf800000, 0x0d800000, COUNT_CLASS},
-    { "  ldst excl",         "ldstx",  0x3f000000, 0x08000000, COUNT_CLASS},
-    { "    Prefetch",        "prfm",   0xff000000, 0xd8000000, COUNT_CLASS},
-    { "  Load Reg (lit)",    "ldlit",  0x1b000000, 0x18000000, COUNT_CLASS},
-    { "  ldst noalloc pair", "ldstnap",0x3b800000, 0x28000000, COUNT_CLASS},
-    { "  ldst pair",         "ldstp",  0x38000000, 0x28000000, COUNT_CLASS},
-    { "  ldst reg",          "ldstr",  0x3b200000, 0x38000000, COUNT_CLASS},
-    { "  Atomic ldst",       "atomic", 0x3b200c00, 0x38200000, COUNT_CLASS},
-    { "  ldst reg (reg off)","ldstro", 0x3b200b00, 0x38200800, COUNT_CLASS},
-    { "  ldst reg (pac)",    "ldstpa", 0x3b200200, 0x38200800, COUNT_CLASS},
-    { "  ldst reg (imm)",    "ldsti",  0x3b000000, 0x39000000, COUNT_CLASS},
-    { "Loads & Stores",      "ldst",   0x0a000000, 0x08000000, COUNT_CLASS},
-    /* Data Processing Register */
-    { "Data Proc Reg",       "dprr",   0x0e000000, 0x0a000000, COUNT_CLASS},
-    /* Scalar FP */
-    { "Scalar FP ",          "fpsimd", 0x0e000000, 0x0e000000, COUNT_CLASS},
-    /* Unclassified */
-    { "Unclassified",        "unclas", 0x00000000, 0x00000000, COUNT_CLASS},
-};
-
-static InsnClassExecCount sparc32_insn_classes[] = {
-    { "Call",                "call",   0xc0000000, 0x40000000, COUNT_CLASS},
-    { "Branch ICond",        "bcc",    0xc1c00000, 0x00800000, COUNT_CLASS},
-    { "Branch Fcond",        "fbcc",   0xc1c00000, 0x01800000, COUNT_CLASS},
-    { "SetHi",               "sethi",  0xc1c00000, 0x01000000, COUNT_CLASS},
-    { "FPU ALU",             "fpu",    0xc1f00000, 0x81a00000, COUNT_CLASS},
-    { "ALU",                 "alu",    0xc0000000, 0x80000000, COUNT_CLASS},
-    { "Load/Store",          "ldst",   0xc0000000, 0xc0000000, COUNT_CLASS},
-    /* Unclassified */
-    { "Unclassified",        "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL},
-};
-
-static InsnClassExecCount sparc64_insn_classes[] = {
-    { "SetHi & Branches",     "op0",   0xc0000000, 0x00000000, COUNT_CLASS},
-    { "Call",                 "op1",   0xc0000000, 0x40000000, COUNT_CLASS},
-    { "Arith/Logical/Move",   "op2",   0xc0000000, 0x80000000, COUNT_CLASS},
-    { "Arith/Logical/Move",   "op3",   0xc0000000, 0xc0000000, COUNT_CLASS},
-    /* Unclassified */
-    { "Unclassified",        "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL},
-};
-
-/* Default matcher for currently unclassified architectures */
-static InsnClassExecCount default_insn_classes[] = {
-    { "Unclassified",        "unclas", 0x00000000, 0x00000000, COUNT_INDIVIDUAL},
-};
-
-typedef struct {
-    const char *qemu_target;
-    InsnClassExecCount *table;
-    int table_sz;
-} ClassSelector;
-
-static ClassSelector class_tables[] =
-{
-    { "aarch64", aarch64_insn_classes, ARRAY_SIZE(aarch64_insn_classes) },
-    { "sparc",   sparc32_insn_classes, ARRAY_SIZE(sparc32_insn_classes) },
-    { "sparc64", sparc64_insn_classes, ARRAY_SIZE(sparc64_insn_classes) },
-    { NULL, default_insn_classes, ARRAY_SIZE(default_insn_classes) },
-};
-
-static InsnClassExecCount *class_table;
-static int class_table_sz;
-
-static gint cmp_exec_count(gconstpointer a, gconstpointer b)
-{
-    InsnExecCount *ea = (InsnExecCount *) a;
-    InsnExecCount *eb = (InsnExecCount *) b;
-    return ea->count > eb->count ? -1 : 1;
-}
-
-static void free_record(gpointer data)
-{
-    InsnExecCount *rec = (InsnExecCount *) data;
-    g_free(rec->insn);
-    g_free(rec);
-}
-
-static void plugin_exit(qemu_plugin_id_t id, void *p)
-{
-    g_autoptr(GString) report = g_string_new("Instruction Classes:\n");
-    int i;
-    GList *counts;
-    InsnClassExecCount *class = NULL;
-
-    for (i = 0; i < class_table_sz; i++) {
-        class = &class_table[i];
-        switch (class->what) {
-        case COUNT_CLASS:
-            if (class->count || verbose) {
-                g_string_append_printf(report, "Class: %-24s\t(%ld hits)\n",
-                                       class->class,
-                                       class->count);
-            }
-            break;
-        case COUNT_INDIVIDUAL:
-            g_string_append_printf(report, "Class: %-24s\tcounted individually\n",
-                                   class->class);
-            break;
-        case COUNT_NONE:
-            g_string_append_printf(report, "Class: %-24s\tnot counted\n",
-                                   class->class);
-            break;
-        default:
-            break;
-        }
-    }
-
-    counts = g_hash_table_get_values(insns);
-    if (counts && g_list_next(counts)) {
-        g_string_append_printf(report,"Individual Instructions:\n");
-        counts = g_list_sort(counts, cmp_exec_count);
-
-        for (i = 0; i < limit && g_list_next(counts);
-             i++, counts = g_list_next(counts)) {
-            InsnExecCount *rec = (InsnExecCount *) counts->data;
-            g_string_append_printf(report,
-                                   "Instr: %-24s\t(%ld hits)\t(op=%#08x/%s)\n",
-                                   rec->insn,
-                                   rec->count,
-                                   rec->opcode,
-                                   rec->class ?
-                                   rec->class->class : "un-categorised");
-        }
-        g_list_free(counts);
-    }
-
-    g_hash_table_destroy(insns);
-
-    qemu_plugin_outs(report->str);
-}
-
-static void plugin_init(void)
-{
-    insns = g_hash_table_new_full(NULL, g_direct_equal, NULL, &free_record);
-}
-
-static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)
-{
-    uint64_t *count = (uint64_t *) udata;
-    (*count)++;
-}
-
-static uint64_t * find_counter(struct qemu_plugin_insn *insn)
-{
-    int i;
-    uint64_t *cnt = NULL;
-    uint32_t opcode;
-    InsnClassExecCount *class = NULL;
-
-    /*
-     * We only match the first 32 bits of the instruction which is
-     * fine for most RISCs but a bit limiting for CISC architectures.
-     * They would probably benefit from a more tailored plugin.
-     * However we can fall back to individual instruction counting.
-     */
-    opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
-
-    for (i = 0; !cnt && i < class_table_sz; i++) {
-        class = &class_table[i];
-        uint32_t masked_bits = opcode & class->mask;
-        if (masked_bits == class->pattern) {
-            break;
-        }
-    }
-
-    g_assert(class);
-
-    switch (class->what) {
-    case COUNT_NONE:
-        return NULL;
-    case COUNT_CLASS:
-        return &class->count;
-    case COUNT_INDIVIDUAL:
-    {
-        InsnExecCount *icount;
-
-        g_mutex_lock(&lock);
-        icount = (InsnExecCount *) g_hash_table_lookup(insns,
-                                                       GUINT_TO_POINTER(opcode));
-
-        if (!icount) {
-            icount = g_new0(InsnExecCount, 1);
-            icount->opcode = opcode;
-            icount->insn = qemu_plugin_insn_disas(insn);
-            icount->class = class;
-
-            g_hash_table_insert(insns, GUINT_TO_POINTER(opcode),
-                                (gpointer) icount);
-        }
-        g_mutex_unlock(&lock);
-
-        return &icount->count;
-    }
-    default:
-        g_assert_not_reached();
-    }
-
-    return NULL;
-}
-
-static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
-{
-    size_t n = qemu_plugin_tb_n_insns(tb);
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        uint64_t *cnt;
-        struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
-        cnt = find_counter(insn);
-
-        if (cnt) {
-            if (do_inline) {
-                qemu_plugin_register_vcpu_insn_exec_inline(
-                    insn, QEMU_PLUGIN_INLINE_ADD_U64, cnt, 1);
-            } else {
-                qemu_plugin_register_vcpu_insn_exec_cb(
-                    insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, cnt);
-            }
-        }
-    }
-}
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
-                                           const qemu_info_t *info,
-                                           int argc, char **argv)
-{
-    int i;
-
-    /* Select a class table appropriate to the guest architecture */
-    for (i = 0; i < ARRAY_SIZE(class_tables); i++) {
-        ClassSelector *entry = &class_tables[i];
-        if (!entry->qemu_target ||
-            strcmp(entry->qemu_target, info->target_name) == 0) {
-            class_table = entry->table;
-            class_table_sz = entry->table_sz;
-            break;
-        }
-    }
-
-    for (i = 0; i < argc; i++) {
-        char *p = argv[i];
-        if (strcmp(p, "inline") == 0) {
-            do_inline = true;
-        } else if (strcmp(p, "verbose") == 0) {
-            verbose = true;
-        } else {
-            int j;
-            CountType type = COUNT_INDIVIDUAL;
-            if (*p == '!') {
-                type = COUNT_NONE;
-                p++;
-            }
-            for (j = 0; j < class_table_sz; j++) {
-                if (strcmp(p, class_table[j].opt) == 0) {
-                    class_table[j].what = type;
-                    break;
-                }
-            }
-        }
-    }
-
-    plugin_init();
-
-    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
-    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
-    return 0;
-}
diff --git a/tests/plugin/lockstep.c b/tests/plugin/lockstep.c
deleted file mode 100644
index a696673dff..0000000000
--- a/tests/plugin/lockstep.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Lockstep Execution Plugin
- *
- * Allows you to execute two QEMU instances in lockstep and report
- * when their execution diverges. This is mainly useful for developers
- * who want to see where a change to TCG code generation has
- * introduced a subtle and hard to find bug.
- *
- * Caveats:
- *   - single-threaded linux-user apps only with non-deterministic syscalls
- *   - no MTTCG enabled system emulation (icount may help)
- *
- * While icount makes things more deterministic it doesn't mean a
- * particular run may execute the exact same sequence of blocks. An
- * asynchronous event (for example X11 graphics update) may cause a
- * block to end early and a new partial block to start. This means
- * serial only test cases are a better bet. -d nochain may also help.
- *
- * This code is not thread safe!
- *
- * Copyright (c) 2020 Linaro Ltd
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include <glib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <qemu-plugin.h>
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-
-/* saved so we can uninstall later */
-static qemu_plugin_id_t our_id;
-
-static unsigned long bb_count;
-static unsigned long insn_count;
-
-/* Information about a translated block */
-typedef struct {
-    uint64_t pc;
-    uint64_t insns;
-} BlockInfo;
-
-/* Information about an execution state in the log */
-typedef struct {
-    BlockInfo *block;
-    unsigned long insn_count;
-    unsigned long block_count;
-} ExecInfo;
-
-/* The execution state we compare */
-typedef struct {
-    uint64_t pc;
-    unsigned long insn_count;
-} ExecState;
-
-typedef struct {
-    GSList *log_pos;
-    int distance;
-} DivergeState;
-
-/* list of translated block info */
-static GSList *blocks;
-
-/* execution log and points of divergence */
-static GSList *log, *divergence_log;
-
-static int socket_fd;
-static char *path_to_unlink;
-
-static bool verbose;
-
-static void plugin_cleanup(qemu_plugin_id_t id)
-{
-    /* Free our block data */
-    g_slist_free_full(blocks, &g_free);
-    g_slist_free_full(log, &g_free);
-    g_slist_free(divergence_log);
-
-    close(socket_fd);
-    if (path_to_unlink) {
-        unlink(path_to_unlink);
-    }
-}
-
-static void plugin_exit(qemu_plugin_id_t id, void *p)
-{
-    g_autoptr(GString) out = g_string_new("No divergence :-)\n");
-    g_string_append_printf(out, "Executed %ld/%d blocks\n",
-                           bb_count, g_slist_length(log));
-    g_string_append_printf(out, "Executed ~%ld instructions\n", insn_count);
-    qemu_plugin_outs(out->str);
-
-    plugin_cleanup(id);
-}
-
-static void report_divergance(ExecState *us, ExecState *them)
-{
-    DivergeState divrec = { log, 0 };
-    g_autoptr(GString) out = g_string_new("");
-    bool diverged = false;
-
-    /*
-     * If we have diverged before did we get back on track or are we
-     * totally loosing it?
-     */
-    if (divergence_log) {
-        DivergeState *last = (DivergeState *) divergence_log->data;
-        GSList *entry;
-
-        for (entry = log; g_slist_next(entry); entry = g_slist_next(entry)) {
-            if (entry == last->log_pos) {
-                break;
-            }
-            divrec.distance++;
-        }
-
-        /*
-         * If the last two records are so close it is likely we will
-         * not recover synchronisation with the other end.
-         */
-        if (divrec.distance == 1 && last->distance == 1) {
-            diverged = true;
-        }
-    }
-    divergence_log = g_slist_prepend(divergence_log,
-                                     g_memdup(&divrec, sizeof(divrec)));
-
-    /* Output short log entry of going out of sync... */
-    if (verbose || divrec.distance == 1 || diverged) {
-        g_string_printf(out, "@ %#016lx vs %#016lx (%d/%d since last)\n",
-                        us->pc, them->pc, g_slist_length(divergence_log),
-                        divrec.distance);
-        qemu_plugin_outs(out->str);
-    }
-
-    if (diverged) {
-        int i;
-        GSList *entry;
-
-        g_string_printf(out, "Δ insn_count @ %#016lx (%ld) vs %#016lx (%ld)\n",
-                        us->pc, us->insn_count, them->pc, them->insn_count);
-
-        for (entry = log, i = 0;
-             g_slist_next(entry) && i < 5;
-             entry = g_slist_next(entry), i++) {
-            ExecInfo *prev = (ExecInfo *) entry->data;
-            g_string_append_printf(out,
-                                   "  previously @ %#016lx/%ld (%ld insns)\n",
-                                   prev->block->pc, prev->block->insns,
-                                   prev->insn_count);
-        }
-        qemu_plugin_outs(out->str);
-        qemu_plugin_outs("too much divergence... giving up.");
-        qemu_plugin_uninstall(our_id, plugin_cleanup);
-    }
-}
-
-static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
-{
-    BlockInfo *bi = (BlockInfo *) udata;
-    ExecState us, them;
-    ssize_t bytes;
-    ExecInfo *exec;
-
-    us.pc = bi->pc;
-    us.insn_count = insn_count;
-
-    /*
-     * Write our current position to the other end. If we fail the
-     * other end has probably died and we should shut down gracefully.
-     */
-    bytes = write(socket_fd, &us, sizeof(ExecState));
-    if (bytes < sizeof(ExecState)) {
-        qemu_plugin_outs(bytes < 0 ?
-                         "problem writing to socket" :
-                         "wrote less than expected to socket");
-        qemu_plugin_uninstall(our_id, plugin_cleanup);
-        return;
-    }
-
-    /*
-     * Now read where our peer has reached. Again a failure probably
-     * indicates the other end died and we should close down cleanly.
-     */
-    bytes = read(socket_fd, &them, sizeof(ExecState));
-    if (bytes < sizeof(ExecState)) {
-        qemu_plugin_outs(bytes < 0 ?
-                         "problem reading from socket" :
-                         "read less than expected");
-        qemu_plugin_uninstall(our_id, plugin_cleanup);
-        return;
-    }
-
-    /*
-     * Compare and report if we have diverged.
-     */
-    if (us.pc != them.pc) {
-        report_divergance(&us, &them);
-    }
-
-    /*
-     * Assume this block will execute fully and record it
-     * in the execution log.
-     */
-    insn_count += bi->insns;
-    bb_count++;
-    exec = g_new0(ExecInfo, 1);
-    exec->block = bi;
-    exec->insn_count = insn_count;
-    exec->block_count = bb_count;
-    log = g_slist_prepend(log, exec);
-}
-
-static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
-{
-    BlockInfo *bi = g_new0(BlockInfo, 1);
-    bi->pc = qemu_plugin_tb_vaddr(tb);
-    bi->insns = qemu_plugin_tb_n_insns(tb);
-
-    /* save a reference so we can free later */
-    blocks = g_slist_prepend(blocks, bi);
-    qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
-                                         QEMU_PLUGIN_CB_NO_REGS, (void *)bi);
-}
-
-
-/*
- * Instead of encoding master/slave status into what is essentially
- * two peers we shall just take the simple approach of checking for
- * the existence of the pipe and assuming if it's not there we are the
- * first process.
- */
-static bool setup_socket(const char *path)
-{
-    struct sockaddr_un sockaddr;
-    int fd;
-
-    fd = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (fd < 0) {
-        perror("create socket");
-        return false;
-    }
-
-    sockaddr.sun_family = AF_UNIX;
-    g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
-    if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
-        perror("bind socket");
-        close(fd);
-        return false;
-    }
-
-    /* remember to clean-up */
-    path_to_unlink = g_strdup(path);
-
-    if (listen(fd, 1) < 0) {
-        perror("listen socket");
-        close(fd);
-        return false;
-    }
-
-    socket_fd = accept(fd, NULL, NULL);
-    if (socket_fd < 0 && errno != EINTR) {
-        perror("accept socket");
-        return false;
-    }
-
-    qemu_plugin_outs("setup_socket::ready\n");
-
-    return true;
-}
-
-static bool connect_socket(const char *path)
-{
-    int fd;
-    struct sockaddr_un sockaddr;
-
-    fd = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (fd < 0) {
-        perror("create socket");
-        return false;
-    }
-
-    sockaddr.sun_family = AF_UNIX;
-    g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
-
-    if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
-        perror("failed to connect");
-        return false;
-    }
-
-    qemu_plugin_outs("connect_socket::ready\n");
-
-    socket_fd = fd;
-    return true;
-}
-
-static bool setup_unix_socket(const char *path)
-{
-    if (g_file_test(path, G_FILE_TEST_EXISTS)) {
-        return connect_socket(path);
-    } else {
-        return setup_socket(path);
-    }
-}
-
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
-                                           const qemu_info_t *info,
-                                           int argc, char **argv)
-{
-    int i;
-
-    if (!argc || !argv[0]) {
-        qemu_plugin_outs("Need a socket path to talk to other instance.");
-        return -1;
-    }
-
-    for (i = 0; i < argc; i++) {
-        char *p = argv[i];
-        if (strcmp(p, "verbose") == 0) {
-            verbose = true;
-        } else if (!setup_unix_socket(argv[0])) {
-            qemu_plugin_outs("Failed to setup socket for communications.");
-            return -1;
-        }
-    }
-
-    our_id = id;
-
-    qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
-    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
-    return 0;
-}
diff --git a/tests/plugin/meson.build b/tests/plugin/meson.build
index dbbdcbaa67..1eacfa6e35 100644
--- a/tests/plugin/meson.build
+++ b/tests/plugin/meson.build
@@ -1,7 +1,7 @@
 t = []
-foreach i : ['bb', 'empty', 'insn', 'mem', 'hotblocks', 'howvec', 'hotpages', 'lockstep']
+foreach i : ['bb', 'empty', 'insn', 'mem']
   t += shared_module(i, files(i + '.c'),
                      include_directories: '../../include/qemu',
                      dependencies: glib)
 endforeach
-alias_target('plugins', t)
+alias_target('test-plugins', t)
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index a0782937b0..596505be2d 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -31,6 +31,11 @@ _cleanup()
     _cleanup_test_img
     _rm_test_img "$TEST_IMG.base"
     _rm_test_img "$TEST_IMG.orig"
+
+    _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base"
+    _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.mid"
+    _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT"
+    rmdir "$TEST_DIR/subdir" &> /dev/null
 }
 trap "_cleanup; exit \$status" 0 1 2 3 15
 
@@ -139,6 +144,45 @@ $QEMU_IO -c 'writev 0 64k' "$TEST_IMG" | _filter_qemu_io
 $QEMU_IMG commit "$TEST_IMG"
 _cleanup
 
+
+echo
+echo 'Testing commit in sub-directory with relative filenames'
+echo
+
+pushd "$TEST_DIR" > /dev/null
+
+mkdir subdir
+
+TEST_IMG="subdir/t.$IMGFMT.base" _make_test_img 1M
+TEST_IMG="subdir/t.$IMGFMT.mid" _make_test_img -b "t.$IMGFMT.base" -F $IMGFMT
+TEST_IMG="subdir/t.$IMGFMT" _make_test_img -b "t.$IMGFMT.mid" -F $IMGFMT
+
+# Should work
+$QEMU_IMG commit -b "t.$IMGFMT.mid" "subdir/t.$IMGFMT"
+
+# Might theoretically work, but does not in practice (we have to
+# decide between this and the above; and since we always represent
+# backing file names as relative to the overlay, we go for the above)
+$QEMU_IMG commit -b "subdir/t.$IMGFMT.mid" "subdir/t.$IMGFMT" 2>&1 | \
+    _filter_imgfmt
+
+# This should work as well
+$QEMU_IMG commit -b "$TEST_DIR/subdir/t.$IMGFMT.mid" "subdir/t.$IMGFMT"
+
+popd > /dev/null
+
+# Now let's try with just absolute filenames
+# (This will not work with external data files, though, because when
+# using relative paths for those, qemu will always resolve them
+# relative to its CWD.  Therefore, it cannot find those data files now
+# that we left $TEST_DIR.)
+if _get_data_file '' > /dev/null; then
+    echo 'Image committed.' # Skip test
+else
+    $QEMU_IMG commit -b "$TEST_DIR/subdir/t.$IMGFMT.mid" \
+        "$TEST_DIR/subdir/t.$IMGFMT"
+fi
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/020.out b/tests/qemu-iotests/020.out
index 5936bc1cae..a5db1962ad 100644
--- a/tests/qemu-iotests/020.out
+++ b/tests/qemu-iotests/020.out
@@ -1083,4 +1083,14 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=json:{'driv
 wrote 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 qemu-img: Block job failed: No space left on device
+
+Testing commit in sub-directory with relative filenames
+
+Formatting 'subdir/t.IMGFMT.base', fmt=IMGFMT size=1048576
+Formatting 'subdir/t.IMGFMT.mid', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.base backing_fmt=IMGFMT
+Formatting 'subdir/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.mid backing_fmt=IMGFMT
+Image committed.
+qemu-img: Did not find 'subdir/t.IMGFMT.mid' in the backing chain of 'subdir/t.IMGFMT'
+Image committed.
+Image committed.
 *** done
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index f58f50d023..caf286571a 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -734,6 +734,244 @@ class TestErrorHandling(iotests.QMPTestCase):
         self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                         'target image does not match source after commit')
 
+class TestCommitWithFilters(iotests.QMPTestCase):
+    img0 = os.path.join(iotests.test_dir, '0.img')
+    img1 = os.path.join(iotests.test_dir, '1.img')
+    img2 = os.path.join(iotests.test_dir, '2.img')
+    img3 = os.path.join(iotests.test_dir, '3.img')
+
+    def do_test_io(self, read_or_write):
+        for index, pattern_file in enumerate(self.pattern_files):
+            result = qemu_io('-f', iotests.imgfmt,
+                             '-c',
+                             f'{read_or_write} -P {index + 1} {index}M 1M',
+                             pattern_file)
+            self.assertFalse('Pattern verification failed' in result)
+
+    def setUp(self):
+        qemu_img('create', '-f', iotests.imgfmt, self.img0, '64M')
+        qemu_img('create', '-f', iotests.imgfmt, self.img1, '64M')
+        qemu_img('create', '-f', iotests.imgfmt, self.img2, '64M')
+        qemu_img('create', '-f', iotests.imgfmt, self.img3, '64M')
+
+        # Distributions of the patterns in the files; this is checked
+        # by tearDown() and should be changed by the test cases as is
+        # necessary
+        self.pattern_files = [self.img0, self.img1, self.img2, self.img3]
+
+        self.do_test_io('write')
+
+        self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi')
+        self.vm.launch()
+
+        result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-add', **{
+                'node-name': 'top-filter',
+                'driver': 'throttle',
+                'throttle-group': 'tg',
+                'file': {
+                    'node-name': 'cow-3',
+                    'driver': iotests.imgfmt,
+                    'file': {
+                        'driver': 'file',
+                        'filename': self.img3
+                    },
+                    'backing': {
+                        'node-name': 'cow-2',
+                        'driver': iotests.imgfmt,
+                        'file': {
+                            'driver': 'file',
+                            'filename': self.img2
+                        },
+                        'backing': {
+                            'node-name': 'cow-1',
+                            'driver': iotests.imgfmt,
+                            'file': {
+                                'driver': 'file',
+                                'filename': self.img1
+                            },
+                            'backing': {
+                                'node-name': 'bottom-filter',
+                                'driver': 'throttle',
+                                'throttle-group': 'tg',
+                                'file': {
+                                    'node-name': 'cow-0',
+                                    'driver': iotests.imgfmt,
+                                    'file': {
+                                        'driver': 'file',
+                                        'filename': self.img0
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            })
+        self.assert_qmp(result, 'return', {})
+
+    def tearDown(self):
+        self.vm.shutdown()
+        self.do_test_io('read')
+
+        os.remove(self.img3)
+        os.remove(self.img2)
+        os.remove(self.img1)
+        os.remove(self.img0)
+
+    # Filters make for funny filenames, so we cannot just use
+    # self.imgX to get them
+    def get_filename(self, node):
+        return self.vm.node_info(node)['image']['filename']
+
+    def test_filterless_commit(self):
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top-filter',
+                             top_node='cow-2',
+                             base_node='cow-1')
+        self.assert_qmp(result, 'return', {})
+        self.wait_until_completed(drive='commit')
+
+        self.assertIsNotNone(self.vm.node_info('cow-3'))
+        self.assertIsNone(self.vm.node_info('cow-2'))
+        self.assertIsNotNone(self.vm.node_info('cow-1'))
+
+        # 2 has been comitted into 1
+        self.pattern_files[2] = self.img1
+
+    def test_commit_through_filter(self):
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top-filter',
+                             top_node='cow-1',
+                             base_node='cow-0')
+        self.assert_qmp(result, 'return', {})
+        self.wait_until_completed(drive='commit')
+
+        self.assertIsNotNone(self.vm.node_info('cow-2'))
+        self.assertIsNone(self.vm.node_info('cow-1'))
+        self.assertIsNone(self.vm.node_info('bottom-filter'))
+        self.assertIsNotNone(self.vm.node_info('cow-0'))
+
+        # 1 has been comitted into 0
+        self.pattern_files[1] = self.img0
+
+    def test_filtered_active_commit_with_filter(self):
+        # Add a device, so the commit job finds a parent it can change
+        # to point to the base node (so we can test that top-filter is
+        # dropped from the graph)
+        result = self.vm.qmp('device_add', id='drv0', driver='scsi-hd',
+                             bus='vio-scsi.0', drive='top-filter')
+        self.assert_qmp(result, 'return', {})
+
+        # Try to release our reference to top-filter; that should not
+        # work because drv0 uses it
+        result = self.vm.qmp('blockdev-del', node_name='top-filter')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+        self.assert_qmp(result, 'error/desc', 'Node top-filter is in use')
+
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top-filter',
+                             base_node='cow-2')
+        self.assert_qmp(result, 'return', {})
+        self.complete_and_wait(drive='commit')
+
+        # Try to release our reference to top-filter again
+        result = self.vm.qmp('blockdev-del', node_name='top-filter')
+        self.assert_qmp(result, 'return', {})
+
+        self.assertIsNone(self.vm.node_info('top-filter'))
+        self.assertIsNone(self.vm.node_info('cow-3'))
+        self.assertIsNotNone(self.vm.node_info('cow-2'))
+
+        # Check that drv0 is now connected to cow-2
+        blockdevs = self.vm.qmp('query-block')['return']
+        drv0 = next(dev for dev in blockdevs if dev['qdev'] == 'drv0')
+        self.assertEqual(drv0['inserted']['node-name'], 'cow-2')
+
+        # 3 has been comitted into 2
+        self.pattern_files[3] = self.img2
+
+    def test_filtered_active_commit_without_filter(self):
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top-filter',
+                             top_node='cow-3',
+                             base_node='cow-2')
+        self.assert_qmp(result, 'return', {})
+        self.complete_and_wait(drive='commit')
+
+        self.assertIsNotNone(self.vm.node_info('top-filter'))
+        self.assertIsNone(self.vm.node_info('cow-3'))
+        self.assertIsNotNone(self.vm.node_info('cow-2'))
+
+        # 3 has been comitted into 2
+        self.pattern_files[3] = self.img2
+
+class TestCommitWithOverriddenBacking(iotests.QMPTestCase):
+    img_base_a = os.path.join(iotests.test_dir, 'base_a.img')
+    img_base_b = os.path.join(iotests.test_dir, 'base_b.img')
+    img_top = os.path.join(iotests.test_dir, 'top.img')
+
+    def setUp(self):
+        qemu_img('create', '-f', iotests.imgfmt, self.img_base_a, '1M')
+        qemu_img('create', '-f', iotests.imgfmt, self.img_base_b, '1M')
+        qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a, \
+                 self.img_top)
+
+        self.vm = iotests.VM()
+        self.vm.launch()
+
+        # Use base_b instead of base_a as the backing of top
+        result = self.vm.qmp('blockdev-add', **{
+                                'node-name': 'top',
+                                'driver': iotests.imgfmt,
+                                'file': {
+                                    'driver': 'file',
+                                    'filename': self.img_top
+                                },
+                                'backing': {
+                                    'node-name': 'base',
+                                    'driver': iotests.imgfmt,
+                                    'file': {
+                                        'driver': 'file',
+                                        'filename': self.img_base_b
+                                    }
+                                }
+                            })
+        self.assert_qmp(result, 'return', {})
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(self.img_top)
+        os.remove(self.img_base_a)
+        os.remove(self.img_base_b)
+
+    def test_commit_to_a(self):
+        # Try committing to base_a (which should fail, as top's
+        # backing image is base_b instead)
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top',
+                             base=self.img_base_a)
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+    def test_commit_to_b(self):
+        # Try committing to base_b (which should work, since that is
+        # actually top's backing image)
+        result = self.vm.qmp('block-commit',
+                             job_id='commit',
+                             device='top',
+                             base=self.img_base_b)
+        self.assert_qmp(result, 'return', {})
+
+        self.vm.event_wait('BLOCK_JOB_READY')
+        self.vm.qmp('block-job-complete', device='commit')
+        self.vm.event_wait('BLOCK_JOB_COMPLETED')
+
 if __name__ == '__main__':
     iotests.main(supported_fmts=['qcow2', 'qed'],
                  supported_protocols=['file'])
diff --git a/tests/qemu-iotests/040.out b/tests/qemu-iotests/040.out
index 6a917130b6..1bb1dc5f0e 100644
--- a/tests/qemu-iotests/040.out
+++ b/tests/qemu-iotests/040.out
@@ -1,5 +1,5 @@
-...........................................................
+.................................................................
 ----------------------------------------------------------------------
-Ran 59 tests
+Ran 65 tests
 
 OK
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index f0a7bf6650..a7780853cd 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -21,8 +21,9 @@
 import time
 import os
 import re
+import json
 import iotests
-from iotests import qemu_img, qemu_io
+from iotests import qemu_img, qemu_img_pipe, qemu_io
 
 backing_img = os.path.join(iotests.test_dir, 'backing.img')
 target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
@@ -1288,6 +1289,149 @@ class TestReplaces(iotests.QMPTestCase):
 
         self.vm.assert_block_path('filter0', '/file', 'target')
 
+# Tests for mirror with filters (and how the mirror filter behaves, as
+# an example for an implicit filter)
+class TestFilters(iotests.QMPTestCase):
+    def setUp(self):
+        qemu_img('create', '-f', iotests.imgfmt, backing_img, '1M')
+        qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, test_img)
+        qemu_img('create', '-f', iotests.imgfmt, '-b', backing_img, target_img)
+
+        qemu_io('-c', 'write -P 1 0 512k', backing_img)
+        qemu_io('-c', 'write -P 2 512k 512k', test_img)
+
+        self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi')
+        self.vm.launch()
+
+        result = self.vm.qmp('blockdev-add', **{
+                                'node-name': 'target',
+                                'driver': iotests.imgfmt,
+                                'file': {
+                                    'driver': 'file',
+                                    'filename': target_img
+                                },
+                                'backing': None
+                            })
+        self.assert_qmp(result, 'return', {})
+
+        self.filterless_chain = {
+                'node-name': 'source',
+                'driver': iotests.imgfmt,
+                'file': {
+                    'driver': 'file',
+                    'filename': test_img
+                },
+                'backing': {
+                    'node-name': 'backing',
+                    'driver': iotests.imgfmt,
+                    'file': {
+                        'driver': 'file',
+                        'filename': backing_img
+                    }
+                }
+            }
+
+    def tearDown(self):
+        self.vm.shutdown()
+
+        os.remove(test_img)
+        os.remove(target_img)
+        os.remove(backing_img)
+
+    def test_cor(self):
+        result = self.vm.qmp('blockdev-add', **{
+                                'node-name': 'filter',
+                                'driver': 'copy-on-read',
+                                'file': self.filterless_chain
+                            })
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-mirror',
+                             job_id='mirror',
+                             device='filter',
+                             target='target',
+                             sync='top')
+        self.assert_qmp(result, 'return', {})
+
+        self.complete_and_wait('mirror')
+
+        self.vm.qmp('blockdev-del', node_name='target')
+
+        target_map = qemu_img_pipe('map', '--output=json', target_img)
+        target_map = json.loads(target_map)
+
+        assert target_map[0]['start'] == 0
+        assert target_map[0]['length'] == 512 * 1024
+        assert target_map[0]['depth'] == 1
+
+        assert target_map[1]['start'] == 512 * 1024
+        assert target_map[1]['length'] == 512 * 1024
+        assert target_map[1]['depth'] == 0
+
+    def test_implicit_mirror_filter(self):
+        result = self.vm.qmp('blockdev-add', **self.filterless_chain)
+        self.assert_qmp(result, 'return', {})
+
+        # We need this so we can query from above the mirror node
+        result = self.vm.qmp('device_add',
+                             driver='scsi-hd',
+                             id='virtio',
+                             bus='vio-scsi.0',
+                             drive='source')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-mirror',
+                             job_id='mirror',
+                             device='source',
+                             target='target',
+                             sync='top')
+        self.assert_qmp(result, 'return', {})
+
+        # The mirror filter is now an implicit node, so it should be
+        # invisible when querying the backing chain
+        blockdevs = self.vm.qmp('query-block')['return']
+        device_info = next(dev for dev in blockdevs if dev['qdev'] == 'virtio')
+
+        assert device_info['inserted']['node-name'] == 'source'
+
+        image_info = device_info['inserted']['image']
+        assert image_info['filename'] == test_img
+        assert image_info['backing-image']['filename'] == backing_img
+
+        self.complete_and_wait('mirror')
+
+    def test_explicit_mirror_filter(self):
+        # Same test as above, but this time we give the mirror filter
+        # a node-name so it will not be invisible
+        result = self.vm.qmp('blockdev-add', **self.filterless_chain)
+        self.assert_qmp(result, 'return', {})
+
+        # We need this so we can query from above the mirror node
+        result = self.vm.qmp('device_add',
+                             driver='scsi-hd',
+                             id='virtio',
+                             bus='vio-scsi.0',
+                             drive='source')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-mirror',
+                             job_id='mirror',
+                             device='source',
+                             target='target',
+                             sync='top',
+                             filter_node_name='mirror-filter')
+        self.assert_qmp(result, 'return', {})
+
+        # With a node-name given to it, the mirror filter should now
+        # be visible
+        blockdevs = self.vm.qmp('query-block')['return']
+        device_info = next(dev for dev in blockdevs if dev['qdev'] == 'virtio')
+
+        assert device_info['inserted']['node-name'] == 'mirror-filter'
+
+        self.complete_and_wait('mirror')
+
+
 if __name__ == '__main__':
     iotests.main(supported_fmts=['qcow2', 'qed'],
                  supported_protocols=['file'],
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
index 53abe11d73..46651953e8 100644
--- a/tests/qemu-iotests/041.out
+++ b/tests/qemu-iotests/041.out
@@ -1,5 +1,5 @@
-........................................................................................................
+...........................................................................................................
 ----------------------------------------------------------------------
-Ran 104 tests
+Ran 107 tests
 
 OK
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
index 051a1c79e0..82b1e6c202 100755
--- a/tests/qemu-iotests/049
+++ b/tests/qemu-iotests/049
@@ -119,6 +119,10 @@ test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=on "$TEST_IMG" 64M
 test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=off "$TEST_IMG" 64M
 test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=on "$TEST_IMG" 64M
 
+echo "== Expect error when backing file name is empty string =="
+echo
+test_qemu_img create -f $IMGFMT -b '' $TEST_IMG 1M
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index a7e220830d..b1d8fd9107 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -209,4 +209,9 @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16
 qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
 
+== Expect error when backing file name is empty string ==
+
+qemu-img create -f qcow2 -b  TEST_DIR/t.qcow2 1M
+qemu-img: TEST_DIR/t.qcow2: Expected backing file name, got empty string
+
 *** done
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
index 8a79e1ee87..fcaa71aeee 100644
--- a/tests/qemu-iotests/153.out
+++ b/tests/qemu-iotests/153.out
@@ -464,7 +464,7 @@ No conflict:
 image: null-co://
 file format: null-co
 virtual size: 1 GiB (1073741824 bytes)
-disk size: unavailable
+disk size: 0 B
 
 Conflict:
 qemu-img: --force-share/-U conflicts with image options
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
index 33dd8d2a4f..eebb53faed 100755
--- a/tests/qemu-iotests/184
+++ b/tests/qemu-iotests/184
@@ -45,8 +45,7 @@ do_run_qemu()
 run_qemu()
 {
     do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
-                          | _filter_qemu_io | _filter_generated_node_ids \
-                          | _filter_actual_image_size
+                          | _filter_qemu_io | _filter_generated_node_ids
 }
 
 test_throttle=$($QEMU_IMG --help|grep throttle)
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index 3deb3cfb94..87c73070e3 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -27,14 +27,21 @@ Testing:
             "iops_rd": 0,
             "detect_zeroes": "off",
             "image": {
+                "backing-image": {
+                    "virtual-size": 1073741824,
+                    "filename": "null-co://",
+                    "format": "null-co",
+                    "actual-size": 0
+                },
                 "virtual-size": 1073741824,
                 "filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"null-co\"}}",
-                "format": "throttle"
+                "format": "throttle",
+                "actual-size": 0
             },
             "iops_wr": 0,
             "ro": false,
             "node-name": "throttle0",
-            "backing_file_depth": 0,
+            "backing_file_depth": 1,
             "drv": "throttle",
             "iops": 0,
             "bps_wr": 0,
@@ -56,7 +63,8 @@ Testing:
             "image": {
                 "virtual-size": 1073741824,
                 "filename": "null-co://",
-                "format": "null-co"
+                "format": "null-co",
+                "actual-size": 0
             },
             "iops_wr": 0,
             "ro": false,
diff --git a/tests/qemu-iotests/204.out b/tests/qemu-iotests/204.out
index 457f72df8f..4d903d20ea 100644
--- a/tests/qemu-iotests/204.out
+++ b/tests/qemu-iotests/204.out
@@ -59,5 +59,6 @@ Offset          Length          File
 0x900000        0x2400000       TEST_DIR/t.IMGFMT
 0x3c00000       0x1100000       TEST_DIR/t.IMGFMT
 0x6a00000       0x400000        TEST_DIR/t.IMGFMT
+0x6e00000       0x1200000       TEST_DIR/t.IMGFMT.base
 No errors were found on the image.
 *** done
diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228
index 60db986d84..266fce6cda 100755
--- a/tests/qemu-iotests/228
+++ b/tests/qemu-iotests/228
@@ -36,7 +36,7 @@ def log_node_info(node):
 
     log('bs->filename: ' + node['image']['filename'],
         filters=[filter_testfiles, filter_imgfmt])
-    log('bs->backing_file: ' + node['backing_file'],
+    log('bs->backing_file: ' + node['image']['full-backing-filename'],
         filters=[filter_testfiles, filter_imgfmt])
 
     if 'backing-image' in node['image']:
@@ -73,8 +73,8 @@ with iotests.FilePath('base.img') as base_img_path, \
                 },
                 filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
 
-    # Filename should be plain, and the backing filename should not
-    # contain the "file:" prefix
+    # Filename should be plain, and the backing node filename should
+    # not contain the "file:" prefix
     log_node_info(vm.node_info('node0'))
 
     vm.qmp_log('blockdev-del', node_name='node0')
diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out
index 4217df24fe..8c82009abe 100644
--- a/tests/qemu-iotests/228.out
+++ b/tests/qemu-iotests/228.out
@@ -4,7 +4,7 @@
 {"return": {}}
 
 bs->filename: TEST_DIR/PID-top.img
-bs->backing_file: TEST_DIR/PID-base.img
+bs->backing_file: file:TEST_DIR/PID-base.img
 bs->backing->bs->filename: TEST_DIR/PID-base.img
 
 {"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
@@ -41,7 +41,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
 {"return": {}}
 
 bs->filename: TEST_DIR/PID-top.img
-bs->backing_file: TEST_DIR/PID-base.img
+bs->backing_file: file:TEST_DIR/PID-base.img
 bs->backing->bs->filename: TEST_DIR/PID-base.img
 
 {"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
@@ -55,7 +55,7 @@ bs->backing->bs->filename: TEST_DIR/PID-base.img
 {"return": {}}
 
 bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
-bs->backing_file: null-co://
+bs->backing_file: TEST_DIR/PID-base.img
 bs->backing->bs->filename: null-co://
 
 {"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
index efe3c0428b..f2b2dddf1c 100755
--- a/tests/qemu-iotests/244
+++ b/tests/qemu-iotests/244
@@ -217,6 +217,55 @@ $QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
 $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
 $QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
 
+echo
+echo "=== Flushing should flush the data file ==="
+echo
+
+# We are going to flush a qcow2 file with a blkdebug node inserted
+# between the qcow2 node and its data file node.  The blkdebug node
+# will return an error for all flushes and so we if the data file is
+# flushed, we will see qemu-io return an error.
+
+# We need to write something or the flush will not do anything; we
+# also need -t writeback so the write is not done as a FUA write
+# (which would then fail thanks to the implicit flush)
+$QEMU_IO -c 'write 0 512' -c flush \
+    -t writeback \
+    "json:{
+         'driver': 'qcow2',
+         'file': {
+             'driver': 'file',
+             'filename': '$TEST_IMG'
+         },
+         'data-file': {
+             'driver': 'blkdebug',
+             'inject-error': [{
+                 'event': 'none',
+                 'iotype': 'flush'
+             }],
+             'image': {
+                 'driver': 'file',
+                 'filename': '$TEST_IMG.data'
+             }
+         }
+     }" \
+    | _filter_qemu_io
+
+result=${PIPESTATUS[0]}
+echo
+
+case $result in
+    0)
+        echo "ERROR: qemu-io succeeded, so the data file was not flushed"
+        ;;
+    1)
+        echo "Success: qemu-io failed, so the data file was flushed"
+        ;;
+    *)
+        echo "ERROR: qemu-io returned unknown exit code $result"
+        ;;
+esac
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
index dbab7359a9..7269b4295a 100644
--- a/tests/qemu-iotests/244.out
+++ b/tests/qemu-iotests/244.out
@@ -131,4 +131,11 @@ Offset          Length          Mapped to       File
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
 Images are identical.
 Images are identical.
+
+=== Flushing should flush the data file ===
+
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+Success: qemu-io failed, so the data file was flushed
 *** done
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index ad91a6f5b4..e60c8326d3 100755
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -725,7 +725,9 @@ class TestBlockdevReopen(iotests.QMPTestCase):
 
         # Detach hd2 from hd0.
         self.reopen(opts, {'backing': None})
-        self.reopen(opts, {}, "backing is missing for 'hd0'")
+
+        # Without a backing file, we can omit 'backing' again
+        self.reopen(opts)
 
         # Remove both hd0 and hd2
         result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out
index 87d4758503..8247cbaea1 100644
--- a/tests/qemu-iotests/273.out
+++ b/tests/qemu-iotests/273.out
@@ -32,7 +32,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
                         "actual-size": SIZE,
                         "dirty-flag": false
                     },
-                    "backing-filename-format": "file",
+                    "backing-filename-format": "IMGFMT",
                     "virtual-size": 67108864,
                     "filename": "TEST_DIR/t.IMGFMT.mid",
                     "cluster-size": 65536,
@@ -112,7 +112,7 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
                     "actual-size": SIZE,
                     "dirty-flag": false
                 },
-                "backing-filename-format": "file",
+                "backing-filename-format": "IMGFMT",
                 "virtual-size": 67108864,
                 "filename": "TEST_DIR/t.IMGFMT.mid",
                 "cluster-size": 65536,
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 3ab859ac1a..e14a1f354d 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -44,7 +44,7 @@ then
         _init_error "failed to obtain source tree name from check symlink"
     fi
     source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree"
-    build_iotests=$PWD
+    build_iotests=$(readlink -f $(dirname "$0"))
 else
     # called from the source tree
     source_iotests=$PWD
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e197c73ca5..64ccaf9061 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -972,8 +972,12 @@ class QMPTestCase(unittest.TestCase):
 
     def wait_ready(self, drive='drive0'):
         """Wait until a BLOCK_JOB_READY event, and return the event."""
-        f = {'data': {'type': 'mirror', 'device': drive}}
-        return self.vm.event_wait(name='BLOCK_JOB_READY', match=f)
+        return self.vm.events_wait([
+            ('BLOCK_JOB_READY',
+             {'data': {'type': 'mirror', 'device': drive}}),
+            ('BLOCK_JOB_READY',
+             {'data': {'type': 'commit', 'device': drive}})
+        ])
 
     def wait_ready_and_cancel(self, drive='drive0'):
         self.wait_ready(drive=drive)
@@ -992,7 +996,7 @@ class QMPTestCase(unittest.TestCase):
         self.assert_qmp(result, 'return', {})
 
         event = self.wait_until_completed(drive=drive, error=completion_error)
-        self.assert_qmp(event, 'data/type', 'mirror')
+        self.assertTrue(event['data']['type'] in ['mirror', 'commit'])
 
     def pause_wait(self, job_id='job0'):
         with Timeout(3, "Timeout waiting for job to pause"):
diff --git a/tests/requirements.txt b/tests/requirements.txt
index f9c84b4ba1..036691c922 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,5 +1,5 @@
 # Add Python module requirements, one per line, to be installed
 # in the tests/venv Python virtual environment. For more info,
 # refer to: https://pip.pypa.io/en/stable/user_guide/#id1
-avocado-framework==76.0
+avocado-framework==81.0
 pycdlib==1.9.0
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index 4b2b696fce..2ae86776cd 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -129,8 +129,7 @@ ifeq ($(CONFIG_PLUGIN),y)
 PLUGIN_SRC=$(SRC_PATH)/tests/plugin
 PLUGIN_LIB=../../plugin
 VPATH+=$(PLUGIN_LIB)
-PLUGINS=$(filter-out liblockstep.so,\
-		$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c))))
+PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
 
 # We need to ensure expand the run-plugin-TEST-with-PLUGIN
 # pre-requistes manually here as we can't use stems to handle it. We
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
index 1e6b0f33ff..8a3c14d92c 100644
--- a/tests/test-qdev-global-props.c
+++ b/tests/test-qdev-global-props.c
@@ -31,19 +31,20 @@
 
 
 #define TYPE_STATIC_PROPS "static_prop_type"
-#define STATIC_TYPE(obj) \
-    OBJECT_CHECK(MyType, (obj), TYPE_STATIC_PROPS)
+typedef struct MyType MyType;
+DECLARE_INSTANCE_CHECKER(MyType, STATIC_TYPE,
+                         TYPE_STATIC_PROPS)
 
 #define TYPE_SUBCLASS "static_prop_subtype"
 
 #define PROP_DEFAULT 100
 
-typedef struct MyType {
+struct MyType {
     DeviceState parent_obj;
 
     uint32_t prop1;
     uint32_t prop2;
-} MyType;
+};
 
 static Property static_props[] = {
     DEFINE_PROP_UINT32("prop1", MyType, prop1, PROP_DEFAULT),
@@ -127,8 +128,8 @@ static void test_static_globalprop(void)
 }
 
 #define TYPE_DYNAMIC_PROPS "dynamic-prop-type"
-#define DYNAMIC_TYPE(obj) \
-    OBJECT_CHECK(MyType, (obj), TYPE_DYNAMIC_PROPS)
+DECLARE_INSTANCE_CHECKER(MyType, DYNAMIC_TYPE,
+                         TYPE_DYNAMIC_PROPS)
 
 #define TYPE_UNUSED_HOTPLUG   "hotplug-type"
 #define TYPE_UNUSED_NOHOTPLUG "nohotplug-type"
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index f8de709a0b..1c763015d0 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -1055,9 +1055,6 @@ static gboolean match_interval_mapping_node(gpointer key,
     TestGTreeMapping *map_a, *map_b;
     TestGTreeInterval *a, *b;
     struct match_node_data *d = (struct match_node_data *)data;
-    char *str = g_strdup_printf("dest");
-
-    g_free(str);
     a = (TestGTreeInterval *)key;
     b = (TestGTreeInterval *)d->key;