aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile.objs1
-rw-r--r--audio/audio.c2
-rw-r--r--audio/paaudio.c70
-rw-r--r--backends/Makefile.objs4
-rw-r--r--backends/dbus-vmstate.c510
-rw-r--r--backends/trace-events7
-rw-r--r--block.c47
-rw-r--r--block/Makefile.objs1
-rw-r--r--block/backup-top.c4
-rw-r--r--block/blkdebug.c93
-rw-r--r--block/filter-compress.c168
-rw-r--r--block/qcow2-bitmap.c41
-rw-r--r--block/qcow2.c102
-rw-r--r--block/throttle-groups.c4
-rwxr-xr-xconfigure25
-rw-r--r--docs/interop/dbus-vmstate.rst74
-rw-r--r--docs/interop/dbus.rst110
-rw-r--r--docs/interop/index.rst2
-rw-r--r--hw/arm/aspeed_ast2600.c3
-rw-r--r--hw/arm/sbsa-ref.c1
-rw-r--r--hw/arm/smmuv3-internal.h6
-rw-r--r--hw/arm/smmuv3.c28
-rw-r--r--hw/audio/hda-codec.c8
-rw-r--r--hw/block/onenand.c2
-rw-r--r--hw/core/Makefile.objs1
-rw-r--r--hw/core/machine.c4
-rw-r--r--hw/core/numa.c7
-rw-r--r--hw/core/qdev.c21
-rw-r--r--hw/core/vmstate-if.c23
-rw-r--r--hw/display/qxl-render.c9
-rw-r--r--hw/display/qxl.c1
-rw-r--r--hw/ide/cmd646.c2
-rw-r--r--hw/ide/isa.c2
-rw-r--r--hw/ide/piix.c2
-rw-r--r--hw/ide/via.c2
-rw-r--r--hw/misc/max111x.c2
-rw-r--r--hw/net/eepro100.c4
-rw-r--r--hw/net/virtio-net.c3
-rw-r--r--hw/nvram/eeprom93xx.c4
-rw-r--r--hw/ppc/spapr_drc.c9
-rw-r--r--hw/ppc/spapr_iommu.c4
-rw-r--r--hw/s390x/s390-skeys.c2
-rw-r--r--hw/vfio/pci.c4
-rw-r--r--include/block/block.h1
-rw-r--r--include/hw/vmstate-if.h40
-rw-r--r--include/migration/register.h4
-rw-r--r--include/migration/vmstate.h10
-rw-r--r--include/qemu/dbus.h19
-rw-r--r--include/qemu/osdep.h1
-rw-r--r--include/qom/object.h3
-rw-r--r--include/ui/console.h2
-rw-r--r--include/ui/qemu-pixman.h2
-rw-r--r--migration/savevm.c20
-rw-r--r--qapi/block-core.json24
-rw-r--r--qemu-deprecated.texi8
-rw-r--r--stubs/vmstate.c4
-rw-r--r--target/arm/arm-powerctl.c3
-rw-r--r--target/arm/cpu.c65
-rw-r--r--target/arm/cpu.h5
-rw-r--r--target/arm/helper.c42
-rw-r--r--target/i386/cpu.c8
-rw-r--r--target/xtensa/cpu.h10
-rwxr-xr-xtarget/xtensa/import_core.sh6
-rw-r--r--target/xtensa/overlay_tool.h15
-rw-r--r--target/xtensa/translate.c3
-rw-r--r--tests/Makefile.include30
-rwxr-xr-xtests/dbus-vmstate-daemon.sh95
-rw-r--r--tests/dbus-vmstate-test.c382
-rw-r--r--tests/dbus-vmstate1.xml12
-rw-r--r--tests/docker/dockerfiles/centos7.docker1
-rw-r--r--tests/docker/dockerfiles/debian10.docker1
-rw-r--r--tests/docker/dockerfiles/fedora.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu.docker1
-rw-r--r--tests/iothread.c30
-rw-r--r--tests/migration-helpers.c167
-rw-r--r--tests/migration-helpers.h37
-rw-r--r--tests/migration-test.c176
-rwxr-xr-xtests/qemu-iotests/0075
-rwxr-xr-xtests/qemu-iotests/0142
-rwxr-xr-xtests/qemu-iotests/0155
-rwxr-xr-xtests/qemu-iotests/0196
-rwxr-xr-xtests/qemu-iotests/0206
-rwxr-xr-xtests/qemu-iotests/02410
-rwxr-xr-xtests/qemu-iotests/0265
-rwxr-xr-xtests/qemu-iotests/0282
-rwxr-xr-xtests/qemu-iotests/0297
-rwxr-xr-xtests/qemu-iotests/0319
-rw-r--r--tests/qemu-iotests/031.out36
-rwxr-xr-xtests/qemu-iotests/03615
-rw-r--r--tests/qemu-iotests/036.out66
-rwxr-xr-xtests/qemu-iotests/03927
-rw-r--r--tests/qemu-iotests/039.out22
-rwxr-xr-xtests/qemu-iotests/04144
-rw-r--r--tests/qemu-iotests/041.out4
-rwxr-xr-xtests/qemu-iotests/0434
-rwxr-xr-xtests/qemu-iotests/0462
-rwxr-xr-xtests/qemu-iotests/0484
-rwxr-xr-xtests/qemu-iotests/0508
-rwxr-xr-xtests/qemu-iotests/0517
-rwxr-xr-xtests/qemu-iotests/0534
-rwxr-xr-xtests/qemu-iotests/0587
-rwxr-xr-xtests/qemu-iotests/05920
-rwxr-xr-xtests/qemu-iotests/06014
-rw-r--r--tests/qemu-iotests/060.out20
-rwxr-xr-xtests/qemu-iotests/06163
-rw-r--r--tests/qemu-iotests/061.out72
-rwxr-xr-xtests/qemu-iotests/0625
-rwxr-xr-xtests/qemu-iotests/06318
-rw-r--r--tests/qemu-iotests/063.out3
-rwxr-xr-xtests/qemu-iotests/0667
-rwxr-xr-xtests/qemu-iotests/0676
-rwxr-xr-xtests/qemu-iotests/0686
-rwxr-xr-xtests/qemu-iotests/0692
-rwxr-xr-xtests/qemu-iotests/0717
-rwxr-xr-xtests/qemu-iotests/0734
-rwxr-xr-xtests/qemu-iotests/0744
-rwxr-xr-xtests/qemu-iotests/0793
-rwxr-xr-xtests/qemu-iotests/0807
-rwxr-xr-xtests/qemu-iotests/0816
-rwxr-xr-xtests/qemu-iotests/08518
-rw-r--r--tests/qemu-iotests/085.out8
-rwxr-xr-xtests/qemu-iotests/0882
-rwxr-xr-xtests/qemu-iotests/0902
-rwxr-xr-xtests/qemu-iotests/0912
-rw-r--r--tests/qemu-iotests/091.out2
-rwxr-xr-xtests/qemu-iotests/0922
-rwxr-xr-xtests/qemu-iotests/0944
-rwxr-xr-xtests/qemu-iotests/0955
-rwxr-xr-xtests/qemu-iotests/0986
-rwxr-xr-xtests/qemu-iotests/09910
-rwxr-xr-xtests/qemu-iotests/1035
-rwxr-xr-xtests/qemu-iotests/1062
-rwxr-xr-xtests/qemu-iotests/10810
-rwxr-xr-xtests/qemu-iotests/1094
-rwxr-xr-xtests/qemu-iotests/11011
-rw-r--r--tests/qemu-iotests/110.out4
-rwxr-xr-xtests/qemu-iotests/1113
-rwxr-xr-xtests/qemu-iotests/11237
-rwxr-xr-xtests/qemu-iotests/1142
-rwxr-xr-xtests/qemu-iotests/1153
-rwxr-xr-xtests/qemu-iotests/1219
-rwxr-xr-xtests/qemu-iotests/1226
-rwxr-xr-xtests/qemu-iotests/1234
-rwxr-xr-xtests/qemu-iotests/1252
-rwxr-xr-xtests/qemu-iotests/13717
-rw-r--r--tests/qemu-iotests/137.out6
-rwxr-xr-xtests/qemu-iotests/1388
-rwxr-xr-xtests/qemu-iotests/1414
-rwxr-xr-xtests/qemu-iotests/1422
-rwxr-xr-xtests/qemu-iotests/1444
-rwxr-xr-xtests/qemu-iotests/15312
-rwxr-xr-xtests/qemu-iotests/15610
-rwxr-xr-xtests/qemu-iotests/1592
-rwxr-xr-xtests/qemu-iotests/1603
-rwxr-xr-xtests/qemu-iotests/1614
-rwxr-xr-xtests/qemu-iotests/1702
-rwxr-xr-xtests/qemu-iotests/1726
-rwxr-xr-xtests/qemu-iotests/1733
-rwxr-xr-xtests/qemu-iotests/1742
-rwxr-xr-xtests/qemu-iotests/1752
-rwxr-xr-xtests/qemu-iotests/1767
-rwxr-xr-xtests/qemu-iotests/1786
-rwxr-xr-xtests/qemu-iotests/1822
-rwxr-xr-xtests/qemu-iotests/1832
-rwxr-xr-xtests/qemu-iotests/1854
-rwxr-xr-xtests/qemu-iotests/1876
-rwxr-xr-xtests/qemu-iotests/1904
-rwxr-xr-xtests/qemu-iotests/19111
-rwxr-xr-xtests/qemu-iotests/1952
-rwxr-xr-xtests/qemu-iotests/1976
-rwxr-xr-xtests/qemu-iotests/1986
-rw-r--r--tests/qemu-iotests/198.out4
-rwxr-xr-xtests/qemu-iotests/2007
-rwxr-xr-xtests/qemu-iotests/2016
-rwxr-xr-xtests/qemu-iotests/21446
-rw-r--r--tests/qemu-iotests/214.out14
-rwxr-xr-xtests/qemu-iotests/2156
-rwxr-xr-xtests/qemu-iotests/2173
-rwxr-xr-xtests/qemu-iotests/2205
-rwxr-xr-xtests/qemu-iotests/2252
-rwxr-xr-xtests/qemu-iotests/2293
-rwxr-xr-xtests/qemu-iotests/2324
-rwxr-xr-xtests/qemu-iotests/2352
-rwxr-xr-xtests/qemu-iotests/24310
-rwxr-xr-xtests/qemu-iotests/24415
-rwxr-xr-xtests/qemu-iotests/2474
-rwxr-xr-xtests/qemu-iotests/2494
-rwxr-xr-xtests/qemu-iotests/2505
-rwxr-xr-xtests/qemu-iotests/2522
-rwxr-xr-xtests/qemu-iotests/2615
-rwxr-xr-xtests/qemu-iotests/2652
-rwxr-xr-xtests/qemu-iotests/26717
-rwxr-xr-xtests/qemu-iotests/2733
-rwxr-xr-xtests/qemu-iotests/check6
-rw-r--r--tests/qemu-iotests/common.filter47
-rw-r--r--tests/qemu-iotests/common.rc63
-rw-r--r--tests/qemu-iotests/iotests.py18
-rwxr-xr-xtests/qemu-iotests/qcow2.py23
-rw-r--r--ui/console.c73
-rw-r--r--ui/trace-events2
-rw-r--r--util/Makefile.objs3
-rw-r--r--util/dbus.c57
-rw-r--r--util/osdep.c15
205 files changed, 3131 insertions, 886 deletions
diff --git a/.travis.yml b/.travis.yml
index 376b7d6..638fba4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -247,7 +247,7 @@ matrix:
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
language: python
python:
- - "3.4"
+ - "3.5"
- env:
diff --git a/MAINTAINERS b/MAINTAINERS
index 8571327..cd2dc13 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2196,6 +2196,8 @@ Migration
M: Juan Quintela <quintela@redhat.com>
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
S: Maintained
+F: hw/core/vmstate-if.c
+F: include/hw/vmstate-if.h
F: include/migration/
F: migration/
F: scripts/vmstate-static-checker.py
@@ -2204,6 +2206,16 @@ F: tests/migration-test.c
F: docs/devel/migration.rst
F: qapi/migration.json
+D-Bus
+M: Marc-André Lureau <marcandre.lureau@redhat.com>
+S: Maintained
+F: backends/dbus-vmstate.c
+F: tests/dbus-vmstate*
+F: util/dbus.c
+F: include/qemu/dbus.h
+F: docs/interop/dbus.rst
+F: docs/interop/dbus-vmstate.rst
+
Seccomp
M: Eduardo Otubo <otubo@redhat.com>
S: Supported
diff --git a/Makefile.objs b/Makefile.objs
index 02bf5ce..7c1e50f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -128,6 +128,7 @@ vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
trace-events-subdirs =
trace-events-subdirs += accel/kvm
trace-events-subdirs += accel/tcg
+trace-events-subdirs += backends
trace-events-subdirs += crypto
trace-events-subdirs += monitor
ifeq ($(CONFIG_USER_ONLY),y)
diff --git a/audio/audio.c b/audio/audio.c
index 56fae55..abea027 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1738,7 +1738,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
if (dev->timer_period <= 0) {
s->period_ticks = 1;
} else {
- s->period_ticks = dev->timer_period * SCALE_US;
+ s->period_ticks = dev->timer_period * (int64_t)SCALE_US;
}
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 55a91f8..dbfe48c 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -156,34 +156,48 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
{
PAVoiceIn *p = (PAVoiceIn *) hw;
PAConnection *c = p->g->conn;
- size_t l;
- int r;
+ size_t total = 0;
pa_threaded_mainloop_lock(c->mainloop);
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
"pa_threaded_mainloop_lock failed\n");
+ if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
+ /* wait for stream to become ready */
+ goto unlock;
+ }
+
+ while (total < length) {
+ size_t l;
+ int r;
+
+ if (!p->read_length) {
+ r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
+ CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+ "pa_stream_peek failed\n");
+ if (!p->read_length) {
+ /* buffer is empty */
+ break;
+ }
+ }
- if (!p->read_length) {
- r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
- CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
- "pa_stream_peek failed\n");
- }
-
- l = MIN(p->read_length, length);
- memcpy(data, p->read_data, l);
+ l = MIN(p->read_length, length - total);
+ memcpy((char *)data + total, p->read_data, l);
- p->read_data += l;
- p->read_length -= l;
+ p->read_data += l;
+ p->read_length -= l;
+ total += l;
- if (!p->read_length) {
- r = pa_stream_drop(p->stream);
- CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
- "pa_stream_drop failed\n");
+ if (!p->read_length) {
+ r = pa_stream_drop(p->stream);
+ CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+ "pa_stream_drop failed\n");
+ }
}
+unlock:
pa_threaded_mainloop_unlock(c->mainloop);
- return l;
+ return total;
unlock_and_fail:
pa_threaded_mainloop_unlock(c->mainloop);
@@ -536,7 +550,6 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
{
int err;
- pa_threaded_mainloop_lock(c->mainloop);
/*
* wait until actually connects. workaround pa bug #247
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
@@ -550,7 +563,6 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
dolog("Failed to disconnect! err=%d\n", err);
}
pa_stream_unref(stream);
- pa_threaded_mainloop_unlock(c->mainloop);
}
static void qpa_fini_out (HWVoiceOut *hw)
@@ -558,8 +570,12 @@ static void qpa_fini_out (HWVoiceOut *hw)
PAVoiceOut *pa = (PAVoiceOut *) hw;
if (pa->stream) {
- qpa_simple_disconnect(pa->g->conn, pa->stream);
+ PAConnection *c = pa->g->conn;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+ qpa_simple_disconnect(c, pa->stream);
pa->stream = NULL;
+ pa_threaded_mainloop_unlock(c->mainloop);
}
}
@@ -568,8 +584,20 @@ static void qpa_fini_in (HWVoiceIn *hw)
PAVoiceIn *pa = (PAVoiceIn *) hw;
if (pa->stream) {
- qpa_simple_disconnect(pa->g->conn, pa->stream);
+ PAConnection *c = pa->g->conn;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+ if (pa->read_length) {
+ int r = pa_stream_drop(pa->stream);
+ if (r) {
+ qpa_logerr(pa_context_errno(c->context),
+ "pa_stream_drop failed\n");
+ }
+ pa->read_length = 0;
+ }
+ qpa_simple_disconnect(c, pa->stream);
pa->stream = NULL;
+ pa_threaded_mainloop_unlock(c->mainloop);
}
}
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index f069111..28a847c 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -17,3 +17,7 @@ endif
common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO)) += vhost-user.o
common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
+
+common-obj-$(CONFIG_GIO) += dbus-vmstate.o
+dbus-vmstate.o-cflags = $(GIO_CFLAGS)
+dbus-vmstate.o-libs = $(GIO_LIBS)
diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c
new file mode 100644
index 0000000..56b482a
--- /dev/null
+++ b/backends/dbus-vmstate.c
@@ -0,0 +1,510 @@
+/*
+ * QEMU dbus-vmstate
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * 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 "qemu/units.h"
+#include "qemu/dbus.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "qapi/qmp/qerror.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+typedef struct DBusVMState DBusVMState;
+typedef struct DBusVMStateClass DBusVMStateClass;
+
+#define TYPE_DBUS_VMSTATE "dbus-vmstate"
+#define DBUS_VMSTATE(obj) \
+ OBJECT_CHECK(DBusVMState, (obj), TYPE_DBUS_VMSTATE)
+#define DBUS_VMSTATE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(DBusVMStateClass, (obj), TYPE_DBUS_VMSTATE)
+#define DBUS_VMSTATE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(DBusVMStateClass, (klass), TYPE_DBUS_VMSTATE)
+
+struct DBusVMStateClass {
+ ObjectClass parent_class;
+};
+
+struct DBusVMState {
+ Object parent;
+
+ GDBusConnection *bus;
+ char *dbus_addr;
+ char *id_list;
+
+ uint32_t data_size;
+ uint8_t *data;
+};
+
+static const GDBusPropertyInfo vmstate_property_info[] = {
+ { -1, (char *) "Id", (char *) "s",
+ G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL },
+};
+
+static const GDBusPropertyInfo * const vmstate_property_info_pointers[] = {
+ &vmstate_property_info[0],
+ NULL
+};
+
+static const GDBusInterfaceInfo vmstate1_interface_info = {
+ -1,
+ (char *) "org.qemu.VMState1",
+ (GDBusMethodInfo **) NULL,
+ (GDBusSignalInfo **) NULL,
+ (GDBusPropertyInfo **) &vmstate_property_info_pointers,
+ NULL,
+};
+
+#define DBUS_VMSTATE_SIZE_LIMIT (1 * MiB)
+
+static GHashTable *
+get_id_list_set(DBusVMState *self)
+{
+ g_auto(GStrv) ids = NULL;
+ g_autoptr(GHashTable) set = NULL;
+ int i;
+
+ if (!self->id_list) {
+ return NULL;
+ }
+
+ ids = g_strsplit(self->id_list, ",", -1);
+ set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ for (i = 0; ids[i]; i++) {
+ g_hash_table_add(set, ids[i]);
+ ids[i] = NULL;
+ }
+
+ return g_steal_pointer(&set);
+}
+
+static GHashTable *
+dbus_get_proxies(DBusVMState *self, GError **err)
+{
+ g_autoptr(GHashTable) proxies = NULL;
+ g_autoptr(GHashTable) ids = NULL;
+ g_auto(GStrv) names = NULL;
+ Error *error = NULL;
+ size_t i;
+
+ ids = get_id_list_set(self);
+ proxies = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+
+ names = qemu_dbus_get_queued_owners(self->bus, "org.qemu.VMState1", &error);
+ if (!names) {
+ g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ error_get_pretty(error));
+ error_free(error);
+ return NULL;
+ }
+
+ for (i = 0; names[i]; i++) {
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GVariant) result = NULL;
+ g_autofree char *id = NULL;
+ size_t size;
+
+ proxy = g_dbus_proxy_new_sync(self->bus, G_DBUS_PROXY_FLAGS_NONE,
+ (GDBusInterfaceInfo *) &vmstate1_interface_info,
+ names[i],
+ "/org/qemu/VMState1",
+ "org.qemu.VMState1",
+ NULL, err);
+ if (!proxy) {
+ return NULL;
+ }
+
+ result = g_dbus_proxy_get_cached_property(proxy, "Id");
+ if (!result) {
+ g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "VMState Id property is missing.");
+ return NULL;
+ }
+
+ id = g_variant_dup_string(result, &size);
+ if (ids && !g_hash_table_remove(ids, id)) {
+ g_clear_pointer(&id, g_free);
+ g_clear_object(&proxy);
+ continue;
+ }
+ if (size == 0 || size >= 256) {
+ g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "VMState Id '%s' is invalid.", id);
+ return NULL;
+ }
+
+ if (!g_hash_table_insert(proxies, id, proxy)) {
+ g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Duplicated VMState Id '%s'", id);
+ return NULL;
+ }
+ id = NULL;
+ proxy = NULL;
+
+ g_clear_pointer(&result, g_variant_unref);
+ }
+
+ if (ids) {
+ g_autofree char **left = NULL;
+
+ left = (char **)g_hash_table_get_keys_as_array(ids, NULL);
+ if (*left) {
+ g_autofree char *leftids = g_strjoinv(",", left);
+ g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Required VMState Id are missing: %s", leftids);
+ return NULL;
+ }
+ }
+
+ return g_steal_pointer(&proxies);
+}
+
+static int
+dbus_load_state_proxy(GDBusProxy *proxy, const uint8_t *data, size_t size)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GVariant) result = NULL;
+ g_autoptr(GVariant) value = NULL;
+
+ value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+ data, size, sizeof(char));
+ result = g_dbus_proxy_call_sync(proxy, "Load",
+ g_variant_new("(@ay)",
+ g_steal_pointer(&value)),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, &err);
+ if (!result) {
+ error_report("%s: Failed to Load: %s", __func__, err->message);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int dbus_vmstate_post_load(void *opaque, int version_id)
+{
+ DBusVMState *self = DBUS_VMSTATE(opaque);
+ g_autoptr(GInputStream) m = NULL;
+ g_autoptr(GDataInputStream) s = NULL;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GHashTable) proxies = NULL;
+ uint32_t nelem;
+
+ trace_dbus_vmstate_post_load(version_id);
+
+ proxies = dbus_get_proxies(self, &err);
+ if (!proxies) {
+ error_report("%s: Failed to get proxies: %s", __func__, err->message);
+ return -1;
+ }
+
+ m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL);
+ s = g_data_input_stream_new(m);
+ g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+
+ nelem = g_data_input_stream_read_uint32(s, NULL, &err);
+ if (err) {
+ goto error;
+ }
+
+ while (nelem > 0) {
+ GDBusProxy *proxy = NULL;
+ uint32_t len;
+ gsize bytes_read, avail;
+ char id[256];
+
+ len = g_data_input_stream_read_uint32(s, NULL, &err);
+ if (err) {
+ goto error;
+ }
+ if (len >= 256) {
+ error_report("%s: Invalid DBus vmstate proxy name %u",
+ __func__, len);
+ return -1;
+ }
+ if (!g_input_stream_read_all(G_INPUT_STREAM(s), id, len,
+ &bytes_read, NULL, &err)) {
+ goto error;
+ }
+ g_return_val_if_fail(bytes_read == len, -1);
+ id[len] = 0;
+
+ trace_dbus_vmstate_loading(id);
+
+ proxy = g_hash_table_lookup(proxies, id);
+ if (!proxy) {
+ error_report("%s: Failed to find proxy Id '%s'", __func__, id);
+ return -1;
+ }
+
+ len = g_data_input_stream_read_uint32(s, NULL, &err);
+ avail = g_buffered_input_stream_get_available(
+ G_BUFFERED_INPUT_STREAM(s));
+
+ if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) {
+ error_report("%s: Invalid vmstate size: %u", __func__, len);
+ return -1;
+ }
+
+ if (dbus_load_state_proxy(proxy,
+ g_buffered_input_stream_peek_buffer(G_BUFFERED_INPUT_STREAM(s),
+ NULL),
+ len) < 0) {
+ error_report("%s: Failed to restore Id '%s'", __func__, id);
+ return -1;
+ }
+
+ if (!g_seekable_seek(G_SEEKABLE(s), len, G_SEEK_CUR, NULL, &err)) {
+ goto error;
+ }
+
+ nelem -= 1;
+ }
+
+ return 0;
+
+error:
+ error_report("%s: Failed to read from stream: %s", __func__, err->message);
+ return -1;
+}
+
+static void
+dbus_save_state_proxy(gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GDataOutputStream *s = user_data;
+ const char *id = key;
+ GDBusProxy *proxy = value;
+ g_autoptr(GVariant) result = NULL;
+ g_autoptr(GVariant) child = NULL;
+ g_autoptr(GError) err = NULL;
+ const uint8_t *data;
+ gsize size;
+
+ trace_dbus_vmstate_saving(id);
+
+ result = g_dbus_proxy_call_sync(proxy, "Save",
+ NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, &err);
+ if (!result) {
+ error_report("%s: Failed to Save: %s", __func__, err->message);
+ return;
+ }
+
+ child = g_variant_get_child_value(result, 0);
+ data = g_variant_get_fixed_array(child, &size, sizeof(char));
+ if (!data) {
+ error_report("%s: Failed to Save: not a byte array", __func__);
+ return;
+ }
+ if (size > DBUS_VMSTATE_SIZE_LIMIT) {
+ error_report("%s: Too large vmstate data to save: %zu",
+ __func__, (size_t)size);
+ return;
+ }
+
+ if (!g_data_output_stream_put_uint32(s, strlen(id), NULL, &err) ||
+ !g_data_output_stream_put_string(s, id, NULL, &err) ||
+ !g_data_output_stream_put_uint32(s, size, NULL, &err) ||
+ !g_output_stream_write_all(G_OUTPUT_STREAM(s),
+ data, size, NULL, NULL, &err)) {
+ error_report("%s: Failed to write to stream: %s",
+ __func__, err->message);
+ }
+}
+
+static int dbus_vmstate_pre_save(void *opaque)
+{
+ DBusVMState *self = DBUS_VMSTATE(opaque);
+ g_autoptr(GOutputStream) m = NULL;
+ g_autoptr(GDataOutputStream) s = NULL;
+ g_autoptr(GHashTable) proxies = NULL;
+ g_autoptr(GError) err = NULL;
+
+ trace_dbus_vmstate_pre_save();
+
+ proxies = dbus_get_proxies(self, &err);
+ if (!proxies) {
+ error_report("%s: Failed to get proxies: %s", __func__, err->message);
+ return -1;
+ }
+
+ m = g_memory_output_stream_new_resizable();
+ s = g_data_output_stream_new(m);
+ g_data_output_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
+
+ if (!g_data_output_stream_put_uint32(s, g_hash_table_size(proxies),
+ NULL, &err)) {
+ error_report("%s: Failed to write to stream: %s",
+ __func__, err->message);
+ return -1;
+ }
+
+ g_hash_table_foreach(proxies, dbus_save_state_proxy, s);
+
+ if (g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m))
+ > UINT32_MAX) {
+ error_report("%s: DBus vmstate buffer is too large", __func__);
+ return -1;
+ }
+
+ if (!g_output_stream_close(G_OUTPUT_STREAM(m), NULL, &err)) {
+ error_report("%s: Failed to close stream: %s", __func__, err->message);
+ return -1;
+ }
+
+ g_free(self->data);
+ self->data_size =
+ g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m));
+ self->data =
+ g_memory_output_stream_steal_data(G_MEMORY_OUTPUT_STREAM(m));
+
+ return 0;
+}
+
+static const VMStateDescription dbus_vmstate = {
+ .name = TYPE_DBUS_VMSTATE,
+ .version_id = 0,
+ .pre_save = dbus_vmstate_pre_save,
+ .post_load = dbus_vmstate_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(data_size, DBusVMState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, DBusVMState, 0, 0, data_size),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void
+dbus_vmstate_complete(UserCreatable *uc, Error **errp)
+{
+ DBusVMState *self = DBUS_VMSTATE(uc);
+ g_autoptr(GError) err = NULL;
+
+ if (!object_resolve_path_type("", TYPE_DBUS_VMSTATE, NULL)) {
+ error_setg(errp, "There is already an instance of %s",
+ TYPE_DBUS_VMSTATE);
+ return;
+ }
+
+ if (!self->dbus_addr) {
+ error_setg(errp, QERR_MISSING_PARAMETER, "addr");
+ return;
+ }
+
+ self->bus = g_dbus_connection_new_for_address_sync(self->dbus_addr,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+ NULL, NULL, &err);
+ if (err) {
+ error_setg(errp, "failed to connect to DBus: '%s'", err->message);
+ return;
+ }
+
+ if (vmstate_register(VMSTATE_IF(self), -1, &dbus_vmstate, self) < 0) {
+ error_setg(errp, "Failed to register vmstate");
+ }
+}
+
+static void
+dbus_vmstate_finalize(Object *o)
+{
+ DBusVMState *self = DBUS_VMSTATE(o);
+
+ vmstate_unregister(VMSTATE_IF(self), &dbus_vmstate, self);
+
+ g_clear_object(&self->bus);
+ g_free(self->dbus_addr);
+ g_free(self->id_list);
+ g_free(self->data);
+}
+
+static char *
+get_dbus_addr(Object *o, Error **errp)
+{
+ DBusVMState *self = DBUS_VMSTATE(o);
+
+ return g_strdup(self->dbus_addr);
+}
+
+static void
+set_dbus_addr(Object *o, const char *str, Error **errp)
+{
+ DBusVMState *self = DBUS_VMSTATE(o);
+
+ g_free(self->dbus_addr);
+ self->dbus_addr = g_strdup(str);
+}
+
+static char *
+get_id_list(Object *o, Error **errp)
+{
+ DBusVMState *self = DBUS_VMSTATE(o);
+
+ return g_strdup(self->id_list);
+}
+
+static void
+set_id_list(Object *o, const char *str, Error **errp)
+{
+ DBusVMState *self = DBUS_VMSTATE(o);
+
+ g_free(self->id_list);
+ self->id_list = g_strdup(str);
+}
+
+static char *
+dbus_vmstate_get_id(VMStateIf *vmif)
+{
+ return g_strdup(TYPE_DBUS_VMSTATE);
+}
+
+static void
+dbus_vmstate_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+ VMStateIfClass *vc = VMSTATE_IF_CLASS(oc);
+
+ ucc->complete = dbus_vmstate_complete;
+ vc->get_id = dbus_vmstate_get_id;
+
+ object_class_property_add_str(oc, "addr",
+ get_dbus_addr, set_dbus_addr,
+ &error_abort);
+ object_class_property_add_str(oc, "id-list",
+ get_id_list, set_id_list,
+ &error_abort);
+}
+
+static const TypeInfo dbus_vmstate_info = {
+ .name = TYPE_DBUS_VMSTATE,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(DBusVMState),
+ .instance_finalize = dbus_vmstate_finalize,
+ .class_size = sizeof(DBusVMStateClass),
+ .class_init = dbus_vmstate_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { TYPE_VMSTATE_IF },
+ { }
+ }
+};
+
+static void
+register_types(void)
+{
+ type_register_static(&dbus_vmstate_info);
+}
+
+type_init(register_types);
diff --git a/backends/trace-events b/backends/trace-events
new file mode 100644
index 0000000..59058f7
--- /dev/null
+++ b/backends/trace-events
@@ -0,0 +1,7 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# dbus-vmstate.c
+dbus_vmstate_pre_save(void)
+dbus_vmstate_post_load(int version_id) "version_id: %d"
+dbus_vmstate_loading(const char *id) "id: %s"
+dbus_vmstate_saving(const char *id) "id: %s"
diff --git a/block.c b/block.c
index 1b6f7c8..ecd09db 100644
--- a/block.c
+++ b/block.c
@@ -2227,6 +2227,24 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
*nshared = shared;
}
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
+{
+ static const uint64_t permissions[] = {
+ [BLOCK_PERMISSION_CONSISTENT_READ] = BLK_PERM_CONSISTENT_READ,
+ [BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
+ [BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
+ [BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
+ [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
+ };
+
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX);
+ QEMU_BUILD_BUG_ON(1UL << ARRAY_SIZE(permissions) != BLK_PERM_ALL + 1);
+
+ assert(qapi_perm < BLOCK_PERMISSION__MAX);
+
+ return permissions[qapi_perm];
+}
+
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs)
{
@@ -4854,36 +4872,23 @@ static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
const BdrvChild *child)
{
- typedef struct {
- unsigned int flag;
- BlockPermission num;
- } PermissionMap;
-
- static const PermissionMap permissions[] = {
- { BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
- { BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
- { BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
- { BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
- { BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
- { 0, 0 }
- };
- const PermissionMap *p;
+ BlockPermission qapi_perm;
XDbgBlockGraphEdge *edge;
- QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);
-
edge = g_new0(XDbgBlockGraphEdge, 1);
edge->parent = xdbg_graph_node_num(gr, parent);
edge->child = xdbg_graph_node_num(gr, child->bs);
edge->name = g_strdup(child->name);
- for (p = permissions; p->flag; p++) {
- if (p->flag & child->perm) {
- QAPI_LIST_ADD(edge->perm, p->num);
+ for (qapi_perm = 0; qapi_perm < BLOCK_PERMISSION__MAX; qapi_perm++) {
+ uint64_t flag = bdrv_qapi_perm_to_blk_perm(qapi_perm);
+
+ if (flag & child->perm) {
+ QAPI_LIST_ADD(edge->perm, qapi_perm);
}
- if (p->flag & child->shared_perm) {
- QAPI_LIST_ADD(edge->shared_perm, p->num);
+ if (flag & child->shared_perm) {
+ QAPI_LIST_ADD(edge->shared_perm, qapi_perm);
}
}
diff --git a/block/Makefile.objs b/block/Makefile.objs
index e394fe0..330529b 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -43,6 +43,7 @@ block-obj-y += crypto.o
block-obj-y += aio_task.o
block-obj-y += backup-top.o
+block-obj-y += filter-compress.o
common-obj-y += stream.o
diff --git a/block/backup-top.c b/block/backup-top.c
index 7cdb1f8..818d3f2 100644
--- a/block/backup-top.c
+++ b/block/backup-top.c
@@ -257,12 +257,12 @@ void bdrv_backup_top_drop(BlockDriverState *bs)
BDRVBackupTopState *s = bs->opaque;
AioContext *aio_context = bdrv_get_aio_context(bs);
- block_copy_state_free(s->bcs);
-
aio_context_acquire(aio_context);
bdrv_drained_begin(bs);
+ block_copy_state_free(s->bcs);
+
s->active = false;
bdrv_child_refresh_perms(bs, bs->backing, &error_abort);
bdrv_replace_node(bs, backing_bs(bs), &error_abort);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 5ae96c5..af44aa9 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -28,10 +28,14 @@
#include "qemu/cutils.h"
#include "qemu/config-file.h"
#include "block/block_int.h"
+#include "block/qdict.h"
#include "qemu/module.h"
#include "qemu/option.h"
+#include "qapi/qapi-visit-block-core.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qstring.h"
+#include "qapi/qobject-input-visitor.h"
#include "sysemu/qtest.h"
typedef struct BDRVBlkdebugState {
@@ -44,6 +48,9 @@ typedef struct BDRVBlkdebugState {
uint64_t opt_discard;
uint64_t max_discard;
+ uint64_t take_child_perms;
+ uint64_t unshare_child_perms;
+
/* For blkdebug_refresh_filename() */
char *config_file;
@@ -344,6 +351,69 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
qdict_put_str(options, "x-image", filename);
}
+static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
+ const char *prefix, Error **errp)
+{
+ int ret = 0;
+ QDict *subqdict = NULL;
+ QObject *crumpled_subqdict = NULL;
+ Visitor *v = NULL;
+ BlockPermissionList *perm_list = NULL, *element;
+ Error *local_err = NULL;
+
+ *dest = 0;
+
+ qdict_extract_subqdict(options, &subqdict, prefix);
+ if (!qdict_size(subqdict)) {
+ goto out;
+ }
+
+ crumpled_subqdict = qdict_crumple(subqdict, errp);
+ if (!crumpled_subqdict) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ v = qobject_input_visitor_new(crumpled_subqdict);
+ visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (element = perm_list; element; element = element->next) {
+ *dest |= bdrv_qapi_perm_to_blk_perm(element->value);
+ }
+
+out:
+ qapi_free_BlockPermissionList(perm_list);
+ visit_free(v);
+ qobject_unref(subqdict);
+ qobject_unref(crumpled_subqdict);
+ return ret;
+}
+
+static int blkdebug_parse_perms(BDRVBlkdebugState *s, QDict *options,
+ Error **errp)
+{
+ int ret;
+
+ ret = blkdebug_parse_perm_list(&s->take_child_perms, options,
+ "take-child-perms.", errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = blkdebug_parse_perm_list(&s->unshare_child_perms, options,
+ "unshare-child-perms.", errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
static QemuOptsList runtime_opts = {
.name = "blkdebug",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
@@ -419,6 +489,12 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
/* Set initial state */
s->state = 1;
+ /* Parse permissions modifiers before opening the image file */
+ ret = blkdebug_parse_perms(s, options, errp);
+ if (ret < 0) {
+ goto out;
+ }
+
/* Open the image file */
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
bs, &child_file, false, &local_err);
@@ -916,6 +992,21 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
return 0;
}
+static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
+ const BdrvChildRole *role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
+{
+ BDRVBlkdebugState *s = bs->opaque;
+
+ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
+ nperm, nshared);
+
+ *nperm |= s->take_child_perms;
+ *nshared &= ~s->unshare_child_perms;
+}
+
static const char *const blkdebug_strong_runtime_opts[] = {
"config",
"inject-error.",
@@ -940,7 +1031,7 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_file_open = blkdebug_open,
.bdrv_close = blkdebug_close,
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
- .bdrv_child_perm = bdrv_filter_default_perms,
+ .bdrv_child_perm = blkdebug_child_perm,
.bdrv_getlength = blkdebug_getlength,
.bdrv_refresh_filename = blkdebug_refresh_filename,
diff --git a/block/filter-compress.c b/block/filter-compress.c
new file mode 100644
index 0000000..60137fb
--- /dev/null
+++ b/block/filter-compress.c
@@ -0,0 +1,168 @@
+/*
+ * Compress filter block driver
+ *
+ * Copyright (c) 2019 Virtuozzo International GmbH
+ *
+ * Author:
+ * Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
+ * (based on block/copy-on-read.c by Max Reitz)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "block/block_int.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+
+
+static int compress_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
+{
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
+ errp);
+ if (!bs->file) {
+ return -EINVAL;
+ }
+
+ if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
+ error_setg(errp,
+ "Compression is not supported for underlying format: %s",
+ bdrv_get_format_name(bs->file->bs) ?: "(no format)");
+
+ return -ENOTSUP;
+ }
+
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
+
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
+ bs->file->bs->supported_zero_flags);
+
+ return 0;
+}
+
+
+static int64_t compress_getlength(BlockDriverState *bs)
+{
+ return bdrv_getlength(bs->file->bs);
+}
+
+
+static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
+ uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov,
+ size_t qiov_offset,
+ int flags)
+{
+ return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
+ flags);
+}
+
+
+static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
+ uint64_t offset,
+ uint64_t bytes,
+ QEMUIOVector *qiov,
+ size_t qiov_offset, int flags)
+{
+ return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
+ flags | BDRV_REQ_WRITE_COMPRESSED);
+}
+
+
+static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
+ int64_t offset, int bytes,
+ BdrvRequestFlags flags)
+{
+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
+}
+
+
+static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
+ int64_t offset, int bytes)
+{
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
+}
+
+
+static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
+{
+ BlockDriverInfo bdi;
+ int ret;
+
+ if (!bs->file) {
+ return;
+ }
+
+ ret = bdrv_get_info(bs->file->bs, &bdi);
+ if (ret < 0 || bdi.cluster_size == 0) {
+ return;
+ }
+
+ bs->bl.request_alignment = bdi.cluster_size;
+}
+
+
+static void compress_eject(BlockDriverState *bs, bool eject_flag)
+{
+ bdrv_eject(bs->file->bs, eject_flag);
+}
+
+
+static void compress_lock_medium(BlockDriverState *bs, bool locked)
+{
+ bdrv_lock_medium(bs->file->bs, locked);
+}
+
+
+static bool compress_recurse_is_first_non_filter(BlockDriverState *bs,
+ BlockDriverState *candidate)
+{
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
+}
+
+
+static BlockDriver bdrv_compress = {
+ .format_name = "compress",
+
+ .bdrv_open = compress_open,
+ .bdrv_child_perm = bdrv_filter_default_perms,
+
+ .bdrv_getlength = compress_getlength,
+
+ .bdrv_co_preadv_part = compress_co_preadv_part,
+ .bdrv_co_pwritev_part = compress_co_pwritev_part,
+ .bdrv_co_pwrite_zeroes = compress_co_pwrite_zeroes,
+ .bdrv_co_pdiscard = compress_co_pdiscard,
+ .bdrv_refresh_limits = compress_refresh_limits,
+
+ .bdrv_eject = compress_eject,
+ .bdrv_lock_medium = compress_lock_medium,
+
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
+
+ .bdrv_recurse_is_first_non_filter = compress_recurse_is_first_non_filter,
+
+ .has_variable_length = true,
+ .is_filter = true,
+};
+
+static void bdrv_compress_init(void)
+{
+ bdrv_register(&bdrv_compress);
+}
+
+block_init(bdrv_compress_init);
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index c6c8ebb..d41f5d0 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1703,8 +1703,14 @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
Error **errp)
{
BDRVQcow2State *s = bs->opaque;
- bool found;
- Qcow2BitmapList *bm_list;
+ BdrvDirtyBitmap *bitmap;
+ uint64_t bitmap_directory_size = 0;
+ uint32_t nb_bitmaps = 0;
+
+ if (bdrv_find_dirty_bitmap(bs, name)) {
+ error_setg(errp, "Bitmap already exists: %s", name);
+ return false;
+ }
if (s->qcow_version < 3) {
/* Without autoclear_features, we would always have to assume
@@ -1720,38 +1726,27 @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
goto fail;
}
- if (s->nb_bitmaps == 0) {
- return true;
+ FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
+ nb_bitmaps++;
+ bitmap_directory_size +=
+ calc_dir_entry_size(strlen(bdrv_dirty_bitmap_name(bitmap)), 0);
+ }
}
+ nb_bitmaps++;
+ bitmap_directory_size += calc_dir_entry_size(strlen(name), 0);
- if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) {
+ if (nb_bitmaps > QCOW2_MAX_BITMAPS) {
error_setg(errp,
"Maximum number of persistent bitmaps is already reached");
goto fail;
}
- if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) >
- QCOW2_MAX_BITMAP_DIRECTORY_SIZE)
- {
+ if (bitmap_directory_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
error_setg(errp, "Not enough space in the bitmap directory");
goto fail;
}
- qemu_co_mutex_lock(&s->lock);
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, errp);
- qemu_co_mutex_unlock(&s->lock);
- if (bm_list == NULL) {
- goto fail;
- }
-
- found = find_bitmap_by_name(bm_list, name);
- bitmap_list_free(bm_list);
- if (found) {
- error_setg(errp, "Bitmap with the same name is already stored");
- goto fail;
- }
-
return true;
fail:
diff --git a/block/qcow2.c b/block/qcow2.c
index 7fbaac8..cef9d72 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4221,10 +4221,8 @@ fail:
return ret;
}
-/* XXX: put compressed sectors first, then all the cluster aligned
- tables to avoid losing bytes in alignment */
static coroutine_fn int
-qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
+qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset)
{
@@ -4234,32 +4232,11 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
uint8_t *buf, *out_buf;
uint64_t cluster_offset;
- if (has_data_file(bs)) {
- return -ENOTSUP;
- }
-
- if (bytes == 0) {
- /* align end of file to a sector boundary to ease reading with
- sector based I/Os */
- int64_t len = bdrv_getlength(bs->file->bs);
- if (len < 0) {
- return len;
- }
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
- }
-
- if (offset_into_cluster(s, offset)) {
- return -EINVAL;
- }
+ assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
+ (offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
buf = qemu_blockalign(bs, s->cluster_size);
- if (bytes != s->cluster_size) {
- if (bytes > s->cluster_size ||
- offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
- {
- qemu_vfree(buf);
- return -EINVAL;
- }
+ if (bytes < s->cluster_size) {
/* Zero-pad last write if image size is not cluster aligned */
memset(buf + bytes, 0, s->cluster_size - bytes);
}
@@ -4308,6 +4285,77 @@ fail:
return ret;
}
+static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
+{
+ Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
+
+ assert(!t->cluster_type && !t->l2meta);
+
+ return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
+ t->qiov_offset);
+}
+
+/*
+ * XXX: put compressed sectors first, then all the cluster aligned
+ * tables to avoid losing bytes in alignment
+ */
+static coroutine_fn int
+qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
+ uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, size_t qiov_offset)
+{
+ BDRVQcow2State *s = bs->opaque;
+ AioTaskPool *aio = NULL;
+ int ret = 0;
+
+ if (has_data_file(bs)) {
+ return -ENOTSUP;
+ }
+
+ if (bytes == 0) {
+ /*
+ * align end of file to a sector boundary to ease reading with
+ * sector based I/Os
+ */
+ int64_t len = bdrv_getlength(bs->file->bs);
+ if (len < 0) {
+ return len;
+ }
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
+ }
+
+ if (offset_into_cluster(s, offset)) {
+ return -EINVAL;
+ }
+
+ while (bytes && aio_task_pool_status(aio) == 0) {
+ uint64_t chunk_size = MIN(bytes, s->cluster_size);
+
+ if (!aio && chunk_size != bytes) {
+ aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
+ }
+
+ ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
+ 0, 0, offset, chunk_size, qiov, qiov_offset, NULL);
+ if (ret < 0) {
+ break;
+ }
+ qiov_offset += chunk_size;
+ offset += chunk_size;
+ bytes -= chunk_size;
+ }
+
+ if (aio) {
+ aio_task_pool_wait_all(aio);
+ if (ret == 0) {
+ ret = aio_task_pool_status(aio);
+ }
+ g_free(aio);
+ }
+
+ return ret;
+}
+
static int coroutine_fn
qcow2_co_preadv_compressed(BlockDriverState *bs,
uint64_t file_cluster_offset,
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 77014c7..37695b0 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -893,8 +893,7 @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
{
ThrottleGroup *tg = THROTTLE_GROUP(obj);
ThrottleConfig cfg;
- ThrottleLimits arg = { 0 };
- ThrottleLimits *argp = &arg;
+ ThrottleLimits *argp;
Error *local_err = NULL;
visit_type_ThrottleLimits(v, name, &argp, &local_err);
@@ -912,6 +911,7 @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
unlock:
qemu_mutex_unlock(&tg->lock);
ret:
+ qapi_free_ThrottleLimits(argp);
error_propagate(errp, local_err);
return;
}
diff --git a/configure b/configure
index 940bf9e..0ce2c03 100755
--- a/configure
+++ b/configure
@@ -903,9 +903,9 @@ fi
: ${install=${INSTALL-install}}
# We prefer python 3.x. A bare 'python' is traditionally
# python 2.x, but some distros have it as python 3.x, so
-# we check that before python2
+# we check that too
python=
-for binary in "${PYTHON-python3}" python python2
+for binary in "${PYTHON-python3}" python
do
if has "$binary"
then
@@ -1842,8 +1842,8 @@ fi
# Note that if the Python conditional here evaluates True we will exit
# with status 1 which is a shell 'false' value.
-if ! $python -c 'import sys; sys.exit(sys.version_info < (2,7))'; then
- error_exit "Cannot use '$python', Python 2 >= 2.7 or Python 3 is required." \
+if ! $python -c 'import sys; sys.exit(sys.version_info < (3,5))'; then
+ error_exit "Cannot use '$python', Python >= 3.5 is required." \
"Use --python=/path/to/python to specify a supported Python."
fi
@@ -3701,10 +3701,16 @@ if $pkg_config --atleast-version=$glib_req_ver gio-2.0; then
gio=yes
gio_cflags=$($pkg_config --cflags gio-2.0)
gio_libs=$($pkg_config --libs gio-2.0)
+ gdbus_codegen=$($pkg_config --variable=gdbus_codegen gio-2.0)
else
gio=no
fi
+if $pkg_config --atleast-version=$glib_req_ver gio-unix-2.0; then
+ gio_cflags="$gio_cflags $($pkg_config --cflags gio-unix-2.0)"
+ gio_libs="$gio_libs $($pkg_config --libs gio-unix-2.0)"
+fi
+
# Sanity check that the current size_t matches the
# size that glib thinks it should be. This catches
# problems on multi-arch where people try to build
@@ -6594,15 +6600,6 @@ if test "$supported_os" = "no"; then
echo "us upstream at qemu-devel@nongnu.org."
fi
-# Note that if the Python conditional here evaluates True we will exit
-# with status 1 which is a shell 'false' value.
-if ! $python -c 'import sys; sys.exit(sys.version_info < (3,0))'; then
- echo
- echo "warning: Python 2 support is deprecated" >&2
- echo "warning: Python 3 will be required for building future versions of QEMU" >&2
- python2="y"
-fi
-
config_host_mak="config-host.mak"
echo "# Automatically generated by configure - do not modify" >config-all-disas.mak
@@ -6913,6 +6910,7 @@ if test "$gio" = "yes" ; then
echo "CONFIG_GIO=y" >> $config_host_mak
echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak
echo "GIO_LIBS=$gio_libs" >> $config_host_mak
+ echo "GDBUS_CODEGEN=$gdbus_codegen" >> $config_host_mak
fi
echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak
if test "$gnutls" = "yes" ; then
@@ -7447,7 +7445,6 @@ echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak
-echo "PYTHON2=$python2" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
if $iasl -h > /dev/null 2>&1; then
echo "IASL=$iasl" >> $config_host_mak
diff --git a/docs/interop/dbus-vmstate.rst b/docs/interop/dbus-vmstate.rst
new file mode 100644
index 0000000..1d719c1
--- /dev/null
+++ b/docs/interop/dbus-vmstate.rst
@@ -0,0 +1,74 @@
+=============
+D-Bus VMState
+=============
+
+Introduction
+============
+
+The QEMU dbus-vmstate object's aim is to migrate helpers' data running
+on a QEMU D-Bus bus. (refer to the :doc:`dbus` document for
+some recommendations on D-Bus usage)
+
+Upon migration, QEMU will go through the queue of
+``org.qemu.VMState1`` D-Bus name owners and query their ``Id``. It
+must be unique among the helpers.
+
+It will then save arbitrary data of each Id to be transferred in the
+migration stream and restored/loaded at the corresponding destination
+helper.
+
+For now, the data amount to be transferred is arbitrarily limited to
+1Mb. The state must be saved quickly (a fraction of a second). (D-Bus
+imposes a time limit on reply anyway, and migration would fail if data
+isn't given quickly enough.)
+
+dbus-vmstate object can be configured with the expected list of
+helpers by setting its ``id-list`` property, with a comma-separated
+``Id`` list.
+
+Interface
+=========
+
+On object path ``/org/qemu/VMState1``, the following
+``org.qemu.VMState1`` interface should be implemented:
+
+.. code:: xml
+
+ <interface name="org.qemu.VMState1">
+ <property name="Id" type="s" access="read"/>
+ <method name="Load">
+ <arg type="ay" name="data" direction="in"/>
+ </method>
+ <method name="Save">
+ <arg type="ay" name="data" direction="out"/>
+ </method>
+ </interface>
+
+"Id" property
+-------------
+
+A string that identifies the helper uniquely. (maximum 256 bytes
+including terminating NUL byte)
+
+.. note::
+
+ The helper ID namespace is a separate namespace. In particular, it is not
+ related to QEMU "id" used in -object/-device objects.
+
+Load(in u8[] bytes) method
+--------------------------
+
+The method called on destination with the state to restore.
+
+The helper may be initially started in a waiting state (with
+an --incoming argument for example), and it may resume on success.
+
+An error may be returned to the caller.
+
+Save(out u8[] bytes) method
+---------------------------
+
+The method called on the source to get the current state to be
+migrated. The helper should continue to run normally.
+
+An error may be returned to the caller.
diff --git a/docs/interop/dbus.rst b/docs/interop/dbus.rst
new file mode 100644
index 0000000..76a5bde
--- /dev/null
+++ b/docs/interop/dbus.rst
@@ -0,0 +1,110 @@
+=====
+D-Bus
+=====
+
+Introduction
+============
+
+QEMU may be running with various helper processes involved:
+ - vhost-user* processes (gpu, virtfs, input, etc...)
+ - TPM emulation (or other devices)
+ - user networking (slirp)
+ - network services (DHCP/DNS, samba/ftp etc)
+ - background tasks (compression, streaming etc)
+ - client UI
+ - admin & cli
+
+Having several processes allows stricter security rules, as well as
+greater modularity.
+
+While QEMU itself uses QMP as primary IPC (and Spice/VNC for remote
+display), D-Bus is the de facto IPC of choice on Unix systems. The
+wire format is machine friendly, good bindings exist for various
+languages, and there are various tools available.
+
+Using a bus, helper processes can discover and communicate with each
+other easily, without going through QEMU. The bus topology is also
+easier to apprehend and debug than a mesh. However, it is wise to
+consider the security aspects of it.
+
+Security
+========
+
+A QEMU D-Bus bus should be private to a single VM. Thus, only
+cooperative tasks are running on the same bus to serve the VM.
+
+D-Bus, the protocol and standard, doesn't have mechanisms to enforce
+security between peers once the connection is established. Peers may
+have additional mechanisms to enforce security rules, based for
+example on UNIX credentials.
+
+The daemon can control which peers can send/recv messages using
+various metadata attributes, however, this is alone is not generally
+sufficient to make the deployment secure. The semantics of the actual
+methods implemented using D-Bus are just as critical. Peers need to
+carefully validate any information they received from a peer with a
+different trust level.
+
+dbus-daemon policy
+------------------
+
+dbus-daemon can enforce various policies based on the UID/GID of the
+processes that are connected to it. It is thus a good idea to run
+helpers as different UID from QEMU and set appropriate policies.
+
+Depending on the use case, you may choose different scenarios:
+
+ - Everything the same UID
+
+ - Convenient for developers
+ - Improved reliability - crash of one part doens't take
+ out entire VM
+ - No security benefit over traditional QEMU, unless additional
+ unless additional controls such as SELinux or AppArmor are
+ applied
+
+ - Two UIDs, one for QEMU, one for dbus & helpers
+
+ - Moderately improved user based security isolation
+
+ - Many UIDs, one for QEMU one for dbus and one for each helpers
+
+ - Best user based security isolation
+ - Complex to manager distinct UIDs needed for each VM
+
+For example, to allow only ``qemu`` user to talk to ``qemu-helper``
+``org.qemu.Helper1`` service, a dbus-daemon policy may contain:
+
+.. code:: xml
+
+ <policy user="qemu">
+ <allow send_destination="org.qemu.Helper1"/>
+ <allow receive_sender="org.qemu.Helper1"/>
+ </policy>
+
+ <policy user="qemu-helper">
+ <allow own="org.qemu.Helper1"/>
+ </policy>
+
+
+dbus-daemon can also perfom SELinux checks based on the security
+context of the source and the target. For example, ``virtiofs_t``
+could be allowed to send a message to ``svirt_t``, but ``virtiofs_t``
+wouldn't be allowed to send a message to ``virtiofs_t``.
+
+See dbus-daemon man page for details.
+
+Guidelines
+==========
+
+When implementing new D-Bus interfaces, it is recommended to follow
+the "D-Bus API Design Guidelines":
+https://dbus.freedesktop.org/doc/dbus-api-design.html
+
+The "org.qemu.*" prefix is reserved for services implemented &
+distributed by the QEMU project.
+
+QEMU Interfaces
+===============
+
+:doc:`dbus-vmstate`
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index 3e33fb5..049387a 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -13,6 +13,8 @@ Contents:
:maxdepth: 2
bitmaps
+ dbus
+ dbus-vmstate
live-block-operations
pr-helper
qemu-ga
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index be88005..89e4b00 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -250,6 +250,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(&s->cpu[i]), aspeed_calc_affinity(i),
"mp-affinity", &error_abort);
+ object_property_set_int(OBJECT(&s->cpu[i]), 1125000000, "cntfrq",
+ &error_abort);
+
/*
* TODO: the secondary CPUs are started and a boot helper
* is needed when using -kernel
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 5853bde..9b5bcb5 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -789,7 +789,6 @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data)
mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props;
mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id;
- mc->numa_mem_supported = true;
}
static const TypeInfo sbsa_ref_info = {
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index d190181..4112394 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -99,7 +99,7 @@ REG32(GERROR_IRQ_CFG2, 0x74)
#define A_STRTAB_BASE 0x80 /* 64b */
-#define SMMU_BASE_ADDR_MASK 0xffffffffffe0
+#define SMMU_BASE_ADDR_MASK 0xfffffffffffc0
REG32(STRTAB_BASE_CFG, 0x88)
FIELD(STRTAB_BASE_CFG, FMT, 16, 2)
@@ -461,8 +461,8 @@ typedef struct SMMUEventInfo {
} while (0)
#define EVT_SET_ADDR2(x, addr) \
do { \
- (x)->word[7] = deposit32((x)->word[7], 3, 29, addr >> 16); \
- (x)->word[7] = deposit32((x)->word[7], 0, 16, addr & 0xffff);\
+ (x)->word[7] = (uint32_t)(addr >> 32); \
+ (x)->word[6] = (uint32_t)(addr & 0xffffffff); \
} while (0)
void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index e2fbb83..8b5f157 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -172,7 +172,7 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
case SMMU_EVT_F_STE_FETCH:
EVT_SET_SSID(&evt, info->u.f_ste_fetch.ssid);
EVT_SET_SSV(&evt, info->u.f_ste_fetch.ssv);
- EVT_SET_ADDR(&evt, info->u.f_ste_fetch.addr);
+ EVT_SET_ADDR2(&evt, info->u.f_ste_fetch.addr);
break;
case SMMU_EVT_C_BAD_STE:
EVT_SET_SSID(&evt, info->u.c_bad_ste.ssid);
@@ -376,21 +376,32 @@ bad_ste:
static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
SMMUEventInfo *event)
{
- dma_addr_t addr;
+ dma_addr_t addr, strtab_base;
+ uint32_t log2size;
+ int strtab_size_shift;
int ret;
trace_smmuv3_find_ste(sid, s->features, s->sid_split);
- /* Check SID range */
- if (sid > (1 << SMMU_IDR1_SIDSIZE)) {
+ log2size = FIELD_EX32(s->strtab_base_cfg, STRTAB_BASE_CFG, LOG2SIZE);
+ /*
+ * Check SID range against both guest-configured and implementation limits
+ */
+ if (sid >= (1 << MIN(log2size, SMMU_IDR1_SIDSIZE))) {
event->type = SMMU_EVT_C_BAD_STREAMID;
return -EINVAL;
}
if (s->features & SMMU_FEATURE_2LVL_STE) {
int l1_ste_offset, l2_ste_offset, max_l2_ste, span;
- dma_addr_t strtab_base, l1ptr, l2ptr;
+ dma_addr_t l1ptr, l2ptr;
STEDesc l1std;
- strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK;
+ /*
+ * Align strtab base address to table size. For this purpose, assume it
+ * is not bounded by SMMU_IDR1_SIDSIZE.
+ */
+ strtab_size_shift = MAX(5, (int)log2size - s->sid_split - 1 + 3);
+ strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
+ ~MAKE_64BIT_MASK(0, strtab_size_shift);
l1_ste_offset = sid >> s->sid_split;
l2_ste_offset = sid & ((1 << s->sid_split) - 1);
l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std));
@@ -429,7 +440,10 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
}
addr = l2ptr + l2_ste_offset * sizeof(*ste);
} else {
- addr = s->strtab_base + sid * sizeof(*ste);
+ strtab_size_shift = log2size + 5;
+ strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
+ ~MAKE_64BIT_MASK(0, strtab_size_shift);
+ addr = strtab_base + sid * sizeof(*ste);
}
if (smmu_get_ste(s, addr, ste, event)) {
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index f17e8d8..e711a99 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -265,8 +265,6 @@ static void hda_audio_input_cb(void *opaque, int avail)
int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail);
- hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1)));
-
while (to_transfer) {
uint32_t start = (uint32_t) (wpos & B_MASK);
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
@@ -278,6 +276,8 @@ static void hda_audio_input_cb(void *opaque, int avail)
break;
}
}
+
+ hda_timer_sync_adjust(st, -((wpos - rpos) - (B_SIZE >> 1)));
}
static void hda_audio_output_timer(void *opaque)
@@ -338,8 +338,6 @@ static void hda_audio_output_cb(void *opaque, int avail)
return;
}
- hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1));
-
while (to_transfer) {
uint32_t start = (uint32_t) (rpos & B_MASK);
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
@@ -351,6 +349,8 @@ static void hda_audio_output_cb(void *opaque, int avail)
break;
}
}
+
+ hda_timer_sync_adjust(st, (wpos - rpos) - (B_SIZE >> 1));
}
static void hda_audio_compat_input_cb(void *opaque, int avail)
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index fcc5a69..9c233c1 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -822,7 +822,7 @@ static void onenand_realize(DeviceState *dev, Error **errp)
onenand_mem_setup(s);
sysbus_init_irq(sbd, &s->intr);
sysbus_init_mmio(sbd, &s->container);
- vmstate_register(dev,
+ vmstate_register(VMSTATE_IF(dev),
((s->shift & 0x7f) << 24)
| ((s->id.man & 0xff) << 16)
| ((s->id.dev & 0xff) << 8)
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index fd0550d..0edd9e6 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -9,6 +9,7 @@ common-obj-y += hotplug.o
common-obj-$(CONFIG_SOFTMMU) += nmi.o
common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
common-obj-y += cpu.o
+common-obj-y += vmstate-if.o
common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
common-obj-$(CONFIG_XILINX_AXI) += stream.o
diff --git a/hw/core/machine.c b/hw/core/machine.c
index ec2e3fc..4f30fb5 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -873,7 +873,7 @@ static void machine_initfn(Object *obj)
NULL);
}
- if (mc->numa_mem_supported) {
+ if (mc->cpu_index_to_instance_props && mc->get_default_cpu_node_id) {
ms->numa_state = g_new0(NumaState, 1);
object_property_add_bool(obj, "hmat",
machine_get_hmat, machine_set_hmat,
@@ -1034,7 +1034,7 @@ void machine_run_board_init(MachineState *machine)
{
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
- if (machine_class->numa_mem_supported) {
+ if (machine->numa_state) {
numa_complete_configuration(machine);
if (machine->numa_state->num_nodes) {
machine_numa_finish_cpu_init(machine);
diff --git a/hw/core/numa.c b/hw/core/numa.c
index 747c968..0d1b4be 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -84,10 +84,6 @@ static void parse_numa_node(MachineState *ms, NumaNodeOptions *node,
return;
}
- if (!mc->cpu_index_to_instance_props || !mc->get_default_cpu_node_id) {
- error_setg(errp, "NUMA is not supported by this machine-type");
- return;
- }
for (cpus = node->cpus; cpus; cpus = cpus->next) {
CpuInstanceProperties props;
if (cpus->value >= max_cpus) {
@@ -449,9 +445,8 @@ void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node,
void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
Error *err = NULL;
- MachineClass *mc = MACHINE_GET_CLASS(ms);
- if (!mc->numa_mem_supported) {
+ if (!ms->numa_state) {
error_setg(errp, "NUMA is not supported by this machine-type");
goto end;
}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 82d3ee5..501228b 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -889,7 +889,8 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
dev->canonical_path = object_get_canonical_path(OBJECT(dev));
if (qdev_get_vmsd(dev)) {
- if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
+ if (vmstate_register_with_alias_id(VMSTATE_IF(dev),
+ -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
dev->alias_required_for_version,
&local_err) < 0) {
@@ -923,7 +924,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
local_err ? NULL : &local_err);
}
if (qdev_get_vmsd(dev)) {
- vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+ vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev);
}
if (dc->unrealize) {
dc->unrealize(dev, local_err ? NULL : &local_err);
@@ -947,7 +948,7 @@ child_realize_fail:
}
if (qdev_get_vmsd(dev)) {
- vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+ vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev);
}
post_realize_fail:
@@ -1087,9 +1088,18 @@ static void device_unparent(Object *obj)
}
}
+static char *
+device_vmstate_if_get_id(VMStateIf *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+
+ return qdev_get_dev_path(dev);
+}
+
static void device_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
+ VMStateIfClass *vc = VMSTATE_IF_CLASS(class);
class->unparent = device_unparent;
@@ -1101,6 +1111,7 @@ static void device_class_init(ObjectClass *class, void *data)
*/
dc->hotpluggable = true;
dc->user_creatable = true;
+ vc->get_id = device_vmstate_if_get_id;
}
void device_class_set_parent_reset(DeviceClass *dc,
@@ -1158,6 +1169,10 @@ static const TypeInfo device_type_info = {
.class_init = device_class_init,
.abstract = true,
.class_size = sizeof(DeviceClass),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_VMSTATE_IF },
+ { }
+ }
};
static void qdev_register_types(void)
diff --git a/hw/core/vmstate-if.c b/hw/core/vmstate-if.c
new file mode 100644
index 0000000..bf45362
--- /dev/null
+++ b/hw/core/vmstate-if.c
@@ -0,0 +1,23 @@
+/*
+ * VMState interface
+ *
+ * Copyright (c) 2009-2019 Red Hat Inc
+ * 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 "hw/vmstate-if.h"
+
+static const TypeInfo vmstate_if_info = {
+ .name = TYPE_VMSTATE_IF,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(VMStateIfClass),
+};
+
+static void vmstate_register_types(void)
+{
+ type_register_static(&vmstate_if_info);
+}
+
+type_init(vmstate_register_types);
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index f7fdc49..3ce2e57 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -109,7 +109,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
qxl->guest_primary.surface.mem,
MEMSLOT_GROUP_GUEST);
if (!qxl->guest_primary.data) {
- return;
+ goto end;
}
qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
qxl->num_dirty_rects = 1;
@@ -137,7 +137,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
}
if (!qxl->guest_primary.data) {
- return;
+ goto end;
}
for (i = 0; i < qxl->num_dirty_rects; i++) {
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
@@ -158,6 +158,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
qxl->dirty[i].bottom - qxl->dirty[i].top);
}
qxl->num_dirty_rects = 0;
+
+end:
+ if (qxl->render_update_cookie_num == 0) {
+ graphic_hw_update_done(qxl->ssd.dcl.con);
+ }
}
/*
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index cd7eb39..6d43b74 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -1181,6 +1181,7 @@ static const QXLInterface qxl_interface = {
static const GraphicHwOps qxl_ops = {
.gfx_update = qxl_hw_update,
+ .gfx_update_async = true,
};
static void qxl_enter_vga_mode(PCIQXLDevice *d)
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 19984d2..3f9be96 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -302,7 +302,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
}
g_free(irq);
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
+ vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
qemu_register_reset(cmd646_reset, d);
}
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 7b6e283..9c7f88b 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -75,7 +75,7 @@ static void isa_ide_realizefn(DeviceState *dev, Error **errp)
ide_init_ioport(&s->bus, isadev, s->iobase, s->iobase2);
isa_init_irq(isadev, &s->irq, s->isairq);
ide_init2(&s->bus, s->irq);
- vmstate_register(dev, 0, &vmstate_ide_isa, s);
+ vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_isa, s);
ide_register_restart_cb(&s->bus);
}
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index db313dd..bc575b4 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -156,7 +156,7 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp)
bmdma_setup_bar(d);
pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
+ vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
pci_piix_init_ports(d);
}
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 053622b..096de8d 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -190,7 +190,7 @@ static void via_ide_realize(PCIDevice *dev, Error **errp)
bmdma_setup_bar(d);
pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
- vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
+ vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index a713149..211008c 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -146,7 +146,7 @@ static int max111x_init(SSISlave *d, int inputs)
s->input[7] = 0x80;
s->com = 0;
- vmstate_register(dev, -1, &vmstate_max111x, s);
+ vmstate_register(VMSTATE_IF(dev), -1, &vmstate_max111x, s);
return 0;
}
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index cc2dd8b..cc71a7a 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -1815,7 +1815,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
{
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
- vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+ vmstate_unregister(VMSTATE_IF(&pci_dev->qdev), s->vmstate, s);
g_free(s->vmstate);
eeprom93xx_free(&pci_dev->qdev, s->eeprom);
qemu_del_nic(s->nic);
@@ -1874,7 +1874,7 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error **errp)
s->vmstate = g_memdup(&vmstate_eepro100, sizeof(vmstate_eepro100));
s->vmstate->name = qemu_get_queue(s->nic)->model;
- vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
+ vmstate_register(VMSTATE_IF(&pci_dev->qdev), -1, s->vmstate, s);
}
static void eepro100_instance_init(Object *obj)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index f325440..d7d3ad6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2853,7 +2853,8 @@ static void virtio_net_handle_migration_primary(VirtIONet *n,
if (migration_in_setup(s) && !should_be_hidden) {
if (failover_unplug_primary(n)) {
- vmstate_unregister(n->primary_dev, qdev_get_vmsd(n->primary_dev),
+ vmstate_unregister(VMSTATE_IF(n->primary_dev),
+ qdev_get_vmsd(n->primary_dev),
n->primary_dev);
qapi_event_send_unplug_primary(n->primary_device_id);
atomic_set(&n->primary_should_be_hidden, true);
diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c
index 5b01b9b..07f0954 100644
--- a/hw/nvram/eeprom93xx.c
+++ b/hw/nvram/eeprom93xx.c
@@ -321,7 +321,7 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
/* Output DO is tristate, read results in 1. */
eeprom->eedo = 1;
logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
- vmstate_register(dev, 0, &vmstate_eeprom, eeprom);
+ vmstate_register(VMSTATE_IF(dev), 0, &vmstate_eeprom, eeprom);
return eeprom;
}
@@ -329,7 +329,7 @@ void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
{
/* Destroy EEPROM. */
logout("eeprom = 0x%p\n", eeprom);
- vmstate_unregister(dev, &vmstate_eeprom, eeprom);
+ vmstate_unregister(VMSTATE_IF(dev), &vmstate_eeprom, eeprom);
g_free(eeprom);
}
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 62f1a42..17aeac3 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -511,7 +511,7 @@ static void realize(DeviceState *d, Error **errp)
error_propagate(errp, err);
return;
}
- vmstate_register(DEVICE(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
+ vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
trace_spapr_drc_realize_complete(spapr_drc_index(drc));
}
@@ -523,7 +523,7 @@ static void unrealize(DeviceState *d, Error **errp)
gchar *name;
trace_spapr_drc_unrealize(spapr_drc_index(drc));
- vmstate_unregister(DEVICE(drc), &vmstate_spapr_drc, drc);
+ vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc);
root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
name = g_strdup_printf("%x", spapr_drc_index(drc));
object_property_del(root_container, name, errp);
@@ -619,7 +619,8 @@ static void realize_physical(DeviceState *d, Error **errp)
return;
}
- vmstate_register(DEVICE(drcp), spapr_drc_index(SPAPR_DR_CONNECTOR(drcp)),
+ vmstate_register(VMSTATE_IF(drcp),
+ spapr_drc_index(SPAPR_DR_CONNECTOR(drcp)),
&vmstate_spapr_drc_physical, drcp);
qemu_register_reset(drc_physical_reset, drcp);
}
@@ -635,7 +636,7 @@ static void unrealize_physical(DeviceState *d, Error **errp)
return;
}
- vmstate_unregister(DEVICE(drcp), &vmstate_spapr_drc_physical, drcp);
+ vmstate_unregister(VMSTATE_IF(drcp), &vmstate_spapr_drc_physical, drcp);
qemu_unregister_reset(drc_physical_reset, drcp);
}
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 3d3bcc8..5704fe6 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -317,7 +317,7 @@ static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
- vmstate_register(DEVICE(tcet), tcet->liobn, &vmstate_spapr_tce_table,
+ vmstate_register(VMSTATE_IF(tcet), tcet->liobn, &vmstate_spapr_tce_table,
tcet);
}
@@ -420,7 +420,7 @@ static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
{
SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
- vmstate_unregister(DEVICE(tcet), &vmstate_spapr_tce_table, tcet);
+ vmstate_unregister(VMSTATE_IF(tcet), &vmstate_spapr_tce_table, tcet);
QLIST_REMOVE(tcet, list);
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index bd37f39..5da6e52 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -392,7 +392,7 @@ static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
register_savevm_live(TYPE_S390_SKEYS, 0, 1,
&savevm_s390_storage_keys, ss);
} else {
- unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss);
+ unregister_savevm(VMSTATE_IF(ss), TYPE_S390_SKEYS, ss);
}
}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 2d40b39..337a173 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3076,7 +3076,9 @@ static void vfio_exitfn(PCIDevice *pdev)
vfio_unregister_req_notifier(vdev);
vfio_unregister_err_notifier(vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
- kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
+ if (vdev->irqchip_change_notifier.notify) {
+ kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
+ }
vfio_disable_interrupts(vdev);
if (vdev->intx.mmap_timer) {
timer_free(vdev->intx.mmap_timer);
diff --git a/include/block/block.h b/include/block/block.h
index 1df9848..e9dcfef 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -280,6 +280,7 @@ enum {
};
char *bdrv_perm_names(uint64_t perm);
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
/* disk I/O throttling */
void bdrv_init(void);
diff --git a/include/hw/vmstate-if.h b/include/hw/vmstate-if.h
new file mode 100644
index 0000000..8ff7f0f
--- /dev/null
+++ b/include/hw/vmstate-if.h
@@ -0,0 +1,40 @@
+/*
+ * VMState interface
+ *
+ * Copyright (c) 2009-2019 Red Hat Inc
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef VMSTATE_IF_H
+#define VMSTATE_IF_H
+
+#include "qom/object.h"
+
+#define TYPE_VMSTATE_IF "vmstate-if"
+
+#define VMSTATE_IF_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VMStateIfClass, (klass), TYPE_VMSTATE_IF)
+#define VMSTATE_IF_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VMStateIfClass, (obj), TYPE_VMSTATE_IF)
+#define VMSTATE_IF(obj) \
+ INTERFACE_CHECK(VMStateIf, (obj), TYPE_VMSTATE_IF)
+
+typedef struct VMStateIf VMStateIf;
+
+typedef struct VMStateIfClass {
+ InterfaceClass parent_class;
+
+ char * (*get_id)(VMStateIf *obj);
+} VMStateIfClass;
+
+static inline char *vmstate_if_get_id(VMStateIf *vmif)
+{
+ if (!vmif) {
+ return NULL;
+ }
+
+ return VMSTATE_IF_GET_CLASS(vmif)->get_id(vmif);
+}
+
+#endif /* VMSTATE_IF_H */
diff --git a/include/migration/register.h b/include/migration/register.h
index a13359a..00c38eb 100644
--- a/include/migration/register.h
+++ b/include/migration/register.h
@@ -14,6 +14,8 @@
#ifndef MIGRATION_REGISTER_H
#define MIGRATION_REGISTER_H
+#include "hw/vmstate-if.h"
+
typedef struct SaveVMHandlers {
/* This runs inside the iothread lock. */
SaveStateHandler *save_state;
@@ -74,6 +76,6 @@ int register_savevm_live(const char *idstr,
const SaveVMHandlers *ops,
void *opaque);
-void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+void unregister_savevm(VMStateIf *obj, const char *idstr, void *opaque);
#endif
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index ac4f46a..4aef72c 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -27,6 +27,8 @@
#ifndef QEMU_VMSTATE_H
#define QEMU_VMSTATE_H
+#include "hw/vmstate-if.h"
+
typedef struct VMStateInfo VMStateInfo;
typedef struct VMStateField VMStateField;
@@ -1156,22 +1158,22 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
/* Returns: 0 on success, -1 on failure */
-int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+int vmstate_register_with_alias_id(VMStateIf *obj, int instance_id,
const VMStateDescription *vmsd,
void *base, int alias_id,
int required_for_version,
Error **errp);
/* Returns: 0 on success, -1 on failure */
-static inline int vmstate_register(DeviceState *dev, int instance_id,
+static inline int vmstate_register(VMStateIf *obj, int instance_id,
const VMStateDescription *vmsd,
void *opaque)
{
- return vmstate_register_with_alias_id(dev, instance_id, vmsd,
+ return vmstate_register_with_alias_id(obj, instance_id, vmsd,
opaque, -1, 0, NULL);
}
-void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
void *opaque);
struct MemoryRegion;
diff --git a/include/qemu/dbus.h b/include/qemu/dbus.h
new file mode 100644
index 0000000..9d591f9
--- /dev/null
+++ b/include/qemu/dbus.h
@@ -0,0 +1,19 @@
+/*
+ * Helpers for using D-Bus
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef DBUS_H
+#define DBUS_H
+
+#include <gio/gio.h>
+
+GStrv qemu_dbus_get_queued_owners(GDBusConnection *connection,
+ const char *name,
+ Error **errp);
+
+#endif /* DBUS_H */
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 0f97d68..9bd3dcf 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -462,6 +462,7 @@ int qemu_mprotect_none(void *addr, size_t size);
int qemu_open(const char *name, int flags, ...);
int qemu_close(int fd);
+int qemu_unlink(const char *name);
#ifndef _WIN32
int qemu_dup(int fd);
#endif
diff --git a/include/qom/object.h b/include/qom/object.h
index 1d7b7e5..54a5488 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1766,4 +1766,7 @@ Object *container_get(Object *root, const char *path);
* Returns the instance_size of the given @typename.
*/
size_t object_type_get_instance_size(const char *typename);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(Object, object_unref)
+
#endif
diff --git a/include/ui/console.h b/include/ui/console.h
index f981696..281f9c1 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -365,6 +365,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
typedef struct GraphicHwOps {
void (*invalidate)(void *opaque);
void (*gfx_update)(void *opaque);
+ bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
void (*text_update)(void *opaque, console_ch_t *text);
void (*update_interval)(void *opaque, uint64_t interval);
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
@@ -380,6 +381,7 @@ void graphic_console_set_hwops(QemuConsole *con,
void graphic_console_close(QemuConsole *con);
void graphic_hw_update(QemuConsole *con);
+void graphic_hw_update_done(QemuConsole *con);
void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
void graphic_hw_gl_block(QemuConsole *con, bool block);
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index 0668109..3b7cf70 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -90,4 +90,6 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
pixman_color_t *bgcol,
int x, int y, int cw, int ch);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref)
+
#endif /* QEMU_PIXMAN_H */
diff --git a/migration/savevm.c b/migration/savevm.c
index a71b930..59efc19 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -760,17 +760,17 @@ int register_savevm_live(const char *idstr,
return 0;
}
-void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
+void unregister_savevm(VMStateIf *obj, const char *idstr, void *opaque)
{
SaveStateEntry *se, *new_se;
char id[256] = "";
- if (dev) {
- char *path = qdev_get_dev_path(dev);
- if (path) {
- pstrcpy(id, sizeof(id), path);
+ if (obj) {
+ char *oid = vmstate_if_get_id(obj);
+ if (oid) {
+ pstrcpy(id, sizeof(id), oid);
pstrcat(id, sizeof(id), "/");
- g_free(path);
+ g_free(oid);
}
}
pstrcat(id, sizeof(id), idstr);
@@ -784,7 +784,7 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
}
}
-int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+int vmstate_register_with_alias_id(VMStateIf *obj, int instance_id,
const VMStateDescription *vmsd,
void *opaque, int alias_id,
int required_for_version,
@@ -802,8 +802,8 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
se->vmsd = vmsd;
se->alias_id = alias_id;
- if (dev) {
- char *id = qdev_get_dev_path(dev);
+ if (obj) {
+ char *id = vmstate_if_get_id(obj);
if (id) {
if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
sizeof(se->idstr)) {
@@ -834,7 +834,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
return 0;
}
-void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
void *opaque)
{
SaveStateEntry *se, *new_se;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index fcb52ec2..7ff5e5e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2884,15 +2884,16 @@
# @copy-on-read: Since 3.0
# @blklogwrites: Since 3.0
# @blkreplay: Since 4.2
+# @compress: Since 5.0
#
# Since: 2.9
##
{ 'enum': 'BlockdevDriver',
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
- 'cloop', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
- 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
- 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
- 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
+ 'cloop', 'compress', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps',
+ 'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi',
+ 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
+ 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
'sheepdog',
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
@@ -3454,6 +3455,16 @@
#
# @set-state: array of state-change descriptions
#
+# @take-child-perms: Permissions to take on @image in addition to what
+# is necessary anyway (which depends on how the
+# blkdebug node is used). Defaults to none.
+# (since 5.0)
+#
+# @unshare-child-perms: Permissions not to share on @image in addition
+# to what cannot be shared anyway (which depends
+# on how the blkdebug node is used). Defaults
+# to none. (since 5.0)
+#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsBlkdebug',
@@ -3463,7 +3474,9 @@
'*opt-write-zero': 'int32', '*max-write-zero': 'int32',
'*opt-discard': 'int32', '*max-discard': 'int32',
'*inject-error': ['BlkdebugInjectErrorOptions'],
- '*set-state': ['BlkdebugSetStateOptions'] } }
+ '*set-state': ['BlkdebugSetStateOptions'],
+ '*take-child-perms': ['BlockPermission'],
+ '*unshare-child-perms': ['BlockPermission'] } }
##
# @BlockdevOptionsBlklogwrites:
@@ -4048,6 +4061,7 @@
'blkreplay': 'BlockdevOptionsBlkreplay',
'bochs': 'BlockdevOptionsGenericFormat',
'cloop': 'BlockdevOptionsGenericFormat',
+ 'compress': 'BlockdevOptionsGenericFormat',
'copy-on-read':'BlockdevOptionsGenericFormat',
'dmg': 'BlockdevOptionsGenericFormat',
'file': 'BlockdevOptionsFile',
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 09d0ca0..0968d37 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -384,6 +384,14 @@ guarantees must resolve the CPU model aliases using te
``alias-of'' field returned by the ``query-cpu-definitions'' QMP
command.
+While those guarantees are kept, the return value of
+``query-cpu-definitions'' will have existing CPU model aliases
+point to a version that doesn't break runnability guarantees
+(specifically, version 1 of those CPU models). In future QEMU
+versions, aliases will point to newer CPU model versions
+depending on the machine type, so management software must
+resolve CPU model aliases before starting a virtual machine.
+
@node Recently removed features
@appendix Recently removed features
diff --git a/stubs/vmstate.c b/stubs/vmstate.c
index e1e89b8..6951d9f 100644
--- a/stubs/vmstate.c
+++ b/stubs/vmstate.c
@@ -3,7 +3,7 @@
const VMStateDescription vmstate_dummy = {};
-int vmstate_register_with_alias_id(DeviceState *dev,
+int vmstate_register_with_alias_id(VMStateIf *obj,
int instance_id,
const VMStateDescription *vmsd,
void *base, int alias_id,
@@ -13,7 +13,7 @@ int vmstate_register_with_alias_id(DeviceState *dev,
return 0;
}
-void vmstate_unregister(DeviceState *dev,
+void vmstate_unregister(VMStateIf *obj,
const VMStateDescription *vmsd,
void *opaque)
{
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index b064513..b75f813 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
target_cpu->env.regs[0] = info->context_id;
}
+ /* CP15 update requires rebuilding hflags */
+ arm_rebuild_hflags(&target_cpu->env);
+
/* Start the new CPU at the requested address */
cpu_set_pc(target_cpu_state, info->entry);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index dd51ada..d62fd5f 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -976,6 +976,10 @@ static void arm_cpu_initfn(Object *obj)
}
}
+static Property arm_cpu_gt_cntfrq_property =
+ DEFINE_PROP_UINT64("cntfrq", ARMCPU, gt_cntfrq_hz,
+ NANOSECONDS_PER_SECOND / GTIMER_SCALE);
+
static Property arm_cpu_reset_cbar_property =
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
@@ -1055,6 +1059,30 @@ static void arm_set_init_svtor(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, &cpu->init_svtor, errp);
}
+unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
+{
+ /*
+ * The exact approach to calculating guest ticks is:
+ *
+ * muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), cpu->gt_cntfrq_hz,
+ * NANOSECONDS_PER_SECOND);
+ *
+ * We don't do that. Rather we intentionally use integer division
+ * truncation below and in the caller for the conversion of host monotonic
+ * time to guest ticks to provide the exact inverse for the semantics of
+ * the QEMUTimer scale factor. QEMUTimer's scale facter is an integer, so
+ * it loses precision when representing frequencies where
+ * `(NANOSECONDS_PER_SECOND % cpu->gt_cntfrq) > 0` holds. Failing to
+ * provide an exact inverse leads to scheduling timers with negative
+ * periods, which in turn leads to sticky behaviour in the guest.
+ *
+ * Finally, CNTFRQ is effectively capped at 1GHz to ensure our scale factor
+ * cannot become zero.
+ */
+ return NANOSECONDS_PER_SECOND > cpu->gt_cntfrq_hz ?
+ NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1;
+}
+
void arm_cpu_post_init(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -1172,6 +1200,11 @@ void arm_cpu_post_init(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property,
&error_abort);
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) {
+ qdev_property_add_static(DEVICE(cpu), &arm_cpu_gt_cntfrq_property,
+ &error_abort);
+ }
}
static void arm_cpu_finalizefn(Object *obj)
@@ -1251,14 +1284,30 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
}
}
- cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_ptimer_cb, cpu);
- cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_vtimer_cb, cpu);
- cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_htimer_cb, cpu);
- cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_stimer_cb, cpu);
+
+ {
+ uint64_t scale;
+
+ if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+ if (!cpu->gt_cntfrq_hz) {
+ error_setg(errp, "Invalid CNTFRQ: %"PRId64"Hz",
+ cpu->gt_cntfrq_hz);
+ return;
+ }
+ scale = gt_cntfrq_period_ns(cpu);
+ } else {
+ scale = GTIMER_SCALE;
+ }
+
+ cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_ptimer_cb, cpu);
+ cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_vtimer_cb, cpu);
+ cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_htimer_cb, cpu);
+ cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_stimer_cb, cpu);
+ }
#endif
cpu_exec_realizefn(cs, &local_err);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 5f70e9e..40f2c45 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -932,8 +932,13 @@ struct ARMCPU {
*/
DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
+
+ /* Generic timer counter frequency, in Hz */
+ uint64_t gt_cntfrq_hz;
};
+unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
+
void arm_cpu_post_init(Object *obj);
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5074b5f..b6bec42 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2449,7 +2449,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
static uint64_t gt_get_countervalue(CPUARMState *env)
{
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE;
+ ARMCPU *cpu = env_archcpu(env);
+
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu);
}
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
@@ -2485,10 +2487,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
* set the timer for as far in the future as possible. When the
* timer expires we will reset the timer for any remaining period.
*/
- if (nexttick > INT64_MAX / GTIMER_SCALE) {
- nexttick = INT64_MAX / GTIMER_SCALE;
+ if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
+ timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX);
+ } else {
+ timer_mod(cpu->gt_timer[timeridx], nexttick);
}
- timer_mod(cpu->gt_timer[timeridx], nexttick);
trace_arm_gt_recalc(timeridx, irqstate, nexttick);
} else {
/* Timer disabled: ISTATUS and timer output always clear */
@@ -2720,6 +2723,13 @@ void arm_gt_stimer_cb(void *opaque)
gt_recalc_timer(cpu, GTIMER_SEC);
}
+static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ cpu->env.cp15.c14_cntfrq = cpu->gt_cntfrq_hz;
+}
+
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
/* Note that CNTFRQ is purely reads-as-written for the benefit
* of software; writing it doesn't actually change the timer frequency.
@@ -2734,7 +2744,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
- .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
+ .resetfn = arm_gt_cntfrq_reset,
},
/* overall control: mostly access permissions */
{ .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
@@ -2913,11 +2923,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
+ ARMCPU *cpu = env_archcpu(env);
+
/* Currently we have no support for QEMUTimer in linux-user so we
* can't call gt_get_countervalue(env), instead we directly
* call the lower level functions.
*/
- return cpu_get_clock() / GTIMER_SCALE;
+ return cpu_get_clock() / gt_cntfrq_period_ns(cpu);
}
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
@@ -11500,6 +11512,20 @@ void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el)
env->hflags = rebuild_hflags_a64(env, el, fp_el, mmu_idx);
}
+static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
+{
+#ifdef CONFIG_DEBUG_TCG
+ uint32_t env_flags_current = env->hflags;
+ uint32_t env_flags_rebuilt = rebuild_hflags_internal(env);
+
+ if (unlikely(env_flags_current != env_flags_rebuilt)) {
+ fprintf(stderr, "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n",
+ env_flags_current, env_flags_rebuilt);
+ abort();
+ }
+#endif
+}
+
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
@@ -11507,9 +11533,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
uint32_t pstate_for_ss;
*cs_base = 0;
-#ifdef CONFIG_DEBUG_TCG
- assert(flags == rebuild_hflags_internal(env));
-#endif
+ assert_hflags_rebuild_correctly(env);
if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) {
*pc = env->pc;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e1eb9f4..31556b7 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -3981,7 +3981,13 @@ static PropValue tcg_default_props[] = {
};
-X86CPUVersion default_cpu_version = CPU_VERSION_LATEST;
+/*
+ * We resolve CPU model aliases using -v1 when using "-machine
+ * none", but this is just for compatibility while libvirt isn't
+ * adapted to resolve CPU model versions before creating VMs.
+ * See "Runnability guarantee of CPU models" at * qemu-deprecated.texi.
+ */
+X86CPUVersion default_cpu_version = 1;
void x86_cpu_set_default_version(X86CPUVersion version)
{
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index b363ffc..75e65df 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -645,7 +645,9 @@ static inline int xtensa_get_cintlevel(const CPUXtensaState *env)
static inline int xtensa_get_ring(const CPUXtensaState *env)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ if (xtensa_option_bits_enabled(env->config,
+ XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) |
+ XTENSA_OPTION_BIT(XTENSA_OPTION_MPU))) {
return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
} else {
return 0;
@@ -654,8 +656,10 @@ static inline int xtensa_get_ring(const CPUXtensaState *env)
static inline int xtensa_get_cring(const CPUXtensaState *env)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
- (env->sregs[PS] & PS_EXCM) == 0) {
+ if (xtensa_option_bits_enabled(env->config,
+ XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) |
+ XTENSA_OPTION_BIT(XTENSA_OPTION_MPU)) &&
+ (env->sregs[PS] & PS_EXCM) == 0) {
return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
} else {
return 0;
diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh
index e4a2e39..8f844cf 100755
--- a/target/xtensa/import_core.sh
+++ b/target/xtensa/import_core.sh
@@ -19,8 +19,9 @@ exit
[ $# -ge 3 ] && FREQ="$3"
mkdir -p "$TARGET"
-tar -xf "$OVERLAY" -C "$TARGET" --strip-components=1 \
- --xform='s/core/core-isa/' config/core.h
+tar -xf "$OVERLAY" -C "$TARGET" --strip-components=2 \
+ xtensa/config/core-isa.h \
+ xtensa/config/core-matmap.h
tar -xf "$OVERLAY" -O gdb/xtensa-config.c | \
sed -n '1,/*\//p;/XTREG/,/XTREG_END/p' > "$TARGET"/gdb-config.inc.c
#
@@ -44,6 +45,7 @@ cat <<EOF > "${TARGET}.c"
#include "qemu/host-utils.h"
#include "core-$NAME/core-isa.h"
+#include "core-$NAME/core-matmap.h"
#include "overlay_tool.h"
#define xtensa_modules xtensa_modules_$NAME
diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h
index f0cc33a..cab5320 100644
--- a/target/xtensa/overlay_tool.h
+++ b/target/xtensa/overlay_tool.h
@@ -373,15 +373,28 @@
#elif XCHAL_HAVE_MPU
#ifndef XTENSA_MPU_BG_MAP
+#ifdef XCHAL_MPU_BACKGROUND_MAP
+#define XCHAL_MPU_BGMAP(s, vaddr_start, vaddr_last, rights, memtype, x...) \
+ { .vaddr = (vaddr_start), .attr = ((rights) << 8) | ((memtype) << 12), },
+
+#define XTENSA_MPU_BG_MAP (xtensa_mpu_entry []){\
+ XCHAL_MPU_BACKGROUND_MAP(0) \
+}
+
+#define XTENSA_MPU_BG_MAP_ENTRIES XCHAL_MPU_BACKGROUND_ENTRIES
+#else
#define XTENSA_MPU_BG_MAP (xtensa_mpu_entry []){\
{ .vaddr = 0, .attr = 0x00006700, }, \
}
+
+#define XTENSA_MPU_BG_MAP_ENTRIES 1
+#endif
#endif
#define TLB_SECTION \
.mpu_align = XCHAL_MPU_ALIGN, \
.n_mpu_fg_segments = XCHAL_MPU_ENTRIES, \
- .n_mpu_bg_segments = 1, \
+ .n_mpu_bg_segments = XTENSA_MPU_BG_MAP_ENTRIES, \
.mpu_bg = XTENSA_MPU_BG_MAP
#ifndef XCHAL_SYSROM0_PADDR
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index a99f529..e6d9107 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -2713,7 +2713,8 @@ static void translate_wsr_ps(DisasContext *dc, const OpcodeArg arg[],
uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
PS_UM | PS_EXCM | PS_INTLEVEL;
- if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+ if (option_enabled(dc, XTENSA_OPTION_MMU) ||
+ option_enabled(dc, XTENSA_OPTION_MPU)) {
mask |= PS_RING;
}
tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, mask);
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 31b8667..49e3b0d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -158,12 +158,17 @@ check-qtest-generic-$(CONFIG_MODULES) += tests/modules-test$(EXESUF)
check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
check-qtest-generic-y += tests/cdrom-test$(EXESUF)
+DBUS_DAEMON := $(shell which dbus-daemon 2>/dev/null)
+ifneq ($(GDBUS_CODEGEN),)
+ifneq ($(DBUS_DAEMON),)
+check-qtest-pci-$(CONFIG_GIO) += tests/dbus-vmstate-test$(EXESUF)
+endif
+endif
check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
check-qtest-pci-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
-
check-qtest-i386-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
check-qtest-i386-y += tests/fdc-test$(EXESUF)
check-qtest-i386-y += tests/ide-test$(EXESUF)
@@ -579,6 +584,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/irq.o \
hw/core/fw-path-provider.o \
hw/core/reset.o \
+ hw/core/vmstate-if.o \
$(test-qapi-obj-y)
tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \
@@ -633,6 +639,19 @@ tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.jso
@mv tests/qapi-schema/doc-good-qapi-doc.texi $@
@rm -f tests/qapi-schema/doc-good-qapi-*.[ch] tests/qapi-schema/doc-good-qmp-*.[ch]
+tests/dbus-vmstate1.h tests/dbus-vmstate1.c: tests/dbus-vmstate1-gen-timestamp ;
+tests/dbus-vmstate1-gen-timestamp: $(SRC_PATH)/tests/dbus-vmstate1.xml
+ $(call quiet-command,$(GDBUS_CODEGEN) $< \
+ --interface-prefix org.qemu --generate-c-code tests/dbus-vmstate1, \
+ "GEN","$(@:%-timestamp=%)")
+ @>$@
+
+tests/dbus-vmstate-test.o-cflags := -DSRCDIR="$(SRC_PATH)"
+tests/dbus-vmstate1.o-cflags := $(GIO_CFLAGS)
+tests/dbus-vmstate1.o-libs := $(GIO_LIBS)
+
+tests/dbus-vmstate-test.o: tests/dbus-vmstate1.h
+
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) tests/test-qapi-events.o
@@ -826,7 +845,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/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o
-tests/migration-test$(EXESUF): tests/migration-test.o
+tests/migration-test$(EXESUF): tests/migration-test.o tests/migration-helpers.o
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)
tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y) $(test-qapi-obj-y)
@@ -836,6 +855,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y)
tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y)
tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+tests/dbus-vmstate-test$(EXESUF): tests/dbus-vmstate-test.o tests/migration-helpers.o tests/dbus-vmstate1.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y)
tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
@@ -1157,7 +1177,6 @@ TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results
AVOCADO_SHOW=app
AVOCADO_TAGS=$(patsubst %-softmmu,-t arch:%, $(filter %-softmmu,$(TARGET_DIRS)))
-ifneq ($(PYTHON2),y)
$(TESTS_VENV_DIR): $(TESTS_VENV_REQ)
$(call quiet-command, \
$(PYTHON) -m venv --system-site-packages $@, \
@@ -1166,10 +1185,6 @@ $(TESTS_VENV_DIR): $(TESTS_VENV_REQ)
$(TESTS_VENV_DIR)/bin/python -m pip -q install -r $(TESTS_VENV_REQ), \
PIP, $(TESTS_VENV_REQ))
$(call quiet-command, touch $@)
-else
-$(TESTS_VENV_DIR):
- $(error "venv directory for tests requires Python 3")
-endif
$(TESTS_RESULTS_DIR):
$(call quiet-command, mkdir -p $@, \
@@ -1199,6 +1214,7 @@ check-clean:
rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y)) $(check-qtest-generic-y))
rm -f tests/test-qapi-gen-timestamp
+ rm -f tests/dbus-vmstate1-gen-timestamp
rm -rf $(TESTS_VENV_DIR) $(TESTS_RESULTS_DIR)
clean: check-clean
diff --git a/tests/dbus-vmstate-daemon.sh b/tests/dbus-vmstate-daemon.sh
new file mode 100755
index 0000000..474e250
--- /dev/null
+++ b/tests/dbus-vmstate-daemon.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+# dbus-daemon wrapper script for dbus-vmstate testing
+#
+# This script allows to tweak the dbus-daemon policy during the test
+# to test different configurations.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright (C) 2019 Red Hat, Inc.
+
+write_config()
+{
+ CONF="$1"
+ cat > "$CONF" <<EOF
+<busconfig>
+ <type>session</type>
+ <listen>unix:tmpdir=$DBUS_VMSTATE_TEST_TMPDIR</listen>
+
+ <policy context="default">
+ <!-- Holes must be punched in service configuration files for
+ name ownership and sending method calls -->
+ <deny own="*"/>
+ <deny send_type="method_call"/>
+
+ <!-- Signals and reply messages (method returns, errors) are allowed
+ by default -->
+ <allow send_type="signal"/>
+ <allow send_requested_reply="true" send_type="method_return"/>
+ <allow send_requested_reply="true" send_type="error"/>
+
+ <!-- All messages may be received by default -->
+ <allow receive_type="method_call"/>
+ <allow receive_type="method_return"/>
+ <allow receive_type="error"/>
+ <allow receive_type="signal"/>
+
+ <!-- Allow anyone to talk to the message bus -->
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus" />
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Introspectable"/>
+ <allow send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Properties"/>
+ <!-- But disallow some specific bus services -->
+ <deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus"
+ send_member="UpdateActivationEnvironment"/>
+ <deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus.Debug.Stats"/>
+ <deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.systemd1.Activator"/>
+
+ <allow own="org.qemu.VMState1"/>
+ <allow send_destination="org.qemu.VMState1"/>
+ <allow receive_sender="org.qemu.VMState1"/>
+
+ </policy>
+
+ <include if_selinux_enabled="yes"
+ selinux_root_relative="yes">contexts/dbus_contexts</include>
+
+</busconfig>
+EOF
+}
+
+ARGS=
+for arg in "$@"
+do
+ case $arg in
+ --config-file=*)
+ CONF="${arg#*=}"
+ write_config "$CONF"
+ ARGS="$ARGS $1"
+ shift
+ ;;
+ *)
+ ARGS="$ARGS $1"
+ shift
+ ;;
+ esac
+done
+
+exec dbus-daemon $ARGS
diff --git a/tests/dbus-vmstate-test.c b/tests/dbus-vmstate-test.c
new file mode 100644
index 0000000..2e5e47d
--- /dev/null
+++ b/tests/dbus-vmstate-test.c
@@ -0,0 +1,382 @@
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include "libqtest.h"
+#include "qemu-common.h"
+#include "dbus-vmstate1.h"
+#include "migration-helpers.h"
+
+static char *workdir;
+
+typedef struct TestServerId {
+ const char *name;
+ const char *data;
+ size_t size;
+} TestServerId;
+
+static const TestServerId idA = {
+ "idA", "I'am\0idA!", sizeof("I'am\0idA!")
+};
+
+static const TestServerId idB = {
+ "idB", "I'am\0idB!", sizeof("I'am\0idB!")
+};
+
+typedef struct TestServer {
+ const TestServerId *id;
+ bool save_called;
+ bool load_called;
+} TestServer;
+
+typedef struct Test {
+ const char *id_list;
+ bool migrate_fail;
+ bool without_dst_b;
+ TestServer srcA;
+ TestServer dstA;
+ TestServer srcB;
+ TestServer dstB;
+ GMainLoop *loop;
+ QTestState *src_qemu;
+} Test;
+
+static gboolean
+vmstate_load(VMState1 *object, GDBusMethodInvocation *invocation,
+ const gchar *arg_data, gpointer user_data)
+{
+ TestServer *h = user_data;
+ g_autoptr(GVariant) var = NULL;
+ GVariant *args;
+ const uint8_t *data;
+ size_t size;
+
+ args = g_dbus_method_invocation_get_parameters(invocation);
+ var = g_variant_get_child_value(args, 0);
+ data = g_variant_get_fixed_array(var, &size, sizeof(char));
+ g_assert_cmpuint(size, ==, h->id->size);
+ g_assert(!memcmp(data, h->id->data, h->id->size));
+ h->load_called = true;
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+ return TRUE;
+}
+
+static gboolean
+vmstate_save(VMState1 *object, GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ TestServer *h = user_data;
+ GVariant *var;
+
+ var = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+ h->id->data, h->id->size, sizeof(char));
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(@ay)", var));
+ h->save_called = true;
+
+ return TRUE;
+}
+
+typedef struct WaitNamed {
+ GMainLoop *loop;
+ bool named;
+} WaitNamed;
+
+static void
+named_cb(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ WaitNamed *t = user_data;
+
+ t->named = true;
+ g_main_loop_quit(t->loop);
+}
+
+static GDBusConnection *
+get_connection(Test *test, guint *ownid)
+{
+ g_autofree gchar *addr = NULL;
+ WaitNamed *wait;
+ GError *err = NULL;
+ GDBusConnection *c;
+
+ wait = g_new0(WaitNamed, 1);
+ wait->loop = test->loop;
+ addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &err);
+ g_assert_no_error(err);
+
+ c = g_dbus_connection_new_for_address_sync(
+ addr,
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION |
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, NULL, &err);
+ g_assert_no_error(err);
+ *ownid = g_bus_own_name_on_connection(c, "org.qemu.VMState1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ named_cb, named_cb, wait, g_free);
+ if (!wait->named) {
+ g_main_loop_run(wait->loop);
+ }
+
+ return c;
+}
+
+static GDBusObjectManagerServer *
+get_server(GDBusConnection *conn, TestServer *s, const TestServerId *id)
+{
+ g_autoptr(GDBusObjectSkeleton) sk = NULL;
+ g_autoptr(VMState1Skeleton) v = NULL;
+ GDBusObjectManagerServer *os;
+
+ s->id = id;
+ os = g_dbus_object_manager_server_new("/org/qemu");
+ sk = g_dbus_object_skeleton_new("/org/qemu/VMState1");
+
+ v = VMSTATE1_SKELETON(vmstate1_skeleton_new());
+ g_object_set(v, "id", id->name, NULL);
+
+ g_signal_connect(v, "handle-load", G_CALLBACK(vmstate_load), s);
+ g_signal_connect(v, "handle-save", G_CALLBACK(vmstate_save), s);
+
+ g_dbus_object_skeleton_add_interface(sk, G_DBUS_INTERFACE_SKELETON(v));
+ g_dbus_object_manager_server_export(os, sk);
+ g_dbus_object_manager_server_set_connection(os, conn);
+
+ return os;
+}
+
+static void
+set_id_list(Test *test, QTestState *s)
+{
+ if (!test->id_list) {
+ return;
+ }
+
+ g_assert(!qmp_rsp_is_err(qtest_qmp(s,
+ "{ 'execute': 'qom-set', 'arguments': "
+ "{ 'path': '/objects/dv', 'property': 'id-list', 'value': %s } }",
+ test->id_list)));
+}
+
+static gpointer
+dbus_vmstate_thread(gpointer data)
+{
+ GMainLoop *loop = data;
+
+ g_main_loop_run(loop);
+
+ return NULL;
+}
+
+static void
+test_dbus_vmstate(Test *test)
+{
+ g_autofree char *src_qemu_args = NULL;
+ g_autofree char *dst_qemu_args = NULL;
+ g_autoptr(GTestDBus) srcbus = NULL;
+ g_autoptr(GTestDBus) dstbus = NULL;
+ g_autoptr(GDBusConnection) srcconnA = NULL;
+ g_autoptr(GDBusConnection) srcconnB = NULL;
+ g_autoptr(GDBusConnection) dstconnA = NULL;
+ g_autoptr(GDBusConnection) dstconnB = NULL;
+ g_autoptr(GDBusObjectManagerServer) srcserverA = NULL;
+ g_autoptr(GDBusObjectManagerServer) srcserverB = NULL;
+ g_autoptr(GDBusObjectManagerServer) dstserverA = NULL;
+ g_autoptr(GDBusObjectManagerServer) dstserverB = NULL;
+ g_auto(GStrv) srcaddr = NULL;
+ g_auto(GStrv) dstaddr = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autofree char *uri = NULL;
+ QTestState *src_qemu = NULL, *dst_qemu = NULL;
+ guint ownsrcA, ownsrcB, owndstA, owndstB;
+
+ uri = g_strdup_printf("unix:%s/migsocket", workdir);
+
+ loop = g_main_loop_new(NULL, FALSE);
+ test->loop = loop;
+
+ srcbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+ g_test_dbus_up(srcbus);
+ srcconnA = get_connection(test, &ownsrcA);
+ srcserverA = get_server(srcconnA, &test->srcA, &idA);
+ srcconnB = get_connection(test, &ownsrcB);
+ srcserverB = get_server(srcconnB, &test->srcB, &idB);
+
+ /* remove ,guid=foo part */
+ srcaddr = g_strsplit(g_test_dbus_get_bus_address(srcbus), ",", 2);
+ src_qemu_args =
+ g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s", srcaddr[0]);
+
+ dstbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+ g_test_dbus_up(dstbus);
+ dstconnA = get_connection(test, &owndstA);
+ dstserverA = get_server(dstconnA, &test->dstA, &idA);
+ if (!test->without_dst_b) {
+ dstconnB = get_connection(test, &owndstB);
+ dstserverB = get_server(dstconnB, &test->dstB, &idB);
+ }
+
+ dstaddr = g_strsplit(g_test_dbus_get_bus_address(dstbus), ",", 2);
+ dst_qemu_args =
+ g_strdup_printf("-object dbus-vmstate,id=dv,addr=%s -incoming %s",
+ dstaddr[0], uri);
+
+ src_qemu = qtest_init(src_qemu_args);
+ dst_qemu = qtest_init(dst_qemu_args);
+ set_id_list(test, src_qemu);
+ set_id_list(test, dst_qemu);
+
+ thread = g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread, loop);
+
+ migrate_qmp(src_qemu, uri, "{}");
+ test->src_qemu = src_qemu;
+ if (test->migrate_fail) {
+ wait_for_migration_fail(src_qemu, true);
+ qtest_set_expected_status(dst_qemu, 1);
+ } else {
+ wait_for_migration_complete(src_qemu);
+ }
+
+ qtest_quit(dst_qemu);
+ qtest_quit(src_qemu);
+ g_bus_unown_name(ownsrcA);
+ g_bus_unown_name(ownsrcB);
+ g_bus_unown_name(owndstA);
+ if (!test->without_dst_b) {
+ g_bus_unown_name(owndstB);
+ }
+
+ g_main_loop_quit(test->loop);
+}
+
+static void
+check_not_migrated(TestServer *s, TestServer *d)
+{
+ assert(!s->save_called);
+ assert(!s->load_called);
+ assert(!d->save_called);
+ assert(!d->load_called);
+}
+
+static void
+check_migrated(TestServer *s, TestServer *d)
+{
+ assert(s->save_called);
+ assert(!s->load_called);
+ assert(!d->save_called);
+ assert(d->load_called);
+}
+
+static void
+test_dbus_vmstate_without_list(void)
+{
+ Test test = { 0, };
+
+ test_dbus_vmstate(&test);
+
+ check_migrated(&test.srcA, &test.dstA);
+ check_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_with_list(void)
+{
+ Test test = { .id_list = "idA,idB" };
+
+ test_dbus_vmstate(&test);
+
+ check_migrated(&test.srcA, &test.dstA);
+ check_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_only_a(void)
+{
+ Test test = { .id_list = "idA" };
+
+ test_dbus_vmstate(&test);
+
+ check_migrated(&test.srcA, &test.dstA);
+ check_not_migrated(&test.srcB, &test.dstB);
+}
+
+static void
+test_dbus_vmstate_missing_src(void)
+{
+ Test test = { .id_list = "idA,idC", .migrate_fail = true };
+
+ /* run in subprocess to silence QEMU error reporting */
+ if (g_test_subprocess()) {
+ test_dbus_vmstate(&test);
+ check_not_migrated(&test.srcA, &test.dstA);
+ check_not_migrated(&test.srcB, &test.dstB);
+ return;
+ }
+
+ g_test_trap_subprocess(NULL, 0, 0);
+ g_test_trap_assert_passed();
+}
+
+static void
+test_dbus_vmstate_missing_dst(void)
+{
+ Test test = { .id_list = "idA,idB",
+ .without_dst_b = true,
+ .migrate_fail = true };
+
+ /* run in subprocess to silence QEMU error reporting */
+ if (g_test_subprocess()) {
+ test_dbus_vmstate(&test);
+ assert(test.srcA.save_called);
+ assert(test.srcB.save_called);
+ assert(!test.dstB.save_called);
+ return;
+ }
+
+ g_test_trap_subprocess(NULL, 0, 0);
+ g_test_trap_assert_passed();
+}
+
+int
+main(int argc, char **argv)
+{
+ GError *err = NULL;
+ g_autofree char *dbus_daemon = NULL;
+ int ret;
+
+ dbus_daemon = g_build_filename(G_STRINGIFY(SRCDIR),
+ "tests",
+ "dbus-vmstate-daemon.sh",
+ NULL);
+ g_setenv("G_TEST_DBUS_DAEMON", dbus_daemon, true);
+
+ g_test_init(&argc, &argv, NULL);
+
+ workdir = g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err);
+ if (!workdir) {
+ g_error("Unable to create temporary dir: %s\n", err->message);
+ exit(1);
+ }
+
+ g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir, true);
+
+ qtest_add_func("/dbus-vmstate/without-list",
+ test_dbus_vmstate_without_list);
+ qtest_add_func("/dbus-vmstate/with-list",
+ test_dbus_vmstate_with_list);
+ qtest_add_func("/dbus-vmstate/only-a",
+ test_dbus_vmstate_only_a);
+ qtest_add_func("/dbus-vmstate/missing-src",
+ test_dbus_vmstate_missing_src);
+ qtest_add_func("/dbus-vmstate/missing-dst",
+ test_dbus_vmstate_missing_dst);
+
+ ret = g_test_run();
+
+ rmdir(workdir);
+ g_free(workdir);
+
+ return ret;
+}
diff --git a/tests/dbus-vmstate1.xml b/tests/dbus-vmstate1.xml
new file mode 100644
index 0000000..cc8563b
--- /dev/null
+++ b/tests/dbus-vmstate1.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="org.qemu.VMState1">
+ <property name="Id" type="s" access="read"/>
+ <method name="Load">
+ <arg type="ay" name="data" direction="in"/>
+ </method>
+ <method name="Save">
+ <arg type="ay" name="data" direction="out"/>
+ </method>
+ </interface>
+</node>
diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker
index 9536370..562d65b 100644
--- a/tests/docker/dockerfiles/centos7.docker
+++ b/tests/docker/dockerfiles/centos7.docker
@@ -8,6 +8,7 @@ ENV PACKAGES \
bzip2-devel \
ccache \
csnappy-devel \
+ dbus-daemon \
flex \
gcc-c++ \
gcc \
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index dad498b..5de79ae 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -21,6 +21,7 @@ RUN apt update && \
build-essential \
ca-certificates \
clang \
+ dbus \
flex \
gettext \
git \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 51d475e..987a3c1 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -8,6 +8,7 @@ ENV PACKAGES \
ccache \
clang \
cyrus-sasl-devel \
+ dbus-daemon \
device-mapper-multipath-devel \
findutils \
flex \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index 18f1100..4177f33 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -13,6 +13,7 @@ FROM ubuntu:19.04
ENV PACKAGES flex bison \
ccache \
clang \
+ dbus \
gcc \
gettext \
git \
diff --git a/tests/iothread.c b/tests/iothread.c
index 13c9fdc..d3a2ee9 100644
--- a/tests/iothread.c
+++ b/tests/iothread.c
@@ -21,6 +21,8 @@
struct IOThread {
AioContext *ctx;
+ GMainContext *worker_context;
+ GMainLoop *main_loop;
QemuThread thread;
QemuMutex init_done_lock;
@@ -35,6 +37,17 @@ AioContext *qemu_get_current_aio_context(void)
return my_iothread ? my_iothread->ctx : qemu_get_aio_context();
}
+static void iothread_init_gcontext(IOThread *iothread)
+{
+ GSource *source;
+
+ iothread->worker_context = g_main_context_new();
+ source = aio_get_g_source(iothread_get_aio_context(iothread));
+ g_source_attach(source, iothread->worker_context);
+ g_source_unref(source);
+ iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
+}
+
static void *iothread_run(void *opaque)
{
IOThread *iothread = opaque;
@@ -44,6 +57,20 @@ static void *iothread_run(void *opaque)
my_iothread = iothread;
qemu_mutex_lock(&iothread->init_done_lock);
iothread->ctx = aio_context_new(&error_abort);
+
+ /*
+ * We must connect the ctx to a GMainContext, because in older versions
+ * of glib the g_source_ref()/unref() functions are not threadsafe
+ * on sources without a context.
+ */
+ iothread_init_gcontext(iothread);
+
+ /*
+ * g_main_context_push_thread_default() must be called before anything
+ * in this new thread uses glib.
+ */
+ g_main_context_push_thread_default(iothread->worker_context);
+
qemu_cond_signal(&iothread->init_done_cond);
qemu_mutex_unlock(&iothread->init_done_lock);
@@ -51,6 +78,7 @@ static void *iothread_run(void *opaque)
aio_poll(iothread->ctx, true);
}
+ g_main_context_pop_thread_default(iothread->worker_context);
rcu_unregister_thread();
return NULL;
}
@@ -66,6 +94,8 @@ void iothread_join(IOThread *iothread)
{
aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread);
qemu_thread_join(&iothread->thread);
+ g_main_context_unref(iothread->worker_context);
+ g_main_loop_unref(iothread->main_loop);
qemu_cond_destroy(&iothread->init_done_cond);
qemu_mutex_destroy(&iothread->init_done_lock);
aio_context_unref(iothread->ctx);
diff --git a/tests/migration-helpers.c b/tests/migration-helpers.c
new file mode 100644
index 0000000..516093b
--- /dev/null
+++ b/tests/migration-helpers.c
@@ -0,0 +1,167 @@
+/*
+ * QTest migration helpers
+ *
+ * Copyright (c) 2016-2018 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 "qapi/qmp/qjson.h"
+
+#include "migration-helpers.h"
+
+bool got_stop;
+
+static void stop_cb(void *opaque, const char *name, QDict *data)
+{
+ if (!strcmp(name, "STOP")) {
+ got_stop = true;
+ }
+}
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
+{
+ va_list ap;
+
+ va_start(ap, command);
+ qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
+ va_end(ap);
+
+ return qtest_qmp_receive_success(who, stop_cb, NULL);
+}
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+QDict *wait_command(QTestState *who, const char *command, ...)
+{
+ va_list ap;
+
+ va_start(ap, command);
+ qtest_qmp_vsend(who, command, ap);
+ va_end(ap);
+
+ return qtest_qmp_receive_success(who, stop_cb, NULL);
+}
+
+/*
+ * Send QMP command "migrate".
+ * Arguments are built from @fmt... (formatted like
+ * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
+ */
+void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args, *rsp;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ qdict_put_str(args, "uri", uri);
+
+ rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
+
+ g_assert(qdict_haskey(rsp, "return"));
+ qobject_unref(rsp);
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * qobject_unref() after use
+ */
+QDict *migrate_query(QTestState *who)
+{
+ return wait_command(who, "{ 'execute': 'query-migrate' }");
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * g_free() after use
+ */
+static gchar *migrate_query_status(QTestState *who)
+{
+ QDict *rsp_return = migrate_query(who);
+ gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
+
+ g_assert(status);
+ qobject_unref(rsp_return);
+
+ return status;
+}
+
+static bool check_migration_status(QTestState *who, const char *goal,
+ const char **ungoals)
+{
+ bool ready;
+ char *current_status;
+ const char **ungoal;
+
+ current_status = migrate_query_status(who);
+ ready = strcmp(current_status, goal) == 0;
+ if (!ungoals) {
+ g_assert_cmpstr(current_status, !=, "failed");
+ /*
+ * If looking for a state other than completed,
+ * completion of migration would cause the test to
+ * hang.
+ */
+ if (strcmp(goal, "completed") != 0) {
+ g_assert_cmpstr(current_status, !=, "completed");
+ }
+ } else {
+ for (ungoal = ungoals; *ungoal; ungoal++) {
+ g_assert_cmpstr(current_status, !=, *ungoal);
+ }
+ }
+ g_free(current_status);
+ return ready;
+}
+
+void wait_for_migration_status(QTestState *who,
+ const char *goal, const char **ungoals)
+{
+ while (!check_migration_status(who, goal, ungoals)) {
+ usleep(1000);
+ }
+}
+
+void wait_for_migration_complete(QTestState *who)
+{
+ wait_for_migration_status(who, "completed", NULL);
+}
+
+void wait_for_migration_fail(QTestState *from, bool allow_active)
+{
+ QDict *rsp_return;
+ char *status;
+ bool failed;
+
+ do {
+ status = migrate_query_status(from);
+ bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
+ (allow_active && !strcmp(status, "active"));
+ if (!result) {
+ fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
+ __func__, status, allow_active);
+ }
+ g_assert(result);
+ failed = !strcmp(status, "failed");
+ g_free(status);
+ } while (!failed);
+
+ /* Is the machine currently running? */
+ rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
+ g_assert(qdict_haskey(rsp_return, "running"));
+ g_assert(qdict_get_bool(rsp_return, "running"));
+ qobject_unref(rsp_return);
+}
diff --git a/tests/migration-helpers.h b/tests/migration-helpers.h
new file mode 100644
index 0000000..a11808b
--- /dev/null
+++ b/tests/migration-helpers.h
@@ -0,0 +1,37 @@
+/*
+ * QTest migration helpers
+ *
+ * Copyright (c) 2016-2018 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.
+ *
+ */
+#ifndef MIGRATION_HELPERS_H_
+#define MIGRATION_HELPERS_H_
+
+#include "libqtest.h"
+
+extern bool got_stop;
+
+GCC_FMT_ATTR(3, 4)
+QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...);
+
+GCC_FMT_ATTR(2, 3)
+QDict *wait_command(QTestState *who, const char *command, ...);
+
+GCC_FMT_ATTR(3, 4)
+void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...);
+
+QDict *migrate_query(QTestState *who);
+
+void wait_for_migration_status(QTestState *who,
+ const char *goal, const char **ungoals);
+
+void wait_for_migration_complete(QTestState *who);
+
+void wait_for_migration_fail(QTestState *from, bool allow_active);
+
+#endif /* MIGRATION_HELPERS_H_ */
diff --git a/tests/migration-test.c b/tests/migration-test.c
index e56e6dc..53afec4 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -14,7 +14,6 @@
#include "libqtest.h"
#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qjson.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/range.h"
@@ -24,6 +23,7 @@
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
+#include "migration-helpers.h"
#include "migration/migration-test.h"
/* TODO actually test the results and get rid of this */
@@ -31,7 +31,6 @@
unsigned start_address;
unsigned end_address;
-bool got_stop;
static bool uffd_feature_thread_id;
#if defined(__linux__)
@@ -157,67 +156,6 @@ static void wait_for_serial(const char *side)
} while (true);
}
-static void stop_cb(void *opaque, const char *name, QDict *data)
-{
- if (!strcmp(name, "STOP")) {
- got_stop = true;
- }
-}
-
-/*
- * Events can get in the way of responses we are actually waiting for.
- */
-GCC_FMT_ATTR(3, 4)
-static QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
-{
- va_list ap;
-
- va_start(ap, command);
- qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
- va_end(ap);
-
- return qtest_qmp_receive_success(who, stop_cb, NULL);
-}
-
-/*
- * Events can get in the way of responses we are actually waiting for.
- */
-GCC_FMT_ATTR(2, 3)
-static QDict *wait_command(QTestState *who, const char *command, ...)
-{
- va_list ap;
-
- va_start(ap, command);
- qtest_qmp_vsend(who, command, ap);
- va_end(ap);
-
- return qtest_qmp_receive_success(who, stop_cb, NULL);
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * qobject_unref() after use
- */
-static QDict *migrate_query(QTestState *who)
-{
- return wait_command(who, "{ 'execute': 'query-migrate' }");
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * g_free() after use
- */
-static gchar *migrate_query_status(QTestState *who)
-{
- QDict *rsp_return = migrate_query(who);
- gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
-
- g_assert(status);
- qobject_unref(rsp_return);
-
- return status;
-}
-
/*
* It's tricky to use qemu's migration event capability with qtest,
* events suddenly appearing confuse the qmp()/hmp() responses.
@@ -265,48 +203,6 @@ static void read_blocktime(QTestState *who)
qobject_unref(rsp_return);
}
-static bool check_migration_status(QTestState *who, const char *goal,
- const char **ungoals)
-{
- bool ready;
- char *current_status;
- const char **ungoal;
-
- current_status = migrate_query_status(who);
- ready = strcmp(current_status, goal) == 0;
- if (!ungoals) {
- g_assert_cmpstr(current_status, !=, "failed");
- /*
- * If looking for a state other than completed,
- * completion of migration would cause the test to
- * hang.
- */
- if (strcmp(goal, "completed") != 0) {
- g_assert_cmpstr(current_status, !=, "completed");
- }
- } else {
- for (ungoal = ungoals; *ungoal; ungoal++) {
- g_assert_cmpstr(current_status, !=, *ungoal);
- }
- }
- g_free(current_status);
- return ready;
-}
-
-static void wait_for_migration_status(QTestState *who,
- const char *goal,
- const char **ungoals)
-{
- while (!check_migration_status(who, goal, ungoals)) {
- usleep(1000);
- }
-}
-
-static void wait_for_migration_complete(QTestState *who)
-{
- wait_for_migration_status(who, "completed", NULL);
-}
-
static void wait_for_migration_pass(QTestState *who)
{
uint64_t initial_pass = get_migration_pass(who);
@@ -506,30 +402,6 @@ static void migrate_set_capability(QTestState *who, const char *capability,
qobject_unref(rsp);
}
-/*
- * Send QMP command "migrate".
- * Arguments are built from @fmt... (formatted like
- * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
- */
-GCC_FMT_ATTR(3, 4)
-static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
-{
- va_list ap;
- QDict *args, *rsp;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- qdict_put_str(args, "uri", uri);
-
- rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
-
- g_assert(qdict_haskey(rsp, "return"));
- qobject_unref(rsp);
-}
-
static void migrate_postcopy_start(QTestState *from, QTestState *to)
{
QDict *rsp;
@@ -800,7 +672,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
g_free(uri);
wait_for_migration_pass(from);
@@ -891,7 +763,7 @@ static void test_postcopy_recovery(void)
wait_for_migration_status(from, "postcopy-paused",
(const char * []) { "failed", "active",
"completed", NULL });
- migrate(from, uri, "{'resume': true}");
+ migrate_qmp(from, uri, "{'resume': true}");
g_free(uri);
/* Restore the postcopy bandwidth to unlimited */
@@ -900,32 +772,6 @@ static void test_postcopy_recovery(void)
migrate_postcopy_complete(from, to);
}
-static void wait_for_migration_fail(QTestState *from, bool allow_active)
-{
- QDict *rsp_return;
- char *status;
- bool failed;
-
- do {
- status = migrate_query_status(from);
- bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
- (allow_active && !strcmp(status, "active"));
- if (!result) {
- fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
- __func__, status, allow_active);
- }
- g_assert(result);
- failed = !strcmp(status, "failed");
- g_free(status);
- } while (!failed);
-
- /* Is the machine currently running? */
- rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
- g_assert(qdict_haskey(rsp_return, "running"));
- g_assert(qdict_get_bool(rsp_return, "running"));
- qobject_unref(rsp_return);
-}
-
static void test_baddest(void)
{
MigrateStart *args = migrate_start_new();
@@ -936,7 +782,7 @@ static void test_baddest(void)
if (test_migrate_start(&from, &to, "tcp:0:0", args)) {
return;
}
- migrate(from, "tcp:0:0", "{}");
+ migrate_qmp(from, "tcp:0:0", "{}");
wait_for_migration_fail(from, false);
test_migrate_end(from, to, false);
}
@@ -963,7 +809,7 @@ static void test_precopy_unix(void)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
@@ -1000,7 +846,7 @@ static void test_ignore_shared(void)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
@@ -1047,7 +893,7 @@ static void test_xbzrle(const char *uri)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
@@ -1098,7 +944,7 @@ static void test_precopy_tcp(void)
uri = migrate_get_socket_address(to, "socket-address");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
wait_for_migration_pass(from);
@@ -1167,7 +1013,7 @@ static void test_migrate_fd_proto(void)
close(pair[1]);
/* Start migration to the 2nd socket*/
- migrate(from, "fd:fd-mig", "{}");
+ migrate_qmp(from, "fd:fd-mig", "{}");
wait_for_migration_pass(from);
@@ -1222,7 +1068,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
if (should_fail) {
qtest_set_expected_status(to, 1);
@@ -1316,7 +1162,7 @@ static void test_migrate_auto_converge(void)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
- migrate(from, uri, "{}");
+ migrate_qmp(from, uri, "{}");
/* Wait for throttling begins */
percentage = 0;
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
index 7d3544b..160683a 100755
--- a/tests/qemu-iotests/007
+++ b/tests/qemu-iotests/007
@@ -41,8 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
# refcount_bits must be at least 4 so we can create ten internal snapshots
-# (1 bit supports none, 2 bits support two, 4 bits support 14)
-_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]'
+# (1 bit supports none, 2 bits support two, 4 bits support 14);
+# snapshot are generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]' data_file
echo
echo "creating image"
diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014
index 2f728a1..e1221c0 100755
--- a/tests/qemu-iotests/014
+++ b/tests/qemu-iotests/014
@@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Compression and snapshots do not work with external data files
+_unsupported_imgopts data_file
TEST_OFFSETS="0 4294967296"
TEST_OPS="writev read write readv"
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
index eec5387..4d8effd 100755
--- a/tests/qemu-iotests/015
+++ b/tests/qemu-iotests/015
@@ -40,8 +40,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# actually any format that supports snapshots
_supported_fmt qcow2
_supported_proto generic
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
echo
echo "creating image"
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
index b4f5234..813a84a 100755
--- a/tests/qemu-iotests/019
+++ b/tests/qemu-iotests/019
@@ -30,9 +30,9 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.base"
- rm -f "$TEST_IMG.orig"
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.base"
+ _rm_test_img "$TEST_IMG.orig"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index f41b92f..20f8f18 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -28,9 +28,9 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.base"
- rm -f "$TEST_IMG.orig"
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.base"
+ _rm_test_img "$TEST_IMG.orig"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024
index 23298c6..e2e7662 100755
--- a/tests/qemu-iotests/024
+++ b/tests/qemu-iotests/024
@@ -29,12 +29,12 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_DIR/t.$IMGFMT.base_old"
- rm -f "$TEST_DIR/t.$IMGFMT.base_new"
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_old"
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_new"
- rm -f "$TEST_DIR/subdir/t.$IMGFMT"
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_old"
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_new"
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT"
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_old"
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_new"
rmdir "$TEST_DIR/subdir" 2> /dev/null
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 3430029..a4aa747 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -49,7 +49,10 @@ _supported_cache_modes writethrough none
# 32 and 64 bits do not work either, however, due to different leaked cluster
# count on error.
# Thus, the only remaining option is refcount_bits=16.
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+#
+# As for data_file, none of the refcount tests can work for it.
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' \
+ data_file
echo "Errors while writing 128 kB"
echo
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
index bba1ee5..e2556d8 100755
--- a/tests/qemu-iotests/028
+++ b/tests/qemu-iotests/028
@@ -32,7 +32,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f "${TEST_IMG}.copy"
+ _rm_test_img "${TEST_IMG}.copy"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
index 94c2713..2161a4b 100755
--- a/tests/qemu-iotests/029
+++ b/tests/qemu-iotests/029
@@ -28,7 +28,7 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f $TEST_IMG.snap
+ _rm_test_img "$TEST_IMG.snap"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -42,8 +42,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_unsupported_proto vxhs
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
offset_size=24
offset_l1_size=36
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index a3c25ec..646ecd5 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -40,19 +40,22 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
+# We want to test compat=0.10, which does not support external data
+# files or refcount widths other than 16
+_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
CLUSTER_SIZE=65536
# qcow2.py output depends on the exact options used, so override the command
# line here as an exception
-for IMGOPTS in "compat=0.10" "compat=1.1"; do
+for compat in "compat=0.10" "compat=1.1"; do
echo
- echo ===== Testing with -o $IMGOPTS =====
+ echo ===== Testing with -o $compat =====
echo
echo === Create image with unknown header extension ===
echo
- _make_test_img 64M
+ _make_test_img -o $compat 64M
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
$PYTHON qcow2.py "$TEST_IMG" dump-header
_check_test_img
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index 68a74d0..d535e40 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -18,9 +18,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -46,9 +46,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -74,9 +74,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -109,9 +109,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 104
@@ -142,9 +142,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 104
@@ -175,9 +175,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 104
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index f06ff67..5125984 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -43,9 +43,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
-
-# Only qcow2v3 and later supports feature bits
-IMGOPTS="compat=1.1"
+# Only qcow2v3 and later supports feature bits;
+# qcow2.py does not support external data files
+_unsupported_imgopts 'compat=0.10' data_file
echo
echo === Image with unknown incompatible feature bit ===
@@ -55,7 +55,8 @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
# Without feature table
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
_img_info
# With feature table containing bit 63
@@ -103,14 +104,16 @@ echo === Create image with unknown autoclear feature bit ===
echo
_make_test_img 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
echo === Repair image ===
echo
_check_test_img -r all
-$PYTHON qcow2.py "$TEST_IMG" dump-header
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
index e489b44..0b52b93 100644
--- a/tests/qemu-iotests/036.out
+++ b/tests/qemu-iotests/036.out
@@ -3,25 +3,9 @@ QA output created by 036
=== Image with unknown incompatible feature bit ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-magic 0x514649fb
-version 3
-backing_file_offset 0x0
-backing_file_size 0x0
-cluster_bits 16
-size 67108864
-crypt_method 0
-l1_size 1
-l1_table_offset 0x30000
-refcount_table_offset 0x10000
-refcount_table_clusters 1
-nb_snapshots 0
-snapshot_offset 0x0
-incompatible_features 0x8000000000000000
-compatible_features 0x0
-autoclear_features 0x0
-refcount_order 4
-header_length 104
-
+incompatible_features [63]
+compatible_features []
+autoclear_features []
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: 8000000000000000
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature
@@ -37,25 +21,9 @@ qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): tes
=== Create image with unknown autoclear feature bit ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-magic 0x514649fb
-version 3
-backing_file_offset 0x0
-backing_file_size 0x0
-cluster_bits 16
-size 67108864
-crypt_method 0
-l1_size 1
-l1_table_offset 0x30000
-refcount_table_offset 0x10000
-refcount_table_clusters 1
-nb_snapshots 0
-snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x8000000000000000
-refcount_order 4
-header_length 104
-
+incompatible_features []
+compatible_features []
+autoclear_features [63]
Header extension:
magic 0x6803f857
length 192
@@ -65,25 +33,9 @@ data <binary>
=== Repair image ===
No errors were found on the image.
-magic 0x514649fb
-version 3
-backing_file_offset 0x0
-backing_file_size 0x0
-cluster_bits 16
-size 67108864
-crypt_method 0
-l1_size 1
-l1_table_offset 0x30000
-refcount_table_offset 0x10000
-refcount_table_clusters 1
-nb_snapshots 0
-snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
-refcount_order 4
-header_length 104
-
+incompatible_features []
+compatible_features []
+autoclear_features []
Header extension:
magic 0x6803f857
length 192
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index 325da63..ddce48a 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -44,14 +44,16 @@ _supported_proto file
_supported_os Linux
_default_cache_mode writethrough
_supported_cache_modes writethrough
+# Some of these test cases expect no external data file so that all
+# clusters are part of the qcow2 image and refcounted
+_unsupported_imgopts data_file
size=128M
echo
echo "== Checking that image is clean on shutdown =="
-IMGOPTS="compat=1.1,lazy_refcounts=on"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
@@ -62,8 +64,7 @@ _check_test_img
echo
echo "== Creating a dirty image file =="
-IMGOPTS="compat=1.1,lazy_refcounts=on"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x5a 0 512" \
@@ -98,8 +99,7 @@ $QEMU_IO -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
echo
echo "== Opening a dirty image read/write should repair it =="
-IMGOPTS="compat=1.1,lazy_refcounts=on"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x5a 0 512" \
@@ -117,8 +117,7 @@ $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
echo
echo "== Creating an image file with lazy_refcounts=off =="
-IMGOPTS="compat=1.1,lazy_refcounts=off"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x5a 0 512" \
@@ -132,11 +131,9 @@ _check_test_img
echo
echo "== Committing to a backing file with lazy_refcounts=on =="
-IMGOPTS="compat=1.1,lazy_refcounts=on"
-TEST_IMG="$TEST_IMG".base _make_test_img $size
+TEST_IMG="$TEST_IMG".base _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
-IMGOPTS="compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base" $size
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG commit "$TEST_IMG"
@@ -151,8 +148,7 @@ TEST_IMG="$TEST_IMG".base _check_test_img
echo
echo "== Changing lazy_refcounts setting at runtime =="
-IMGOPTS="compat=1.1,lazy_refcounts=off"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
_NO_VALGRIND \
$QEMU_IO -c "reopen -o lazy-refcounts=on" \
@@ -164,8 +160,7 @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_check_test_img
-IMGOPTS="compat=1.1,lazy_refcounts=on"
-_make_test_img $size
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
_NO_VALGRIND \
$QEMU_IO -c "reopen -o lazy-refcounts=off" \
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index 2e356d5..bdafa3a 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -4,7 +4,7 @@ QA output created by 039
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-incompatible_features 0x0
+incompatible_features []
No errors were found on the image.
== Creating a dirty image file ==
@@ -12,7 +12,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x1
+incompatible_features [0]
ERROR cluster 5 refcount=0 reference=1
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -22,7 +22,7 @@ Data may be corrupted, or further writes to the image may corrupt it.
== Read-only access must still work ==
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-incompatible_features 0x1
+incompatible_features [0]
== Repairing the image file must succeed ==
ERROR cluster 5 refcount=0 reference=1
@@ -36,7 +36,7 @@ The following inconsistencies were found and repaired:
Double checking the fixed image now...
No errors were found on the image.
-incompatible_features 0x0
+incompatible_features []
== Data should still be accessible after repair ==
read 512/512 bytes at offset 0
@@ -47,21 +47,21 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x1
+incompatible_features [0]
ERROR cluster 5 refcount=0 reference=1
Rebuilding refcount structure
Repairing cluster 1 refcount=1 reference=0
Repairing cluster 2 refcount=1 reference=0
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-incompatible_features 0x0
+incompatible_features []
== Creating an image file with lazy_refcounts=off ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x0
+incompatible_features []
No errors were found on the image.
== Committing to a backing file with lazy_refcounts=on ==
@@ -70,8 +70,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image committed.
-incompatible_features 0x0
-incompatible_features 0x0
+incompatible_features []
+incompatible_features []
No errors were found on the image.
No errors were found on the image.
@@ -80,7 +80,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x1
+incompatible_features [0]
ERROR cluster 5 refcount=0 reference=1
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -90,6 +90,6 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x0
+incompatible_features []
No errors were found on the image.
*** done
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 8568426..d7be30b 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -1121,6 +1121,50 @@ class TestOrphanedSource(iotests.QMPTestCase):
target='dest-ro')
self.assert_qmp(result, 'error/class', 'GenericError')
+ def test_failing_permission_in_complete(self):
+ self.assert_no_active_block_jobs()
+
+ # Unshare consistent-read on the target
+ # (The mirror job does not care)
+ result = self.vm.qmp('blockdev-add',
+ driver='blkdebug',
+ node_name='dest-perm',
+ image='dest',
+ unshare_child_perms=['consistent-read'])
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-mirror', job_id='job', device='src',
+ sync='full', target='dest',
+ filter_node_name='mirror-filter')
+ self.assert_qmp(result, 'return', {})
+
+ # Require consistent-read on the source
+ # (We can only add this node once the job has started, or it
+ # will complain that it does not want to run on non-root nodes)
+ result = self.vm.qmp('blockdev-add',
+ driver='blkdebug',
+ node_name='src-perm',
+ image='src',
+ take_child_perms=['consistent-read'])
+ self.assert_qmp(result, 'return', {})
+
+ # While completing, mirror will attempt to replace src by
+ # dest, which must fail because src-perm requires
+ # consistent-read but dest-perm does not share it; thus
+ # aborting the job when it is supposed to complete
+ self.complete_and_wait('job',
+ completion_error='Operation not permitted')
+
+ # Assert that all of our nodes are still there (except for the
+ # mirror filter, which should be gone despite the failure)
+ nodes = self.vm.qmp('query-named-block-nodes')['return']
+ nodes = [node['node-name'] for node in nodes]
+
+ for expect in ('src', 'src-perm', 'dest', 'dest-perm'):
+ self.assertTrue(expect in nodes, '%s disappeared' % expect)
+ self.assertFalse('mirror-filter' in nodes,
+ 'Mirror filter node did not disappear')
+
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 2c448b4..f496be9 100644
--- a/tests/qemu-iotests/041.out
+++ b/tests/qemu-iotests/041.out
@@ -1,5 +1,5 @@
-..........................................................................................
+...........................................................................................
----------------------------------------------------------------------
-Ran 90 tests
+Ran 91 tests
OK
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
index 67cc7e7..b102e49 100755
--- a/tests/qemu-iotests/043
+++ b/tests/qemu-iotests/043
@@ -29,7 +29,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG".[123].base
+ for img in "$TEST_IMG".[123].base; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index 4e03ead..a066eec 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -38,6 +38,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
+# data_file does not support compressed clusters
+_unsupported_imgopts data_file
CLUSTER_SIZE=64k
size=128M
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
index bde408c..2af6b74 100755
--- a/tests/qemu-iotests/048
+++ b/tests/qemu-iotests/048
@@ -31,7 +31,7 @@ _cleanup()
{
echo "Cleanup"
_cleanup_test_img
- rm "${TEST_IMG_FILE2}"
+ _rm_test_img "${TEST_IMG_FILE2}"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -49,6 +49,8 @@ _compare()
_supported_fmt raw qcow2 qed luks
_supported_proto file
_supported_os Linux
+# Using 'cp' is incompatible with external data files
+_unsupported_imgopts data_file
# Remove once all tests are fixed to use TEST_IMG_FILE
# correctly and common.rc sets it unconditionally
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
index 211fc00..cdc5356 100755
--- a/tests/qemu-iotests/050
+++ b/tests/qemu-iotests/050
@@ -29,8 +29,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.old"
- rm -f "$TEST_IMG.new"
+ _rm_test_img "$TEST_IMG.old"
+ _rm_test_img "$TEST_IMG.new"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -41,10 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2 qed
_supported_proto file
-if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
- IMGOPTS=compat=1.1
-fi
-
echo
echo "== Creating images =="
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index a13bce2..034d3a3 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -39,8 +39,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
# A compat=0.10 image is created in this test which does not support anything
-# other than refcount_bits=16
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+# other than refcount_bits=16;
+# it also will not support an external data file
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
_require_drivers nbd
do_run_qemu()
@@ -158,7 +159,7 @@ echo
echo === With version 2 images enabling lazy refcounts must fail ===
echo
-_make_test_img -ocompat=0.10 $size
+_make_test_img -o compat=0.10 $size
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=on
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=off
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
index e82bb69..71d299c 100755
--- a/tests/qemu-iotests/053
+++ b/tests/qemu-iotests/053
@@ -28,8 +28,8 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f "$TEST_IMG.orig"
- _cleanup_test_img
+ _rm_test_img "$TEST_IMG.orig"
+ _cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
index 8c3212a..d5304bb 100755
--- a/tests/qemu-iotests/058
+++ b/tests/qemu-iotests/058
@@ -42,7 +42,7 @@ _cleanup()
{
nbd_server_stop
_cleanup_test_img
- rm -f "$converted_image"
+ _rm_test_img "$converted_image"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -56,8 +56,9 @@ _supported_fmt qcow2
_supported_proto file
_supported_os Linux
_require_command QEMU_NBD
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
index 10bfbae..5438025 100755
--- a/tests/qemu-iotests/059
+++ b/tests/qemu-iotests/059
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.qcow2"
+ IMGFMT=qcow2 _rm_test_img "$TEST_IMG.qcow2"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -70,18 +70,18 @@ poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00"
echo
echo "=== Testing monolithicFlat creation and opening ==="
-IMGOPTS="subformat=monolithicFlat" _make_test_img 2G
+_make_test_img -o "subformat=monolithicFlat" 2G
_img_info
_cleanup_test_img
echo
echo "=== Testing monolithicFlat with zeroed_grain ==="
-IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
+_make_test_img -o "subformat=monolithicFlat,zeroed_grain=on" 2G
_cleanup_test_img
echo
echo "=== Testing big twoGbMaxExtentFlat ==="
-IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G
+_make_test_img -o "subformat=twoGbMaxExtentFlat" 1000G
$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/'
_cleanup_test_img
@@ -101,13 +101,13 @@ _img_info
echo
echo "=== Testing truncated sparse ==="
-IMGOPTS="subformat=monolithicSparse" _make_test_img 100G
+_make_test_img -o "subformat=monolithicSparse" 100G
truncate -s 10M $TEST_IMG
_img_info
echo
echo "=== Converting to streamOptimized from image with small cluster size==="
-TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G
+TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 _make_test_img -o "cluster_size=4096" 1G
$QEMU_IO -f qcow2 -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io
$QEMU_IO -f qcow2 -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io
$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1
@@ -117,7 +117,7 @@ echo "=== Testing monolithicFlat with internally generated JSON file name ==="
echo '--- blkdebug ---'
# Should work, because bdrv_dirname() works fine with blkdebug
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
+_make_test_img -o "subformat=monolithicFlat" 64M
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
-c info \
2>&1 \
@@ -126,7 +126,7 @@ _cleanup_test_img
echo '--- quorum ---'
# Should not work, because bdrv_dirname() does not work with quorum
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
+_make_test_img -o "subformat=monolithicFlat" 64M
cp "$TEST_IMG" "$TEST_IMG.orig"
filename="json:{
@@ -161,7 +161,7 @@ _cleanup_test_img
echo
echo "=== Testing 4TB monolithicFlat creation and IO ==="
-IMGOPTS="subformat=monolithicFlat" _make_test_img 4T
+_make_test_img -o "subformat=monolithicFlat" 4T
_img_info
$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io
@@ -170,7 +170,7 @@ _cleanup_test_img
echo
echo "=== Testing qemu-img map on extents ==="
for fmt in monolithicSparse twoGbMaxExtentSparse; do
- IMGOPTS="subformat=$fmt" _make_test_img 31G
+ _make_test_img -o "subformat=$fmt" 31G
$QEMU_IO -c "write 65024 1k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index d96f17a..043f129 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -44,10 +44,14 @@ _filter_io_error()
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# These tests only work for compat=1.1 images without an external
+# data file with refcount_bits=16
+_unsupported_imgopts 'compat=0.10' data_file \
+ 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
# The repair process will create a large file - so check for availability first
_require_large_file 64G
@@ -58,8 +62,6 @@ l1_offset=196608 # 0x30000 (XXX: just an assumption)
l2_offset=262144 # 0x40000 (XXX: just an assumption)
l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
-IMGOPTS="compat=1.1"
-
OPEN_RW="open -o overlap-check=all $TEST_IMG"
# Overlap checks are done before write operations only, therefore opening an
# image read-only makes the overlap-check option irrelevant
@@ -161,7 +163,7 @@ $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
# compat=0.10 is required in order to make the following discard actually
# unallocate the sector rather than make it a zero sector - we want COW, after
# all.
-IMGOPTS='compat=0.10' _make_test_img -b "$BACKING_IMG" 1G
+_make_test_img -o 'compat=0.10' -b "$BACKING_IMG" 1G
# Write two clusters, the second one enforces creation of an L2 table after
# the first data cluster.
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
@@ -401,7 +403,7 @@ echo
echo "=== Discarding a non-covered in-bounds refblock ==="
echo
-IMGOPTS='refcount_bits=1' _make_test_img 64M
+_make_test_img -o 'refcount_bits=1' 64M
# Pretend there's a refblock somewhere where there is no refblock to
# cover it (but the covering refblock has a valid index in the
@@ -425,7 +427,7 @@ echo
echo "=== Discarding a refblock covered by an unaligned refblock ==="
echo
-IMGOPTS='refcount_bits=1' _make_test_img 64M
+_make_test_img -o 'refcount_bits=1' 64M
# Same as above
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index 0f6b065..d27692a 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -7,10 +7,10 @@ ERROR cluster 3 refcount=1 reference=3
1 errors were found on the image.
Data may be corrupted, or further writes to the image may corrupt it.
-incompatible_features 0x0
+incompatible_features []
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed
write failed: Input/output error
-incompatible_features 0x2
+incompatible_features [1]
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
@@ -33,10 +33,10 @@ ERROR cluster 2 refcount=1 reference=2
2 errors were found on the image.
Data may be corrupted, or further writes to the image may corrupt it.
-incompatible_features 0x0
+incompatible_features []
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount block); further corruption events will be suppressed
write failed: Input/output error
-incompatible_features 0x2
+incompatible_features [1]
ERROR refcount block 0 refcount=2
ERROR cluster 2 refcount=1 reference=2
Rebuilding refcount structure
@@ -49,10 +49,10 @@ The following inconsistencies were found and repaired:
Double checking the fixed image now...
No errors were found on the image.
-incompatible_features 0x0
+incompatible_features []
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-incompatible_features 0x0
+incompatible_features []
=== Testing cluster data reference into inactive L2 table ===
@@ -69,10 +69,10 @@ Data may be corrupted, or further writes to the image may corrupt it.
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-incompatible_features 0x0
+incompatible_features []
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with inactive L2 table); further corruption events will be suppressed
write failed: Input/output error
-incompatible_features 0x2
+incompatible_features [1]
ERROR cluster 4 refcount=1 reference=2
Leaked cluster 9 refcount=1 reference=0
Repairing cluster 4 refcount=1 reference=2
@@ -85,10 +85,10 @@ The following inconsistencies were found and repaired:
Double checking the fixed image now...
No errors were found on the image.
-incompatible_features 0x0
+incompatible_features []
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-incompatible_features 0x0
+incompatible_features []
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
index 4eac5b8..36b0404 100755
--- a/tests/qemu-iotests/061
+++ b/tests/qemu-iotests/061
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.data
+ _rm_test_img "$TEST_IMG.data"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -37,15 +37,20 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Conversion between different compat versions can only really work
+# with refcount_bits=16;
+# we have explicit tests for data_file here, but the whole test does
+# not work with it
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
echo
echo "=== Testing version downgrade with zero expansion ==="
echo
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
@@ -56,7 +61,7 @@ _check_test_img
echo
echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
echo
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
@@ -72,7 +77,7 @@ _check_test_img
echo
echo "=== Testing dirty version downgrade ==="
echo
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
@@ -85,7 +90,7 @@ _check_test_img
echo
echo "=== Testing version downgrade with unknown compat/autoclear flags ==="
echo
-IMGOPTS="compat=1.1" _make_test_img 64M
+_make_test_img -o "compat=1.1" 64M
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
$PYTHON qcow2.py "$TEST_IMG" dump-header
@@ -96,7 +101,7 @@ _check_test_img
echo
echo "=== Testing version upgrade and resize ==="
echo
-IMGOPTS="compat=0.10" _make_test_img 64M
+_make_test_img -o "compat=0.10" 64M
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
@@ -107,7 +112,7 @@ _check_test_img
echo
echo "=== Testing dirty lazy_refcounts=off ==="
echo
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
_NO_VALGRIND \
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
@@ -120,8 +125,8 @@ _check_test_img
echo
echo "=== Testing backing file ==="
echo
-IMGOPTS="compat=1.1" _make_test_img 64M
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+_make_test_img -o "compat=1.1" 64M
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" "$TEST_IMG"
@@ -131,7 +136,7 @@ _check_test_img
echo
echo "=== Testing invalid configurations ==="
echo
-IMGOPTS="compat=0.10" _make_test_img 64M
+_make_test_img -o "compat=0.10" 64M
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
$QEMU_IMG amend -o "compat=1.1" "$TEST_IMG" # actually valid
$QEMU_IMG amend -o "compat=0.10,lazy_refcounts=on" "$TEST_IMG"
@@ -144,7 +149,7 @@ $QEMU_IMG amend -o "preallocation=on" "$TEST_IMG"
echo
echo "=== Testing correct handling of unset value ==="
echo
-IMGOPTS="compat=1.1,cluster_size=1k" _make_test_img 64M
+_make_test_img -o "compat=1.1,cluster_size=1k" 64M
echo "Should work:"
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
echo "Should not work:" # Just to know which of these tests actually fails
@@ -153,7 +158,7 @@ $QEMU_IMG amend -o "cluster_size=64k" "$TEST_IMG"
echo
echo "=== Testing zero expansion on inactive clusters ==="
echo
-IMGOPTS="compat=1.1" _make_test_img 64M
+_make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -c foo "$TEST_IMG"
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
@@ -167,7 +172,7 @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
echo
echo "=== Testing zero expansion on shared L2 table ==="
echo
-IMGOPTS="compat=1.1" _make_test_img 64M
+_make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -c foo "$TEST_IMG"
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
@@ -180,9 +185,9 @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
echo
echo "=== Testing zero expansion on backed image ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
$QEMU_IO -c "read -P 0x2a 0 128k" -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
_check_test_img
@@ -191,9 +196,9 @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
echo
echo "=== Testing zero expansion on backed inactive clusters ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
$QEMU_IO -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -c foo "$TEST_IMG"
$QEMU_IO -c "write -P 0x42 0 128k" "$TEST_IMG" | _filter_qemu_io
@@ -207,9 +212,9 @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
echo
echo "=== Testing zero expansion on backed image with shared L2 table ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -c foo "$TEST_IMG"
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
@@ -222,7 +227,7 @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
echo
echo "=== Testing preallocated zero expansion on full image ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG" _make_test_img 64M
+TEST_IMG="$TEST_IMG" _make_test_img -o "compat=1.1" 64M
$QEMU_IO -c "write -P 0x2a 0 64M" "$TEST_IMG" -c "write -z 0 64M" | _filter_qemu_io
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
_check_test_img
@@ -231,8 +236,8 @@ $QEMU_IO -c "read -P 0 0 64M" "$TEST_IMG" | _filter_qemu_io
echo
echo "=== Testing progress report without snapshot ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
$QEMU_IO -c "write -z 0 64k" \
-c "write -z 1G 64k" \
-c "write -z 2G 64k" \
@@ -243,8 +248,8 @@ _check_test_img
echo
echo "=== Testing progress report with snapshot ==="
echo
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
$QEMU_IO -c "write -z 0 64k" \
-c "write -z 1G 64k" \
-c "write -z 2G 64k" \
@@ -256,7 +261,7 @@ _check_test_img
echo
echo "=== Testing version downgrade with external data file ==="
echo
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
_img_info --format-specific
_check_test_img
@@ -264,11 +269,11 @@ _check_test_img
echo
echo "=== Try changing the external data file ==="
echo
-IMGOPTS="compat=1.1" _make_test_img 64M
+_make_test_img -o "compat=1.1" 64M
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
echo
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
_img_info --format-specific
TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
@@ -281,7 +286,7 @@ TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info -
echo
echo "=== Clearing and setting data-file-raw ==="
echo
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" 64M
$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG"
_img_info --format-specific
_check_test_img
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index d6a7c2a..8b3091a 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -18,9 +18,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x1
-autoclear_features 0x0
+incompatible_features []
+compatible_features [0]
+autoclear_features []
refcount_order 4
header_length 104
@@ -42,9 +42,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -76,9 +76,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x1
-autoclear_features 0x0
+incompatible_features []
+compatible_features [0]
+autoclear_features []
refcount_order 4
header_length 104
@@ -100,9 +100,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -132,9 +132,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x1
-compatible_features 0x1
-autoclear_features 0x0
+incompatible_features [0]
+compatible_features [0]
+autoclear_features []
refcount_order 4
header_length 104
@@ -161,9 +161,9 @@ refcount_table_offset 0x80000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -187,9 +187,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x40000000000
-autoclear_features 0x40000000000
+incompatible_features []
+compatible_features [42]
+autoclear_features [42]
refcount_order 4
header_length 104
@@ -211,9 +211,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -237,9 +237,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 72
@@ -256,9 +256,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x1
-autoclear_features 0x0
+incompatible_features []
+compatible_features [0]
+autoclear_features []
refcount_order 4
header_length 104
@@ -290,9 +290,9 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x1
-compatible_features 0x1
-autoclear_features 0x0
+incompatible_features [0]
+compatible_features [0]
+autoclear_features []
refcount_order 4
header_length 104
@@ -319,9 +319,9 @@ refcount_table_offset 0x80000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
-incompatible_features 0x0
-compatible_features 0x0
-autoclear_features 0x0
+incompatible_features []
+compatible_features []
+autoclear_features []
refcount_order 4
header_length 104
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
index d5f818f..f26b88d 100755
--- a/tests/qemu-iotests/062
+++ b/tests/qemu-iotests/062
@@ -37,11 +37,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto generic
+# We need zero clusters and snapshots
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
-IMGOPTS="compat=1.1"
IMG_SIZE=64M
echo
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
index 7cf0427..c750b38 100755
--- a/tests/qemu-iotests/063
+++ b/tests/qemu-iotests/063
@@ -29,8 +29,10 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.orig" "$TEST_IMG.raw1" "$TEST_IMG.raw2"
+ _cleanup_test_img
+ for img in "$TEST_IMG".{orig,raw1,raw2,target}; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -49,15 +51,13 @@ _unsupported_imgopts "subformat=monolithicFlat" \
_make_test_img 4M
echo "== Testing conversion with -n fails with no target file =="
-# check .orig file does not exist
-rm -f "$TEST_IMG.orig"
if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" >/dev/null 2>&1; then
exit 1
fi
echo "== Testing conversion with -n succeeds with a target file =="
-rm -f "$TEST_IMG.orig"
-cp "$TEST_IMG" "$TEST_IMG.orig"
+_rm_test_img "$TEST_IMG.orig"
+TEST_IMG="$TEST_IMG.orig" _make_test_img 4M
if ! $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" ; then
exit 1
fi
@@ -83,10 +83,8 @@ fi
_check_test_img
echo "== Testing conversion to a smaller file fails =="
-rm -f "$TEST_IMG.orig"
-mv "$TEST_IMG" "$TEST_IMG.orig"
-_make_test_img 2M
-if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev/null 2>&1; then
+TEST_IMG="$TEST_IMG.target" _make_test_img 2M
+if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.target" >/dev/null 2>&1; then
exit 1
fi
diff --git a/tests/qemu-iotests/063.out b/tests/qemu-iotests/063.out
index 7b691b2..890b719 100644
--- a/tests/qemu-iotests/063.out
+++ b/tests/qemu-iotests/063.out
@@ -2,11 +2,12 @@ QA output created by 063
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
== Testing conversion with -n fails with no target file ==
== Testing conversion with -n succeeds with a target file ==
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=4194304
== Testing conversion to raw is the same after conversion with -n ==
== Testing conversion back to original format ==
No errors were found on the image.
== Testing conversion to a smaller file fails ==
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
+Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=2097152
== Regression testing for copy offloading bug ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=1048576
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
index 28f8c98..a4ac613 100755
--- a/tests/qemu-iotests/066
+++ b/tests/qemu-iotests/066
@@ -36,12 +36,15 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto generic
+# We need zero clusters and snapshots
+# (TODO: Consider splitting the snapshot part into a separate test
+# file, so this one runs with refcount_bits=1 and data_file)
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
# Intentionally create an unaligned image
-IMGOPTS="compat=1.1"
IMG_SIZE=$((64 * 1024 * 1024 + 512))
echo
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 926c79b..a63be9c 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -32,8 +32,10 @@ status=1 # failure is the default!
_supported_fmt qcow2
_supported_proto file
-# Because anything other than 16 would change the output of query-block
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+# Because anything other than 16 would change the output of query-block,
+# and external data files would change the output of
+# query-named-block-nodes
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
do_run_qemu()
{
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
index 22f5ca3..ccd1a9f 100755
--- a/tests/qemu-iotests/068
+++ b/tests/qemu-iotests/068
@@ -36,11 +36,13 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto generic
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
-IMGOPTS="compat=1.1"
IMG_SIZE=128K
case "$QEMU_DEFAULT_MACHINE" in
diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069
index 3974714..b997b12 100755
--- a/tests/qemu-iotests/069
+++ b/tests/qemu-iotests/069
@@ -47,7 +47,7 @@ echo "=== Creating an image with a backing file and deleting that file ==="
echo
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
_make_test_img -b "$TEST_IMG.base" $IMG_SIZE
-rm -f "$TEST_IMG.base"
+_rm_test_img "$TEST_IMG.base"
# Just open the image and close it right again (this should print an error message)
$QEMU_IO -c quit "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index fab5266..88faebc 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -39,6 +39,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_require_drivers blkdebug blkverify
+# blkdebug can only inject errors on bs->file, not on the data_file,
+# so thie test does not work with external data files
+_unsupported_imgopts data_file
do_run_qemu()
{
@@ -58,7 +61,7 @@ echo
echo "=== Testing blkverify through filename ==="
echo
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
_filter_imgfmt
_make_test_img $IMG_SIZE
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \
@@ -73,7 +76,7 @@ echo
echo "=== Testing blkverify through file blockref ==="
echo
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
_filter_imgfmt
_make_test_img $IMG_SIZE
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
index e684b1b..23a1bdf 100755
--- a/tests/qemu-iotests/073
+++ b/tests/qemu-iotests/073
@@ -39,6 +39,10 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_unsupported_proto vxhs
+# External data files do not support compressed clusters
+# (TODO: Consider writing a version for external data files that does
+# not test compressed clusters)
+_unsupported_imgopts data_file
CLUSTER_SIZE=64k
size=128M
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
index bb4ad1c..db03edf 100755
--- a/tests/qemu-iotests/074
+++ b/tests/qemu-iotests/074
@@ -31,7 +31,7 @@ _cleanup()
{
echo "Cleanup"
_cleanup_test_img
- rm "${TEST_IMG2}"
+ _rm_test_img "${TEST_IMG2}"
rm -f "$TEST_DIR/blkdebug.conf"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -50,6 +50,8 @@ _compare()
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# blkdebug can only inject errors on bs->file
+_unsupported_imgopts data_file
# Setup test basic parameters
TEST_IMG2=$TEST_IMG.2
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
index 78536d3..3642b51 100755
--- a/tests/qemu-iotests/079
+++ b/tests/qemu-iotests/079
@@ -47,8 +47,7 @@ echo
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
for s in $cluster_sizes; do
- IMGOPTS=$(_optstr_add "$IMGOPTS" "preallocation=metadata,cluster_size=$s") \
- _make_test_img 4G
+ _make_test_img -o "preallocation=metadata,cluster_size=$s" 4G
done
# success, all done
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
index 4bcb502..a3d13c4 100755
--- a/tests/qemu-iotests/080
+++ b/tests/qemu-iotests/080
@@ -28,7 +28,7 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f $TEST_IMG.snap
+ _rm_test_img "$TEST_IMG.snap"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -40,9 +40,10 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
-# - Internal snapshots are (currently) impossible with refcount_bits=1
+# - Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
# - This is generally a test for compat=1.1 images
-_unsupported_imgopts 'refcount_bits=1[^0-9]' 'compat=0.10'
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file 'compat=0.10'
header_size=104
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
index 85acdf7..537d40d 100755
--- a/tests/qemu-iotests/081
+++ b/tests/qemu-iotests/081
@@ -28,9 +28,9 @@ status=1 # failure is the default!
_cleanup()
{
- rm -rf $TEST_DIR/1.raw
- rm -rf $TEST_DIR/2.raw
- rm -rf $TEST_DIR/3.raw
+ _rm_test_img "$TEST_DIR/1.raw"
+ _rm_test_img "$TEST_DIR/2.raw"
+ _rm_test_img "$TEST_DIR/3.raw"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
index d40fdab..46981db 100755
--- a/tests/qemu-iotests/085
+++ b/tests/qemu-iotests/085
@@ -41,10 +41,13 @@ _cleanup()
_cleanup_qemu
for i in $(seq 1 ${SNAPSHOTS})
do
- rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
- rm -f "${TEST_DIR}/${i}-${snapshot_virt1}"
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt0}"
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt1}"
+ done
+ for img in "${TEST_IMG}".{1,2,base}
+ do
+ _rm_test_img "$img"
done
- rm -f "${TEST_IMG}" "${TEST_IMG}.1" "${TEST_IMG}.2" "${TEST_IMG}.base"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -102,8 +105,7 @@ add_snapshot_image()
{
base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}"
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
- _make_test_img -u -b "${base_image}" "$size"
- mv "${TEST_IMG}" "${snapshot_file}"
+ TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" "$size"
do_blockdev_add "$1" "'backing': null, " "${snapshot_file}"
}
@@ -119,10 +121,8 @@ blockdev_snapshot()
size=128M
-_make_test_img $size
-mv "${TEST_IMG}" "${TEST_IMG}.1"
-_make_test_img $size
-mv "${TEST_IMG}" "${TEST_IMG}.2"
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
echo
echo === Running QEMU ===
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
index bb50227..d94ad22 100644
--- a/tests/qemu-iotests/085.out
+++ b/tests/qemu-iotests/085.out
@@ -1,6 +1,6 @@
QA output created by 085
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
=== Running QEMU ===
@@ -68,12 +68,12 @@ Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_fil
=== Create a couple of snapshots using blockdev-snapshot ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
+Formatting 'TEST_DIR/11-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_11', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/11-snapshot-v0.IMGFMT', 'node-name': 'file_11' } } }
{"return": {}}
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } }
{"return": {}}
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
+Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_12', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/12-snapshot-v0.IMGFMT', 'node-name': 'file_12' } } }
{"return": {}}
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_12' } }
diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088
index b44edd0..ef11633 100755
--- a/tests/qemu-iotests/088
+++ b/tests/qemu-iotests/088
@@ -28,7 +28,7 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f $TEST_IMG.snap
+ _rm_test_img "$TEST_IMG.snap"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
index 9f8cfbb..1246e4f 100755
--- a/tests/qemu-iotests/090
+++ b/tests/qemu-iotests/090
@@ -38,6 +38,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file nfs
+# External data files do not support compressed clusters
+_unsupported_imgopts data_file
IMG_SIZE=128K
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index f4b4465..0874fa8 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -101,7 +101,7 @@ echo "Check image pattern"
${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
echo "Running 'qemu-img check -r all \$TEST_IMG'"
-"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu
+_check_test_img -r all
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out
index 5017f8c..5ec7b00 100644
--- a/tests/qemu-iotests/091.out
+++ b/tests/qemu-iotests/091.out
@@ -23,6 +23,4 @@ read 4194304/4194304 bytes at offset 0
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Running 'qemu-img check -r all $TEST_IMG'
No errors were found on the image.
-80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters
-Image end offset: 5570560
*** done
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
index e2e0726..40ec62b 100755
--- a/tests/qemu-iotests/092
+++ b/tests/qemu-iotests/092
@@ -28,7 +28,7 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f $TEST_IMG.snap
+ _rm_test_img "$TEST_IMG.snap"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
index 9343e09..2d3e100 100755
--- a/tests/qemu-iotests/094
+++ b/tests/qemu-iotests/094
@@ -30,7 +30,7 @@ _cleanup()
{
_cleanup_qemu
_cleanup_test_img
- rm -f "$TEST_DIR/source.$IMGFMT"
+ _rm_test_img "$TEST_DIR/source.$IMGFMT"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -45,7 +45,7 @@ _supported_proto nbd
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
_make_test_img 64M
-$QEMU_IMG create -f $IMGFMT "$TEST_DIR/source.$IMGFMT" 64M | _filter_img_create
+TEST_IMG_FILE="$TEST_DIR/source.$IMGFMT" IMGPROTO=file _make_test_img 64M
_launch_qemu -drive if=none,id=src,file="$TEST_DIR/source.$IMGFMT",format=raw \
-nodefaults
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
index 58fe174..155ae86 100755
--- a/tests/qemu-iotests/095
+++ b/tests/qemu-iotests/095
@@ -32,8 +32,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f "${TEST_IMG}.base" "${TEST_IMG}.snp1"
- _cleanup_test_img
+ _rm_test_img "${TEST_IMG}.base"
+ _rm_test_img "${TEST_IMG}.snp1"
+ _cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
index 1c1d1c4..1e29d96 100755
--- a/tests/qemu-iotests/098
+++ b/tests/qemu-iotests/098
@@ -40,8 +40,10 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
-
-IMGOPTS="compat=1.1"
+# The code path we want to test here only works for compat=1.1 images;
+# blkdebug can only inject errors on bs->file, so external data files
+# do not work with this test
+_unsupported_imgopts 'compat=0.10' data_file
for event in l1_update empty_image_prepare reftable_update refblock_alloc; do
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
index c3cf667..65e8e92 100755
--- a/tests/qemu-iotests/099
+++ b/tests/qemu-iotests/099
@@ -29,7 +29,10 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.compare"
+ rm -f "$TEST_DIR/blkdebug.conf"
+
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -43,8 +46,9 @@ _supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
_supported_proto file
_supported_os Linux
_require_drivers blkdebug blkverify
+# data_file would change the json:{} filenames
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
- "subformat=twoGbMaxExtentSparse"
+ "subformat=twoGbMaxExtentSparse" data_file
do_run_qemu()
{
@@ -121,8 +125,6 @@ echo
test_qemu "file.driver=blkdebug,file.image.filename=$TEST_IMG"
-rm -f "$TEST_IMG.compare" "$TEST_DIR/blkdebug.conf"
-
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index 554b9de..8c1ebe0 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -38,8 +38,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file nfs
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
IMG_SIZE=64K
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
index ac47eaa..b5d1ec4 100755
--- a/tests/qemu-iotests/106
+++ b/tests/qemu-iotests/106
@@ -51,7 +51,7 @@ for create_mode in off falloc full; do
echo
echo "--- create_mode=$create_mode growth_mode=$growth_mode ---"
- IMGOPTS="preallocation=$create_mode" _make_test_img ${CREATION_SIZE}K
+ _make_test_img -o "preallocation=$create_mode" ${CREATION_SIZE}K
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
expected_size=0
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
index 9c08172..5f7076f 100755
--- a/tests/qemu-iotests/108
+++ b/tests/qemu-iotests/108
@@ -37,12 +37,14 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
-# This test directly modifies a refblock so it relies on refcount_bits being 16
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+# This test directly modifies a refblock so it relies on refcount_bits being 16;
+# and the low-level modification it performs are not tuned for external data
+# files
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
echo
echo '=== Repairing an image without any refcount table ==='
@@ -65,7 +67,7 @@ echo
echo '=== Repairing unreferenced data cluster in new refblock area ==='
echo
-IMGOPTS='cluster_size=512' _make_test_img 64M
+_make_test_img -o 'cluster_size=512' 64M
# Allocate the first 128 kB in the image (first refblock)
$QEMU_IO -c 'write 0 0x1b200' "$TEST_IMG" | _filter_qemu_io
# should be 131072 == 0x20000
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
index 9897ceb..ba638db 100755
--- a/tests/qemu-iotests/109
+++ b/tests/qemu-iotests/109
@@ -29,8 +29,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f $TEST_IMG.src
- _cleanup_test_img
+ _rm_test_img "$TEST_IMG.src"
+ _cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
index 2ef516b..139c02c 100755
--- a/tests/qemu-iotests/110
+++ b/tests/qemu-iotests/110
@@ -28,8 +28,8 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.copy"
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.copy"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -67,6 +67,7 @@ echo
# Across blkdebug without a config file, you cannot reconstruct filenames, so
# qemu is incapable of knowing the directory of the top image from the filename
# alone. However, using bdrv_dirname(), it should still work.
+# (Filter out the json:{} filename so this test works with external data files)
TEST_IMG="json:{
'driver': '$IMGFMT',
'file': {
@@ -82,7 +83,8 @@ TEST_IMG="json:{
}
]
}
-}" _img_info | _filter_img_info | grep -v 'backing file format'
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
+ | _filter_json_filename
echo
echo '=== Backing name is always relative to the backed image ==='
@@ -114,7 +116,8 @@ TEST_IMG="json:{
}
]
}
-}" _img_info | _filter_img_info | grep -v 'backing file format'
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
+ | _filter_json_filename
# success, all done
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
index f60b263..f835553 100644
--- a/tests/qemu-iotests/110.out
+++ b/tests/qemu-iotests/110.out
@@ -11,7 +11,7 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
=== Non-reconstructable filename ===
-image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
+image: json:{ /* filtered */ }
file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
@@ -22,7 +22,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.b
=== Nodes without a common directory ===
-image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}}
+image: json:{ /* filtered */ }
file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
backing file: t.IMGFMT.base (cannot determine actual path)
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
index 490a5bb..3b43d1b 100755
--- a/tests/qemu-iotests/111
+++ b/tests/qemu-iotests/111
@@ -41,8 +41,7 @@ _supported_fmt qed qcow qcow2 vmdk
_supported_proto file
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
-$QEMU_IMG create -f $IMGFMT -b "$TEST_IMG.inexistent" "$TEST_IMG" 2>&1 \
- | _filter_testdir | _filter_imgfmt
+_make_test_img -b "$TEST_IMG.inexistent"
# success, all done
echo '*** done'
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 706c10b..20ff5c2 100755
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -40,8 +40,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
# This test will set refcount_bits on its own which would conflict with the
-# manual setting; compat will be overridden as well
-_unsupported_imgopts refcount_bits 'compat=0.10'
+# manual setting; compat will be overridden as well;
+# and external data files do not work well with our refcount testing
+_unsupported_imgopts refcount_bits 'compat=0.10' data_file
print_refcount_bits()
{
@@ -53,20 +54,20 @@ echo '=== refcount_bits limits ==='
echo
# Must be positive (non-zero)
-IMGOPTS="$IMGOPTS,refcount_bits=0" _make_test_img 64M
+_make_test_img -o "refcount_bits=0" 64M
# Must be positive (non-negative)
-IMGOPTS="$IMGOPTS,refcount_bits=-1" _make_test_img 64M
+_make_test_img -o "refcount_bits=-1" 64M
# May not exceed 64
-IMGOPTS="$IMGOPTS,refcount_bits=128" _make_test_img 64M
+_make_test_img -o "refcount_bits=128" 64M
# Must be a power of two
-IMGOPTS="$IMGOPTS,refcount_bits=42" _make_test_img 64M
+_make_test_img -o "refcount_bits=42" 64M
# 1 is the minimum
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+_make_test_img -o "refcount_bits=1" 64M
print_refcount_bits
# 64 is the maximum
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+_make_test_img -o "refcount_bits=64" 64M
print_refcount_bits
# 16 is the default
@@ -78,19 +79,19 @@ echo '=== refcount_bits and compat=0.10 ==='
echo
# Should work
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=16" _make_test_img 64M
+_make_test_img -o "compat=0.10,refcount_bits=16" 64M
print_refcount_bits
# Should not work
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=1" _make_test_img 64M
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=64" _make_test_img 64M
+_make_test_img -o "compat=0.10,refcount_bits=1" 64M
+_make_test_img -o "compat=0.10,refcount_bits=64" 64M
echo
echo '=== Snapshot limit on refcount_bits=1 ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+_make_test_img -o "refcount_bits=1" 64M
print_refcount_bits
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
@@ -106,7 +107,7 @@ echo
echo '=== Snapshot limit on refcount_bits=2 ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=2" _make_test_img 64M
+_make_test_img -o "refcount_bits=2" 64M
print_refcount_bits
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
@@ -124,7 +125,7 @@ echo
echo '=== Compressed clusters with refcount_bits=1 ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+_make_test_img -o "refcount_bits=1" 64M
print_refcount_bits
# Both should fit into a single host cluster; instead of failing to increase the
@@ -140,7 +141,7 @@ echo
echo '=== MSb set in 64 bit refcount ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+_make_test_img -o "refcount_bits=64" 64M
print_refcount_bits
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
@@ -158,7 +159,7 @@ echo
echo '=== Snapshot on maximum 64 bit refcount value ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+_make_test_img -o "refcount_bits=64" 64M
print_refcount_bits
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
@@ -239,7 +240,7 @@ echo
echo '=== Testing too many references for check ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+_make_test_img -o "refcount_bits=1" 64M
print_refcount_bits
# This cluster should be created at 0x50000
@@ -262,7 +263,7 @@ echo
echo '=== Multiple walks necessary during amend ==='
echo
-IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k
+_make_test_img -o "refcount_bits=1,cluster_size=512" 64k
# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a
# single L2 table, the reftable and a single refblock. This creates 58 data
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
index f90a744..26104ff 100755
--- a/tests/qemu-iotests/114
+++ b/tests/qemu-iotests/114
@@ -39,6 +39,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_unsupported_proto vxhs
+# qcow2.py does not work too well with external data files
+_unsupported_imgopts data_file
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
index 9ed3cb6..d254b18 100755
--- a/tests/qemu-iotests/115
+++ b/tests/qemu-iotests/115
@@ -64,8 +64,7 @@ echo
# least 256 MB. We can achieve that by using preallocation=metadata for an image
# which has a guest disk size of 256 MB.
-IMGOPTS="$IMGOPTS,refcount_bits=64,cluster_size=512,preallocation=metadata" \
- _make_test_img 256M
+_make_test_img -o "refcount_bits=64,cluster_size=512,preallocation=metadata" 256M
# We know for sure that the L1 and refcount tables do not overlap with any other
# structure because the metadata overlap checks would have caught that case.
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
index 90a0424..90ea0db 100755
--- a/tests/qemu-iotests/121
+++ b/tests/qemu-iotests/121
@@ -39,6 +39,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Refcount structures are used much differently with external data
+# files
+_unsupported_imgopts data_file
echo
echo '=== New refcount structures may not conflict with existing structures ==='
@@ -50,7 +53,7 @@ echo
# Preallocation speeds up the write operation, but preallocating everything will
# destroy the purpose of the write; so preallocate one KB less than what would
# cause a reftable growth...
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64512K
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64512K
# ...and make the image the desired size afterwards.
$QEMU_IMG resize "$TEST_IMG" 65M
@@ -73,7 +76,7 @@ echo
echo '--- Test 2 ---'
echo
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64513K
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64513K
# This results in an L1 table growth which in turn results in some clusters at
# the start of the image becoming free
$QEMU_IMG resize "$TEST_IMG" 65M
@@ -96,7 +99,7 @@ echo
echo '=== Allocating a new refcount block must not leave holes in the image ==='
echo
-IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M
+_make_test_img -o 'cluster_size=512,refcount_bits=16' 1M
# This results in an image with 256 used clusters: the qcow2 header,
# the refcount table, one refcount block, the L1 table, four L2 tables
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
index 059011e..dfa3509 100755
--- a/tests/qemu-iotests/122
+++ b/tests/qemu-iotests/122
@@ -28,8 +28,10 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f "$TEST_IMG".[123]
- _cleanup_test_img
+ for img in "$TEST_IMG".[123]; do
+ _rm_test_img "$img"
+ done
+ _cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
index d33950e..01b771c 100755
--- a/tests/qemu-iotests/123
+++ b/tests/qemu-iotests/123
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$SRC_IMG"
+ _rm_test_img "$SRC_IMG"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -44,7 +44,7 @@ _supported_os Linux
SRC_IMG="$TEST_DIR/source.$IMGFMT"
_make_test_img 1M
-$QEMU_IMG create -f $IMGFMT "$SRC_IMG" 1M | _filter_img_create
+TEST_IMG_FILE=$SRC_IMG IMGPROTO=file _make_test_img 1M
$QEMU_IO -c 'write -P 42 0 1M' "$SRC_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
index 4e31aa4..d510984 100755
--- a/tests/qemu-iotests/125
+++ b/tests/qemu-iotests/125
@@ -114,7 +114,7 @@ for GROWTH_SIZE in 16 48 80; do
for growth_mode in off metadata falloc full; do
echo "--- cluster_size=$cluster_size growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
- IMGOPTS="preallocation=$create_mode,cluster_size=$cluster_size" _make_test_img ${CREATION_SIZE}
+ _make_test_img -o "preallocation=$create_mode,cluster_size=$cluster_size" ${CREATION_SIZE}
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
host_size_0=$(get_image_size_on_host)
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index 089821d..7ae8689 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -117,7 +117,7 @@ $QEMU_IO \
-c "reopen -o cache-clean-interval=-1" \
"$TEST_IMG" | _filter_qemu_io
-IMGOPTS="cluster_size=256k" _make_test_img 32P
+_make_test_img -o "cluster_size=256k" 32P
$QEMU_IO \
-c "reopen -o l2-cache-entry-size=512,l2-cache-size=1T" \
"$TEST_IMG" | _filter_qemu_io
@@ -138,14 +138,21 @@ $QEMU_IO \
"$TEST_IMG" 2>&1 | _filter_qemu_io
# The dirty bit must not be set
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+# (Filter the external data file bit)
+if $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features \
+ | grep -q '\<0\>'
+then
+ echo 'ERROR: Dirty bit set'
+else
+ echo 'OK: Dirty bit not set'
+fi
# Similarly we can test whether corruption detection has been enabled:
-# Create L1/L2, overwrite first entry in refcount block, allocate something.
+# Create L1, overwrite refcounts, force allocation of L2 by writing
+# data.
# Disabling the checks should fail, so the corruption must be detected.
_make_test_img 64M
-$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
-poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00"
+poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00\x00\x00\x00\x00\x00\x00"
$QEMU_IO \
-c "reopen -o overlap-check=none,lazy-refcounts=42" \
-c "write 64k 64k" \
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
index 1c6569e..86377c8 100644
--- a/tests/qemu-iotests/137.out
+++ b/tests/qemu-iotests/137.out
@@ -36,11 +36,9 @@ qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
-incompatible_features 0x0
+OK: Dirty bit not set
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-wrote 65536/65536 bytes at offset 0
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io: Parameter 'lazy-refcounts' expects 'on' or 'off'
-qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed
+qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed
write failed: Input/output error
*** done
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
index 6a73137..54b0104 100755
--- a/tests/qemu-iotests/138
+++ b/tests/qemu-iotests/138
@@ -36,17 +36,19 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# With an external data file, data clusters are not refcounted
+# (and so qemu-img check does not check their refcount)
+_unsupported_imgopts data_file
echo
echo '=== Check on an image with a multiple of 2^32 clusters ==='
echo
-IMGOPTS=$(_optstr_add "$IMGOPTS" "cluster_size=512") \
- _make_test_img 512
+_make_test_img -o "cluster_size=512" 512
# Allocate L2 table
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
index 8c2ae79..5192d25 100755
--- a/tests/qemu-iotests/141
+++ b/tests/qemu-iotests/141
@@ -30,7 +30,9 @@ _cleanup()
{
_cleanup_qemu
_cleanup_test_img
- rm -f "$TEST_DIR"/{b,m,o}.$IMGFMT
+ for img in "$TEST_DIR"/{b,m,o}.$IMGFMT; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
index 6b62271..daefcba 100755
--- a/tests/qemu-iotests/142
+++ b/tests/qemu-iotests/142
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.snap
+ _rm_test_img "$TEST_IMG.snap"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
index 011ed4f..4569ac0 100755
--- a/tests/qemu-iotests/144
+++ b/tests/qemu-iotests/144
@@ -34,7 +34,9 @@ TMP_SNAP2=${TEST_DIR}/tmp2.qcow2
_cleanup()
{
_cleanup_qemu
- rm -f "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"
+ for img in "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
index c969a1a..2b13111 100755
--- a/tests/qemu-iotests/153
+++ b/tests/qemu-iotests/153
@@ -30,13 +30,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "${TEST_IMG}.base"
- rm -f "${TEST_IMG}.overlay"
- rm -f "${TEST_IMG}.convert"
- rm -f "${TEST_IMG}.a"
- rm -f "${TEST_IMG}.b"
- rm -f "${TEST_IMG}.c"
- rm -f "${TEST_IMG}.lnk"
+ for img in "${TEST_IMG}".{base,overlay,convert,a,b,c,lnk}; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -98,7 +94,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do
echo
echo "== Creating test image =="
- $QEMU_IMG create -f $IMGFMT "${TEST_IMG}" -b ${TEST_IMG}.base | _filter_img_create
+ _make_test_img -b "${TEST_IMG}.base"
echo
echo "== Launching QEMU, opts: '$opts1' =="
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
index 2ffa3ca..5559df6 100755
--- a/tests/qemu-iotests/156
+++ b/tests/qemu-iotests/156
@@ -37,7 +37,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f "$TEST_IMG"{,.target}{,.backing,.overlay}
+ for img in "$TEST_IMG"{,.target}{,.backing,.overlay}; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -49,6 +51,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2 qed
_supported_proto generic
_unsupported_proto vxhs
+# Copying files around with cp does not work with external data files
+_unsupported_imgopts data_file
# Create source disk
TEST_IMG="$TEST_IMG.backing" _make_test_img 1M
@@ -120,7 +124,9 @@ _send_qemu_cmd $QEMU_HANDLE \
'"status": "null"'
# Remove the source images
-rm -f "$TEST_IMG{,.backing,.overlay}"
+for img in "$TEST_IMG{,.backing,.overlay}"; do
+ _rm_test_img "$img"
+done
echo
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
index 2557140..f969005 100755
--- a/tests/qemu-iotests/159
+++ b/tests/qemu-iotests/159
@@ -28,7 +28,7 @@ status=1
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.out"
+ _rm_test_img "$TEST_IMG.out"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160
index df89d38..0572b5a 100755
--- a/tests/qemu-iotests/160
+++ b/tests/qemu-iotests/160
@@ -28,7 +28,8 @@ status=1
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd"
+ _rm_test_img "$TEST_IMG.out"
+ _rm_test_img "$TEST_IMG.out.dd"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
index 456a4bd..f572a19 100755
--- a/tests/qemu-iotests/161
+++ b/tests/qemu-iotests/161
@@ -30,8 +30,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.base"
- rm -f "$TEST_IMG.int"
+ _rm_test_img "$TEST_IMG.base"
+ _rm_test_img "$TEST_IMG.int"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
index 05dd6ed..6c8f0e8 100755
--- a/tests/qemu-iotests/170
+++ b/tests/qemu-iotests/170
@@ -28,7 +28,7 @@ status=1
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.out"
+ _rm_test_img "$TEST_IMG.out"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172
index d67997e..7195fb8 100755
--- a/tests/qemu-iotests/172
+++ b/tests/qemu-iotests/172
@@ -28,9 +28,9 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.2"
- rm -f "$TEST_IMG.3"
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.2"
+ _rm_test_img "$TEST_IMG.3"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173
index 29dcaa1..ec6d170 100755
--- a/tests/qemu-iotests/173
+++ b/tests/qemu-iotests/173
@@ -29,7 +29,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f "${QEMU_TEST_DIR}/image.base" "${QEMU_TEST_DIR}/image.snp1"
+ _rm_test_img "${TEST_DIR}/image.base"
+ _rm_test_img "${TEST_DIR}/image.snp1"
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
index 0a952a7..e2f14a3 100755
--- a/tests/qemu-iotests/174
+++ b/tests/qemu-iotests/174
@@ -40,7 +40,7 @@ _unsupported_fmt raw
size=256K
-IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt
+IMGFMT=raw IMGKEYSECRET= _make_test_img --no-opts $size | _filter_imgfmt
echo
echo "== reading wrong format should fail =="
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index 55db280..020ed8e 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -95,7 +95,7 @@ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_block
for mode in off full falloc; do
echo
echo "== creating image with preallocation $mode =="
- IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
+ _make_test_img -o preallocation=$mode $size | _filter_imgfmt
stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
done
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
index 50df4c0..117c8b6 100755
--- a/tests/qemu-iotests/176
+++ b/tests/qemu-iotests/176
@@ -47,8 +47,11 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
-# Persistent dirty bitmaps require compat=1.1
-_unsupported_imgopts 'compat=0.10'
+# Persistent dirty bitmaps require compat=1.1;
+# Internal snapshots forbid using an external data file
+# (they work with refcount_bits=1 here, though, because there actually
+# is no data when creating the snapshot)
+_unsupported_imgopts 'compat=0.10' data_file
run_qemu()
{
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
index 21231ca..51a70fe 100755
--- a/tests/qemu-iotests/178
+++ b/tests/qemu-iotests/178
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.converted"
+ _rm_test_img "$TEST_IMG.converted"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -62,8 +62,8 @@ $QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format
make_test_img_with_fmt() {
# Shadow global variables within this function
- local IMGFMT="$1" IMGOPTS=""
- _make_test_img "$2"
+ local IMGFMT="$1"
+ _make_test_img --no-opts "$2"
}
qemu_io_with_fmt() {
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
index 1ccb850..56a2dd5 100755
--- a/tests/qemu-iotests/182
+++ b/tests/qemu-iotests/182
@@ -30,7 +30,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.overlay"
+ _rm_test_img "$TEST_IMG.overlay"
rm -f "$SOCK_DIR/nbd.socket"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
index bced83f..3f74b9f 100755
--- a/tests/qemu-iotests/183
+++ b/tests/qemu-iotests/183
@@ -31,7 +31,7 @@ MIG_SOCKET="${SOCK_DIR}/migrate"
_cleanup()
{
rm -f "${MIG_SOCKET}"
- rm -f "${TEST_IMG}.dest"
+ _rm_test_img "${TEST_IMG}.dest"
_cleanup_test_img
_cleanup_qemu
}
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
index 454ff60..e50f19e 100755
--- a/tests/qemu-iotests/185
+++ b/tests/qemu-iotests/185
@@ -28,8 +28,8 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f "${TEST_IMG}.mid"
- rm -f "${TEST_IMG}.copy"
+ _rm_test_img "${TEST_IMG}.mid"
+ _rm_test_img "${TEST_IMG}.copy"
_cleanup_test_img
_cleanup_qemu
}
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
index 2fcef9e..c6e1dc5 100755
--- a/tests/qemu-iotests/187
+++ b/tests/qemu-iotests/187
@@ -28,9 +28,9 @@ status=1 # failure is the default!
_cleanup()
{
- _cleanup_test_img
- rm -f "$TEST_IMG.2"
- rm -f "$TEST_IMG.3"
+ _cleanup_test_img
+ _rm_test_img "$TEST_IMG.2"
+ _rm_test_img "$TEST_IMG.3"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
index eb766ad..6d416504 100755
--- a/tests/qemu-iotests/190
+++ b/tests/qemu-iotests/190
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.converted"
+ _rm_test_img "$TEST_IMG.converted"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -45,7 +45,7 @@ _supported_proto file
echo "== Huge file =="
echo
-IMGOPTS='cluster_size=2M' _make_test_img 2T
+_make_test_img -o 'cluster_size=2M' 2T
$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
index 528022e..b05db68 100755
--- a/tests/qemu-iotests/191
+++ b/tests/qemu-iotests/191
@@ -28,9 +28,9 @@ status=1 # failure is the default!
_cleanup()
{
- rm -f "${TEST_IMG}.mid"
- rm -f "${TEST_IMG}.ovl2"
- rm -f "${TEST_IMG}.ovl3"
+ _rm_test_img "${TEST_IMG}.mid"
+ _rm_test_img "${TEST_IMG}.ovl2"
+ _rm_test_img "${TEST_IMG}.ovl3"
_cleanup_test_img
_cleanup_qemu
}
@@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
+# An external data file would change the query-named-block-nodes output
+_unsupported_imgopts data_file
size=64M
@@ -51,8 +53,7 @@ echo === Preparing and starting VM ===
echo
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
-IMGOPTS=$(_optstr_add "$IMGOPTS" "backing_fmt=$IMGFMT") \
- TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
+TEST_IMG="${TEST_IMG}.mid" _make_test_img -o "backing_fmt=$IMGFMT" -b "${TEST_IMG}.base"
_make_test_img -b "${TEST_IMG}.mid"
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
index ef7b9a9..48984b7 100755
--- a/tests/qemu-iotests/195
+++ b/tests/qemu-iotests/195
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.mid"
+ _rm_test_img "$TEST_IMG.mid"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
index 1d4f678..95f05b0 100755
--- a/tests/qemu-iotests/197
+++ b/tests/qemu-iotests/197
@@ -43,7 +43,7 @@ esac
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_WRAP"
+ _rm_test_img "$TEST_WRAP"
rm -f "$BLKDBG_CONF"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -66,8 +66,8 @@ if [ "$IMGFMT" = "vpc" ]; then
fi
_make_test_img 4G
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
# Ensure that a read of two clusters, but where one is already allocated,
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
index c8f824c..fb0d5a2 100755
--- a/tests/qemu-iotests/198
+++ b/tests/qemu-iotests/198
@@ -92,13 +92,15 @@ echo
echo "== checking image base =="
$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info --format-specific \
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
+ | _filter_json_filename
echo
echo "== checking image layer =="
$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info --format-specific \
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
+ | _filter_json_filename
# success, all done
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
index e86b175..831ce3a 100644
--- a/tests/qemu-iotests/198.out
+++ b/tests/qemu-iotests/198.out
@@ -32,7 +32,7 @@ read 16777216/16777216 bytes at offset 0
16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== checking image base ==
-image: json:{"encrypt.key-secret": "sec0", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.base"}}
+image: json:{ /* filtered */ }
file format: IMGFMT
virtual size: 16 MiB (16777216 bytes)
Format specific information:
@@ -74,7 +74,7 @@ Format specific information:
master key iters: 1024
== checking image layer ==
-image: json:{"encrypt.key-secret": "sec1", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}
+image: json:{ /* filtered */ }
file format: IMGFMT
virtual size: 16 MiB (16777216 bytes)
backing file: TEST_DIR/t.IMGFMT.base
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
index 72d431f..a2cdd7f 100755
--- a/tests/qemu-iotests/200
+++ b/tests/qemu-iotests/200
@@ -31,7 +31,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
- rm -f "${TEST_IMG}" "${BACKING_IMG}"
+ _rm_test_img "${TEST_IMG}"
+ _rm_test_img "${BACKING_IMG}"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -46,8 +47,8 @@ _supported_proto file
BACKING_IMG="${TEST_DIR}/backing.img"
TEST_IMG="${TEST_DIR}/test.img"
-${QEMU_IMG} create -f $IMGFMT "${BACKING_IMG}" 512M | _filter_img_create
-${QEMU_IMG} create -f $IMGFMT -F $IMGFMT "${TEST_IMG}" -b "${BACKING_IMG}" 512M | _filter_img_create
+TEST_IMG="$BACKING_IMG" _make_test_img 512M
+_make_test_img -F $IMGFMT -b "$BACKING_IMG" 512M
${QEMU_IO} -c "write -P 0xa5 512 300M" "${BACKING_IMG}" | _filter_qemu_io
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
index 86fa37e..133ba9f 100755
--- a/tests/qemu-iotests/201
+++ b/tests/qemu-iotests/201
@@ -43,9 +43,9 @@ _supported_fmt qcow2
_supported_proto generic
_supported_os Linux
-# Internal snapshots are (currently) impossible with refcount_bits=1
-# This was taken from test 080
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
size=64M
_make_test_img $size
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
index 21ec8a2..3500e0c 100755
--- a/tests/qemu-iotests/214
+++ b/tests/qemu-iotests/214
@@ -39,7 +39,8 @@ _supported_proto file
# Repairing the corrupted image requires qemu-img check to store a
# refcount up to 3, which requires at least two refcount bits.
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# External data files do not support compressed clusters.
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
echo
@@ -89,6 +90,49 @@ _check_test_img -r all
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
+echo
+echo "=== Write compressed data of multiple clusters ==="
+echo
+cluster_size=0x10000
+_make_test_img 2M -o cluster_size=$cluster_size
+
+echo "Write uncompressed data:"
+let data_size="8 * $cluster_size"
+$QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \
+ 2>&1 | _filter_qemu_io | _filter_testdir
+sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" |
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
+
+_make_test_img 2M -o cluster_size=$cluster_size
+echo "Write compressed data:"
+let data_size="3 * $cluster_size + $cluster_size / 2"
+# Set compress on. That will align the written data
+# by the cluster size and will write them compressed.
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
+$QEMU_IO -c "write -P 0xbb 0 $data_size" --image-opts \
+ "driver=compress,file.driver=$IMGFMT,file.file.driver=file,file.file.filename=$TEST_IMG" \
+ 2>&1 | _filter_qemu_io | _filter_testdir
+
+let offset="4 * $cluster_size + $cluster_size / 4"
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
+$QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\
+ 'driver': 'compress',
+ 'file': {'driver': '$IMGFMT',
+ 'file': {'driver': 'file',
+ 'filename': '$TEST_IMG'}}}" | \
+ _filter_qemu_io | _filter_testdir
+
+sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" |
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
+
+if [ $sizeA -le $sizeB ]
+then
+ echo "Compression ERROR"
+fi
+
+$QEMU_IMG check --output=json "$TEST_IMG" |
+ sed -n 's/,$//; /"compressed-clusters":/ s/^ *//p'
+
# success, all done
echo '*** done'
rm -f $seq.full
diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out
index 0fcd8dc..9fc6728 100644
--- a/tests/qemu-iotests/214.out
+++ b/tests/qemu-iotests/214.out
@@ -32,4 +32,18 @@ read 4194304/4194304 bytes at offset 0
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 4194304/4194304 bytes at offset 4194304
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Write compressed data of multiple clusters ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
+Write uncompressed data:
+wrote 524288/524288 bytes at offset 0
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
+Write compressed data:
+wrote 229376/229376 bytes at offset 0
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 229376/229376 bytes at offset 278528
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+"compressed-clusters": 8
*** done
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
index 2eb377d..f99bae7 100755
--- a/tests/qemu-iotests/215
+++ b/tests/qemu-iotests/215
@@ -40,7 +40,7 @@ esac
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_WRAP"
+ _rm_test_img "$TEST_WRAP"
rm -f "$BLKDBG_CONF"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -63,8 +63,8 @@ if [ "$IMGFMT" = "vpc" ]; then
fi
_make_test_img 4G
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
# Ensure that a read of two clusters, but where one is already allocated,
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
index 58a78a6..d89116c 100755
--- a/tests/qemu-iotests/217
+++ b/tests/qemu-iotests/217
@@ -40,7 +40,8 @@ _supported_proto file
# This test needs clusters with at least a refcount of 2 so that
# OFLAG_COPIED is not set. refcount_bits=1 is therefore unsupported.
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# (As are external data files.)
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
echo
echo '=== Simulating an I/O error during snapshot deletion ==='
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
index 1515927..a9259b7 100755
--- a/tests/qemu-iotests/220
+++ b/tests/qemu-iotests/220
@@ -37,6 +37,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# To use a different refcount width but 16 bits we need compat=1.1,
+# and external data files do not support compressed clusters.
+_unsupported_imgopts 'compat=0.10' data_file
echo "== Creating huge file =="
@@ -44,7 +47,7 @@ echo "== Creating huge file =="
# of a HUGE (but very sparse) file. tmpfs works, ext4 does not.
_require_large_file 513T
-IMGOPTS='cluster_size=2M,refcount_bits=1' _make_test_img 513T
+_make_test_img -o 'cluster_size=2M,refcount_bits=1' 513T
echo "== Populating refcounts =="
# We want an image with 256M refcounts * 2M clusters = 512T referenced.
diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225
index fbd7404..c9a334c 100755
--- a/tests/qemu-iotests/225
+++ b/tests/qemu-iotests/225
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.not_base"
+ _rm_test_img "$TEST_IMG.not_base"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
index e18a464..866168b 100755
--- a/tests/qemu-iotests/229
+++ b/tests/qemu-iotests/229
@@ -31,7 +31,8 @@ _cleanup()
{
_cleanup_qemu
_cleanup_test_img
- rm -f "$TEST_IMG" "$DEST_IMG"
+ _rm_test_img "$TEST_IMG"
+ _rm_test_img "$DEST_IMG"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
index 65b0e42..685356a 100755
--- a/tests/qemu-iotests/232
+++ b/tests/qemu-iotests/232
@@ -29,7 +29,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.[01234]
+ for img in "$TEST_IMG".[01234]; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
index fedd111..3d75339 100755
--- a/tests/qemu-iotests/235
+++ b/tests/qemu-iotests/235
@@ -49,7 +49,7 @@ qemu_img_create('-f', iotests.imgfmt, '-o', 'preallocation=metadata', disk,
str(size))
vm = QEMUMachine(iotests.qemu_prog)
-vm.add_args('-machine', 'accel=kvm:tcg')
+vm.add_args('-accel', 'kvm', '-accel', 'tcg')
if iotests.qemu_default_machine == 's390-ccw-virtio':
vm.add_args('-no-shutdown')
vm.add_args('-drive', 'id=src,file=' + disk)
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
index e563761..a61852f 100755
--- a/tests/qemu-iotests/243
+++ b/tests/qemu-iotests/243
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.data
+ _rm_test_img "$TEST_IMG.data"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -40,6 +40,10 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# External data files do not work with compat=0.10, and because there
+# is an explicit case for external data files here, we cannot allow
+# the user to specify whether to use one
+_unsupported_imgopts 'compat=0.10' data_file
for mode in off metadata falloc full; do
@@ -47,7 +51,7 @@ for mode in off metadata falloc full; do
echo "=== preallocation=$mode ==="
echo
- IMGOPTS="preallocation=$mode" _make_test_img 64M
+ _make_test_img -o "preallocation=$mode" 64M
printf "File size: "
du -b $TEST_IMG | cut -f1
@@ -64,7 +68,7 @@ for mode in off metadata falloc full; do
echo "=== External data file: preallocation=$mode ==="
echo
- IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M
+ _make_test_img -o "data_file=$TEST_IMG.data,preallocation=$mode" 64M
echo -n "qcow2 file size: "
du -b $TEST_IMG | cut -f1
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
index 13978f9..0d1efee 100755
--- a/tests/qemu-iotests/244
+++ b/tests/qemu-iotests/244
@@ -29,8 +29,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.data
- rm -f $TEST_IMG.src
+ _rm_test_img "$TEST_IMG.data"
+ _rm_test_img "$TEST_IMG.src"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -41,13 +41,16 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# External data files do not work with compat=0.10, and because we use
+# our own external data file, we cannot let the user specify one
+_unsupported_imgopts 'compat=0.10' data_file
echo
echo "=== Create and open image with external data file ==="
echo
echo "With data file name in the image:"
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
_check_test_img
$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
@@ -104,7 +107,7 @@ echo
echo "=== Standalone image with external data file (efficient) ==="
echo
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
echo -n "qcow2 file size before I/O: "
du -b $TEST_IMG | cut -f1
@@ -154,7 +157,7 @@ echo
echo "=== Standalone image with external data file (valid raw) ==="
echo
-IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
+_make_test_img -o "data_file=$TEST_IMG.data,data_file_raw=on" 64M
echo -n "qcow2 file size before I/O: "
du -b $TEST_IMG | cut -f1
@@ -187,7 +190,7 @@ echo
echo "=== bdrv_co_block_status test for file and offset=0 ==="
echo
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
index c853b73..87e37b3 100755
--- a/tests/qemu-iotests/247
+++ b/tests/qemu-iotests/247
@@ -29,7 +29,9 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f $TEST_IMG.[01234]
+ for img in "$TEST_IMG".[01234]; do
+ _rm_test_img "$img"
+ done
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249
index e4650ec..2b99c97 100755
--- a/tests/qemu-iotests/249
+++ b/tests/qemu-iotests/249
@@ -30,8 +30,8 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.base"
- rm -f "$TEST_IMG.int"
+ _rm_test_img "$TEST_IMG.base"
+ _rm_test_img "$TEST_IMG.int"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
index c9c0a84..9bb6b94 100755
--- a/tests/qemu-iotests/250
+++ b/tests/qemu-iotests/250
@@ -39,6 +39,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# This test does not make much sense with external data files
+_unsupported_imgopts data_file
# This test checks that qcow2_process_discards does not truncate a discard
# request > 2G.
@@ -55,9 +57,8 @@ disk_usage()
}
size=2100M
-IMGOPTS="cluster_size=1M,preallocation=metadata"
-_make_test_img $size
+_make_test_img -o "cluster_size=1M,preallocation=metadata" $size
$QEMU_IO -c 'discard 0 10M' -c 'discard 2090M 10M' \
-c 'write 2090M 10M' -c 'write 0 10M' "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/252 b/tests/qemu-iotests/252
index f6c8f71..83280c1 100755
--- a/tests/qemu-iotests/252
+++ b/tests/qemu-iotests/252
@@ -29,7 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
- rm -f "$TEST_IMG.base_new"
+ _rm_test_img "$TEST_IMG.base_new"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261
index fb96bcf..ddcb04f 100755
--- a/tests/qemu-iotests/261
+++ b/tests/qemu-iotests/261
@@ -40,14 +40,15 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-# This tests qocw2-specific low-level functionality
+# This tests qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
# (1) We create a v2 image that supports nothing but refcount_bits=16
# (2) We do some refcount management on our own which expects
# refcount_bits=16
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
+# As for data files, they do not support snapshots at all.
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
# Parameters:
# $1: image filename
diff --git a/tests/qemu-iotests/265 b/tests/qemu-iotests/265
index dce6f77..00f2ec7 100755
--- a/tests/qemu-iotests/265
+++ b/tests/qemu-iotests/265
@@ -41,7 +41,7 @@ _supported_os Linux
echo '--- Writing to the image ---'
# Reduce cluster size so we get more and quicker I/O
-IMGOPTS='cluster_size=4096' _make_test_img 1M
+_make_test_img -o 'cluster_size=4096' 1M
(for ((kb = 1024 - 4; kb >= 0; kb -= 4)); do \
echo "aio_write -P 42 $((kb + 1))k 2k"; \
done) \
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
index b823668..c296877 100755
--- a/tests/qemu-iotests/267
+++ b/tests/qemu-iotests/267
@@ -42,8 +42,9 @@ _supported_proto file
_supported_os Linux
_require_drivers copy-on-read
-# Internal snapshots are (currently) impossible with refcount_bits=1
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
+# Internal snapshots are (currently) impossible with refcount_bits=1,
+# and generally impossible with external data files
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
do_run_qemu()
{
@@ -69,7 +70,11 @@ size=128M
run_test()
{
- _make_test_img $size
+ if [ -n "$BACKING_FILE" ]; then
+ _make_test_img -b "$BACKING_FILE" $size
+ else
+ _make_test_img $size
+ fi
printf "savevm snap0\ninfo snapshots\nloadvm snap0\n" | run_qemu "$@" | _filter_date
}
@@ -120,12 +125,12 @@ echo
TEST_IMG="$TEST_IMG.base" _make_test_img $size
-IMGOPTS="backing_file=$TEST_IMG.base" \
+BACKING_FILE="$TEST_IMG.base" \
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
-blockdev driver=$IMGFMT,file=file,backing=backing-file,node-name=fmt
-IMGOPTS="backing_file=$TEST_IMG.base" \
+BACKING_FILE="$TEST_IMG.base" \
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
-blockdev driver=$IMGFMT,file=backing-file,node-name=backing-fmt \
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
@@ -142,7 +147,7 @@ echo
echo "=== -blockdev with NBD server on the backing file ==="
echo
-IMGOPTS="backing_file=$TEST_IMG.base" _make_test_img $size
+_make_test_img -b "$TEST_IMG.base" $size
cat <<EOF |
nbd_server_start unix:$SOCK_DIR/nbd
nbd_server_add -w backing-fmt
diff --git a/tests/qemu-iotests/273 b/tests/qemu-iotests/273
index d598c47..00ff79b 100755
--- a/tests/qemu-iotests/273
+++ b/tests/qemu-iotests/273
@@ -37,6 +37,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# External data files would add nodes to the block graph, so it would
+# not match the reference output
+_unsupported_imgopts data_file
do_run_qemu()
{
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 90970b0..2890785 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -587,13 +587,13 @@ export QEMU_PROG="$(type -p "$QEMU_PROG")"
case "$QEMU_PROG" in
*qemu-system-arm|*qemu-system-aarch64)
- export QEMU_OPTIONS="-nodefaults -display none -machine virt,accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -machine virt -accel qtest"
;;
*qemu-system-tricore)
- export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard,accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard -accel qtest"
;;
*)
- export QEMU_OPTIONS="-nodefaults -display none -machine accel=qtest"
+ export QEMU_OPTIONS="-nodefaults -display none -accel qtest"
;;
esac
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 5367dee..3f8ee3e 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -122,7 +122,13 @@ _filter_actual_image_size()
# replace driver-specific options in the "Formatting..." line
_filter_img_create()
{
- $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
+ data_file_filter=()
+ if data_file=$(_get_data_file "$TEST_IMG"); then
+ data_file_filter=(-e "s# data_file=$data_file##")
+ fi
+
+ $SED "${data_file_filter[@]}" \
+ -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$SOCK_DIR#SOCK_DIR#g" \
@@ -209,9 +215,22 @@ _filter_img_info()
# human and json output
_filter_qemu_img_map()
{
+ # Assuming the data_file value in $IMGOPTS contains a '$TEST_IMG',
+ # create a filter that replaces the data file name by $TEST_IMG.
+ # Example:
+ # In $IMGOPTS: 'data_file=$TEST_IMG.data_file'
+ # Then data_file_pattern == '\(.*\).data_file'
+ # And data_file_filter == -e 's#\(.*\).data_file#\1#
+ data_file_filter=()
+ if data_file_pattern=$(_get_data_file '\\(.*\\)'); then
+ data_file_filter=(-e "s#$data_file_pattern#\\1#")
+ fi
+
$SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \
-e 's/"offset": [0-9]\+/"offset": OFFSET/g' \
- -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt
+ -e 's/Mapped to *//' \
+ "${data_file_filter[@]}" \
+ | _filter_testdir | _filter_imgfmt
}
_filter_nbd()
@@ -232,5 +251,29 @@ _filter_qmp_empty_return()
grep -v '{"return": {}}'
}
+_filter_json_filename()
+{
+ $PYTHON -c 'import sys
+result, *fnames = sys.stdin.read().split("json:{")
+depth = 0
+for fname in fnames:
+ depth += 1 # For the opening brace in the split separator
+ for chr_i, chr in enumerate(fname):
+ if chr == "{":
+ depth += 1
+ elif chr == "}":
+ depth -= 1
+ if depth == 0:
+ break
+
+ # json:{} filenames may be nested; filter out everything from
+ # inside the outermost one
+ if depth == 0:
+ chr_i += 1 # First character past the filename
+ result += "json:{ /* filtered */ }" + fname[chr_i:]
+
+sys.stdout.write(result)'
+}
+
# make sure this script returns success
true
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 555c453..d088392 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -298,17 +298,32 @@ _stop_nbd_server()
fi
}
+# Gets the data_file value from IMGOPTS and replaces the '$TEST_IMG'
+# pattern by '$1'
+# Caution: The replacement is done with sed, so $1 must be escaped
+# properly. (The delimiter is '#'.)
+_get_data_file()
+{
+ if ! echo "$IMGOPTS" | grep -q 'data_file='; then
+ return 1
+ fi
+
+ echo "$IMGOPTS" | sed -e 's/.*data_file=\([^,]*\).*/\1/' \
+ | sed -e "s#\\\$TEST_IMG#$1#"
+}
+
_make_test_img()
{
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
local extra_img_options=""
- local image_size=$*
local optstr=""
local img_name=""
local use_backing=0
local backing_file=""
local object_options=""
+ local opts_param=false
+ local misc_params=()
if [ -n "$TEST_IMG_FILE" ]; then
img_name=$TEST_IMG_FILE
@@ -317,18 +332,43 @@ _make_test_img()
fi
if [ -n "$IMGOPTS" ]; then
- optstr=$(_optstr_add "$optstr" "$IMGOPTS")
+ imgopts_expanded=$(echo "$IMGOPTS" | sed -e "s#\\\$TEST_IMG#$img_name#")
+ optstr=$(_optstr_add "$optstr" "$imgopts_expanded")
fi
if [ -n "$IMGKEYSECRET" ]; then
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
fi
- if [ "$1" = "-b" ]; then
- use_backing=1
- backing_file=$2
- image_size=$3
- fi
+ for param; do
+ if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
+ backing_file=$param
+ continue
+ elif $opts_param; then
+ optstr=$(_optstr_add "$optstr" "$param")
+ opts_param=false
+ continue
+ fi
+
+ case "$param" in
+ -b)
+ use_backing=1
+ ;;
+
+ -o)
+ opts_param=true
+ ;;
+
+ --no-opts)
+ optstr=""
+ ;;
+
+ *)
+ misc_params=("${misc_params[@]}" "$param")
+ ;;
+ esac
+ done
+
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
fi
@@ -344,9 +384,9 @@ _make_test_img()
# XXX(hch): have global image options?
(
if [ $use_backing = 1 ]; then
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" "${misc_params[@]}" 2>&1
else
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" "${misc_params[@]}" 2>&1
fi
) | _filter_img_create
@@ -375,6 +415,11 @@ _rm_test_img()
# Remove all the extents for vmdk
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
| xargs -I {} rm -f "{}"
+ elif [ "$IMGFMT" = "qcow2" ]; then
+ # Remove external data file
+ if data_file=$(_get_data_file "$img"); then
+ rm -f "$data_file"
+ fi
fi
rm -f "$img"
}
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 8739ec6..13fd8b5 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -811,15 +811,20 @@ class QMPTestCase(unittest.TestCase):
self.assert_no_active_block_jobs()
return result
- def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0):
+ def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0,
+ error=None):
'''Wait for a block job to finish, returning the event'''
while True:
for event in self.vm.get_qmp_events(wait=wait):
if event['event'] == 'BLOCK_JOB_COMPLETED':
self.assert_qmp(event, 'data/device', drive)
- self.assert_qmp_absent(event, 'data/error')
- if check_offset:
- self.assert_qmp(event, 'data/offset', event['data']['len'])
+ if error is None:
+ self.assert_qmp_absent(event, 'data/error')
+ if check_offset:
+ self.assert_qmp(event, 'data/offset',
+ event['data']['len'])
+ else:
+ self.assert_qmp(event, 'data/error', error)
self.assert_no_active_block_jobs()
return event
elif event['event'] == 'JOB_STATUS_CHANGE':
@@ -837,7 +842,8 @@ class QMPTestCase(unittest.TestCase):
self.assert_qmp(event, 'data/type', 'mirror')
self.assert_qmp(event, 'data/offset', event['data']['len'])
- def complete_and_wait(self, drive='drive0', wait_ready=True):
+ def complete_and_wait(self, drive='drive0', wait_ready=True,
+ completion_error=None):
'''Complete a block job and wait for it to finish'''
if wait_ready:
self.wait_ready(drive=drive)
@@ -845,7 +851,7 @@ class QMPTestCase(unittest.TestCase):
result = self.vm.qmp('block-job-complete', device=drive)
self.assert_qmp(result, 'return', {})
- event = self.wait_until_completed(drive=drive)
+ event = self.wait_until_completed(drive=drive, error=completion_error)
self.assert_qmp(event, 'data/type', 'mirror')
def pause_wait(self, job_id='job0'):
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
index b392972..91e4420 100755
--- a/tests/qemu-iotests/qcow2.py
+++ b/tests/qemu-iotests/qcow2.py
@@ -42,9 +42,9 @@ class QcowHeader:
[ uint64_t, '%#x', 'snapshot_offset' ],
# Version 3 header fields
- [ uint64_t, '%#x', 'incompatible_features' ],
- [ uint64_t, '%#x', 'compatible_features' ],
- [ uint64_t, '%#x', 'autoclear_features' ],
+ [ uint64_t, 'mask', 'incompatible_features' ],
+ [ uint64_t, 'mask', 'compatible_features' ],
+ [ uint64_t, 'mask', 'autoclear_features' ],
[ uint32_t, '%d', 'refcount_order' ],
[ uint32_t, '%d', 'header_length' ],
];
@@ -130,7 +130,17 @@ class QcowHeader:
def dump(self):
for f in QcowHeader.fields:
- print("%-25s" % f[2], f[1] % self.__dict__[f[2]])
+ value = self.__dict__[f[2]]
+ if f[1] == 'mask':
+ bits = []
+ for bit in range(64):
+ if value & (1 << bit):
+ bits.append(bit)
+ value_str = str(bits)
+ else:
+ value_str = f[1] % value
+
+ print("%-25s" % f[2], value_str)
print("")
def dump_extensions(self):
@@ -154,6 +164,10 @@ def cmd_dump_header(fd):
h.dump()
h.dump_extensions()
+def cmd_dump_header_exts(fd):
+ h = QcowHeader(fd)
+ h.dump_extensions()
+
def cmd_set_header(fd, name, value):
try:
value = int(value, 0)
@@ -230,6 +244,7 @@ def cmd_set_feature_bit(fd, group, bit):
cmds = [
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
+ [ 'dump-header-exts', cmd_dump_header_exts, 0, 'Dump image header extensions' ],
[ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
[ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
[ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ],
diff --git a/ui/console.c b/ui/console.c
index 82d1dda..ac79d67 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -33,6 +33,7 @@
#include "chardev/char-fe.h"
#include "trace.h"
#include "exec/memory.h"
+#include "io/channel-file.h"
#define DEFAULT_BACKSCROLL 512
#define CONSOLE_CURSOR_PERIOD 500
@@ -193,6 +194,7 @@ static void dpy_refresh(DisplayState *s);
static DisplayState *get_alloc_displaystate(void);
static void text_console_update_cursor_timer(void);
static void text_console_update_cursor(void *opaque);
+static bool ppm_save(int fd, DisplaySurface *ds, Error **errp);
static void gui_update(void *opaque)
{
@@ -259,13 +261,22 @@ static void gui_setup_refresh(DisplayState *ds)
ds->have_text = have_text;
}
+void graphic_hw_update_done(QemuConsole *con)
+{
+}
+
void graphic_hw_update(QemuConsole *con)
{
+ bool async = false;
if (!con) {
con = active_console;
}
if (con && con->hw_ops->gfx_update) {
con->hw_ops->gfx_update(con->hw);
+ async = con->hw_ops->gfx_update_async;
+ }
+ if (!async) {
+ graphic_hw_update_done(con);
}
}
@@ -299,52 +310,34 @@ void graphic_hw_invalidate(QemuConsole *con)
}
}
-static void ppm_save(const char *filename, DisplaySurface *ds,
- Error **errp)
+static bool ppm_save(int fd, DisplaySurface *ds, Error **errp)
{
int width = pixman_image_get_width(ds->image);
int height = pixman_image_get_height(ds->image);
- int fd;
- FILE *f;
+ g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
+ g_autofree char *header = NULL;
+ g_autoptr(pixman_image_t) linebuf = NULL;
int y;
- int ret;
- pixman_image_t *linebuf;
- trace_ppm_save(filename, ds);
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
- if (fd == -1) {
- error_setg(errp, "failed to open file '%s': %s", filename,
- strerror(errno));
- return;
- }
- f = fdopen(fd, "wb");
- ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
- if (ret < 0) {
- linebuf = NULL;
- goto write_err;
+ trace_ppm_save(fd, ds);
+
+ header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
+ if (qio_channel_write_all(QIO_CHANNEL(ioc),
+ header, strlen(header), errp) < 0) {
+ return false;
}
+
linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
for (y = 0; y < height; y++) {
qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
- clearerr(f);
- ret = fwrite(pixman_image_get_data(linebuf), 1,
- pixman_image_get_stride(linebuf), f);
- (void)ret;
- if (ferror(f)) {
- goto write_err;
+ if (qio_channel_write_all(QIO_CHANNEL(ioc),
+ (char *)pixman_image_get_data(linebuf),
+ pixman_image_get_stride(linebuf), errp) < 0) {
+ return false;
}
}
-out:
- qemu_pixman_image_unref(linebuf);
- fclose(f);
- return;
-
-write_err:
- error_setg(errp, "failed to write to file '%s': %s", filename,
- strerror(errno));
- unlink(filename);
- goto out;
+ return true;
}
void qmp_screendump(const char *filename, bool has_device, const char *device,
@@ -352,6 +345,7 @@ void qmp_screendump(const char *filename, bool has_device, const char *device,
{
QemuConsole *con;
DisplaySurface *surface;
+ int fd;
if (has_device) {
con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
@@ -378,7 +372,16 @@ void qmp_screendump(const char *filename, bool has_device, const char *device,
return;
}
- ppm_save(filename, surface, errp);
+ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (fd == -1) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
+ return;
+ }
+
+ if (!ppm_save(fd, surface, errp)) {
+ qemu_unlink(filename);
+ }
}
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
diff --git a/ui/trace-events b/ui/trace-events
index 63de72a..0dcda39 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -15,7 +15,7 @@ displaysurface_create_pixman(void *display_surface) "surface=%p"
displaysurface_free(void *display_surface) "surface=%p"
displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]"
displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]"
-ppm_save(const char *filename, void *display_surface) "%s surface=%p"
+ppm_save(int fd, void *display_surface) "fd=%d surface=%p"
# gtk.c
# gtk-gl-area.c
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 63599d6..11262aa 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -56,3 +56,6 @@ util-obj-$(call lnot,$(CONFIG_INOTIFY1)) += filemonitor-stub.o
util-obj-$(CONFIG_LINUX) += vfio-helpers.o
util-obj-$(CONFIG_POSIX) += drm.o
util-obj-y += guest-random.o
+util-obj-$(CONFIG_GIO) += dbus.o
+dbus.o-cflags = $(GIO_CFLAGS)
+dbus.o-libs = $(GIO_LIBS)
diff --git a/util/dbus.c b/util/dbus.c
new file mode 100644
index 0000000..9099dc5
--- /dev/null
+++ b/util/dbus.c
@@ -0,0 +1,57 @@
+/*
+ * Helpers for using D-Bus
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/dbus.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+/*
+ * qemu_dbus_get_queued_owners() - return the list of queued unique names
+ * @connection: A GDBusConnection
+ * @name: a service name
+ *
+ * Return: a GStrv of unique names, or NULL on failure.
+ */
+GStrv
+qemu_dbus_get_queued_owners(GDBusConnection *connection, const char *name,
+ Error **errp)
+{
+ g_autoptr(GDBusProxy) proxy = NULL;
+ g_autoptr(GVariant) result = NULL;
+ g_autoptr(GVariant) child = NULL;
+ g_autoptr(GError) err = NULL;
+
+ proxy = g_dbus_proxy_new_sync(connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ NULL, &err);
+ if (!proxy) {
+ error_setg(errp, "Failed to create DBus proxy: %s", err->message);
+ return NULL;
+ }
+
+ result = g_dbus_proxy_call_sync(proxy, "ListQueuedOwners",
+ g_variant_new("(s)", name),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, &err);
+ if (!result) {
+ if (g_error_matches(err,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER)) {
+ return g_new0(char *, 1);
+ }
+ error_setg(errp, "Failed to call ListQueuedOwners: %s", err->message);
+ return NULL;
+ }
+
+ child = g_variant_get_child_value(result, 0);
+ return g_variant_dup_strv(child, NULL);
+}
diff --git a/util/osdep.c b/util/osdep.c
index 3f04326..f7d0605 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -371,6 +371,21 @@ int qemu_close(int fd)
}
/*
+ * Delete a file from the filesystem, unless the filename is /dev/fdset/...
+ *
+ * Returns: On success, zero is returned. On error, -1 is returned,
+ * and errno is set appropriately.
+ */
+int qemu_unlink(const char *name)
+{
+ if (g_str_has_prefix(name, "/dev/fdset/")) {
+ return 0;
+ }
+
+ return unlink(name);
+}
+
+/*
* A variant of write(2) which handles partial write.
*
* Return the number of bytes transferred.